Commit 0c52750caaac for kernel

commit 0c52750caaaccee8b0e929450fe6538ec4985722
Author: Matthias Goergens <matthias.goergens@gmail.com>
Date:   Fri Oct 30 22:05:36 2026 +0800

    udf: fix preallocation discarding before an empty allocation extent

    udf_discard_prealloc() finds the last extent of a file by peeking at
    the next one with udf_next_aext() and stopping when that returns 0.
    The peek reads into eloc and elen, and the code then uses them as the
    last extent.  But when udf_next_aext() returns 0 they hold no defined
    value: if the extent list ends in a continuation descriptor that leads
    to an empty allocation extent, they describe that continuation, i.e.
    the block of the empty allocation extent, one block long.

    The kernel creates such lists itself: when udf_delete_aext() removes
    the only descriptor of the last allocation extent in a list, it leaves
    that allocation extent empty and the continuation to it in place.

    If the last extent is a preallocation, udf_discard_prealloc() deletes
    it with udf_delete_aext(), which finds the following allocation extent
    empty, so it also removes the continuation and frees that allocation
    extent's block.  udf_discard_prealloc() then frees eloc and elen: that
    block a second time, instead of the preallocated blocks.  On a space
    bitmap the preallocated blocks leak and the free block count drifts.
    On an unallocated space table the second free adds a second free
    extent for the same block, which is later handed out twice: fsx as run
    by generic/091 and generic/263 ends up with two parts of its test file
    in one block and reads back bad data.

    Peek into separate variables, so that eloc and elen keep the last
    extent that udf_next_aext() returned with 1.

    Fixes: cfe4c1b25dd6 ("udf: Fix preallocation discarding at indirect extent boundary")
    Cc: stable@vger.kernel.org
    Suggested-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
    Link: https://patch.msgid.link/480eccd1264a4cea5226fc36ed108931b2c403fb.1793349907.git.matthias.goergens@gmail.com
    Signed-off-by: Jan Kara <jack@suse.cz>

diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 0990f94b8551..75151a59f0da 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -124,8 +124,8 @@ void udf_discard_prealloc(struct inode *inode)
 {
 	struct extent_position epos = {};
 	struct extent_position prev_epos = {};
-	struct kernel_lb_addr eloc;
-	uint32_t elen;
+	struct kernel_lb_addr eloc, tmpeloc;
+	uint32_t elen, tmpelen;
 	uint64_t lbcount = 0;
 	int8_t etype = -1;
 	struct udf_inode_info *iinfo = UDF_I(inode);
@@ -141,7 +141,8 @@ void udf_discard_prealloc(struct inode *inode)

 	/* Find the last extent in the file */
 	while (1) {
-		ret = udf_next_aext(inode, &epos, &eloc, &elen, &tmpetype, 0);
+		ret = udf_next_aext(inode, &epos, &tmpeloc, &tmpelen,
+				    &tmpetype, 0);
 		if (ret < 0)
 			goto out;
 		if (ret == 0)