Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

quota: Change quotactl_path() systcall to an fd-based one

Some users have pointed out that path-based syscalls are problematic in
some environments and at least directory fd argument and possibly also
resolve flags are desirable for such syscalls. Rather than
reimplementing all details of pathname lookup and following where it may
eventually evolve, let's go for full file descriptor based syscall
similar to how ioctl(2) works since the beginning. Managing of quotas
isn't performance sensitive so the extra overhead of open does not
matter and we are able to consume O_PATH descriptors as well which makes
open cheap anyway. Also for frequent operations (such as retrieving
usage information for all users) we can reuse single fd and in fact get
even better performance as well as avoiding races with possible remounts
etc.

Tested-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 64c2c2c6 21e4e15a

+18 -20
+13 -15
fs/quota/quota.c
··· 968 968 return ret; 969 969 } 970 970 971 - SYSCALL_DEFINE4(quotactl_path, unsigned int, cmd, const char __user *, 972 - mountpoint, qid_t, id, void __user *, addr) 971 + SYSCALL_DEFINE4(quotactl_fd, unsigned int, fd, unsigned int, cmd, 972 + qid_t, id, void __user *, addr) 973 973 { 974 974 struct super_block *sb; 975 - struct path mountpath; 976 975 unsigned int cmds = cmd >> SUBCMDSHIFT; 977 976 unsigned int type = cmd & SUBCMDMASK; 977 + struct fd f; 978 978 int ret; 979 979 980 + f = fdget_raw(fd); 981 + if (!f.file) 982 + return -EBADF; 983 + 984 + ret = -EINVAL; 980 985 if (type >= MAXQUOTAS) 981 - return -EINVAL; 982 - 983 - ret = user_path_at(AT_FDCWD, mountpoint, 984 - LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT, &mountpath); 985 - if (ret) 986 - return ret; 987 - 988 - sb = mountpath.mnt->mnt_sb; 986 + goto out; 989 987 990 988 if (quotactl_cmd_write(cmds)) { 991 - ret = mnt_want_write(mountpath.mnt); 989 + ret = mnt_want_write(f.file->f_path.mnt); 992 990 if (ret) 993 991 goto out; 994 992 } 995 993 994 + sb = f.file->f_path.mnt->mnt_sb; 996 995 if (quotactl_cmd_onoff(cmds)) 997 996 down_write(&sb->s_umount); 998 997 else ··· 1005 1006 up_read(&sb->s_umount); 1006 1007 1007 1008 if (quotactl_cmd_write(cmds)) 1008 - mnt_drop_write(mountpath.mnt); 1009 + mnt_drop_write(f.file->f_path.mnt); 1009 1010 out: 1010 - path_put(&mountpath); 1011 - 1011 + fdput(f); 1012 1012 return ret; 1013 1013 }
+2 -2
include/linux/syscalls.h
··· 485 485 /* fs/quota.c */ 486 486 asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, 487 487 qid_t id, void __user *addr); 488 - asmlinkage long sys_quotactl_path(unsigned int cmd, const char __user *mountpoint, 489 - qid_t id, void __user *addr); 488 + asmlinkage long sys_quotactl_fd(unsigned int fd, unsigned int cmd, qid_t id, 489 + void __user *addr); 490 490 491 491 /* fs/readdir.c */ 492 492 asmlinkage long sys_getdents64(unsigned int fd,
+2 -2
include/uapi/asm-generic/unistd.h
··· 863 863 __SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2) 864 864 #define __NR_mount_setattr 442 865 865 __SYSCALL(__NR_mount_setattr, sys_mount_setattr) 866 - #define __NR_quotactl_path 443 867 - __SYSCALL(__NR_quotactl_path, sys_quotactl_path) 866 + #define __NR_quotactl_fd 443 867 + __SYSCALL(__NR_quotactl_fd, sys_quotactl_fd) 868 868 869 869 #define __NR_landlock_create_ruleset 444 870 870 __SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset)
+1 -1
kernel/sys_ni.c
··· 99 99 100 100 /* fs/quota.c */ 101 101 COND_SYSCALL(quotactl); 102 - COND_SYSCALL(quotactl_path); 102 + COND_SYSCALL(quotactl_fd); 103 103 104 104 /* fs/readdir.c */ 105 105