Skip to content

Commit

Permalink
quota: Change quotactl_path() systcall to an fd-based one
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jan Kara committed Jun 7, 2021
1 parent 21e4e15 commit 64c2c2c
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 20 deletions.
28 changes: 13 additions & 15 deletions fs/quota/quota.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,31 +968,30 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
return ret;
}

SYSCALL_DEFINE4(quotactl_path, unsigned int, cmd, const char __user *,
mountpoint, qid_t, id, void __user *, addr)
SYSCALL_DEFINE4(quotactl_fd, unsigned int, fd, unsigned int, cmd,
qid_t, id, void __user *, addr)
{
struct super_block *sb;
struct path mountpath;
unsigned int cmds = cmd >> SUBCMDSHIFT;
unsigned int type = cmd & SUBCMDMASK;
struct fd f;
int ret;

if (type >= MAXQUOTAS)
return -EINVAL;
f = fdget_raw(fd);
if (!f.file)
return -EBADF;

ret = user_path_at(AT_FDCWD, mountpoint,
LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT, &mountpath);
if (ret)
return ret;

sb = mountpath.mnt->mnt_sb;
ret = -EINVAL;
if (type >= MAXQUOTAS)
goto out;

if (quotactl_cmd_write(cmds)) {
ret = mnt_want_write(mountpath.mnt);
ret = mnt_want_write(f.file->f_path.mnt);
if (ret)
goto out;
}

sb = f.file->f_path.mnt->mnt_sb;
if (quotactl_cmd_onoff(cmds))
down_write(&sb->s_umount);
else
Expand All @@ -1006,9 +1005,8 @@ SYSCALL_DEFINE4(quotactl_path, unsigned int, cmd, const char __user *,
up_read(&sb->s_umount);

if (quotactl_cmd_write(cmds))
mnt_drop_write(mountpath.mnt);
mnt_drop_write(f.file->f_path.mnt);
out:
path_put(&mountpath);

fdput(f);
return ret;
}
4 changes: 2 additions & 2 deletions include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,8 @@ asmlinkage long sys_pipe2(int __user *fildes, int flags);
/* fs/quota.c */
asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special,
qid_t id, void __user *addr);
asmlinkage long sys_quotactl_path(unsigned int cmd, const char __user *mountpoint,
qid_t id, void __user *addr);
asmlinkage long sys_quotactl_fd(unsigned int fd, unsigned int cmd, qid_t id,
void __user *addr);

/* fs/readdir.c */
asmlinkage long sys_getdents64(unsigned int fd,
Expand Down
4 changes: 2 additions & 2 deletions include/uapi/asm-generic/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -863,8 +863,8 @@ __SYSCALL(__NR_process_madvise, sys_process_madvise)
__SC_COMP(__NR_epoll_pwait2, sys_epoll_pwait2, compat_sys_epoll_pwait2)
#define __NR_mount_setattr 442
__SYSCALL(__NR_mount_setattr, sys_mount_setattr)
#define __NR_quotactl_path 443
__SYSCALL(__NR_quotactl_path, sys_quotactl_path)
#define __NR_quotactl_fd 443
__SYSCALL(__NR_quotactl_fd, sys_quotactl_fd)

#define __NR_landlock_create_ruleset 444
__SYSCALL(__NR_landlock_create_ruleset, sys_landlock_create_ruleset)
Expand Down
2 changes: 1 addition & 1 deletion kernel/sys_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ COND_SYSCALL(flock);

/* fs/quota.c */
COND_SYSCALL(quotactl);
COND_SYSCALL(quotactl_path);
COND_SYSCALL(quotactl_fd);

/* fs/readdir.c */

Expand Down

0 comments on commit 64c2c2c

Please sign in to comment.