diff options
author | Jan Kara <jack@suse.cz> | 2023-01-23 16:18:47 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-03-11 18:31:50 +0300 |
commit | 14e4ec443cbf5522d8ada268c39302e5cefe8126 (patch) | |
tree | 8b7580629d0ada0735ded267ba86793e48cabc5a | |
parent | 5a6c373d761f55635e175fa2f407544bae8f583b (diff) | |
download | linux-14e4ec443cbf5522d8ada268c39302e5cefe8126.tar.xz |
udf: Fix file corruption when appending just after end of preallocated extent
commit 36ec52ea038b18a53e198116ef7d7e70c87db046 upstream.
When we append new block just after the end of preallocated extent, the
code in inode_getblk() wrongly determined we're going to use the
preallocated extent which resulted in adding block into a wrong logical
offset in the file. Sequence like this manifests it:
xfs_io -f -c "pwrite 0x2cacf 0xd122" -c "truncate 0x2dd6f" \
-c "pwrite 0x27fd9 0x69a9" -c "pwrite 0x32981 0x7244" <file>
The code that determined the use of preallocated extent is actually
stale because udf_do_extend_file() does not create preallocation anymore
so after calling that function we are sure there's no usable
preallocation. Just remove the faulty condition.
CC: stable@vger.kernel.org
Fixes: 16d055656814 ("udf: Discard preallocation before extending file with a hole")
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/udf/inode.c | 24 |
1 files changed, 11 insertions, 13 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 570ad1069313..af1180104e56 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -800,19 +800,17 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, c = 0; offset = 0; count += ret; - /* We are not covered by a preallocated extent? */ - if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != - EXT_NOT_RECORDED_ALLOCATED) { - /* Is there any real extent? - otherwise we overwrite - * the fake one... */ - if (count) - c = !c; - laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | - inode->i_sb->s_blocksize; - memset(&laarr[c].extLocation, 0x00, - sizeof(struct kernel_lb_addr)); - count++; - } + /* + * Is there any real extent? - otherwise we overwrite the fake + * one... + */ + if (count) + c = !c; + laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | + inode->i_sb->s_blocksize; + memset(&laarr[c].extLocation, 0x00, + sizeof(struct kernel_lb_addr)); + count++; endnum = c + 1; lastblock = 1; } else { |