diff mbox

[2/7] quota: add new quotactl Q_XGETNEXTQUOTA

Message ID 1453487136-12681-3-git-send-email-sandeen@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Eric Sandeen Jan. 22, 2016, 6:25 p.m. UTC
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 <sandeen@redhat.com>
---
 fs/quota/quota.c               |   31 +++++++++++++++++++++++++++++++
 include/linux/quota.h          |    2 ++
 include/uapi/linux/dqblk_xfs.h |    1 +
 3 files changed, 34 insertions(+), 0 deletions(-)

Comments

Jan Kara Jan. 25, 2016, 2:51 p.m. UTC | #1
On Fri 22-01-16 12:25:31, Eric Sandeen wrote:
> 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.

This paragraph is no longer true. Otherwise the patch looks good to me.

								Honza

> 
> 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 <sandeen@redhat.com>
> ---
>  fs/quota/quota.c               |   31 +++++++++++++++++++++++++++++++
>  include/linux/quota.h          |    2 ++
>  include/uapi/linux/dqblk_xfs.h |    1 +
>  3 files changed, 34 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index ea66670..0a6dd71 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 b2505ac..fba92f5 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 dcd75cc..11b3b31 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:
> -- 
> 1.7.1
>
Jan Kara Jan. 26, 2016, 12:57 p.m. UTC | #2
On Fri 22-01-16 12:25:31, Eric Sandeen wrote:
> 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.

Actually, is -ESRCH the right return value? It seems XFS traditionally
returns -ENOENT when id doesn't exist. So that would look more logical to
me.

								Honza

> 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 <sandeen@redhat.com>
> ---
>  fs/quota/quota.c               |   31 +++++++++++++++++++++++++++++++
>  include/linux/quota.h          |    2 ++
>  include/uapi/linux/dqblk_xfs.h |    1 +
>  3 files changed, 34 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index ea66670..0a6dd71 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 b2505ac..fba92f5 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 dcd75cc..11b3b31 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:
> -- 
> 1.7.1
>
Eric Sandeen Jan. 26, 2016, 3 p.m. UTC | #3
On 1/26/16 6:57 AM, Jan Kara wrote:
> On Fri 22-01-16 12:25:31, Eric Sandeen wrote:
>> 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.
> 
> Actually, is -ESRCH the right return value? It seems XFS traditionally
> returns -ENOENT when id doesn't exist. So that would look more logical to
> me.

Hm, I was just going by the quotactl manpage, TBH, which says:

       ESRCH          No disc quota is found for the indicated user.


But yes, you are right, it is ENOENT for xfs... argh.  I suppose the
quotactl manpage could use an update as well, then.

