Re: [f2fs-dev] [PATCH v4 2/2] f2fs: fix compat F2FS_IOC_{MOVE, GARBAGE_COLLECT}_RANGE

From: Chao Yu
Date: Sun Nov 08 2020 - 21:29:34 EST


On 2020/11/8 1:16, Eric Biggers wrote:
On Sat, Nov 07, 2020 at 05:25:23PM +0800, Chao Yu wrote:
On 2020/11/7 2:03, Eric Biggers wrote:
On Fri, Nov 06, 2020 at 02:53:31PM +0800, Chao Yu wrote:
+#if defined(__KERNEL__)
+struct compat_f2fs_gc_range {
+ u32 sync;
+ compat_u64 start;
+ compat_u64 len;
+};

There's no need to use '#if defined(__KERNEL__)' in kernel source files.

Likewise for compat_f2fs_move_range.

Correct.


+static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(file));
+ struct compat_f2fs_gc_range __user *urange;
+ struct f2fs_gc_range range;
+ int err;
+
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+ if (!f2fs_is_checkpoint_ready(sbi))
+ return -ENOSPC;

I still don't understand why this checkpoint-related stuff is getting added
here, and only to the compat versions of the ioctls. It wasn't in the original
version. If they are needed then they should be added to __f2fs_ioc_gc_range()
and __f2fs_ioc_move_range() (preferably by a separate patch) so that they are

If so, cp-related stuff will be checked redundantly in both f2fs_ioctl() and
__f2fs_ioc_xxx() function for native GC_RANGE and MOVE_RANGE ioctls, it's
not needed.


Oh I see, the cp-related checks are at the beginning of f2fs_ioctl() too.

In that case a much better approach would be to add __f2fs_ioctl() which is
called by f2fs_ioctl() and f2fs_compat_ioctl(), and have f2fs_ioctl() and
f2fs_compat_ioctl() do the cp-related checks but not __f2fs_ioctl().

Will this cleanup make sense to you?

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 458724c00d98..1439577108c2 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4249,16 +4249,10 @@ struct compat_f2fs_gc_range {

static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
{
- struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(file));
struct compat_f2fs_gc_range __user *urange;
struct f2fs_gc_range range;
int err;

- if (unlikely(f2fs_cp_error(sbi)))
- return -EIO;
- if (!f2fs_is_checkpoint_ready(sbi))
- return -ENOSPC;
-
urange = compat_ptr(arg);
err = get_user(range.sync, &urange->sync);
err |= get_user(range.start, &urange->start);
@@ -4280,16 +4274,10 @@ struct compat_f2fs_move_range {

static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
{
- struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(file));
struct compat_f2fs_move_range __user *urange;
struct f2fs_move_range range;
int err;

- if (unlikely(f2fs_cp_error(sbi)))
- return -EIO;
- if (!f2fs_is_checkpoint_ready(sbi))
- return -ENOSPC;
-
urange = compat_ptr(arg);
err = get_user(range.dst_fd, &urange->dst_fd);
err |= get_user(range.pos_in, &urange->pos_in);
@@ -4301,6 +4289,27 @@ static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
return __f2fs_ioc_move_range(file, &range);
}

+static long __f2fs_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(file));
+
+ if (unlikely(f2fs_cp_error(sbi)))
+ return -EIO;
+ if (!f2fs_is_checkpoint_ready(sbi))
+ return -ENOSPC;
+
+ switch (cmd) {
+ case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
+ return f2fs_compat_ioc_gc_range(file, arg);
+ case F2FS_IOC32_MOVE_RANGE:
+ return f2fs_compat_ioc_move_range(file, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
@@ -4314,9 +4323,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
cmd = FS_IOC_GETVERSION;
break;
case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
- return f2fs_compat_ioc_gc_range(file, arg);
case F2FS_IOC32_MOVE_RANGE:
- return f2fs_compat_ioc_move_range(file, arg);
+ return __f2fs_compat_ioctl(file, cmd, arg);
case F2FS_IOC_START_ATOMIC_WRITE:
case F2FS_IOC_COMMIT_ATOMIC_WRITE:
case F2FS_IOC_START_VOLATILE_WRITE:

Thanks,


I feel that's still not entirely correct, because ENOTTY should take precedence
over EIO or ENOSPC from the cp-related stuff. But at least it would be
consistent between the native and compat ioctls, and the cp-related checks
wouldn't have to be duplicated in random ioctls...

- Eric
.