5 * Truncate handling routines for the OSTA-UDF(tm) filesystem.
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.
13 * (C) 1999-2004 Ben Fennema
14 * (C) 1999 Stelias Computing Inc
18 * 02/24/99 blf Created.
25 #include <linux/udf_fs.h>
26 #include <linux/buffer_head.h>
31 static void extent_trunc(struct inode
* inode
, struct extent_position
*epos
,
32 kernel_lb_addr eloc
, int8_t etype
, uint32_t elen
, uint32_t nelen
)
34 kernel_lb_addr neloc
= { 0, 0 };
35 int last_block
= (elen
+ inode
->i_sb
->s_blocksize
- 1) >> inode
->i_sb
->s_blocksize_bits
;
36 int first_block
= (nelen
+ inode
->i_sb
->s_blocksize
- 1) >> inode
->i_sb
->s_blocksize_bits
;
40 if (etype
== (EXT_NOT_RECORDED_ALLOCATED
>> 30))
42 udf_free_blocks(inode
->i_sb
, inode
, eloc
, 0, last_block
);
43 etype
= (EXT_NOT_RECORDED_NOT_ALLOCATED
>> 30);
47 nelen
= (etype
<< 30) | nelen
;
52 udf_write_aext(inode
, epos
, neloc
, nelen
, 0);
53 if (last_block
- first_block
> 0)
55 if (etype
== (EXT_RECORDED_ALLOCATED
>> 30))
56 mark_inode_dirty(inode
);
58 if (etype
!= (EXT_NOT_RECORDED_NOT_ALLOCATED
>> 30))
59 udf_free_blocks(inode
->i_sb
, inode
, eloc
, first_block
, last_block
- first_block
);
64 void udf_discard_prealloc(struct inode
* inode
)
66 struct extent_position epos
= { NULL
, 0, {0, 0}};
70 int8_t etype
= -1, netype
;
73 if (UDF_I_ALLOCTYPE(inode
) == ICBTAG_FLAG_AD_IN_ICB
||
74 inode
->i_size
== UDF_I_LENEXTENTS(inode
))
77 if (UDF_I_ALLOCTYPE(inode
) == ICBTAG_FLAG_AD_SHORT
)
78 adsize
= sizeof(short_ad
);
79 else if (UDF_I_ALLOCTYPE(inode
) == ICBTAG_FLAG_AD_LONG
)
80 adsize
= sizeof(long_ad
);
84 epos
.block
= UDF_I_LOCATION(inode
);
86 /* Find the last extent in the file */
87 while ((netype
= udf_next_aext(inode
, &epos
, &eloc
, &elen
, 1)) != -1)
91 if (lbcount
> inode
->i_size
&& lbcount
- elen
< inode
->i_size
)
93 WARN_ON(lbcount
- inode
->i_size
>= inode
->i_sb
->s_blocksize
);
94 nelen
= elen
- (lbcount
- inode
->i_size
);
95 epos
.offset
-= adsize
;
96 extent_trunc(inode
, &epos
, eloc
, etype
, elen
, nelen
);
97 epos
.offset
+= adsize
;
98 lbcount
= inode
->i_size
;
101 if (etype
== (EXT_NOT_RECORDED_ALLOCATED
>> 30)) {
102 epos
.offset
-= adsize
;
104 extent_trunc(inode
, &epos
, eloc
, etype
, elen
, 0);
107 UDF_I_LENALLOC(inode
) = epos
.offset
- udf_file_entry_alloc_offset(inode
);
108 mark_inode_dirty(inode
);
112 struct allocExtDesc
*aed
= (struct allocExtDesc
*)(epos
.bh
->b_data
);
113 aed
->lengthAllocDescs
= cpu_to_le32(epos
.offset
- sizeof(struct allocExtDesc
));
114 if (!UDF_QUERY_FLAG(inode
->i_sb
, UDF_FLAG_STRICT
) || UDF_SB_UDFREV(inode
->i_sb
) >= 0x0201)
115 udf_update_tag(epos
.bh
->b_data
, epos
.offset
);
117 udf_update_tag(epos
.bh
->b_data
, sizeof(struct allocExtDesc
));
118 mark_buffer_dirty_inode(epos
.bh
, inode
);
121 UDF_I_LENEXTENTS(inode
) = lbcount
;
123 WARN_ON(lbcount
!= inode
->i_size
);
127 void udf_truncate_extents(struct inode
* inode
)
129 struct extent_position epos
;
130 kernel_lb_addr eloc
, neloc
= { 0, 0 };
131 uint32_t elen
, nelen
= 0, indirect_ext_len
= 0, lenalloc
;
133 struct super_block
*sb
= inode
->i_sb
;
134 sector_t first_block
= inode
->i_size
>> sb
->s_blocksize_bits
, offset
;
138 if (UDF_I_ALLOCTYPE(inode
) == ICBTAG_FLAG_AD_SHORT
)
139 adsize
= sizeof(short_ad
);
140 else if (UDF_I_ALLOCTYPE(inode
) == ICBTAG_FLAG_AD_LONG
)
141 adsize
= sizeof(long_ad
);
145 etype
= inode_bmap(inode
, first_block
, &epos
, &eloc
, &elen
, &offset
);
146 byte_offset
= (offset
<< sb
->s_blocksize_bits
) + (inode
->i_size
& (sb
->s_blocksize
-1));
149 epos
.offset
-= adsize
;
150 extent_trunc(inode
, &epos
, eloc
, etype
, elen
, byte_offset
);
151 epos
.offset
+= adsize
;
153 lenalloc
= epos
.offset
;
155 lenalloc
= epos
.offset
- adsize
;
158 lenalloc
-= udf_file_entry_alloc_offset(inode
);
160 lenalloc
-= sizeof(struct allocExtDesc
);
162 while ((etype
= udf_current_aext(inode
, &epos
, &eloc
, &elen
, 0)) != -1)
164 if (etype
== (EXT_NEXT_EXTENT_ALLOCDECS
>> 30))
166 udf_write_aext(inode
, &epos
, neloc
, nelen
, 0);
167 if (indirect_ext_len
)
169 /* We managed to free all extents in the
170 * indirect extent - free it too */
173 udf_free_blocks(sb
, inode
, epos
.block
, 0, indirect_ext_len
);
179 UDF_I_LENALLOC(inode
) = lenalloc
;
180 mark_inode_dirty(inode
);
184 struct allocExtDesc
*aed
= (struct allocExtDesc
*)(epos
.bh
->b_data
);
185 aed
->lengthAllocDescs
= cpu_to_le32(lenalloc
);
186 if (!UDF_QUERY_FLAG(sb
, UDF_FLAG_STRICT
) || UDF_SB_UDFREV(sb
) >= 0x0201)
187 udf_update_tag(epos
.bh
->b_data
, lenalloc
+
188 sizeof(struct allocExtDesc
));
190 udf_update_tag(epos
.bh
->b_data
, sizeof(struct allocExtDesc
));
191 mark_buffer_dirty_inode(epos
.bh
, inode
);
195 epos
.offset
= sizeof(struct allocExtDesc
);
197 epos
.bh
= udf_tread(sb
, udf_get_lb_pblock(sb
, eloc
, 0));
199 indirect_ext_len
= (elen
+
200 sb
->s_blocksize
- 1) >>
201 sb
->s_blocksize_bits
;
203 indirect_ext_len
= 1;
207 extent_trunc(inode
, &epos
, eloc
, etype
, elen
, 0);
208 epos
.offset
+= adsize
;
212 if (indirect_ext_len
)
216 udf_free_blocks(sb
, inode
, epos
.block
, 0, indirect_ext_len
);
222 UDF_I_LENALLOC(inode
) = lenalloc
;
223 mark_inode_dirty(inode
);
227 struct allocExtDesc
*aed
= (struct allocExtDesc
*)(epos
.bh
->b_data
);
228 aed
->lengthAllocDescs
= cpu_to_le32(lenalloc
);
229 if (!UDF_QUERY_FLAG(sb
, UDF_FLAG_STRICT
) || UDF_SB_UDFREV(sb
) >= 0x0201)
230 udf_update_tag(epos
.bh
->b_data
, lenalloc
+
231 sizeof(struct allocExtDesc
));
233 udf_update_tag(epos
.bh
->b_data
, sizeof(struct allocExtDesc
));
234 mark_buffer_dirty_inode(epos
.bh
, inode
);
238 else if (inode
->i_size
)
242 kernel_long_ad extent
;
245 * OK, there is not extent covering inode->i_size and
246 * no extent above inode->i_size => truncate is
247 * extending the file by 'offset' blocks.
249 if ((!epos
.bh
&& epos
.offset
== udf_file_entry_alloc_offset(inode
)) ||
250 (epos
.bh
&& epos
.offset
== sizeof(struct allocExtDesc
))) {
251 /* File has no extents at all or has empty last
252 * indirect extent! Create a fake extent... */
253 extent
.extLocation
.logicalBlockNum
= 0;
254 extent
.extLocation
.partitionReferenceNum
= 0;
255 extent
.extLength
= EXT_NOT_RECORDED_NOT_ALLOCATED
;
258 epos
.offset
-= adsize
;
259 etype
= udf_next_aext(inode
, &epos
,
260 &extent
.extLocation
, &extent
.extLength
, 0);
261 extent
.extLength
|= etype
<< 30;
263 udf_extend_file(inode
, &epos
, &extent
, offset
+((inode
->i_size
& (sb
->s_blocksize
-1)) != 0));
266 UDF_I_LENEXTENTS(inode
) = inode
->i_size
;