aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2016-02-07 19:22:21 -0500
committerDave Chinner <david@fromorbit.com>2016-02-07 19:22:21 -0500
commit926132c0257a5a8d149a6a395cc3405e55420566 (patch)
tree5913c59e71e12e53e4002bf0e973539af13a4f89
parent8b37524962b9c54423374717786198f5c0820a28 (diff)
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 <sandeen@redhat.com> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/quota/quota.c31
-rw-r--r--include/uapi/linux/quota.h14
2 files changed, 45 insertions, 0 deletions
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,
222 return 0; 222 return 0;
223} 223}
224 224
225/*
226 * Return quota for next active quota >= this id, if any exists,
227 * otherwise return -ESRCH via ->get_nextdqblk
228 */
229static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
230 void __user *addr)
231{
232 struct kqid qid;
233 struct qc_dqblk fdq;
234 struct if_nextdqblk idq;
235 int ret;
236
237 if (!sb->s_qcop->get_nextdqblk)
238 return -ENOSYS;
239 qid = make_kqid(current_user_ns(), type, id);
240 if (!qid_valid(qid))
241 return -EINVAL;
242 ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
243 if (ret)
244 return ret;
245 /* struct if_nextdqblk is a superset of struct if_dqblk */
246 copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
247 idq.dqb_id = from_kqid(current_user_ns(), qid);
248 if (copy_to_user(addr, &idq, sizeof(idq)))
249 return -EFAULT;
250 return 0;
251}
252
225static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src) 253static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
226{ 254{
227 dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit); 255 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,
698 return quota_setinfo(sb, type, addr); 726 return quota_setinfo(sb, type, addr);
699 case Q_GETQUOTA: 727 case Q_GETQUOTA:
700 return quota_getquota(sb, type, id, addr); 728 return quota_getquota(sb, type, id, addr);
729 case Q_GETNEXTQUOTA:
730 return quota_getnextquota(sb, type, id, addr);
701 case Q_SETQUOTA: 731 case Q_SETQUOTA:
702 return quota_setquota(sb, type, id, addr); 732 return quota_setquota(sb, type, id, addr);
703 case Q_SYNC: 733 case Q_SYNC:
@@ -738,6 +768,7 @@ static int quotactl_cmd_write(int cmd)
738 switch (cmd) { 768 switch (cmd) {
739 case Q_GETFMT: 769 case Q_GETFMT:
740 case Q_GETINFO: 770 case Q_GETINFO:
771 case Q_GETNEXTQUOTA:
741 case Q_SYNC: 772 case Q_SYNC:
742 case Q_XGETQSTAT: 773 case Q_XGETQSTAT:
743 case Q_XGETQSTATV: 774 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 @@
71#define Q_SETINFO 0x800006 /* set information about quota files */ 71#define Q_SETINFO 0x800006 /* set information about quota files */
72#define Q_GETQUOTA 0x800007 /* get user quota structure */ 72#define Q_GETQUOTA 0x800007 /* get user quota structure */
73#define Q_SETQUOTA 0x800008 /* set user quota structure */ 73#define Q_SETQUOTA 0x800008 /* set user quota structure */
74#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */
74 75
75/* Quota format type IDs */ 76/* Quota format type IDs */
76#define QFMT_VFS_OLD 1 77#define QFMT_VFS_OLD 1
@@ -119,6 +120,19 @@ struct if_dqblk {
119 __u32 dqb_valid; 120 __u32 dqb_valid;
120}; 121};
121 122
123struct if_nextdqblk {
124 __u64 dqb_bhardlimit;
125 __u64 dqb_bsoftlimit;
126 __u64 dqb_curspace;
127 __u64 dqb_ihardlimit;
128 __u64 dqb_isoftlimit;
129 __u64 dqb_curinodes;
130 __u64 dqb_btime;
131 __u64 dqb_itime;
132 __u32 dqb_valid;
133 __u32 dqb_id;
134};
135
122/* 136/*
123 * Structure used for setting quota information about file via quotactl 137 * Structure used for setting quota information about file via quotactl
124 * Following flags are used to specify which fields are valid 138 * Following flags are used to specify which fields are valid