From: "Darrick J. Wong" <djwong@kernel.org>
To: tytso@mit.edu
Cc: linux-ext4@vger.kernel.org
Subject: [PATCH 17/8] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range
Date: Thu, 17 Jul 2025 15:01:39 -0700 [thread overview]
Message-ID: <20250717220139.GM2672022@frogsfrogsfrogs> (raw)
In-Reply-To: <175182662934.1984706.3737778061161342509.stgit@frogsfrogsfrogs>
From: Darrick J. Wong <djwong@kernel.org>
In non-iomap mode, generic/008 tries to fzero the first byte of a block
and instead zeroes the entire file:
--- a/tests/generic/008.out 2025-07-15 14:45:14.937058680 -0700
+++ b/tests/generic/008.out.bad 2025-07-16 13:31:03.909315508 -0700
@@ -4,10 +4,7 @@
XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1024/1024 bytes at offset 1024
XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-00000000: 00 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA
-00000010: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
-*
-00000400: 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 BBBBBBBBBBBBBBBB
+00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
*
read 2048/2048 bytes at offset 0
XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Looking at the fuse2fs debugging output, the reason why is obvious:
FUSE2FS (sda): op_fallocate: ino=50 mode=0x10 start=0x0 end=0x1
FUSE2FS (sda): fuse2fs_punch_range: ino=50 mode=0x11 offset=0x0 len=0x1 start=0 end=0
start and end are both zero, so we call ext2fs_punch with those
arguments. ext2fs_punch interprets [start, end] as a closed interval
and removes block 0, which is not what we asked for!
The computation of end is also too subtle -- the dividend is the
expression (0 + 1 - 4096) which produces a negative number because off_t
is defined to be long long, at least on amd64 Linux. We rely on the
behavior that dividing a negative dividend by a positive divisor
produces a quotient of zero.
Really what we should do here is round offset up to the next fsblock
and offset+len down to the nearest fsblock. The first quantity is the
first byte of the range to punch and the second quantity is the next
byte past the range to punch. Using those as the basis to compute start
and end, the punch should only happen if start < end, and we should pass
[start, end - 1] to ext2fs_punch because it expects a closed interval.
Improve the comments here so that I don't have to work all this out
again the next time I read through here.
Cc: <linux-ext4@vger.kernel.org> # v1.43
Fixes: 81cbf1ef4f5dab ("misc: add fuse2fs, a FUSE server for e2fsprogs")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 49 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 41 insertions(+), 8 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 6155dff6645ff6..cee9e657c36767 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -124,6 +124,28 @@
static ext2_filsys global_fs; /* Try not to use this directly */
+static inline uint64_t round_up(uint64_t b, unsigned int align)
+{
+ unsigned int m;
+
+ if (align == 0)
+ return b;
+ m = b % align;
+ if (m)
+ b += align - m;
+ return b;
+}
+
+static inline uint64_t round_down(uint64_t b, unsigned int align)
+{
+ unsigned int m;
+
+ if (align == 0)
+ return b;
+ m = b % align;
+ return b - m;
+}
+
#define dbg_printf(fuse2fs, format, ...) \
while ((fuse2fs)->debug) { \
printf("FUSE2FS (%s): " format, (fuse2fs)->shortdev, ##__VA_ARGS__); \
@@ -4095,11 +4117,18 @@ static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
if (!(mode & FL_KEEP_SIZE_FLAG))
return -EINVAL;
- /* Punch out a bunch of blocks */
- start = FUSE2FS_B_TO_FSB(ff, offset);
- end = (offset + len - fs->blocksize) / fs->blocksize;
- dbg_printf(ff, "%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
- fh->ino, mode, start, end);
+ /*
+ * Unmap out all full blocks in the middle of the range being punched.
+ * The start of the unmap range should be the first byte of the first
+ * fsblock that starts within the range. The end of the range should
+ * be the next byte after the last fsblock to end in the range.
+ */
+ start = FUSE2FS_B_TO_FSBT(ff, round_up(offset, fs->blocksize));
+ end = FUSE2FS_B_TO_FSBT(ff, round_down(offset + len, fs->blocksize));
+
+ dbg_printf(ff,
+ "%s: ino=%d mode=0x%x offset=0x%jx len=0x%jx start=0x%llx end=0x%llx\n",
+ __func__, fh->ino, mode, offset, len, start, end);
err = fuse2fs_read_inode(fs, fh->ino, &inode);
if (err)
@@ -4120,10 +4149,14 @@ static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
if (err)
return translate_error(fs, fh->ino, err);
- /* Unmap full blocks in the middle */
- if (start <= end) {
+ /*
+ * Unmap full blocks in the middle, which is to say that start - end
+ * must be at least one fsblock. ext2fs_punch takes a closed interval
+ * as its argument, so we pass [start, end - 1].
+ */
+ if (start < end) {
err = ext2fs_punch(fs, fh->ino, EXT2_INODE(&inode),
- NULL, start, end);
+ NULL, start, end - 1);
if (err)
return translate_error(fs, fh->ino, err);
}
next prev parent reply other threads:[~2025-07-17 22:01 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
2025-07-06 18:31 ` [PATCH 1/8] libext2fs: fix off-by-one bug in punch_extent_blocks Darrick J. Wong
2025-07-06 18:31 ` [PATCH 2/8] libext2fs: fix arguments passed to ->block_alloc_stats_range Darrick J. Wong
2025-07-06 18:31 ` [PATCH 3/8] fuse2fs: refactor uid/gid setting Darrick J. Wong
2025-07-06 18:31 ` [PATCH 4/8] fuse2fs: fix gid inheritance on sgid parent directories Darrick J. Wong
2025-07-06 18:32 ` [PATCH 5/8] fuse2fs: don't truncate when creating a new file Darrick J. Wong
2025-07-06 18:32 ` [PATCH 6/8] fuse2fs: fix incorrect EOFS input handling in FITRIM Darrick J. Wong
2025-07-06 18:32 ` [PATCH 7/8] fuse2fs: fix incorrect unit conversion at the end of FITRIM Darrick J. Wong
2025-07-06 18:32 ` [PATCH 8/8] fuse2fs: don't try to mount after option parsing errors Darrick J. Wong
2025-07-07 16:05 ` [PATCH 9/8] fuse2fs: fix relatime comparisons Darrick J. Wong
2025-07-08 17:33 ` [PATCH 10/8] fuse2fs: fix lockfile creation, again Darrick J. Wong
2025-07-09 16:51 ` [PATCH 11/8] fuse2fs: fix race condition in op_destroy Darrick J. Wong
2025-07-09 16:52 ` [PATCH 12/8] fuse2fs: fix races in statfs Darrick J. Wong
2025-07-17 14:59 ` [PATCH 13/8] fuse2fs: fix ST_RDONLY setting Darrick J. Wong
2025-07-17 14:59 ` [PATCH 14/8] libext2fs: fix data read corruption in ext2fs_file_read_inline_data Darrick J. Wong
2025-07-17 14:59 ` [PATCH 15/8] libext2fs: fix data corruption when writing to inline data files Darrick J. Wong
2025-07-17 22:01 ` [PATCH 16/8] fuse2fs: fix clean_block_middle when punching byte 0 of a block Darrick J. Wong
2025-07-17 22:01 ` Darrick J. Wong [this message]
2025-07-22 19:40 ` [PATCH 18/8] fuse2fs: fix logging redirection Darrick J. Wong
2025-07-25 15:56 ` [PATCH 19/8] fuse2fs: don't record every errno in the superblock as an fs failure Darrick J. Wong
2025-07-26 16:28 ` [PATCH 20/8] fuse2fs: fix punching post-EOF blocks during truncate Darrick J. Wong
2025-07-30 17:23 ` [PATCH 21/8] fuse2fs: fix block parameter truncation on 32-bit Darrick J. Wong
2025-07-31 14:47 ` [PATCHSET] fuse2fs: more bug fixes Theodore Ts'o
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250717220139.GM2672022@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox