* [PATCHSET] fuse2fs: more bug fixes
@ 2025-07-06 18:30 Darrick J. Wong
2025-07-06 18:31 ` [PATCH 1/8] libext2fs: fix off-by-one bug in punch_extent_blocks Darrick J. Wong
` (21 more replies)
0 siblings, 22 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:30 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
Hi all,
This series fixes more bugs in fuse2fs.
If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.
Comments and questions are, as always, welcome.
e2fsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/e2fsprogs.git/log/?h=fuse2fs-fixes
---
Commits in this patchset:
* libext2fs: fix off-by-one bug in punch_extent_blocks
* libext2fs: fix arguments passed to ->block_alloc_stats_range
* fuse2fs: refactor uid/gid setting
* fuse2fs: fix gid inheritance on sgid parent directories
* fuse2fs: don't truncate when creating a new file
* fuse2fs: fix incorrect EOFS input handling in FITRIM
* fuse2fs: fix incorrect unit conversion at the end of FITRIM
* fuse2fs: don't try to mount after option parsing errors
---
lib/ext2fs/alloc_stats.c | 5 ++
lib/ext2fs/punch.c | 2 -
misc/fuse2fs.c | 111 ++++++++++++++++++++++++++++++++--------------
3 files changed, 83 insertions(+), 35 deletions(-)
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/8] libext2fs: fix off-by-one bug in punch_extent_blocks
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
@ 2025-07-06 18:31 ` Darrick J. Wong
2025-07-06 18:31 ` [PATCH 2/8] libext2fs: fix arguments passed to ->block_alloc_stats_range Darrick J. Wong
` (20 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:31 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
punch_extent_blocks tries to validate its input parameters to make sure
that the physical range of blocks being punched do not go past the end
of the filesystem. Unfortunately, there's an off-by-one bug in the
valiation, because start==0 count==10 is a perfectly valid range on a
10-block filesystem.
Cc: <linux-ext4@vger.kernel.org> # v1.46.6
Fixes: 6772d4969e9c90 ("libext2fs: check for invalid blocks in ext2fs_punch_blocks()")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
lib/ext2fs/punch.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index 80c699eb0c13f5..19b6a37824c589 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -201,7 +201,7 @@ static errcode_t punch_extent_blocks(ext2_filsys fs, ext2_ino_t ino,
errcode_t retval = 0;
if (free_start < fs->super->s_first_data_block ||
- (free_start + free_count) >= ext2fs_blocks_count(fs->super))
+ (free_start + free_count) > ext2fs_blocks_count(fs->super))
return EXT2_ET_BAD_BLOCK_NUM;
/* No bigalloc? Just free each block. */
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 2/8] libext2fs: fix arguments passed to ->block_alloc_stats_range
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 ` Darrick J. Wong
2025-07-06 18:31 ` [PATCH 3/8] fuse2fs: refactor uid/gid setting Darrick J. Wong
` (19 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:31 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
In ext2fs_block_alloc_stats_range, we use @num as the loop counter but
then pass it to the callback and @blk as the loop cursor. This means
that the range passed to e2fsck_block_alloc_stats_range starts beyond
the range that was actually freed and has a length of zero, which is not
at all correct.
Fix this by saving the original values and passing those instead.
Cc: <linux-ext4@vger.kernel.org> # v1.43
Fixes: 647e8786156061 ("libext2fs: add new hooks to support large allocations")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
lib/ext2fs/alloc_stats.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
index 6f98bcc7cbd5f3..95a6438f252e0f 100644
--- a/lib/ext2fs/alloc_stats.c
+++ b/lib/ext2fs/alloc_stats.c
@@ -110,6 +110,9 @@ void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs,
void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
blk_t num, int inuse)
{
+ const blk64_t orig_blk = blk;
+ const blk_t orig_num = num;
+
#ifndef OMIT_COM_ERR
if (blk + num > ext2fs_blocks_count(fs->super)) {
com_err("ext2fs_block_alloc_stats_range", 0,
@@ -147,7 +150,7 @@ void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
ext2fs_mark_super_dirty(fs);
ext2fs_mark_bb_dirty(fs);
if (fs->block_alloc_stats_range)
- (fs->block_alloc_stats_range)(fs, blk, num, inuse);
+ (fs->block_alloc_stats_range)(fs, orig_blk, orig_num, inuse);
}
void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs,
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 3/8] fuse2fs: refactor uid/gid setting
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 ` Darrick J. Wong
2025-07-06 18:31 ` [PATCH 4/8] fuse2fs: fix gid inheritance on sgid parent directories Darrick J. Wong
` (18 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:31 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Don't open-code the uid and gid update logic.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 42 ++++++++++++++++++++++--------------------
1 file changed, 22 insertions(+), 20 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index d209bc790fbd36..86fef7765e5e46 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -1053,6 +1053,18 @@ static int propagate_default_acls(struct fuse2fs *ff, ext2_ino_t parent,
return ret;
}
+static inline void fuse2fs_set_uid(struct ext2_inode_large *inode, uid_t uid)
+{
+ inode->i_uid = uid;
+ ext2fs_set_i_uid_high(*inode, uid >> 16);
+}
+
+static inline void fuse2fs_set_gid(struct ext2_inode_large *inode, gid_t gid)
+{
+ inode->i_gid = gid;
+ ext2fs_set_i_gid_high(*inode, gid >> 16);
+}
+
static int op_mknod(const char *path, mode_t mode, dev_t dev)
{
struct fuse_context *ctxt = fuse_get_context();
@@ -1145,10 +1157,8 @@ static int op_mknod(const char *path, mode_t mode, dev_t dev)
inode.i_links_count = 1;
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
- inode.i_uid = ctxt->uid;
- ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
- inode.i_gid = ctxt->gid;
- ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
+ fuse2fs_set_uid(&inode, ctxt->uid);
+ fuse2fs_set_gid(&inode, ctxt->gid);
err = ext2fs_write_new_inode(fs, child, EXT2_INODE(&inode));
if (err) {
@@ -1262,10 +1272,8 @@ static int op_mkdir(const char *path, mode_t mode)
goto out2;
}
- inode.i_uid = ctxt->uid;
- ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
- inode.i_gid = ctxt->gid;
- ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
+ fuse2fs_set_uid(&inode, ctxt->uid);
+ fuse2fs_set_gid(&inode, ctxt->gid);
inode.i_mode = LINUX_S_IFDIR | (mode & ~S_ISUID) |
parent_sgid;
inode.i_generation = ff->next_generation++;
@@ -1691,10 +1699,8 @@ static int op_symlink(const char *src, const char *dest)
goto out2;
}
- inode.i_uid = ctxt->uid;
- ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
- inode.i_gid = ctxt->gid;
- ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
+ fuse2fs_set_uid(&inode, ctxt->uid);
+ fuse2fs_set_gid(&inode, ctxt->gid);
inode.i_generation = ff->next_generation++;
init_times(&inode);
@@ -2243,8 +2249,7 @@ static int op_chown(const char *path, uid_t owner, gid_t group
ret = -EPERM;
goto out;
}
- inode.i_uid = owner;
- ext2fs_set_i_uid_high(inode, owner >> 16);
+ fuse2fs_set_uid(&inode, owner);
}
if (group != (gid_t) ~0) {
@@ -2256,8 +2261,7 @@ static int op_chown(const char *path, uid_t owner, gid_t group
}
/* XXX: We /should/ check group membership but FUSE */
- inode.i_gid = group;
- ext2fs_set_i_gid_high(inode, group >> 16);
+ fuse2fs_set_gid(&inode, group);
}
ret = update_ctime(fs, ino, &inode);
@@ -3300,10 +3304,8 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
inode.i_links_count = 1;
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
- inode.i_uid = ctxt->uid;
- ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
- inode.i_gid = ctxt->gid;
- ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
+ fuse2fs_set_uid(&inode, ctxt->uid);
+ fuse2fs_set_gid(&inode, ctxt->gid);
if (ext2fs_has_feature_extents(fs->super)) {
ext2_extent_handle_t handle;
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 4/8] fuse2fs: fix gid inheritance on sgid parent directories
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (2 preceding siblings ...)
2025-07-06 18:31 ` [PATCH 3/8] fuse2fs: refactor uid/gid setting Darrick J. Wong
@ 2025-07-06 18:31 ` Darrick J. Wong
2025-07-06 18:32 ` [PATCH 5/8] fuse2fs: don't truncate when creating a new file Darrick J. Wong
` (17 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:31 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
When a child file is created inside a setgid parent directory, the child
is supposed to inherit the gid of the parent, not the fsgid of the
creating process. Fix this error, which was discovered by generic/633,
generic/696, and generic/697.
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 | 62 ++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 49 insertions(+), 13 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 86fef7765e5e46..0e9576b6ca6aa7 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -1065,6 +1065,30 @@ static inline void fuse2fs_set_gid(struct ext2_inode_large *inode, gid_t gid)
ext2fs_set_i_gid_high(*inode, gid >> 16);
}
+static int fuse2fs_new_child_gid(struct fuse2fs *ff, ext2_ino_t parent,
+ gid_t *gid, int *parent_sgid)
+{
+ struct ext2_inode_large inode;
+ struct fuse_context *ctxt = fuse_get_context();
+ errcode_t err;
+
+ err = fuse2fs_read_inode(ff->fs, parent, &inode);
+ if (err)
+ return translate_error(ff->fs, parent, err);
+
+ if (inode.i_mode & S_ISGID) {
+ if (parent_sgid)
+ *parent_sgid = 1;
+ *gid = inode.i_gid;
+ } else {
+ if (parent_sgid)
+ *parent_sgid = 0;
+ *gid = ctxt->gid;
+ }
+
+ return 0;
+}
+
static int op_mknod(const char *path, mode_t mode, dev_t dev)
{
struct fuse_context *ctxt = fuse_get_context();
@@ -1076,6 +1100,7 @@ static int op_mknod(const char *path, mode_t mode, dev_t dev)
char *node_name, a;
int filetype;
struct ext2_inode_large inode;
+ gid_t gid;
int ret = 0;
FUSE2FS_CHECK_CONTEXT(ff);
@@ -1128,6 +1153,10 @@ static int op_mknod(const char *path, mode_t mode, dev_t dev)
goto out2;
}
+ err = fuse2fs_new_child_gid(ff, parent, &gid, NULL);
+ if (err)
+ goto out2;
+
err = ext2fs_new_inode(fs, parent, mode, 0, &child);
if (err) {
ret = translate_error(fs, 0, err);
@@ -1158,7 +1187,7 @@ static int op_mknod(const char *path, mode_t mode, dev_t dev)
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
fuse2fs_set_uid(&inode, ctxt->uid);
- fuse2fs_set_gid(&inode, ctxt->gid);
+ fuse2fs_set_gid(&inode, gid);
err = ext2fs_write_new_inode(fs, child, EXT2_INODE(&inode));
if (err) {
@@ -1199,7 +1228,8 @@ static int op_mkdir(const char *path, mode_t mode)
char *block;
blk64_t blk;
int ret = 0;
- mode_t parent_sgid;
+ gid_t gid;
+ int parent_sgid;
FUSE2FS_CHECK_CONTEXT(ff);
fs = ff->fs;
@@ -1235,13 +1265,9 @@ static int op_mkdir(const char *path, mode_t mode)
if (ret)
goto out2;
- /* Is the parent dir sgid? */
- err = fuse2fs_read_inode(fs, parent, &inode);
- if (err) {
- ret = translate_error(fs, parent, err);
+ err = fuse2fs_new_child_gid(ff, parent, &gid, &parent_sgid);
+ if (err)
goto out2;
- }
- parent_sgid = inode.i_mode & S_ISGID;
*node_name = a;
@@ -1273,9 +1299,10 @@ static int op_mkdir(const char *path, mode_t mode)
}
fuse2fs_set_uid(&inode, ctxt->uid);
- fuse2fs_set_gid(&inode, ctxt->gid);
- inode.i_mode = LINUX_S_IFDIR | (mode & ~S_ISUID) |
- parent_sgid;
+ fuse2fs_set_gid(&inode, gid);
+ inode.i_mode = LINUX_S_IFDIR | (mode & ~S_ISUID);
+ if (parent_sgid)
+ inode.i_mode |= S_ISGID;
inode.i_generation = ff->next_generation++;
init_times(&inode);
@@ -1629,6 +1656,7 @@ static int op_symlink(const char *src, const char *dest)
errcode_t err;
char *node_name, a;
struct ext2_inode_large inode;
+ gid_t gid;
int ret = 0;
FUSE2FS_CHECK_CONTEXT(ff);
@@ -1661,6 +1689,9 @@ static int op_symlink(const char *src, const char *dest)
if (ret)
goto out2;
+ err = fuse2fs_new_child_gid(ff, parent, &gid, NULL);
+ if (err)
+ goto out2;
/* Create symlink */
err = ext2fs_symlink(fs, parent, 0, node_name, src);
@@ -1700,7 +1731,7 @@ static int op_symlink(const char *src, const char *dest)
}
fuse2fs_set_uid(&inode, ctxt->uid);
- fuse2fs_set_gid(&inode, ctxt->gid);
+ fuse2fs_set_gid(&inode, gid);
inode.i_generation = ff->next_generation++;
init_times(&inode);
@@ -3240,6 +3271,7 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
char *node_name, a;
int filetype;
struct ext2_inode_large inode;
+ gid_t gid;
int ret = 0;
FUSE2FS_CHECK_CONTEXT(ff);
@@ -3276,6 +3308,10 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
if (ret)
goto out2;
+ err = fuse2fs_new_child_gid(ff, parent, &gid, NULL);
+ if (err)
+ goto out2;
+
*node_name = a;
filetype = ext2_file_type(mode);
@@ -3305,7 +3341,7 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
inode.i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
fuse2fs_set_uid(&inode, ctxt->uid);
- fuse2fs_set_gid(&inode, ctxt->gid);
+ fuse2fs_set_gid(&inode, gid);
if (ext2fs_has_feature_extents(fs->super)) {
ext2_extent_handle_t handle;
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 5/8] fuse2fs: don't truncate when creating a new file
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (3 preceding siblings ...)
2025-07-06 18:31 ` [PATCH 4/8] fuse2fs: fix gid inheritance on sgid parent directories Darrick J. Wong
@ 2025-07-06 18:32 ` Darrick J. Wong
2025-07-06 18:32 ` [PATCH 6/8] fuse2fs: fix incorrect EOFS input handling in FITRIM Darrick J. Wong
` (16 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:32 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
New files can't have contents, so there's no need to truncate them,
which then messes with ctime/mtime.
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 | 1 +
1 file changed, 1 insertion(+)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 0e9576b6ca6aa7..5b866aed98237f 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -3376,6 +3376,7 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
if (ret)
goto out2;
+ fp->flags &= ~O_TRUNC;
ret = __op_open(ff, path, fp);
if (ret)
goto out2;
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 6/8] fuse2fs: fix incorrect EOFS input handling in FITRIM
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (4 preceding siblings ...)
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 ` Darrick J. Wong
2025-07-06 18:32 ` [PATCH 7/8] fuse2fs: fix incorrect unit conversion at the end of FITRIM Darrick J. Wong
` (15 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:32 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
FITRIM isn't well documented, which means that I missed that
len == -1ULL always means "trim to end of filesystem". generic/260 has
been failing with:
--- a/tests/generic/260.out 2025-04-30 16:20:44.532797310 -0700
+++ b/tests/generic/260.out.bad 2025-07-03 11:44:26.946394170 -0700
@@ -11,4 +11,5 @@
[+] Default length with start set (should succeed)
[+] Length beyond the end of fs (should succeed)
[+] Length beyond the end of fs with start set (should succeed)
+After the full fs discard 0 bytes were discarded however the file system is 10401542144 bytes long.
Test done
because the addition used to compute end suffered an integer overflow,
resulting in end < start, which meant nothing happened. Fix this by
explicitly checking for -1ULL.
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 | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 5b866aed98237f..34eaad1573132f 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -3775,7 +3775,10 @@ static int ioctl_fitrim(struct fuse2fs *ff, struct fuse2fs_file_handle *fh,
return -EROFS;
start = FUSE2FS_B_TO_FSBT(ff, fr->start);
- end = FUSE2FS_B_TO_FSBT(ff, fr->start + fr->len - 1);
+ if (fr->len == -1ULL)
+ end = -1ULL;
+ else
+ end = FUSE2FS_B_TO_FSBT(ff, fr->start + fr->len - 1);
minlen = FUSE2FS_B_TO_FSBT(ff, fr->minlen);
if (EXT2FS_NUM_B2C(fs, minlen) > EXT2_CLUSTERS_PER_GROUP(fs->super) ||
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 7/8] fuse2fs: fix incorrect unit conversion at the end of FITRIM
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (5 preceding siblings ...)
2025-07-06 18:32 ` [PATCH 6/8] fuse2fs: fix incorrect EOFS input handling in FITRIM Darrick J. Wong
@ 2025-07-06 18:32 ` Darrick J. Wong
2025-07-06 18:32 ` [PATCH 8/8] fuse2fs: don't try to mount after option parsing errors Darrick J. Wong
` (14 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:32 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
generic/260 also points out that the bytes cleared are in the wrong
units -- they're supposed to be in bytes, but the "cleared" variable is
in units of fsblocks. Fix that.
Cc: <linux-ext4@vger.kernel.org> # v1.47.3-rc1
Fixes: 7235b58533b9cd ("fuse2fs: fix FITRIM validation")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 34eaad1573132f..ff8aa023d1c555 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -3831,7 +3831,8 @@ static int ioctl_fitrim(struct fuse2fs *ff, struct fuse2fs_file_handle *fh,
}
out:
- fr->len = cleared;
+ fr->len = FUSE2FS_FSB_TO_B(ff, cleared);
+ dbg_printf(ff, "%s: len=%llu err=%ld\n", __func__, fr->len, err);
return err;
}
#endif /* FITRIM */
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 8/8] fuse2fs: don't try to mount after option parsing errors
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (6 preceding siblings ...)
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 ` Darrick J. Wong
2025-07-07 16:05 ` [PATCH 9/8] fuse2fs: fix relatime comparisons Darrick J. Wong
` (13 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-06 18:32 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Actually check the outcome of parsing CLI options before trying to
mount.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index ff8aa023d1c555..ab3efea66d3def 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -4407,14 +4407,16 @@ int main(int argc, char *argv[])
FILE *orig_stderr = stderr;
char *logfile;
char extra_args[BUFSIZ];
- int ret = 0;
+ int ret;
int flags = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | EXT2_FLAG_EXCLUSIVE |
EXT2_FLAG_RW;
memset(&fctx, 0, sizeof(fctx));
fctx.magic = FUSE2FS_MAGIC;
- fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
+ ret = fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
+ if (ret)
+ exit(1);
if (fctx.device == NULL) {
fprintf(stderr, "Missing ext4 device/image\n");
fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 9/8] fuse2fs: fix relatime comparisons
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (7 preceding siblings ...)
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 ` Darrick J. Wong
2025-07-08 17:33 ` [PATCH 10/8] fuse2fs: fix lockfile creation, again Darrick J. Wong
` (12 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-07 16:05 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
generic/192 fails like this even before we start adding iomap code:
--- tests/generic/192.out 2025-04-30 16:20:44.512675591 -0700
+++ tests/generic/192.out.bad 2025-07-06 22:26:11.666015735 -0700
@@ -1,5 +1,6 @@
QA output created by 192
sleep for 5 seconds
test
-delta1 is in range
+delta1 has value of 0
+delta1 is NOT in range 5 .. 7
delta2 is in range
The cause of this regression is that the timestamp comparisons account
only for seconds, not nanoseconds. If a write came in 100ms after the
last read but still in the same second, then we fail to update atime on
a subsequent read.
Fix this by converting the timespecs to doubles so that we can include
the nanoseconds component, and then perform the comparison in floating
point mode.
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 | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index ab3efea66d3def..b7201f7c8ed185 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -461,6 +461,7 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)
errcode_t err;
struct ext2_inode_large inode, *pinode;
struct timespec atime, mtime, now;
+ double datime, dmtime, dnow;
if (!(fs->flags & EXT2_FLAG_RW))
return 0;
@@ -472,11 +473,17 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino)
EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
get_now(&now);
+
+ datime = atime.tv_sec + ((double)atime.tv_nsec / 1000000000);
+ dmtime = mtime.tv_sec + ((double)mtime.tv_nsec / 1000000000);
+ dnow = now.tv_sec + ((double)now.tv_nsec / 1000000000);
+
/*
* If atime is newer than mtime and atime hasn't been updated in thirty
- * seconds, skip the atime update. Same idea as Linux "relatime".
+ * seconds, skip the atime update. Same idea as Linux "relatime". Use
+ * doubles to account for nanosecond resolution.
*/
- if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
+ if (datime >= dmtime && datime >= dnow - 30)
return 0;
EXT4_INODE_SET_XTIME(i_atime, &now, &inode);
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 10/8] fuse2fs: fix lockfile creation, again
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (8 preceding siblings ...)
2025-07-07 16:05 ` [PATCH 9/8] fuse2fs: fix relatime comparisons Darrick J. Wong
@ 2025-07-08 17:33 ` Darrick J. Wong
2025-07-09 16:51 ` [PATCH 11/8] fuse2fs: fix race condition in op_destroy Darrick J. Wong
` (11 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-08 17:33 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
On closer examination of the lockfile code, there is still a fatal flaw
in the locking logic. This is born out by the fact that you can run:
# truncate -s 300m /tmp/a
# mkfs.ext2 /tmp/a
# fuse2fs -o kernel /tmp/a /mnt -o lockfile=/tmp/fuselock
# fuse2fs -o kernel /tmp/a /mnt -o lockfile=/tmp/fuselock
and the second mount attempt succeeds where it really shouldn't. This
is due to the use of fopen(..., "w"), because "w" means "truncate or
create". It does /not/ imply O_CREAT | O_EXCL, which fails if the file
already exists. Theoretically that could have been done with mode
string "wx", but that's a glibc extension.
Fix this by calling open() directly with the O_ modes that we want.
Cc: <linux-ext4@vger.kernel.org> # v1.47.3-rc3
Fixes: e50fbaa4d156a6 ("fuse2fs: clean up the lockfile handling")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index b7201f7c8ed185..ff8d4668cee217 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -4473,11 +4473,15 @@ int main(int argc, char *argv[])
}
if (fctx.lockfile) {
- FILE *lockfile = fopen(fctx.lockfile, "w");
char *resolved;
+ int lockfd;
- if (!lockfile) {
- err = errno;
+ lockfd = open(fctx.lockfile, O_RDWR | O_CREAT | O_EXCL, 0400);
+ if (lockfd < 0) {
+ if (errno == EEXIST)
+ err = EWOULDBLOCK;
+ else
+ err = errno;
err_printf(&fctx, "%s: %s: %s\n", fctx.lockfile,
_("opening lockfile failed"),
strerror(err));
@@ -4485,7 +4489,7 @@ int main(int argc, char *argv[])
ret |= 32;
goto out;
}
- fclose(lockfile);
+ close(lockfd);
resolved = realpath(fctx.lockfile, NULL);
if (!resolved) {
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 11/8] fuse2fs: fix race condition in op_destroy
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (9 preceding siblings ...)
2025-07-08 17:33 ` [PATCH 10/8] fuse2fs: fix lockfile creation, again Darrick J. Wong
@ 2025-07-09 16:51 ` Darrick J. Wong
2025-07-09 16:52 ` [PATCH 12/8] fuse2fs: fix races in statfs Darrick J. Wong
` (10 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-09 16:51 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
On a regular fuse server (i.e. one not running in fuseblk mode), libfuse
synthesizes and dispatches a FUSE_DESTROY command as soon as the event
dispatch loop terminates after the kernel disconnects /dev/fuse.
Unfortunately, this is done without coordinating with any other threads
that may have already received a real FUSE command from the kernel.
In other words, FUSE_DESTROY can run in parallel with other
fuse_operations. Therefore, we must guard the body of this function
with the BKL just like any other fuse operation or risk races within
libext2fs. If we're lucky, we trash the ext2_filsys state and
generic/488 will crash.
[23512.452451] [U] fuse: reading device: Software caused connection abort
[23512.453886] [U] fuse: reading device: Software caused connection abort
If we're not lucky, it corrupts the ondisk filesystem resulting in a
e2fsck complaining as well.
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 | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index ff8d4668cee217..f0250bd1cec2ec 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -728,7 +728,10 @@ static void op_destroy(void *p EXT2FS_ATTR((unused)))
translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
return;
}
+
+ pthread_mutex_lock(&ff->bfl);
fs = ff->fs;
+
dbg_printf(ff, "%s: dev=%s\n", __func__, fs->device_name);
if (fs->flags & EXT2_FLAG_RW) {
fs->super->s_state |= EXT2_VALID_FS;
@@ -763,6 +766,8 @@ static void op_destroy(void *p EXT2FS_ATTR((unused)))
uuid_unparse(fs->super->s_uuid, uuid);
log_printf(ff, "%s %s.\n", _("unmounting filesystem"), uuid);
}
+
+ pthread_mutex_unlock(&ff->bfl);
}
static void *op_init(struct fuse_conn_info *conn
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 12/8] fuse2fs: fix races in statfs
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (10 preceding siblings ...)
2025-07-09 16:51 ` [PATCH 11/8] fuse2fs: fix race condition in op_destroy Darrick J. Wong
@ 2025-07-09 16:52 ` Darrick J. Wong
2025-07-17 14:59 ` [PATCH 13/8] fuse2fs: fix ST_RDONLY setting Darrick J. Wong
` (9 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-09 16:52 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Take the BFL in statfs so that we don't expose a torn access to
userspace. Found via code inspection.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index f0250bd1cec2ec..bc9fed6f4a8525 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -2743,8 +2743,9 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
blk64_t overhead, reserved, free;
FUSE2FS_CHECK_CONTEXT(ff);
- fs = ff->fs;
dbg_printf(ff, "%s: path=%s\n", __func__, path);
+ fs = ff->fs;
+ pthread_mutex_lock(&ff->bfl);
buf->f_bsize = fs->blocksize;
buf->f_frsize = 0;
@@ -2777,6 +2778,7 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
if (fs->flags & EXT2_FLAG_RW)
buf->f_flag |= ST_RDONLY;
buf->f_namemax = EXT2_NAME_LEN;
+ pthread_mutex_unlock(&ff->bfl);
return 0;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 13/8] fuse2fs: fix ST_RDONLY setting
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (11 preceding siblings ...)
2025-07-09 16:52 ` [PATCH 12/8] fuse2fs: fix races in statfs Darrick J. Wong
@ 2025-07-17 14:59 ` 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
` (8 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-17 14:59 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Only set ST_RDONLY if the filesystem isn't writable.
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 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index bc9fed6f4a8525..bff303a10e7186 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -2775,7 +2775,7 @@ static int op_statfs(const char *path EXT2FS_ATTR((unused)),
fsid ^= *f;
buf->f_fsid = fsid;
buf->f_flag = 0;
- if (fs->flags & EXT2_FLAG_RW)
+ if (!(fs->flags & EXT2_FLAG_RW))
buf->f_flag |= ST_RDONLY;
buf->f_namemax = EXT2_NAME_LEN;
pthread_mutex_unlock(&ff->bfl);
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 14/8] libext2fs: fix data read corruption in ext2fs_file_read_inline_data
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (12 preceding siblings ...)
2025-07-17 14:59 ` [PATCH 13/8] fuse2fs: fix ST_RDONLY setting Darrick J. Wong
@ 2025-07-17 14:59 ` Darrick J. Wong
2025-07-17 14:59 ` [PATCH 15/8] libext2fs: fix data corruption when writing to inline data files Darrick J. Wong
` (7 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-17 14:59 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Fix numerous problems in the function that reads data from an inlinedata
file:
- Reads starting after isize should be returned as short reads.
- Reads past the end of the inline data should return zeroes.
- Reads from the inline data buffer must not exceed isize.
Cc: <linux-ext4@vger.kernel.org> # v1.43
Fixes: 54e880b870f7fe ("libext2fs: handle inline data in read/write function")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
lib/ext2fs/fileio.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 818f7f05420029..900002c5295682 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -255,18 +255,26 @@ ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
unsigned int wanted, unsigned int *got)
{
ext2_filsys fs;
- errcode_t retval;
+ errcode_t retval = 0;
unsigned int count = 0;
+ uint64_t isize = EXT2_I_SIZE(&file->inode);
size_t size;
+ if (file->pos >= isize)
+ goto out;
+
fs = file->fs;
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
file->buf, &size);
if (retval)
return retval;
- if (file->pos >= size)
- goto out;
+ /*
+ * size is the number of bytes available for inline data storage, which
+ * means it can exceed isize.
+ */
+ if (size > isize)
+ size = isize;
count = size - file->pos;
if (count > wanted)
@@ -275,6 +283,14 @@ ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
file->pos += count;
buf = (char *) buf + count;
+ /* zero-fill the rest of the buffer */
+ wanted -= count;
+ if (wanted > 0) {
+ memset(buf, 0, wanted);
+ file->pos += wanted;
+ count += wanted;
+ }
+
out:
if (got)
*got = count;
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 15/8] libext2fs: fix data corruption when writing to inline data files
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (13 preceding siblings ...)
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 ` 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
` (6 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-17 14:59 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Fix various bugs in ext2fs_file_write_inline_data:
- "count = nbytes - pos" makes no sense since nbytes is already a
length value and results in short writes if pos > 0.
- Pass the correct file size to ext2fs_inline_data_set because count
will not be the file size if pos > 0.
- Simplify the decision to increase the file size.
- Don't let a huge write corrupt memory beyond file->buf.
- Zero the buffer between isize and pos if we're doing a sparse write
past EOF.
Cc: <linux-ext4@vger.kernel.org> # v1.43
Fixes: 54e880b870f7fe ("libext2fs: handle inline data in read/write function")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
lib/ext2fs/fileio.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 900002c5295682..3a36e9e7fff43b 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -349,31 +349,42 @@ ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
unsigned int nbytes, unsigned int *written)
{
ext2_filsys fs;
+ uint64_t old_isize = EXT2_I_SIZE(&file->inode);
+ uint64_t new_isize = old_isize;
errcode_t retval;
- unsigned int count = 0;
size_t size;
+ if (file->pos + nbytes > old_isize)
+ new_isize = file->pos + nbytes;
+
fs = file->fs;
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
file->buf, &size);
if (retval)
return retval;
- if (file->pos < size) {
- count = nbytes - file->pos;
- memcpy(file->buf + file->pos, buf, count);
+ /*
+ * Only try to set new inline data if it won't go past the end of
+ * @file->buf; if there's not enough space in the ondisk inode, we'll
+ * jump out to the expand code.
+ */
+ if (new_isize < fs->blocksize) {
+ if (file->pos > old_isize)
+ memset(file->buf + old_isize, 0, file->pos - old_isize);
+
+ memcpy(file->buf + file->pos, buf, nbytes);
retval = ext2fs_inline_data_set(fs, file->ino, &file->inode,
- file->buf, count);
+ file->buf, new_isize);
if (retval == EXT2_ET_INLINE_DATA_NO_SPACE)
goto expand;
if (retval)
return retval;
- file->pos += count;
+ file->pos += nbytes;
/* Update inode size */
- if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
+ if (old_isize < new_isize) {
errcode_t rc;
rc = ext2fs_file_set_size2(file, file->pos);
@@ -382,7 +393,7 @@ ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
}
if (written)
- *written = count;
+ *written = nbytes;
return 0;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 16/8] fuse2fs: fix clean_block_middle when punching byte 0 of a block
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (14 preceding siblings ...)
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 ` Darrick J. Wong
2025-07-17 22:01 ` [PATCH 17/8] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range Darrick J. Wong
` (5 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-17 22:01 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
In non-iomap mode, generic/008 tries to fzero the first byte of a block
and fails:
--- a/tests/generic/008.out 2025-07-15 14:45:14.937058680 -0700
+++ b/tests/generic/008.out.bad 2025-07-16 11:43:42.427989360 -0700
@@ -4,8 +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
+00000000: 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
*
Here we can clearly see that the first byte of the block has not been
zeroed, even though that's what the caller wanted us to do. This is due
to an incorrect check of the residue variable that was most likely copy
pasted from clean_block_edge years ago.
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 | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index bff303a10e7186..6155dff6645ff6 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -4007,14 +4007,10 @@ static errcode_t clean_block_middle(struct fuse2fs *ff, ext2_ino_t ino,
{
ext2_filsys fs = ff->fs;
blk64_t blk;
- off_t residue;
+ off_t residue = FUSE2FS_OFF_IN_FSB(ff, offset);
int retflags;
errcode_t err;
- residue = FUSE2FS_OFF_IN_FSB(ff, offset);
- if (residue == 0)
- return 0;
-
if (!*buf) {
err = ext2fs_get_mem(fs->blocksize, buf);
if (err)
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 17/8] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (15 preceding siblings ...)
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
2025-07-22 19:40 ` [PATCH 18/8] fuse2fs: fix logging redirection Darrick J. Wong
` (4 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-17 22:01 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
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);
}
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 18/8] fuse2fs: fix logging redirection
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (16 preceding siblings ...)
2025-07-17 22:01 ` [PATCH 17/8] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range Darrick J. Wong
@ 2025-07-22 19:40 ` 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
` (3 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-22 19:40 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4, sam
From: Darrick J. Wong <djwong@kernel.org>
Someone pointed out that you can't just go around reassigning stdout and
stderr because section 7.23.1 paragraph 4 of a recent C2y draft says
that stdin, stdout, and stderr “are expressions of type "pointer to
FILE" that point to the FILE objects associated, respectively, with the
standard error, input, and output streams.”
The use of the word "expression" should have been the warning sign that
a symbol that can be mostly used as a pointer is not simply a pointer.
Seven pages later, footnote 318 of the C2y draft clarifies that stdin,
stdout, and stderr “need not be modifiable lvalues to which the value
returned by the fopen function could be assigned.”
"need not be" is the magic phrasing that means that glibc, musl, and
mingw (for example) have very different declarations of stdout:
glibc:
extern FILE *stdout; /* Standard output stream. */
musl:
extern FILE *const stdout;
mingw:
#define stdout (&_iob[STDOUT_FILENO])
All three are following the specification, yet you can write C code that
fails to compile what otherwise looks like a normal assignment on two of
the libraries:
static FILE *const fark; /* musl */
FILE crap[3]; /* mingw */
#define crows (&crap[0])
static FILE *stupid; /* glibc */
int main(int argc, char *argv[])
{
fark = NULL;
crows = NULL;
stupid = NULL;
}
/tmp/a.c: In function ‘main’:
/tmp/a.c:20:14: error: assignment of read-only variable ‘fark’
20 | fark = NULL;
| ^
/tmp/a.c:21:15: error: lvalue required as left operand of assignment
21 | crows = NULL;
| ^
What a useless specification! You don't even get the same error!
Unfortunately, this leadership vacuum means that each implementation of
a so-called standard C library is perfectly within its right to do this.
IOWs, the authors decided that every C programmer must divert some of
the brainpower they could spend on their program's core algorithms to be
really smart about this quirk.
A whole committee of very smart programmers collectively decided this
was a good way to run things decades ago so that C library authors in
the 1980s wouldn't have to change their code, and subsequent gatherings
have reaffirmed this "practical" decision. Their suggestion to reassign
stdout and stderr is to use freopen, but that walks the specified path,
which is racy if you want both streams to point to the same file. You
could pass /dev/fd/XX to solve the race, but then you lose portability.
In other words, they "engineered" an incomplete solution with problems
to achieve a short term goal that nobody should care about 40 years
later.
Fix fuse2fs by rearranging the code to change STD{OUT,ERR}_FILENO to
point to the same open logfile via dup2 and then try to use freopen on
/dev/fd/XX to capture any stdout/err usage by the libraries that fuse2fs
depends on.
Note that we must do the whole thing over again in op_init because
libfuse will dup2 STD{OUT,ERR}_FILE to /dev/null as part of daemonizing
the server.
Cc: <linux-ext4@vger.kernel.org> # v1.47.3
Fixes: 5cdebf3eebc22c ("fuse2fs: stop aliasing stderr with ff->err_fp")
Link: https://github.com/tytso/e2fsprogs/issues/235
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 123 insertions(+), 18 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index cee9e657c36767..242bbfd221eb3a 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -229,6 +229,7 @@ struct fuse2fs {
uint8_t directio;
uint8_t acl;
+ int logfd;
int blocklog;
unsigned int blockmask;
unsigned long offset;
@@ -792,6 +793,111 @@ static void op_destroy(void *p EXT2FS_ATTR((unused)))
pthread_mutex_unlock(&ff->bfl);
}
+/* Reopen @stream with @fileno */
+static int fuse2fs_freopen_stream(const char *path, int fileno, FILE *stream)
+{
+ char _fdpath[256];
+ const char *fdpath;
+ FILE *fp;
+ int ret;
+
+ ret = snprintf(_fdpath, sizeof(_fdpath), "/dev/fd/%d", fileno);
+ if (ret >= sizeof(_fdpath))
+ fdpath = path;
+ else
+ fdpath = _fdpath;
+
+ /*
+ * C23 defines std{out,err} as an expression of type FILE* that need
+ * not be an lvalue. What this means is that we can't just assign to
+ * stdout: we have to use freopen, which takes a path.
+ *
+ * There's no guarantee that the OS provides a /dev/fd/X alias for open
+ * file descriptors, so if that fails, fall back to the original log
+ * file path. We'd rather not do a path-based reopen because that
+ * exposes us to rename race attacks.
+ */
+ fp = freopen(fdpath, "a", stream);
+ if (!fp && errno == ENOENT && fdpath == _fdpath)
+ fp = freopen(path, "a", stream);
+ if (!fp) {
+ perror(fdpath);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Redirect stdout/stderr to a file, or return a mount-compatible error. */
+static int fuse2fs_capture_output(struct fuse2fs *ff, const char *path)
+{
+ int ret;
+ int fd;
+
+ /*
+ * First, open the log file path with system calls so that we can
+ * redirect the stdout/stderr file numbers (typically 1 and 2) to our
+ * logfile descriptor. We'd like to avoid allocating extra file
+ * objects in the kernel if we can because pos will be the same between
+ * stdout and stderr.
+ */
+ if (ff->logfd < 0) {
+ fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0600);
+ if (fd < 0) {
+ perror(path);
+ return -1;
+ }
+
+ /*
+ * Save the newly opened fd in case we have to do this again in
+ * op_init.
+ */
+ ff->logfd = fd;
+ }
+
+ ret = dup2(ff->logfd, STDOUT_FILENO);
+ if (ret < 0) {
+ perror(path);
+ return -1;
+ }
+
+ ret = dup2(ff->logfd, STDERR_FILENO);
+ if (ret < 0) {
+ perror(path);
+ return -1;
+ }
+
+ /*
+ * Now that we've changed STD{OUT,ERR}_FILENO to be the log file, use
+ * freopen to make sure that std{out,err} (the C library abstractions)
+ * point to the STDXXX_FILENO because any of our library dependencies
+ * might decide to printf to one of those streams and we want to
+ * capture all output in the log.
+ */
+ ret = fuse2fs_freopen_stream(path, STDOUT_FILENO, stdout);
+ if (ret)
+ return ret;
+ ret = fuse2fs_freopen_stream(path, STDERR_FILENO, stderr);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* Set up debug and error logging files */
+static int fuse2fs_setup_logging(struct fuse2fs *ff)
+{
+ char *logfile = getenv("FUSE2FS_LOGFILE");
+ if (logfile)
+ return fuse2fs_capture_output(ff, logfile);
+
+ /* in kernel mode, try to log errors to the kernel log */
+ if (ff->kernel)
+ fuse2fs_capture_output(ff, "/dev/ttyprintk");
+
+ return 0;
+}
+
static void *op_init(struct fuse_conn_info *conn
#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
, struct fuse_config *cfg EXT2FS_ATTR((unused))
@@ -807,6 +913,17 @@ static void *op_init(struct fuse_conn_info *conn
translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
return NULL;
}
+
+ /*
+ * Configure logging a second time, because libfuse might have
+ * redirected std{out,err} as part of daemonization. If this fails,
+ * give up and move on.
+ */
+ fuse2fs_setup_logging(ff);
+ if (ff->logfd >= 0)
+ close(ff->logfd);
+ ff->logfd = -1;
+
fs = ff->fs;
dbg_printf(ff, "%s: dev=%s\n", __func__, fs->device_name);
#ifdef FUSE_CAP_IOCTL_DIR
@@ -4448,7 +4565,6 @@ int main(int argc, char *argv[])
struct fuse2fs fctx;
errcode_t err;
FILE *orig_stderr = stderr;
- char *logfile;
char extra_args[BUFSIZ];
int ret;
int flags = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | EXT2_FLAG_EXCLUSIVE |
@@ -4456,6 +4572,7 @@ int main(int argc, char *argv[])
memset(&fctx, 0, sizeof(fctx));
fctx.magic = FUSE2FS_MAGIC;
+ fctx.logfd = -1;
ret = fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
if (ret)
@@ -4482,23 +4599,11 @@ int main(int argc, char *argv[])
#endif
add_error_table(&et_ext2_error_table);
- /* Set up error logging */
- logfile = getenv("FUSE2FS_LOGFILE");
- if (logfile) {
- FILE *fp = fopen(logfile, "a");
- if (!fp) {
- perror(logfile);
- goto out;
- }
- stderr = fp;
- stdout = fp;
- } else if (fctx.kernel) {
- /* in kernel mode, try to log errors to the kernel log */
- FILE *fp = fopen("/dev/ttyprintk", "a");
- if (fp) {
- stderr = fp;
- stdout = fp;
- }
+ ret = fuse2fs_setup_logging(&fctx);
+ if (ret) {
+ /* operational error */
+ ret = 2;
+ goto out;
}
/* Will we allow users to allocate every last block? */
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 19/8] fuse2fs: don't record every errno in the superblock as an fs failure
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (17 preceding siblings ...)
2025-07-22 19:40 ` [PATCH 18/8] fuse2fs: fix logging redirection Darrick J. Wong
@ 2025-07-25 15:56 ` Darrick J. Wong
2025-07-26 16:28 ` [PATCH 20/8] fuse2fs: fix punching post-EOF blocks during truncate Darrick J. Wong
` (2 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-25 15:56 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
fstests just blew up because somewhere in the fuse iomap code we
returned an ESTALE, which was then passed to translate_error. That
function decided it was a Serious Error and wrote it to the superblock,
so every subsequent mount attempt failed.
I should go figure out why the iomap cache upsert operation returned
ESTALE, but that's not a sign that the *ondisk* filesystem is corrupt.
Prior to commit 71f046a788adba we wouldn't have written that to the
superblock either.
Fix this by isolating the handful of errno that usually mean corruption
problems in filesystems and writing those to the superblock; the other
errno are merely operational errors that can be passed back to the
kernel and up to userspace.
I'm not sure why e2fsck doesn't flag when s_error_count > 0. That might
be an error on its own.
Cc: <linux-ext4@vger.kernel.org> # v1.47.3
Fixes: 71f046a788adba ("fuse2fs: correctly handle system errno values in __translate_error()")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 242bbfd221eb3a..18d8f426a5eb43 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -4969,9 +4969,23 @@ static int __translate_error(ext2_filsys fs, ext2_ino_t ino, errcode_t err,
is_err = 1;
ret = -EUCLEAN;
break;
- default:
+ case EIO:
+#ifdef EILSEQ
+ case EILSEQ:
+#endif
+ case EUCLEAN:
+ /* these errnos usually denote corruption or persistence fail */
is_err = 1;
- ret = (err < 256) ? -err : -EIO;
+ ret = -err;
+ break;
+ default:
+ if (err < 256) {
+ /* other errno are usually operational errors */
+ ret = -err;
+ } else {
+ is_err = 1;
+ ret = -EIO;
+ }
break;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 20/8] fuse2fs: fix punching post-EOF blocks during truncate
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (18 preceding siblings ...)
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 ` 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
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-26 16:28 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
ext2fs_punch() can update the inode that's passed in, so we need to
write it back. This should fix some fstests failures where the test
file system ends up with inodes where all extent records fit within the
inode but inexplicably have extents beyond EOF. While we're at it, add
the fuse2fs prefix to the two helper functions.
Cc: <linux-ext4@vger.kernel.org> # v1.47.3
Fixes: 4581ac60eb53ec ("fuse2fs: fix post-EOF preallocation clearing on truncation")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 18d8f426a5eb43..c6b1684f53e2e4 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -2461,7 +2461,8 @@ static int op_chown(const char *path, uid_t owner, gid_t group
return ret;
}
-static int punch_posteof(struct fuse2fs *ff, ext2_ino_t ino, off_t new_size)
+static int fuse2fs_punch_posteof(struct fuse2fs *ff, ext2_ino_t ino,
+ off_t new_size)
{
ext2_filsys fs = ff->fs;
struct ext2_inode_large inode;
@@ -2477,10 +2478,14 @@ static int punch_posteof(struct fuse2fs *ff, ext2_ino_t ino, off_t new_size)
if (err)
return translate_error(fs, ino, err);
+ err = fuse2fs_write_inode(fs, ino, &inode);
+ if (err)
+ return translate_error(fs, ino, err);
+
return 0;
}
-static int truncate_helper(struct fuse2fs *ff, ext2_ino_t ino, off_t new_size)
+static int fuse2fs_truncate(struct fuse2fs *ff, ext2_ino_t ino, off_t new_size)
{
ext2_filsys fs = ff->fs;
ext2_file_t file;
@@ -2523,7 +2528,7 @@ static int truncate_helper(struct fuse2fs *ff, ext2_ino_t ino, off_t new_size)
* we should clear out post-EOF preallocations.
*/
if (new_size == old_isize)
- return punch_posteof(ff, ino, new_size);
+ return fuse2fs_punch_posteof(ff, ino, new_size);
return 0;
}
@@ -2559,7 +2564,7 @@ static int op_truncate(const char *path, off_t len
if (ret)
goto out;
- ret = truncate_helper(ff, ino, len);
+ ret = fuse2fs_truncate(ff, ino, len);
if (ret)
goto out;
@@ -2659,7 +2664,7 @@ static int __op_open(struct fuse2fs *ff, const char *path,
}
if (fp->flags & O_TRUNC) {
- ret = truncate_helper(ff, file->ino, 0);
+ ret = fuse2fs_truncate(ff, file->ino, 0);
if (ret)
goto out;
}
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 21/8] fuse2fs: fix block parameter truncation on 32-bit
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (19 preceding siblings ...)
2025-07-26 16:28 ` [PATCH 20/8] fuse2fs: fix punching post-EOF blocks during truncate Darrick J. Wong
@ 2025-07-30 17:23 ` Darrick J. Wong
2025-07-31 14:47 ` [PATCHSET] fuse2fs: more bug fixes Theodore Ts'o
21 siblings, 0 replies; 23+ messages in thread
From: Darrick J. Wong @ 2025-07-30 17:23 UTC (permalink / raw)
To: tytso; +Cc: linux-ext4
From: Darrick J. Wong <djwong@kernel.org>
Use the blk64_t variants of the io channel read/write methods when we
have to do partial block zeroing for hole punching because otherwise
we corrupt large 64-bit filesystems on 32-bit fuse2fs due to integer
truncation.
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 | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index c6b1684f53e2e4..4d42a634bf377b 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -4168,13 +4168,13 @@ static errcode_t clean_block_middle(struct fuse2fs *ff, ext2_ino_t ino,
if (!blk || (retflags & BMAP_RET_UNINIT))
return 0;
- err = io_channel_read_blk(fs->io, blk, 1, *buf);
+ err = io_channel_read_blk64(fs->io, blk, 1, *buf);
if (err)
return err;
memset(*buf + residue, 0, len);
- return io_channel_write_blk(fs->io, blk, 1, *buf);
+ return io_channel_write_blk64(fs->io, blk, 1, *buf);
}
static errcode_t clean_block_edge(struct fuse2fs *ff, ext2_ino_t ino,
@@ -4202,7 +4202,7 @@ static errcode_t clean_block_edge(struct fuse2fs *ff, ext2_ino_t ino,
if (err)
return err;
- err = io_channel_read_blk(fs->io, blk, 1, *buf);
+ err = io_channel_read_blk64(fs->io, blk, 1, *buf);
if (err)
return err;
if (!blk || (retflags & BMAP_RET_UNINIT))
@@ -4213,7 +4213,7 @@ static errcode_t clean_block_edge(struct fuse2fs *ff, ext2_ino_t ino,
else
memset(*buf + residue, 0, fs->blocksize - residue);
- return io_channel_write_blk(fs->io, blk, 1, *buf);
+ return io_channel_write_blk64(fs->io, blk, 1, *buf);
}
static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCHSET] fuse2fs: more bug fixes
2025-07-06 18:30 [PATCHSET] fuse2fs: more bug fixes Darrick J. Wong
` (20 preceding siblings ...)
2025-07-30 17:23 ` [PATCH 21/8] fuse2fs: fix block parameter truncation on 32-bit Darrick J. Wong
@ 2025-07-31 14:47 ` Theodore Ts'o
21 siblings, 0 replies; 23+ messages in thread
From: Theodore Ts'o @ 2025-07-31 14:47 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: Theodore Ts'o, linux-ext4
On Sun, 06 Jul 2025 11:30:54 -0700, Darrick J. Wong wrote:
> This series fixes more bugs in fuse2fs.
>
> If you're going to start using this code, I strongly recommend pulling
> from my git trees, which are linked below.
>
> Comments and questions are, as always, welcome.
>
> [...]
Applied, thanks!
[1/8] libext2fs: fix off-by-one bug in punch_extent_blocks
commit: 509da98991e2a3f72042c6b29e538a5269357a80
[2/8] libext2fs: fix arguments passed to ->block_alloc_stats_range
commit: 520caea10dec63fb9abebaa55578a671d9f2aa15
[3/8] fuse2fs: refactor uid/gid setting
commit: e1d3faea4ed9875a438a54a6b89c1089d81098c2
[4/8] fuse2fs: fix gid inheritance on sgid parent directories
commit: 33880eea11b71ec6f7ef80c5f4911464d5de2edb
[5/8] fuse2fs: don't truncate when creating a new file
commit: e3a1437758398e8adcd141aabb7c572af8ef356a
[6/8] fuse2fs: fix incorrect EOFS input handling in FITRIM
commit: 62b2a1619d858f65acaa6ce64623fb8684a88882
[7/8] fuse2fs: fix incorrect unit conversion at the end of FITRIM
commit: 861aa217652426711a619d11aab5c92006a98e22
[8/8] fuse2fs: don't try to mount after option parsing errors
commit: e7774d8fef39d16eb96f1e55cf2f33d3acb14d88
[9/9] fuse2fs: fix relatime comparisons
commit: 5cd55fe0aca3fed5a7ca6f0b4976f0e7b1e4a972
[10/10] fuse2fs: fix lockfile creation, again
commit: 9bdd3c20c1bb2b47fdd7bff59f75110b792bfc13
[11/11] fuse2fs: fix race condition in op_destroy
commit: dde5994fa0c314fb5b0f4020106937db4b12d68c
[12/12] fuse2fs: fix races in statfs
commit: 5aeeba417fd0a6598046cd59807235db00e99908
[13/13] fuse2fs: fix ST_RDONLY setting
commit: b9d23a1a128e553f6ce73766bc884263ba30990d
[14/14] libext2fs: fix data read corruption in ext2fs_file_read_inline_data
commit: 10d7761527fa0778a64ea5cf3482744869dbb3a7
[15/15] libext2fs: fix data corruption when writing to inline data files
commit: bc599a8bf3d448a12d14e9b2f2f1618600c2daa1
[16/16] fuse2fs: fix clean_block_middle when punching byte 0 of a block
commit: 9b44c01c1f9d800a56bb7a01a53e4f318c08d9f2
[17/17] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range
commit: e18b350af2d77f1e063ad9ae765dd161022bb04a
[18/18] fuse2fs: fix logging redirection
commit: f79abd8554e600eacc2a7c864a8332b670c9e262
[19/19] fuse2fs: don't record every errno in the superblock as an fs failure
commit: bed461d69f4c14b35f86ff25bad220ba3c5d500e
[20/20] fuse2fs: fix punching post-EOF blocks during truncate
commit: 86a24ae12c4fb81ec0b27ae1b63d3e5b05c7d46f
[21/21] fuse2fs: fix block parameter truncation on 32-bit
commit: a5da316e5b54e12da000c60191c6220692c00f0f
Best regards,
--
Theodore Ts'o <tytso@mit.edu>
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2025-07-31 14:47 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 17/8] fuse2fs: fix punch-out range calculation in fuse2fs_punch_range Darrick J. Wong
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).