From 3218a3ec87f7d0063b48b10cf3d649ce75966223 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Feb 2016 11:21:24 +1100 Subject: quota: remove unused cmd argument from quota_quotaon() The cmd argument to quota_quotaon() via Q_QUOTAON quotactl is not used, so remove it. Signed-off-by: Eric Sandeen Reviewed-by: Jan Kara Signed-off-by: Dave Chinner --- fs/quota/quota.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/quota') diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 3746367098fd..ea6667083b3e 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -79,7 +79,7 @@ unsigned int qtype_enforce_flag(int type) return 0; } -static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, +static int quota_quotaon(struct super_block *sb, int type, qid_t id, struct path *path) { if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable) @@ -659,7 +659,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, switch (cmd) { case Q_QUOTAON: - return quota_quotaon(sb, type, cmd, id, path); + return quota_quotaon(sb, type, id, path); case Q_QUOTAOFF: return quota_quotaoff(sb, type); case Q_GETFMT: -- cgit v1.2.3 From 8b37524962b9c54423374717786198f5c0820a28 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Feb 2016 11:21:50 +1100 Subject: quota: add new quotactl Q_XGETNEXTQUOTA Q_XGETNEXTQUOTA is exactly like Q_XGETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the requested id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota, -ESRCH is returned. This allows filesystems to do efficient iteration in kernelspace, much like extN filesystems do in userspace when asked to report all active quotas. The patch adds a d_id field to struct qc_dqblk so that we can pass back the id of the quota which was found, and return it to userspace. Today, filesystems such as XFS require getpwent-style iterations, and for systems which have i.e. LDAP backends, this can be very slow, or even impossible if iteration is not allowed in the configuration. Signed-off-by: Eric Sandeen Reviewed-by: Jan Kara Signed-off-by: Dave Chinner --- fs/quota/quota.c | 31 +++++++++++++++++++++++++++++++ include/linux/quota.h | 2 ++ include/uapi/linux/dqblk_xfs.h | 1 + 3 files changed, 34 insertions(+) (limited to 'fs/quota') diff --git a/fs/quota/quota.c b/fs/quota/quota.c index ea6667083b3e..0a6dd71ea309 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -625,6 +625,34 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id, return ret; } +/* + * Return quota for next active quota >= this id, if any exists, + * otherwise return -ESRCH via ->get_nextdqblk. + */ +static int quota_getnextxquota(struct super_block *sb, int type, qid_t id, + void __user *addr) +{ + struct fs_disk_quota fdq; + struct qc_dqblk qdq; + struct kqid qid; + qid_t id_out; + int ret; + + if (!sb->s_qcop->get_nextdqblk) + return -ENOSYS; + qid = make_kqid(current_user_ns(), type, id); + if (!qid_valid(qid)) + return -EINVAL; + ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq); + if (ret) + return ret; + id_out = from_kqid(current_user_ns(), qid); + copy_to_xfs_dqblk(&fdq, &qdq, type, id_out); + if (copy_to_user(addr, &fdq, sizeof(fdq))) + return -EFAULT; + return ret; +} + static int quota_rmxquota(struct super_block *sb, void __user *addr) { __u32 flags; @@ -690,6 +718,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, return quota_setxquota(sb, type, id, addr); case Q_XGETQUOTA: return quota_getxquota(sb, type, id, addr); + case Q_XGETNEXTQUOTA: + return quota_getnextxquota(sb, type, id, addr); case Q_XQUOTASYNC: if (sb->s_flags & MS_RDONLY) return -EROFS; @@ -712,6 +742,7 @@ static int quotactl_cmd_write(int cmd) case Q_XGETQSTAT: case Q_XGETQSTATV: case Q_XGETQUOTA: + case Q_XGETNEXTQUOTA: case Q_XQUOTASYNC: return 0; } diff --git a/include/linux/quota.h b/include/linux/quota.h index b2505acfd3c0..fba92f5c1a63 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -425,6 +425,8 @@ struct quotactl_ops { int (*quota_sync)(struct super_block *, int); int (*set_info)(struct super_block *, int, struct qc_info *); int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); + int (*get_nextdqblk)(struct super_block *, struct kqid *, + struct qc_dqblk *); int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); int (*get_state)(struct super_block *, struct qc_state *); int (*rm_xquota)(struct super_block *, unsigned int); diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h index dcd75cc26196..11b3b31faf14 100644 --- a/include/uapi/linux/dqblk_xfs.h +++ b/include/uapi/linux/dqblk_xfs.h @@ -39,6 +39,7 @@ #define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */ #define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ #define Q_XGETQSTATV XQM_CMD(8) /* newer version of get quota */ +#define Q_XGETNEXTQUOTA XQM_CMD(9) /* get disk limits and usage >= ID */ /* * fs_disk_quota structure: -- cgit v1.2.3 From 926132c0257a5a8d149a6a395cc3405e55420566 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Feb 2016 11:22:21 +1100 Subject: quota: add new quotactl Q_GETNEXTQUOTA Q_GETNEXTQUOTA is exactly like Q_GETQUOTA, except that it will return quota information for the id equal to or greater than the id requested. In other words, if the requested id has no quota, the command will return quota information for the next higher id which does have a quota set. If no higher id has an active quota, -ESRCH is returned. This allows filesystems to do efficient iteration in kernelspace, much like extN filesystems do in userspace when asked to report all active quotas. This does require a new data structure for userspace, as the current structure does not include an ID for the returned quota information. Today, Ext4 with a hidden quota inode requires getpwent-style iterations, and for systems which have i.e. LDAP backends, this can be very slow, or even impossible if iteration is not allowed in the configuration. Signed-off-by: Eric Sandeen Reviewed-by: Jan Kara Signed-off-by: Dave Chinner --- fs/quota/quota.c | 31 +++++++++++++++++++++++++++++++ include/uapi/linux/quota.h | 14 ++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'fs/quota') diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 0a6dd71ea309..0ebc90496525 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -222,6 +222,34 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id, return 0; } +/* + * Return quota for next active quota >= this id, if any exists, + * otherwise return -ESRCH via ->get_nextdqblk + */ +static int quota_getnextquota(struct super_block *sb, int type, qid_t id, + void __user *addr) +{ + struct kqid qid; + struct qc_dqblk fdq; + struct if_nextdqblk idq; + int ret; + + if (!sb->s_qcop->get_nextdqblk) + return -ENOSYS; + qid = make_kqid(current_user_ns(), type, id); + if (!qid_valid(qid)) + return -EINVAL; + ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq); + if (ret) + return ret; + /* struct if_nextdqblk is a superset of struct if_dqblk */ + copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq); + idq.dqb_id = from_kqid(current_user_ns(), qid); + if (copy_to_user(addr, &idq, sizeof(idq))) + return -EFAULT; + return 0; +} + static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src) { dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit); @@ -698,6 +726,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, return quota_setinfo(sb, type, addr); case Q_GETQUOTA: return quota_getquota(sb, type, id, addr); + case Q_GETNEXTQUOTA: + return quota_getnextquota(sb, type, id, addr); case Q_SETQUOTA: return quota_setquota(sb, type, id, addr); case Q_SYNC: @@ -738,6 +768,7 @@ static int quotactl_cmd_write(int cmd) switch (cmd) { case Q_GETFMT: case Q_GETINFO: + case Q_GETNEXTQUOTA: case Q_SYNC: case Q_XGETQSTAT: case Q_XGETQSTATV: diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h index 9c95b2c1c88a..38baddb807f5 100644 --- a/include/uapi/linux/quota.h +++ b/include/uapi/linux/quota.h @@ -71,6 +71,7 @@ #define Q_SETINFO 0x800006 /* set information about quota files */ #define Q_GETQUOTA 0x800007 /* get user quota structure */ #define Q_SETQUOTA 0x800008 /* set user quota structure */ +#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */ /* Quota format type IDs */ #define QFMT_VFS_OLD 1 @@ -119,6 +120,19 @@ struct if_dqblk { __u32 dqb_valid; }; +struct if_nextdqblk { + __u64 dqb_bhardlimit; + __u64 dqb_bsoftlimit; + __u64 dqb_curspace; + __u64 dqb_ihardlimit; + __u64 dqb_isoftlimit; + __u64 dqb_curinodes; + __u64 dqb_btime; + __u64 dqb_itime; + __u32 dqb_valid; + __u32 dqb_id; +}; + /* * Structure used for setting quota information about file via quotactl * Following flags are used to specify which fields are valid -- cgit v1.2.3