OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [udf/] [truncate.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * truncate.c
3
 *
4
 * PURPOSE
5
 *      Truncate handling routines for the OSTA-UDF(tm) filesystem.
6
 *
7
 * COPYRIGHT
8
 *      This file is distributed under the terms of the GNU General Public
9
 *      License (GPL). Copies of the GPL can be obtained from:
10
 *              ftp://prep.ai.mit.edu/pub/gnu/GPL
11
 *      Each contributing author retains all rights to their own work.
12
 *
13
 *  (C) 1999-2004 Ben Fennema
14
 *  (C) 1999 Stelias Computing Inc
15
 *
16
 * HISTORY
17
 *
18
 *  02/24/99 blf  Created.
19
 *
20
 */
21
 
22
#include "udfdecl.h"
23
#include <linux/fs.h>
24
#include <linux/mm.h>
25
#include <linux/udf_fs.h>
26
#include <linux/buffer_head.h>
27
 
28
#include "udf_i.h"
29
#include "udf_sb.h"
30
 
31
static void extent_trunc(struct inode *inode, struct extent_position *epos,
32
                         kernel_lb_addr eloc, int8_t etype, uint32_t elen,
33
                         uint32_t nelen)
34
{
35
        kernel_lb_addr neloc = {};
36
        int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
37
                inode->i_sb->s_blocksize_bits;
38
        int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
39
                inode->i_sb->s_blocksize_bits;
40
 
41
        if (nelen) {
42
                if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
43
                        udf_free_blocks(inode->i_sb, inode, eloc, 0,
44
                                        last_block);
45
                        etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
46
                } else
47
                        neloc = eloc;
48
                nelen = (etype << 30) | nelen;
49
        }
50
 
51
        if (elen != nelen) {
52
                udf_write_aext(inode, epos, neloc, nelen, 0);
53
                if (last_block - first_block > 0) {
54
                        if (etype == (EXT_RECORDED_ALLOCATED >> 30))
55
                                mark_inode_dirty(inode);
56
 
57
                        if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
58
                                udf_free_blocks(inode->i_sb, inode, eloc,
59
                                                first_block,
60
                                                last_block - first_block);
61
                }
62
        }
63
}
64
 
65
/*
66
 * Truncate the last extent to match i_size. This function assumes
67
 * that preallocation extent is already truncated.
68
 */
69
void udf_truncate_tail_extent(struct inode *inode)
70
{
71
        struct extent_position epos = {};
72
        kernel_lb_addr eloc;
73
        uint32_t elen, nelen;
74
        uint64_t lbcount = 0;
75
        int8_t etype = -1, netype;
76
        int adsize;
77
 
78
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
79
            inode->i_size == UDF_I_LENEXTENTS(inode))
80
                return;
81
        /* Are we going to delete the file anyway? */
82
        if (inode->i_nlink == 0)
83
                return;
84
 
85
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
86
                adsize = sizeof(short_ad);
87
        else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
88
                adsize = sizeof(long_ad);
89
        else
90
                BUG();
91
 
92
        /* Find the last extent in the file */
93
        while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
94
                etype = netype;
95
                lbcount += elen;
96
                if (lbcount > inode->i_size) {
97
                        if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
98
                                printk(KERN_WARNING
99
                                       "udf_truncate_tail_extent(): Too long "
100
                                       "extent after EOF in inode %u: i_size: "
101
                                       "%Ld lbcount: %Ld extent %u+%u\n",
102
                                       (unsigned)inode->i_ino,
103
                                       (long long)inode->i_size,
104
                                       (long long)lbcount,
105
                                       (unsigned)eloc.logicalBlockNum,
106
                                       (unsigned)elen);
107
                        nelen = elen - (lbcount - inode->i_size);
108
                        epos.offset -= adsize;
109
                        extent_trunc(inode, &epos, eloc, etype, elen, nelen);
110
                        epos.offset += adsize;
111
                        if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
112
                                printk(KERN_ERR "udf_truncate_tail_extent(): "
113
                                       "Extent after EOF in inode %u.\n",
114
                                       (unsigned)inode->i_ino);
115
                        break;
116
                }
