]> git.baikalelectronics.ru Git - kernel.git/commitdiff
udf: Fix file corruption when appending just after end of preallocated extent
authorJan Kara <jack@suse.cz>
Mon, 23 Jan 2023 13:18:47 +0000 (14:18 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Mar 2023 15:44:01 +0000 (16:44 +0100)
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: 189b02ac597c ("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>
fs/udf/inode.c

index 500cee8cb7a1008da8fadfc7fa691ae0c97b566d..6b3531f55ee88c96d32fc4d5df0cab0fe066efd0 100644 (file)
@@ -807,19 +807,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 {