At this point do you want me to update the patches & resend or do you
want to fix that up too?  :(  I reference -ESRCH in comments too, I think.

-Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kara Jan. 26, 2016, 5:52 p.m. UTC | #4
On Tue 26-01-16 09:00:25, Eric Sandeen wrote:
> On 1/26/16 6:57 AM, Jan Kara wrote:
> > On Fri 22-01-16 12:25:31, Eric Sandeen wrote:
> >> 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.
> > 
> > Actually, is -ESRCH the right return value? It seems XFS traditionally
> > returns -ENOENT when id doesn't exist. So that would look more logical to
> > me.
> 
> Hm, I was just going by the quotactl manpage, TBH, which says:
> 
>        ESRCH          No disc quota is found for the indicated user.
> 
> 
> But yes, you are right, it is ENOENT for xfs... argh.  I suppose the
> quotactl manpage could use an update as well, then.

Yeah, so VFS quotas use ESRCH when quota for particular fs is not enabled
(while ENOENT means device you passed in doesn't exist). So probably a
solution that keeps XFS and VFS interfaces most selfconsistent is to return
ENOENT from Q_XGETNEXTQUOTA and ESRCH from Q_GETNEXTQUOTA. I'll update your
patches in this sense in the comments and changelogs. But XFS patches
(which I don't carry) need updating the actual code...

								Honza
Eric Sandeen Jan. 26, 2016, 5:57 p.m. UTC | #5
On 1/26/16 11:52 AM, Jan Kara wrote:
> On Tue 26-01-16 09:00:25, Eric Sandeen wrote:
>> On 1/26/16 6:57 AM, Jan Kara wrote:
>>> On Fri 22-01-16 12:25:31, Eric Sandeen wrote:
>>>> 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.
>>>
>>> Actually, is -ESRCH the right return value? It seems XFS traditionally
>>> returns -ENOENT when id doesn't exist. So that would look more logical to
>>> me.
>>
>> Hm, I was just going by the quotactl manpage, TBH, which says:
>>
>>        ESRCH          No disc quota is found for the indicated user.
>>
>>
>> But yes, you are right, it is ENOENT for xfs... argh.  I suppose the
>> quotactl manpage could use an update as well, then.
> 
> Yeah, so VFS quotas use ESRCH when quota for particular fs is not enabled
> (while ENOENT means device you passed in doesn't exist). So probably a
> solution that keeps XFS and VFS interfaces most selfconsistent is to return
> ENOENT from Q_XGETNEXTQUOTA and ESRCH from Q_GETNEXTQUOTA. I'll update your
> patches in this sense in the comments and changelogs. But XFS patches
> (which I don't carry) need updating the actual code...

*nod* thanks.  I'll just resend the XFS patches to the XFS list.

-Eric

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Sandeen Jan. 26, 2016, 6:39 p.m. UTC | #6
On 1/26/16 11:52 AM, Jan Kara wrote:

> Yeah, so VFS quotas use ESRCH when quota for particular fs is not enabled
> (while ENOENT means device you passed in doesn't exist).

And what does it return for "that ID has no quota?"  Anything?  Maybe not,
see below?

> So probably a
> solution that keeps XFS and VFS interfaces most selfconsistent is to return
> ENOENT from Q_XGETNEXTQUOTA and ESRCH from Q_GETNEXTQUOTA. I'll update your
> patches in this sense in the comments and changelogs. But XFS patches
> (which I don't carry) need updating the actual code...

Actually, ok, now I'm a little more confused.

Today, Q_XGETQUOTA and Q_GETQUOTA will both return -ENOENT on XFS if a
quota doesn't exist for that ID:

quotactl(Q_GETQUOTA|USRQUOTA, "/dev/sdb2", 123456789, 0x7ffdf2edbc80) = -1 ENOENT (No such file or directory)
quotactl(Q_XGETQUOTA|USRQUOTA, "/dev/sdb2", 123456789, 0x7ffdf2edbc10) = -1 ENOENT (No such file or directory)

It seems like the *NEXT* variants (on xfs at least?) may as well continue to do the same...

But on ext4, I see 0 returned for a nonexistent quota:

quotactl(Q_GETQUOTA|USRQUOTA, "/dev/sdb1", 123456789, {bhardlimit=0, bsoftlimit=0, curspace=0, ihardlimit=0, isoftlimit=0, curinodes=0, ...}) = 0
quotactl(Q_XGETQUOTA|USRQUOTA, "/dev/sdb1", 123456789, {version=1, flags=XFS_USER_QUOTA, fieldmask=0, id=123456789, blk_hardlimit=0, blk_softlimit=0, ino_hardlimit=0, ino_softlimit=0, bcount=0, icount=0, ...}) = 0

So the difference doesn't seem to be XGETQUOTA vs GETQUOTA, rather it's the filesystem handling the call?

Still, we do need a way to pass back "No more quotas to find" from Q_[X]GETNEXTQUOTA; XFS will do -ENOENT, but if -ENOENT and -ESRCH already have specific meanings on non-xfs filesystems, I'm not sure where we go from there.

Sorry for my confusion.  :(

-Eric
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jan Kara Jan. 26, 2016, 8:40 p.m. UTC | #7
On Tue 26-01-16 12:39:59, Eric Sandeen wrote:
> On 1/26/16 11:52 AM, Jan Kara wrote:
> 
> > Yeah, so VFS quotas use ESRCH when quota for particular fs is not enabled
> > (while ENOENT means device you passed in doesn't exist).
> 
> And what does it return for "that ID has no quota?"  Anything?  Maybe not,
> see below?
> 
> > So probably a
> > solution that keeps XFS and VFS interfaces most selfconsistent is to return
> > ENOENT from Q_XGETNEXTQUOTA and ESRCH from Q_GETNEXTQUOTA. I'll update your
> > patches in this sense in the comments and changelogs. But XFS patches
> > (which I don't carry) need updating the actual code...
> 
> Actually, ok, now I'm a little more confused.
> 
> Today, Q_XGETQUOTA and Q_GETQUOTA will both return -ENOENT on XFS if a
> quota doesn't exist for that ID:
> 
> quotactl(Q_GETQUOTA|USRQUOTA, "/dev/sdb2", 123456789, 0x7ffdf2edbc80) = -1 ENOENT (No such file or directory)
> quotactl(Q_XGETQUOTA|USRQUOTA, "/dev/sdb2", 123456789, 0x7ffdf2edbc10) = -1 ENOENT (No such file or directory)
> 
> It seems like the *NEXT* variants (on xfs at least?) may as well continue
> to do the same...
> 
> But on ext4, I see 0 returned for a nonexistent quota:
> 
> quotactl(Q_GETQUOTA|USRQUOTA, "/dev/sdb1", 123456789, {bhardlimit=0, bsoftlimit=0, curspace=0, ihardlimit=0, isoftlimit=0, curinodes=0, ...}) = 0
> quotactl(Q_XGETQUOTA|USRQUOTA, "/dev/sdb1", 123456789, {version=1, flags=XFS_USER_QUOTA, fieldmask=0, id=123456789, blk_hardlimit=0, blk_softlimit=0, ino_hardlimit=0, ino_softlimit=0, bcount=0, icount=0, ...}) = 0
> 
> So the difference doesn't seem to be XGETQUOTA vs GETQUOTA, rather it's
> the filesystem handling the call?

Yes, it's about whether fs/quota/dquot.c or XFS handles the call. VFS
traditionally returns structure full of zeros when you call Q_GETQUOTA for
non-existent ID on a system that otherwise supports quotas (that is a
historical heritage of old quota file format). This is however
impractical for Q_GETNEXTQUOTA so there we have to define some error
terminating the iteration.

> Still, we do need a way to pass back "No more quotas to find" from
> Q_[X]GETNEXTQUOTA; XFS will do -ENOENT, but if -ENOENT and -ESRCH already
> have specific meanings on non-xfs filesystems, I'm not sure where we go
> from there.

Yeah, we have to simply overload one of the error codes for VFS
implementation and I'm not strongly convinced which one. But since you
pointed out that it's not really about the interface but about backing fs,
I think making both ENOENT is probably going to be less confusing for
userspace.

								Honza
diff mbox

Patch

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index ea66670..0a6dd71 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 b2505ac..fba92f5 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 dcd75cc..11b3b31 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: