Commit 9dfa23c8 authored by Sascha Hauer's avatar Sascha Hauer Committed by Jan Kara
Browse files

quota: Add mountpath based quota support

Add syscall quotactl_path, a variant of quotactl which allows to specify
the mountpath instead of a path of to a block device.

The quotactl syscall expects a path to the mounted block device to
specify the filesystem to work on. This limits usage to filesystems
which actually have a block device. quotactl_path replaces the path
to the block device with a path where the filesystem is mounted at.

The global Q_SYNC command to sync all filesystems is not supported for
this new syscall, otherwise quotactl_path behaves like quotactl.

Link: https://lore.kernel.org/r/20210304123541.30749-2-s.hauer@pengutronix.de


Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 1e28eed1
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/capability.h>
#include <linux/quotaops.h>
#include <linux/types.h>
#include <linux/mount.h>
#include <linux/writeback.h>
#include <linux/nospec.h>
#include "compat.h"
@@ -827,8 +828,6 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
	}
}

#ifdef CONFIG_BLOCK

/* Return 1 if 'cmd' will block on frozen filesystem */
static int quotactl_cmd_write(int cmd)
{
@@ -850,7 +849,6 @@ static int quotactl_cmd_write(int cmd)
	}
	return 1;
}
#endif /* CONFIG_BLOCK */

/* Return true if quotactl command is manipulating quota on/off state */
static bool quotactl_cmd_onoff(int cmd)
@@ -968,3 +966,48 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
		path_put(pathp);
	return ret;
}

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

	if (type >= MAXQUOTAS)
		return -EINVAL;

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

	sb = mountpath.mnt->mnt_sb;

	if (quotactl_cmd_write(cmds)) {
		ret = mnt_want_write(mountpath.mnt);
		if (ret)
			goto out;
	}

	if (quotactl_cmd_onoff(cmds))
		down_write(&sb->s_umount);
	else
		down_read(&sb->s_umount);

	ret = do_quotactl(sb, type, cmds, id, addr, ERR_PTR(-EINVAL));

	if (quotactl_cmd_onoff(cmds))
		up_write(&sb->s_umount);
	else
		up_read(&sb->s_umount);

	if (quotactl_cmd_write(cmds))
		mnt_drop_write(mountpath.mnt);
out:
	path_put(&mountpath);

	return ret;
}