From: Darrick J. Wong Date: Thu, 24 Apr 2025 21:44:41 +0000 (-0700) Subject: fuse2fs: fix FITRIM validation X-Git-Tag: v1.47.3-rc1~85 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7235b58533b9cd72b783daa4d6d554a9d8ee088c;p=thirdparty%2Fe2fsprogs.git fuse2fs: fix FITRIM validation Fix the validation here to match the kernel, and report the number of blocks trimmed. Signed-off-by: Darrick J. Wong Link: https://lore.kernel.org/r/174553065195.1160461.15575039465292160279.stgit@frogsfrogsfrogs Signed-off-by: Theodore Ts'o --- diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c index eb370217..178d3eb0 100644 --- a/misc/fuse2fs.c +++ b/misc/fuse2fs.c @@ -3206,17 +3206,27 @@ static int ioctl_fitrim(struct fuse2fs *ff, struct fuse2fs_file_handle *fh, { ext2_filsys fs = ff->fs; struct fstrim_range *fr = data; - blk64_t start, end, max_blocks, b, cleared; + blk64_t start, end, max_blocks, b, cleared, minlen; + blk64_t max_blks = ext2fs_blocks_count(fs->super); errcode_t err = 0; + if (!fs_writeable(fs)) + return -EROFS; + start = fr->start / fs->blocksize; end = (fr->start + fr->len - 1) / fs->blocksize; - dbg_printf(ff, "%s: start=%llu end=%llu\n", __func__, start, end); + minlen = fr->minlen / fs->blocksize; + + if (EXT2FS_NUM_B2C(fs, minlen) > EXT2_CLUSTERS_PER_GROUP(fs->super) || + start >= max_blks || + fr->len < fs->blocksize) + return -EINVAL; + + dbg_printf(ff, "%s: start=%llu end=%llu minlen=%llu\n", __func__, + start, end, minlen); if (start < fs->super->s_first_data_block) start = fs->super->s_first_data_block; - if (start >= ext2fs_blocks_count(fs->super)) - start = ext2fs_blocks_count(fs->super) - 1; if (end < fs->super->s_first_data_block) end = fs->super->s_first_data_block; @@ -3230,17 +3240,23 @@ static int ioctl_fitrim(struct fuse2fs *ff, struct fuse2fs_file_handle *fh, while (start <= end) { err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, start, end, &start); - if (err == ENOENT) - return 0; - else if (err) + switch (err) { + case 0: + break; + case ENOENT: + /* no free blocks found, so we're done */ + err = 0; + goto out; + default: return translate_error(fs, fh->ino, err); + } b = start + max_blocks < end ? start + max_blocks : end; err = ext2fs_find_first_set_block_bitmap2(fs->block_map, start, b, &b); if (err && err != ENOENT) return translate_error(fs, fh->ino, err); - if (b - start >= fr->minlen) { + if (b - start >= minlen) { err = io_channel_discard(fs->io, start, b - start); if (err) return translate_error(fs, fh->ino, err); @@ -3250,6 +3266,8 @@ static int ioctl_fitrim(struct fuse2fs *ff, struct fuse2fs_file_handle *fh, start = b + 1; } +out: + fr->len = cleared; return err; } #endif /* FITRIM */