Skip to content

Commit 926132c

Browse files
Eric Sandeendchinner
authored andcommitted
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>
1 parent 8b37524 commit 926132c

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

fs/quota/quota.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,34 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
222222
return 0;
223223
}
224224

225+
/*
226+
* Return quota for next active quota >= this id, if any exists,
227+
* otherwise return -ESRCH via ->get_nextdqblk
228+
*/
229+
static 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+
225253
static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
226254
{
227255
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,
698726
return quota_setinfo(sb, type, addr);
699727
case Q_GETQUOTA:
700728
return quota_getquota(sb, type, id, addr);
729+
case Q_GETNEXTQUOTA:
730+
return quota_getnextquota(sb, type, id, addr);
701731
case Q_SETQUOTA:
702732
return quota_setquota(sb, type, id, addr);
703733
case Q_SYNC:
@@ -738,6 +768,7 @@ static int quotactl_cmd_write(int cmd)
738768
switch (cmd) {
739769
case Q_GETFMT:
740770
case Q_GETINFO:
771+
case Q_GETNEXTQUOTA:
741772
case Q_SYNC:
742773
case Q_XGETQSTAT:
743774
case Q_XGETQSTATV:

include/uapi/linux/quota.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#define Q_SETINFO 0x800006 /* set information about quota files */
7272
#define Q_GETQUOTA 0x800007 /* get user quota structure */
7373
#define Q_SETQUOTA 0x800008 /* set user quota structure */
74+
#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */
7475

7576
/* Quota format type IDs */
7677
#define QFMT_VFS_OLD 1
@@ -119,6 +120,19 @@ struct if_dqblk {
119120
__u32 dqb_valid;
120121
};
121122

123+
struct 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+
122136
/*
123137
* Structure used for setting quota information about file via quotactl
124138
* Following flags are used to specify which fields are valid

0 commit comments

Comments
 (0)