117
        }
118
        /* This inode entry is in-memory only and thus we don't have to mark
119
         * the inode dirty */
120
        UDF_I_LENEXTENTS(inode) = inode->i_size;
121
        brelse(epos.bh);
122
}
123
 
124
void udf_discard_prealloc(struct inode *inode)
125
{
126
        struct extent_position epos = { NULL, 0, {0, 0} };
127
        kernel_lb_addr eloc;
128
        uint32_t elen;
129
        uint64_t lbcount = 0;
130
        int8_t etype = -1, netype;
131
        int adsize;
132
 
133
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
134
            inode->i_size == UDF_I_LENEXTENTS(inode))
135
                return;
136
 
137
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
138
                adsize = sizeof(short_ad);
139
        else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
140
                adsize = sizeof(long_ad);
141
        else
142
                adsize = 0;
143
 
144
        epos.block = UDF_I_LOCATION(inode);
145
 
146
        /* Find the last extent in the file */
147
        while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
148
                etype = netype;
149
                lbcount += elen;
150
        }
151
        if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
152
                epos.offset -= adsize;
153
                lbcount -= elen;
154
                extent_trunc(inode, &epos, eloc, etype, elen, 0);
155
                if (!epos.bh) {
156
                        UDF_I_LENALLOC(inode) =
157
                                epos.offset - udf_file_entry_alloc_offset(inode);
158
                        mark_inode_dirty(inode);
159
                } else {
160
                        struct allocExtDesc *aed =
161
                                (struct allocExtDesc *)(epos.bh->b_data);
162
                        aed->lengthAllocDescs =
163
                                cpu_to_le32(epos.offset -
164
                                            sizeof(struct allocExtDesc));
165
                        if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
166
                            UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
167
                                udf_update_tag(epos.bh->b_data, epos.offset);
168
                        else
169
                                udf_update_tag(epos.bh->b_data,
170
                                               sizeof(struct allocExtDesc));
171
                        mark_buffer_dirty_inode(epos.bh, inode);
172
                }
173
        }
174
        /* This inode entry is in-memory only and thus we don't have to mark
175
         * the inode dirty */
176
        UDF_I_LENEXTENTS(inode) = lbcount;
177
        brelse(epos.bh);
178
}
179
 
