Skip to content

Commit 16d0556

Browse files
committed
udf: Discard preallocation before extending file with a hole
When extending file with a hole, we tried to preserve existing preallocation for the file. However that is not very useful and complicates code because the previous extent may need to be rounded to block boundary as well (which we forgot to do thus causing data corruption for sequence like: xfs_io -f -c "pwrite 0x75e63 11008" -c "truncate 0x7b24b" \ -c "truncate 0xabaa3" -c "pwrite 0xac70b 22954" \ -c "pwrite 0x93a43 11358" -c "pwrite 0xb8e65 52211" file with 512-byte block size. Just discard preallocation before extending file to simplify things and also fix this data corruption. CC: [email protected] Signed-off-by: Jan Kara <[email protected]>
1 parent 6ad53f0 commit 16d0556

File tree

1 file changed

+18
-28
lines changed

1 file changed

+18
-28
lines changed

fs/udf/inode.c

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,12 @@ static int udf_get_block(struct inode *inode, sector_t block,
434434
iinfo->i_next_alloc_goal++;
435435
}
436436

437+
/*
438+
* Block beyond EOF and prealloc extents? Just discard preallocation
439+
* as it is not useful and complicates things.
440+
*/
441+
if (((loff_t)block) << inode->i_blkbits > iinfo->i_lenExtents)
442+
udf_discard_prealloc(inode);
437443
udf_clear_extent_cache(inode);
438444
phys = inode_getblk(inode, block, &err, &new);
439445
if (!phys)
@@ -483,8 +489,6 @@ static int udf_do_extend_file(struct inode *inode,
483489
uint32_t add;
484490
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
485491
struct super_block *sb = inode->i_sb;
486-
struct kernel_lb_addr prealloc_loc = {};
487-
uint32_t prealloc_len = 0;
488492
struct udf_inode_info *iinfo;
489493
int err;
490494

@@ -505,19 +509,6 @@ static int udf_do_extend_file(struct inode *inode,
505509
~(sb->s_blocksize - 1);
506510
}
507511

508-
/* Last extent are just preallocated blocks? */
509-
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
510-
EXT_NOT_RECORDED_ALLOCATED) {
511-
/* Save the extent so that we can reattach it to the end */
512-
prealloc_loc = last_ext->extLocation;
513-
prealloc_len = last_ext->extLength;
514-
/* Mark the extent as a hole */
515-
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
516-
(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
517-
last_ext->extLocation.logicalBlockNum = 0;
518-
last_ext->extLocation.partitionReferenceNum = 0;
519-
}
520-
521512
/* Can we merge with the previous extent? */
522513
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
523514
EXT_NOT_RECORDED_NOT_ALLOCATED) {
@@ -545,7 +536,7 @@ static int udf_do_extend_file(struct inode *inode,
545536
* more extents, we may need to enter possible following
546537
* empty indirect extent.
547538
*/
548-
if (new_block_bytes || prealloc_len)
539+
if (new_block_bytes)
549540
udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0);
550541
}
551542

@@ -579,17 +570,6 @@ static int udf_do_extend_file(struct inode *inode,
579570
}
580571

581572
out:
582-
/* Do we have some preallocated blocks saved? */
583-
if (prealloc_len) {
584-
err = udf_add_aext(inode, last_pos, &prealloc_loc,
585-
prealloc_len, 1);
586-
if (err)
587-
return err;
588-
last_ext->extLocation = prealloc_loc;
589-
last_ext->extLength = prealloc_len;
590-
count++;
591-
}
592-
593573
/* last_pos should point to the last written extent... */
594574
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
595575
last_pos->offset -= sizeof(struct short_ad);
@@ -642,8 +622,17 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
642622
else
643623
BUG();
644624

625+
/*
626+
* When creating hole in file, just don't bother with preserving
627+
* preallocation. It likely won't be very useful anyway.
628+
*/
629+
udf_discard_prealloc(inode);
630+
645631
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
646632
within_final_block = (etype != -1);
633+
/* We don't expect extents past EOF... */
634+
WARN_ON_ONCE(etype != -1 &&
635+
elen > ((loff_t)offset + 1) << inode->i_blkbits);
647636

648637
if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
649638
(epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
@@ -772,10 +761,11 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
772761
goto out_free;
773762
}
774763

775-
/* Are we beyond EOF? */
764+
/* Are we beyond EOF and preallocated extent? */
776765
if (etype == -1) {
777766
int ret;
778767
loff_t hole_len;
768+
779769
isBeyondEOF = true;
780770
if (count) {
781771
if (c)

0 commit comments

Comments
 (0)