aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf/truncate.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2007-05-08 03:35:21 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:21 -0400
commit31170b6ad4ebe6c43c1cc3b8112274cf59474de0 (patch)
tree25e19a70a323f18757c60a658d930b63e8e45124 /fs/udf/truncate.c
parent948b9b2c967c3bec6136b2dbb9e1c12f62e03efa (diff)
udf: support files larger than 1G
Make UDF work correctly for files larger than 1GB. As no extent can be longer than (1<<30)-blocksize bytes, we have to create several extents if a big hole is being created. As a side-effect, we now don't discard preallocated blocks when creating a hole. Signed-off-by: Jan Kara <jack@suse.cz> Acked-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/udf/truncate.c')
-rw-r--r--fs/udf/truncate.c68
1 files changed, 22 insertions, 46 deletions
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 0e328cdc9a45..77975ae291a5 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -130,7 +130,8 @@ void udf_truncate_extents(struct inode * inode)
130 kernel_lb_addr eloc, neloc = { 0, 0 }; 130 kernel_lb_addr eloc, neloc = { 0, 0 };
131 uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; 131 uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
132 int8_t etype; 132 int8_t etype;
133 sector_t first_block = inode->i_size >> inode->i_sb->s_blocksize_bits, offset; 133 struct super_block *sb = inode->i_sb;
134 sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
134 loff_t byte_offset; 135 loff_t byte_offset;
135 int adsize; 136 int adsize;
136 137
@@ -142,7 +143,7 @@ void udf_truncate_extents(struct inode * inode)
142 BUG(); 143 BUG();
143 144
144 etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); 145 etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
145 byte_offset = (offset << inode->i_sb->s_blocksize_bits) + (inode->i_size & (inode->i_sb->s_blocksize-1)); 146 byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1));
146 if (etype != -1) 147 if (etype != -1)
147 { 148 {
148 epos.offset -= adsize; 149 epos.offset -= adsize;
@@ -169,7 +170,7 @@ void udf_truncate_extents(struct inode * inode)
169 * indirect extent - free it too */ 170 * indirect extent - free it too */
170 if (!epos.bh) 171 if (!epos.bh)
171 BUG(); 172 BUG();
172 udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len); 173 udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
173 } 174 }
174 else 175 else
175 { 176 {
@@ -182,7 +183,7 @@ void udf_truncate_extents(struct inode * inode)
182 { 183 {
183 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data); 184 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
184 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 185 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
185 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 186 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
186 udf_update_tag(epos.bh->b_data, lenalloc + 187 udf_update_tag(epos.bh->b_data, lenalloc +
187 sizeof(struct allocExtDesc)); 188 sizeof(struct allocExtDesc));
188 else 189 else
@@ -193,11 +194,11 @@ void udf_truncate_extents(struct inode * inode)
193 brelse(epos.bh); 194 brelse(epos.bh);
194 epos.offset = sizeof(struct allocExtDesc); 195 epos.offset = sizeof(struct allocExtDesc);
195 epos.block = eloc; 196 epos.block = eloc;
196 epos.bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, eloc, 0)); 197 epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
197 if (elen) 198 if (elen)
198 indirect_ext_len = (elen + 199 indirect_ext_len = (elen +
199 inode->i_sb->s_blocksize - 1) >> 200 sb->s_blocksize - 1) >>
200 inode->i_sb->s_blocksize_bits; 201 sb->s_blocksize_bits;
201 else 202 else
202 indirect_ext_len = 1; 203 indirect_ext_len = 1;
203 } 204 }
@@ -212,7 +213,7 @@ void udf_truncate_extents(struct inode * inode)
212 { 213 {
213 if (!epos.bh) 214 if (!epos.bh)
214 BUG(); 215 BUG();
215 udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len); 216 udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
216 } 217 }
217 else 218 else
218 { 219 {
@@ -225,7 +226,7 @@ void udf_truncate_extents(struct inode * inode)
225 { 226 {
226 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data); 227 struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
227 aed->lengthAllocDescs = cpu_to_le32(lenalloc); 228 aed->lengthAllocDescs = cpu_to_le32(lenalloc);
228 if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) 229 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
229 udf_update_tag(epos.bh->b_data, lenalloc + 230 udf_update_tag(epos.bh->b_data, lenalloc +
230 sizeof(struct allocExtDesc)); 231 sizeof(struct allocExtDesc));
231 else 232 else
@@ -238,53 +239,28 @@ void udf_truncate_extents(struct inode * inode)
238 { 239 {
239 if (byte_offset) 240 if (byte_offset)
240 { 241 {
242 kernel_long_ad extent;
243
241 /* 244 /*
242 * OK, there is not extent covering inode->i_size and 245 * OK, there is not extent covering inode->i_size and
243 * no extent above inode->i_size => truncate is 246 * no extent above inode->i_size => truncate is
244 * extending the file by 'offset'. 247 * extending the file by 'offset' blocks.
245 */ 248 */
246 if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || 249 if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
247 (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { 250 (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
248 /* File has no extents at all! */ 251 /* File has no extents at all or has empty last
249 memset(&eloc, 0x00, sizeof(kernel_lb_addr)); 252 * indirect extent! Create a fake extent... */
250 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset; 253 extent.extLocation.logicalBlockNum = 0;
251 udf_add_aext(inode, &epos, eloc, elen, 1); 254 extent.extLocation.partitionReferenceNum = 0;
255 extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
252 } 256 }
253 else { 257 else {
254 epos.offset -= adsize; 258 epos.offset -= adsize;
255 etype = udf_next_aext(inode, &epos, &eloc, &elen, 1); 259 etype = udf_next_aext(inode, &epos,
256 260 &extent.extLocation, &extent.extLength, 0);
257 if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 261 extent.extLength |= etype << 30;
258 {
259 epos.offset -= adsize;
260 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + byte_offset);
261 udf_write_aext(inode, &epos, eloc, elen, 0);
262 }
263 else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
264 {
265 kernel_lb_addr neloc = { 0, 0 };
266 epos.offset -= adsize;
267 nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
268 ((elen + byte_offset + inode->i_sb->s_blocksize - 1) &
269 ~(inode->i_sb->s_blocksize - 1));
270 udf_write_aext(inode, &epos, neloc, nelen, 1);
271 udf_add_aext(inode, &epos, eloc, (etype << 30) | elen, 1);
272 }
273 else
274 {
275 if (elen & (inode->i_sb->s_blocksize - 1))
276 {
277 epos.offset -= adsize;
278 elen = EXT_RECORDED_ALLOCATED |
279 ((elen + inode->i_sb->s_blocksize - 1) &
280 ~(inode->i_sb->s_blocksize - 1));
281 udf_write_aext(inode, &epos, eloc, elen, 1);
282 }
283 memset(&eloc, 0x00, sizeof(kernel_lb_addr));
284 elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset;
285 udf_add_aext(inode, &epos, eloc, elen, 1);
286 }
287 } 262 }
263 udf_extend_file(inode, &epos, &extent, offset+((inode->i_size & (sb->s_blocksize-1)) != 0));
288 } 264 }
289 } 265 }
290 UDF_I_LENEXTENTS(inode) = inode->i_size; 266 UDF_I_LENEXTENTS(inode) = inode->i_size;