180
void udf_truncate_extents(struct inode *inode)
181
{
182
        struct extent_position epos;
183
        kernel_lb_addr eloc, neloc = {};
184
        uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
185
        int8_t etype;
186
        struct super_block *sb = inode->i_sb;
187
        sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
188
        loff_t byte_offset;
189
        int adsize;
190
 
191
        if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
192
                adsize = sizeof(short_ad);
193
        else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
194
                adsize = sizeof(long_ad);
195
        else
196
                BUG();
197
 
198
        etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
199
        byte_offset = (offset << sb->s_blocksize_bits) +
200
                (inode->i_size & (sb->s_blocksize - 1));
201
        if (etype != -1) {
202
                epos.offset -= adsize;
203
                extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
204
                epos.offset += adsize;
205
                if (byte_offset)
206
                        lenalloc = epos.offset;
207
                else
208
                        lenalloc = epos.offset - adsize;
209
 
210
                if (!epos.bh)
211
                        lenalloc -= udf_file_entry_alloc_offset(inode);
212
                else
213
                        lenalloc -= sizeof(struct allocExtDesc);
214
 
215
                while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
216
                        if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
217
                                udf_write_aext(inode, &epos, neloc, nelen, 0);
218
                                if (indirect_ext_len) {
219
                                        /* We managed to free all extents in the
220
                                         * indirect extent - free it too */
221
                                        if (!epos.bh)
222
                                                BUG();
223
                                        udf_free_blocks(sb, inode, epos.block,
224
                                                        0, indirect_ext_len);
225
                                } else {
226
                                        if (!epos.bh) {
227
                                                UDF_I_LENALLOC(inode) = lenalloc;
228
                                                mark_inode_dirty(inode);
229
                                        } else {
230
                                                struct allocExtDesc *aed =
231
                                                        (struct allocExtDesc *)(epos.bh->b_data);
232
                                                aed->lengthAllocDescs =
233
                                                    cpu_to_le32(lenalloc);
234
                                                if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
235
                                                    UDF_SB_UDFREV(sb) >= 0x0201)
236
                                                        udf_update_tag(epos.bh->b_data,
237
                                                                       lenalloc +
238
                                                                       sizeof(struct allocExtDesc));
239
                                                else
240
                                                        udf_update_tag(epos.bh->b_data,
241
                                                                       sizeof(struct allocExtDesc));
242
                                                mark_buffer_dirty_inode(epos.bh, inode);
243
                                        }
244
                                }
245
                                brelse(epos.bh);
246
                                epos.offset = sizeof(struct allocExtDesc);
247
                                epos.block = eloc;
248
                                epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
249
                                if (elen)
250
                                        indirect_ext_len = (elen + sb->s_blocksize -1) >>
251
                                                sb->s_blocksize_bits;
252
                                else
253
                                        indirect_ext_len = 1;
254
                        } else {
255
                                extent_trunc(inode, &epos, eloc, etype, elen, 0);
256
                                epos.offset += adsize;
257
                        }
258
                }
259
 
260
                if (indirect_ext_len) {
261
                        if (!epos.bh)
262
                                BUG();
263
                        udf_free_blocks(sb, inode, epos.block, 0,
264
                                        indirect_ext_len);
265
                } else {
266
                        if (!epos.bh) {
267
                                UDF_I_LENALLOC(inode) = lenalloc;
268
                                mark_inode_dirty(inode);
269
                        } else {
270
                                struct allocExtDesc *aed =
271
                                    (struct allocExtDesc *)(epos.bh->b_data);
272
                                aed->lengthAllocDescs = cpu_to_le32(lenalloc);
273
                                if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
274
                                    UDF_SB_UDFREV(sb) >= 0x0201)
275
                                        udf_update_tag(epos.bh->b_data,
276
                                                       lenalloc + sizeof(struct allocExtDesc));
277
                                else
278
                                        udf_update_tag(epos.bh->b_data,
279
                                                       sizeof(struct allocExtDesc));
280
                                mark_buffer_dirty_inode(epos.bh, inode);
281
                        }
282
                }
283
        } else if (inode->i_size) {
284
                if (byte_offset) {
285
                        kernel_long_ad extent;
286
 
287
                        /*
288
                         *  OK, there is not extent covering inode->i_size and
289
                         *  no extent above inode->i_size => truncate is
290
                         *  extending the file by 'offset' blocks.
291
                         */
292
                        if ((!epos.bh &&
293
                             epos.offset == udf_file_entry_alloc_offset(inode)) ||
294
                            (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
295
                                /* File has no extents at all or has empty last
296
                                 * indirect extent! Create a fake extent... */
297
                                extent.extLocation.logicalBlockNum = 0;
298
                                extent.extLocation.partitionReferenceNum = 0;
299
                                extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
300
                        } else {
301
                                epos.offset -= adsize;
302
                                etype = udf_next_aext(inode, &epos,
303
                                                      &extent.extLocation,
304
                                                      &extent.extLength, 0);
305
                                extent.extLength |= etype << 30;
306
                        }
307
                        udf_extend_file(inode, &epos, &extent,
308
                                        offset + ((inode->i_size & (sb->s_blocksize - 1)) != 0));
309
                }
310
        }
311
        UDF_I_LENEXTENTS(inode) = inode->i_size;
312
 
313
        brelse(epos.bh);
314
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.