aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/udf/inode.c192
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/udf/truncate.c68
3 files changed, 180 insertions, 82 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 2171bcfeec20..c8461551e108 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -356,9 +356,106 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
356 return NULL; 356 return NULL;
357} 357}
358 358
359/* Extend the file by 'blocks' blocks, return the number of extents added */
360int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
361 kernel_long_ad *last_ext, sector_t blocks)
362{
363 sector_t add;
364 int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
365 struct super_block *sb = inode->i_sb;
366 kernel_lb_addr prealloc_loc = {0, 0};
367 int prealloc_len = 0;
368
369 /* The previous extent is fake and we should not extend by anything
370 * - there's nothing to do... */
371 if (!blocks && fake)
372 return 0;
373 /* Round the last extent up to a multiple of block size */
374 if (last_ext->extLength & (sb->s_blocksize - 1)) {
375 last_ext->extLength =
376 (last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
377 (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
378 sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
379 UDF_I_LENEXTENTS(inode) =
380 (UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
381 ~(sb->s_blocksize - 1);
382 }
383 /* Last extent are just preallocated blocks? */
384 if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
385 /* Save the extent so that we can reattach it to the end */
386 prealloc_loc = last_ext->extLocation;
387 prealloc_len = last_ext->extLength;
388 /* Mark the extent as a hole */
389 last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
390 (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
391 last_ext->extLocation.logicalBlockNum = 0;
392 last_ext->extLocation.partitionReferenceNum = 0;
393 }
394 /* Can we merge with the previous extent? */
395 if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
396 add = ((1<<30) - sb->s_blocksize - (last_ext->extLength &
397 UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
398 if (add > blocks)
399 add = blocks;
400 blocks -= add;
401 last_ext->extLength += add << sb->s_blocksize_bits;
402 }
403
404 if (fake) {
405 udf_add_aext(inode, last_pos, last_ext->extLocation,
406 last_ext->extLength, 1);
407 count++;
408 }
409 else
410 udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
411 /* Managed to do everything necessary? */
412 if (!blocks)
413 goto out;
414
415 /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
416 last_ext->extLocation.logicalBlockNum = 0;
417 last_ext->extLocation.partitionReferenceNum = 0;
418 add = (1 << (30-sb->s_blocksize_bits)) - 1;
419 last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
420 /* Create enough extents to cover the whole hole */
421 while (blocks > add) {
422 blocks -= add;
423 if (udf_add_aext(inode, last_pos, last_ext->extLocation,
424 last_ext->extLength, 1) == -1)
425 return -1;
426 count++;
427 }
428 if (blocks) {
429 last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
430 (blocks << sb->s_blocksize_bits);
431 if (udf_add_aext(inode, last_pos, last_ext->extLocation,
432 last_ext->extLength, 1) == -1)
433 return -1;
434 count++;
435 }
436out:
437 /* Do we have some preallocated blocks saved? */
438 if (prealloc_len) {
439 if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1)
440 return -1;
441 last_ext->extLocation = prealloc_loc;
442 last_ext->extLength = prealloc_len;
443 count++;
444 }
445 /* last_pos should point to the last written extent... */
446 if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
447 last_pos->offset -= sizeof(short_ad);
448 else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
449 last_pos->offset -= sizeof(long_ad);
450 else
451 return -1;
452 return count;
453}
454
359static struct buffer_head * inode_getblk(struct inode * inode, sector_t block, 455static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
360 int *err, long *phys, int *new) 456 int *err, long *phys, int *new)
361{ 457{
458 static sector_t last_block;
362 struct buffer_head *result = NULL; 459 struct buffer_head *result = NULL;
363 kernel_long_ad laarr[EXTENT_MERGE_SIZE]; 460 kernel_long_ad laarr[EXTENT_MERGE_SIZE];
364 struct extent_position prev_epos, cur_epos, next_epos; 461 struct extent_position prev_epos, cur_epos, next_epos;
@@ -371,7 +468,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
371 sector_t offset = 0; 468 sector_t offset = 0;
372 int8_t etype; 469 int8_t etype;
373 int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; 470 int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
374 char lastblock = 0; 471 int lastblock = 0;
375 472
376 prev_epos.offset = udf_file_entry_alloc_offset(inode); 473 prev_epos.offset = udf_file_entry_alloc_offset(inode);
377 prev_epos.block = UDF_I_LOCATION(inode); 474 prev_epos.block = UDF_I_LOCATION(inode);
@@ -423,6 +520,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
423 520
424 b_off -= lbcount; 521 b_off -= lbcount;
425 offset = b_off >> inode->i_sb->s_blocksize_bits; 522 offset = b_off >> inode->i_sb->s_blocksize_bits;
523 /* Move into indirect extent if we are at a pointer to it */
524 udf_next_aext(inode, &prev_epos, &eloc, &elen, 0);
426 525
427 /* if the extent is allocated and recorded, return the block 526 /* if the extent is allocated and recorded, return the block
428 if the extent is not a multiple of the blocksize, round up */ 527 if the extent is not a multiple of the blocksize, round up */
@@ -444,43 +543,66 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
444 return NULL; 543 return NULL;
445 } 544 }
446 545
546 last_block = block;
547 /* Are we beyond EOF? */
447 if (etype == -1) 548 if (etype == -1)
448 { 549 {
449 endnum = startnum = ((count > 1) ? 1 : count); 550 int ret;
450 if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1)) 551
451 { 552 if (count) {
452 laarr[c].extLength = 553 if (c)
453 (laarr[c].extLength & UDF_EXTENT_FLAG_MASK) | 554 laarr[0] = laarr[1];
454 (((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) + 555 startnum = 1;
455 inode->i_sb->s_blocksize - 1) & 556 }
456 ~(inode->i_sb->s_blocksize - 1)); 557 else {
457 UDF_I_LENEXTENTS(inode) = 558 /* Create a fake extent when there's not one */
458 (UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) & 559 memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
459 ~(inode->i_sb->s_blocksize - 1); 560 laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
561 /* Will udf_extend_file() create real extent from a fake one? */
562 startnum = (offset > 0);
563 }
564 /* Create extents for the hole between EOF and offset */
565 ret = udf_extend_file(inode, &prev_epos, laarr, offset);
566 if (ret == -1) {
567 brelse(prev_epos.bh);
568 brelse(cur_epos.bh);
569 brelse(next_epos.bh);
570 /* We don't really know the error here so we just make
571 * something up */
572 *err = -ENOSPC;
573 return NULL;
460 } 574 }
461 c = !c; 575 c = 0;
462 laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | 576 offset = 0;
463 ((offset + 1) << inode->i_sb->s_blocksize_bits); 577 count += ret;
464 memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); 578 /* We are not covered by a preallocated extent? */
465 count ++; 579 if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) {
466 endnum ++; 580 /* Is there any real extent? - otherwise we overwrite
581 * the fake one... */
582 if (count)
583 c = !c;
584 laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
585 inode->i_sb->s_blocksize;
586 memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
587 count ++;
588 endnum ++;
589 }
590 endnum = c+1;
467 lastblock = 1; 591 lastblock = 1;
468 } 592 }
469 else 593 else {
470 endnum = startnum = ((count > 2) ? 2 : count); 594 endnum = startnum = ((count > 2) ? 2 : count);
471 595
472 /* if the current extent is in position 0, swap it with the previous */ 596 /* if the current extent is in position 0, swap it with the previous */
473 if (!c && count != 1) 597 if (!c && count != 1)
474 { 598 {
475 laarr[2] = laarr[0]; 599 laarr[2] = laarr[0];
476 laarr[0] = laarr[1]; 600 laarr[0] = laarr[1];
477 laarr[1] = laarr[2]; 601 laarr[1] = laarr[2];
478 c = 1; 602 c = 1;
479 } 603 }
480 604
481 /* if the current block is located in a extent, read the next extent */ 605 /* if the current block is located in an extent, read the next extent */
482 if (etype != -1)
483 {
484 if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) 606 if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)
485 { 607 {
486 laarr[c+1].extLength = (etype << 30) | elen; 608 laarr[c+1].extLength = (etype << 30) | elen;
@@ -489,11 +611,10 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
489 startnum ++; 611 startnum ++;
490 endnum ++; 612 endnum ++;
491 } 613 }
492 else 614 else {
493 lastblock = 1; 615 lastblock = 1;
616 }
494 } 617 }
495 brelse(cur_epos.bh);
496 brelse(next_epos.bh);
497 618
498 /* if the current extent is not recorded but allocated, get the 619 /* if the current extent is not recorded but allocated, get the
499 block in the extent corresponding to the requested block */ 620 block in the extent corresponding to the requested block */
@@ -534,8 +655,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
534 udf_merge_extents(inode, laarr, &endnum); 655 udf_merge_extents(inode, laarr, &endnum);
535 656
536 /* write back the new extents, inserting new extents if the new number 657 /* write back the new extents, inserting new extents if the new number
537 of extents is greater than the old number, and deleting extents if 658 of extents is greater than the old number, and deleting extents if
538 the new number of extents is less than the old number */ 659 the new number of extents is less than the old number */
539 udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); 660 udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
540 661
541 brelse(prev_epos.bh); 662 brelse(prev_epos.bh);
@@ -991,6 +1112,7 @@ __udf_read_inode(struct inode *inode)
991 return; 1112 return;
992 } 1113 }
993 udf_fill_inode(inode, bh); 1114 udf_fill_inode(inode, bh);
1115
994 brelse(bh); 1116 brelse(bh);
995} 1117}
996 1118
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 9f516d4baf9d..a92daaba6c4c 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1661,7 +1661,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
1661 iput(inode); 1661 iput(inode);
1662 goto error_out; 1662 goto error_out;
1663 } 1663 }
1664 sb->s_maxbytes = 1<<30; 1664 sb->s_maxbytes = MAX_LFS_FILESIZE;
1665 return 0; 1665 return 0;
1666 1666
1667error_out: 1667error_out:
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;