All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-22 18:25 ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

This adds a 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 specified 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.

So if you ask for id X, you can get back quota for id X,
id X+N, or -ESRCH if no higher id has a quota.

This allows filesystems to do efficient iteration in kernelspace,
much like extN filesystems do in userspace when asked to report
all active quotas.

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.

Patches 1 and 4 are just small fixups that turned up along the way;
2 and 3 add the actual quota plumbing, and the rest are xfs-specific
to allow xfs to support this new interface.

For non-xfs quota, this does require a new structure which is
able to pass back the discovered ID along with the quota info.
For xfs-quota, the id is already present in the structure.

V3:
* Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
* Require CAP_SYS_ADMIN for these calls
* Pass back found ID in &qid passed to ->get_nextdqblk, rather
  than modifying struct qc_dqblk
* Munge that found ID back through user-namespace conversions
  before returning it in the user structure.

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-22 18:25 ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

This adds a 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 specified 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.

So if you ask for id X, you can get back quota for id X,
id X+N, or -ESRCH if no higher id has a quota.

This allows filesystems to do efficient iteration in kernelspace,
much like extN filesystems do in userspace when asked to report
all active quotas.

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.

Patches 1 and 4 are just small fixups that turned up along the way;
2 and 3 add the actual quota plumbing, and the rest are xfs-specific
to allow xfs to support this new interface.

For non-xfs quota, this does require a new structure which is
able to pass back the discovered ID along with the quota info.
For xfs-quota, the id is already present in the structure.

V3:
* Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
* Require CAP_SYS_ADMIN for these calls
* Pass back found ID in &qid passed to ->get_nextdqblk, rather
  than modifying struct qc_dqblk
* Munge that found ID back through user-namespace conversions
  before returning it in the user structure.

Thanks,
-Eric

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
is not used, so remove it.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/quota/quota.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 3746367..ea66670 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:
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
is not used, so remove it.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/quota/quota.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 3746367..ea66670 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:
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

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(-)

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


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

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(-)

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

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 3/7] quota: add new quotactl Q_GETNEXTQUOTA
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

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>
---
 fs/quota/quota.c           |   30 ++++++++++++++++++++++++++++++
 include/uapi/linux/quota.h |   14 ++++++++++++++
 2 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 0a6dd71..ffa4e0b 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:
diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
index 9c95b2c..38baddb 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
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 3/7] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

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>
---
 fs/quota/quota.c           |   30 ++++++++++++++++++++++++++++++
 include/uapi/linux/quota.h |   14 ++++++++++++++
 2 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 0a6dd71..ffa4e0b 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:
diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
index 9c95b2c..38baddb 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
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 4/7] xfs: don't overflow quota ID when initializing dqblk
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Quota IDs are unsigned, and so we can pass in values up
to 2^32-1.  But if we try to initialize a block containing
values over MAX_INT, curid will overflow and assert.

curid holds a quota ID, so give it the proper
xfs_dqid_t type (and remove the now-impossible ASSERT).

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_dquot.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 9c44d38..c9c7c2d 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -232,7 +232,8 @@ xfs_qm_init_dquot_blk(
 {
 	struct xfs_quotainfo	*q = mp->m_quotainfo;
 	xfs_dqblk_t	*d;
-	int		curid, i;
+	xfs_dqid_t	curid;
+	int		i;
 
 	ASSERT(tp);
 	ASSERT(xfs_buf_islocked(bp));
@@ -243,7 +244,6 @@ xfs_qm_init_dquot_blk(
 	 * ID of the first dquot in the block - id's are zero based.
 	 */
 	curid = id - (id % q->qi_dqperchunk);
-	ASSERT(curid >= 0);
 	memset(d, 0, BBTOB(q->qi_dqchunklen));
 	for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) {
 		d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 4/7] xfs: don't overflow quota ID when initializing dqblk
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Quota IDs are unsigned, and so we can pass in values up
to 2^32-1.  But if we try to initialize a block containing
values over MAX_INT, curid will overflow and assert.

curid holds a quota ID, so give it the proper
xfs_dqid_t type (and remove the now-impossible ASSERT).

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_dquot.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 9c44d38..c9c7c2d 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -232,7 +232,8 @@ xfs_qm_init_dquot_blk(
 {
 	struct xfs_quotainfo	*q = mp->m_quotainfo;
 	xfs_dqblk_t	*d;
-	int		curid, i;
+	xfs_dqid_t	curid;
+	int		i;
 
 	ASSERT(tp);
 	ASSERT(xfs_buf_islocked(bp));
@@ -243,7 +244,6 @@ xfs_qm_init_dquot_blk(
 	 * ID of the first dquot in the block - id's are zero based.
 	 */
 	curid = id - (id % q->qi_dqperchunk);
-	ASSERT(curid >= 0);
 	memset(d, 0, BBTOB(q->qi_dqchunklen));
 	for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) {
 		d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 5/7] xfs: get quota inode from mp & flags rather than dqp
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Allow us to get the appropriate quota inode from any
mp & quota flags, not necessarily associated with a
particular dqp.  Needed for when we are searching for
the next active ID with quotas and we want to examine
the quota inode.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_dquot.c |    3 ++-
 fs/xfs/xfs_qm.h    |   10 +++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index c9c7c2d..5dbde0d 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -464,12 +464,13 @@ xfs_qm_dqtobp(
 	struct xfs_bmbt_irec	map;
 	int			nmaps = 1, error;
 	struct xfs_buf		*bp;
-	struct xfs_inode	*quotip = xfs_dq_to_quota_inode(dqp);
+	struct xfs_inode	*quotip;
 	struct xfs_mount	*mp = dqp->q_mount;
 	xfs_dqid_t		id = be32_to_cpu(dqp->q_core.d_id);
 	struct xfs_trans	*tp = (tpp ? *tpp : NULL);
 	uint			lock_mode;
 
+	quotip = xfs_quota_inode(dqp->q_mount, dqp->dq_flags);
 	dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
 
 	lock_mode = xfs_ilock_data_map_shared(quotip);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 996a040..8901a01 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -104,15 +104,15 @@ xfs_dquot_tree(
 }
 
 static inline struct xfs_inode *
-xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
+xfs_quota_inode(xfs_mount_t *mp, uint dq_flags)
 {
-	switch (dqp->dq_flags & XFS_DQ_ALLTYPES) {
+	switch (dq_flags & XFS_DQ_ALLTYPES) {
 	case XFS_DQ_USER:
-		return dqp->q_mount->m_quotainfo->qi_uquotaip;
+		return mp->m_quotainfo->qi_uquotaip;
 	case XFS_DQ_GROUP:
-		return dqp->q_mount->m_quotainfo->qi_gquotaip;
+		return mp->m_quotainfo->qi_gquotaip;
 	case XFS_DQ_PROJ:
-		return dqp->q_mount->m_quotainfo->qi_pquotaip;
+		return mp->m_quotainfo->qi_pquotaip;
 	default:
 		ASSERT(0);
 	}
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 5/7] xfs: get quota inode from mp & flags rather than dqp
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Allow us to get the appropriate quota inode from any
mp & quota flags, not necessarily associated with a
particular dqp.  Needed for when we are searching for
the next active ID with quotas and we want to examine
the quota inode.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_dquot.c |    3 ++-
 fs/xfs/xfs_qm.h    |   10 +++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index c9c7c2d..5dbde0d 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -464,12 +464,13 @@ xfs_qm_dqtobp(
 	struct xfs_bmbt_irec	map;
 	int			nmaps = 1, error;
 	struct xfs_buf		*bp;
-	struct xfs_inode	*quotip = xfs_dq_to_quota_inode(dqp);
+	struct xfs_inode	*quotip;
 	struct xfs_mount	*mp = dqp->q_mount;
 	xfs_dqid_t		id = be32_to_cpu(dqp->q_core.d_id);
 	struct xfs_trans	*tp = (tpp ? *tpp : NULL);
 	uint			lock_mode;
 
+	quotip = xfs_quota_inode(dqp->q_mount, dqp->dq_flags);
 	dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk;
 
 	lock_mode = xfs_ilock_data_map_shared(quotip);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 996a040..8901a01 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -104,15 +104,15 @@ xfs_dquot_tree(
 }
 
 static inline struct xfs_inode *
-xfs_dq_to_quota_inode(struct xfs_dquot *dqp)
+xfs_quota_inode(xfs_mount_t *mp, uint dq_flags)
 {
-	switch (dqp->dq_flags & XFS_DQ_ALLTYPES) {
+	switch (dq_flags & XFS_DQ_ALLTYPES) {
 	case XFS_DQ_USER:
-		return dqp->q_mount->m_quotainfo->qi_uquotaip;
+		return mp->m_quotainfo->qi_uquotaip;
 	case XFS_DQ_GROUP:
-		return dqp->q_mount->m_quotainfo->qi_gquotaip;
+		return mp->m_quotainfo->qi_gquotaip;
 	case XFS_DQ_PROJ:
-		return dqp->q_mount->m_quotainfo->qi_pquotaip;
+		return mp->m_quotainfo->qi_pquotaip;
 	default:
 		ASSERT(0);
 	}
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 6/7] xfs: Factor xfs_seek_hole_data into helper
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Factor xfs_seek_hole_data into an unlocked helper which takes
an xfs inode rather than a file for internal use.

Also allow specification of "end" - the vfs lseek interface is
defined such that any offset past eof/i_size shall return -ENXIO,
but we will use this for quota code which does not maintain i_size,
and we want to be able to SEEK_DATA past i_size as well.  So the
lseek path can send in i_size, and the quota code can determine
its own ending offset.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_file.c  |   82 ++++++++++++++++++++++++++++++++++++----------------
 fs/xfs/xfs_inode.h |    2 +
 2 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index ebe9b82..5dc7113 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1337,31 +1337,31 @@ out:
 	return found;
 }
 
-STATIC loff_t
-xfs_seek_hole_data(
-	struct file		*file,
+/*
+ * caller must lock inode with xfs_ilock_data_map_shared,
+ * can we craft an appropriate ASSERT?
+ *
+ * end is because the VFS-level lseek interface is defined such that any
+ * offset past i_size shall return -ENXIO, but we use this for quota code
+ * which does not maintain i_size, and we want to SEEK_DATA past i_size.
+ */
+loff_t
+__xfs_seek_hole_data(
+	struct inode		*inode,
 	loff_t			start,
+	loff_t			end,
 	int			whence)
 {
-	struct inode		*inode = file->f_mapping->host;
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
 	loff_t			uninitialized_var(offset);
-	xfs_fsize_t		isize;
 	xfs_fileoff_t		fsbno;
-	xfs_filblks_t		end;
-	uint			lock;
+	xfs_filblks_t		lastbno;
 	int			error;
 
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return -EIO;
-
-	lock = xfs_ilock_data_map_shared(ip);
-
-	isize = i_size_read(inode);
-	if (start >= isize) {
+	if (start >= end) {
 		error = -ENXIO;
-		goto out_unlock;
+		goto out_error;
 	}
 
 	/*
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(
 	 * by fsbno to the end block of the file.
 	 */
 	fsbno = XFS_B_TO_FSBT(mp, start);
-	end = XFS_B_TO_FSB(mp, isize);
+	lastbno = XFS_B_TO_FSB(mp, end);
 
 	for (;;) {
 		struct xfs_bmbt_irec	map[2];
 		int			nmap = 2;
 		unsigned int		i;
 
-		error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
+		error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap,
 				       XFS_BMAPI_ENTIRE);
 		if (error)
-			goto out_unlock;
+			goto out_error;
 
 		/* No extents at given offset, must be beyond EOF */
 		if (nmap == 0) {
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 
 		for (i = 0; i < nmap; i++) {
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(
 			 * hole at the end of any file).
 		 	 */
 			if (whence == SEEK_HOLE) {
-				offset = isize;
+				offset = end;
 				break;
 			}
 			/*
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(
 			 */
 			ASSERT(whence == SEEK_DATA);
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 
 		ASSERT(i > 1);
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(
 		 */
 		fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
 		start = XFS_FSB_TO_B(mp, fsbno);
-		if (start >= isize) {
+		if (start >= end) {
 			if (whence == SEEK_HOLE) {
-				offset = isize;
+				offset = end;
 				break;
 			}
 			ASSERT(whence == SEEK_DATA);
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 	}
 
@@ -1464,7 +1464,39 @@ out:
 	 * situation in particular.
 	 */
 	if (whence == SEEK_HOLE)
-		offset = min_t(loff_t, offset, isize);
+		offset = min_t(loff_t, offset, end);
+
+	return offset;
+
+out_error:
+	return error;
+}
+
+STATIC loff_t
+xfs_seek_hole_data(
+	struct file		*file,
+	loff_t			start,
+	int			whence)
+{
+	struct inode		*inode = file->f_mapping->host;
+	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_mount	*mp = ip->i_mount;
+	uint			lock;
+	loff_t			offset, end;
+	int			error = 0;
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	lock = xfs_ilock_data_map_shared(ip);
+
+	end = i_size_read(inode);
+	offset = __xfs_seek_hole_data(inode, start, end, whence);
+	if (offset < 0) {
+		error = offset;
+		goto out_unlock;
+	}
+
 	offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index ca9e119..ed7e933 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -437,6 +437,8 @@ int	xfs_update_prealloc_flags(struct xfs_inode *ip,
 int	xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
 		     xfs_fsize_t isize, bool *did_zeroing);
 int	xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
+loff_t	__xfs_seek_hole_data(struct inode *inode, loff_t start,
+			     loff_t eof, int whence);
 
 
 /* from xfs_iops.c */
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 6/7] xfs: Factor xfs_seek_hole_data into helper
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Factor xfs_seek_hole_data into an unlocked helper which takes
an xfs inode rather than a file for internal use.

Also allow specification of "end" - the vfs lseek interface is
defined such that any offset past eof/i_size shall return -ENXIO,
but we will use this for quota code which does not maintain i_size,
and we want to be able to SEEK_DATA past i_size as well.  So the
lseek path can send in i_size, and the quota code can determine
its own ending offset.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_file.c  |   82 ++++++++++++++++++++++++++++++++++++----------------
 fs/xfs/xfs_inode.h |    2 +
 2 files changed, 59 insertions(+), 25 deletions(-)

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index ebe9b82..5dc7113 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1337,31 +1337,31 @@ out:
 	return found;
 }
 
-STATIC loff_t
-xfs_seek_hole_data(
-	struct file		*file,
+/*
+ * caller must lock inode with xfs_ilock_data_map_shared,
+ * can we craft an appropriate ASSERT?
+ *
+ * end is because the VFS-level lseek interface is defined such that any
+ * offset past i_size shall return -ENXIO, but we use this for quota code
+ * which does not maintain i_size, and we want to SEEK_DATA past i_size.
+ */
+loff_t
+__xfs_seek_hole_data(
+	struct inode		*inode,
 	loff_t			start,
+	loff_t			end,
 	int			whence)
 {
-	struct inode		*inode = file->f_mapping->host;
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_mount	*mp = ip->i_mount;
 	loff_t			uninitialized_var(offset);
-	xfs_fsize_t		isize;
 	xfs_fileoff_t		fsbno;
-	xfs_filblks_t		end;
-	uint			lock;
+	xfs_filblks_t		lastbno;
 	int			error;
 
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return -EIO;
-
-	lock = xfs_ilock_data_map_shared(ip);
-
-	isize = i_size_read(inode);
-	if (start >= isize) {
+	if (start >= end) {
 		error = -ENXIO;
-		goto out_unlock;
+		goto out_error;
 	}
 
 	/*
@@ -1369,22 +1369,22 @@ xfs_seek_hole_data(
 	 * by fsbno to the end block of the file.
 	 */
 	fsbno = XFS_B_TO_FSBT(mp, start);
-	end = XFS_B_TO_FSB(mp, isize);
+	lastbno = XFS_B_TO_FSB(mp, end);
 
 	for (;;) {
 		struct xfs_bmbt_irec	map[2];
 		int			nmap = 2;
 		unsigned int		i;
 
-		error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
+		error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap,
 				       XFS_BMAPI_ENTIRE);
 		if (error)
-			goto out_unlock;
+			goto out_error;
 
 		/* No extents at given offset, must be beyond EOF */
 		if (nmap == 0) {
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 
 		for (i = 0; i < nmap; i++) {
@@ -1426,7 +1426,7 @@ xfs_seek_hole_data(
 			 * hole at the end of any file).
 		 	 */
 			if (whence == SEEK_HOLE) {
-				offset = isize;
+				offset = end;
 				break;
 			}
 			/*
@@ -1434,7 +1434,7 @@ xfs_seek_hole_data(
 			 */
 			ASSERT(whence == SEEK_DATA);
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 
 		ASSERT(i > 1);
@@ -1445,14 +1445,14 @@ xfs_seek_hole_data(
 		 */
 		fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount;
 		start = XFS_FSB_TO_B(mp, fsbno);
-		if (start >= isize) {
+		if (start >= end) {
 			if (whence == SEEK_HOLE) {
-				offset = isize;
+				offset = end;
 				break;
 			}
 			ASSERT(whence == SEEK_DATA);
 			error = -ENXIO;
-			goto out_unlock;
+			goto out_error;
 		}
 	}
 
@@ -1464,7 +1464,39 @@ out:
 	 * situation in particular.
 	 */
 	if (whence == SEEK_HOLE)
-		offset = min_t(loff_t, offset, isize);
+		offset = min_t(loff_t, offset, end);
+
+	return offset;
+
+out_error:
+	return error;
+}
+
+STATIC loff_t
+xfs_seek_hole_data(
+	struct file		*file,
+	loff_t			start,
+	int			whence)
+{
+	struct inode		*inode = file->f_mapping->host;
+	struct xfs_inode	*ip = XFS_I(inode);
+	struct xfs_mount	*mp = ip->i_mount;
+	uint			lock;
+	loff_t			offset, end;
+	int			error = 0;
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	lock = xfs_ilock_data_map_shared(ip);
+
+	end = i_size_read(inode);
+	offset = __xfs_seek_hole_data(inode, start, end, whence);
+	if (offset < 0) {
+		error = offset;
+		goto out_unlock;
+	}
+
 	offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index ca9e119..ed7e933 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -437,6 +437,8 @@ int	xfs_update_prealloc_flags(struct xfs_inode *ip,
 int	xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset,
 		     xfs_fsize_t isize, bool *did_zeroing);
 int	xfs_iozero(struct xfs_inode *ip, loff_t pos, size_t count);
+loff_t	__xfs_seek_hole_data(struct inode *inode, loff_t start,
+			     loff_t eof, int whence);
 
 
 /* from xfs_iops.c */
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 7/7] xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-22 18:25   ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Add code to allow the Q_XGETNEXTQUOTA quotactl to quickly find
all active quotas by examining the quota inode, and skipping
over unallocated or uninitialized regions.

Userspace can then use this interface rather than i.e. a
getpwent() loop when asked to report all active quotas.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/libxfs/xfs_quota_defs.h |    3 +-
 fs/xfs/xfs_dquot.c             |   96 ++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_qm.h                |    4 +-
 fs/xfs/xfs_qm_syscalls.c       |   12 +++--
 fs/xfs/xfs_quotaops.c          |   36 ++++++++++++++-
 5 files changed, 142 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index f51078f..8eed512 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -37,7 +37,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_DQ_PROJ		0x0002		/* project quota */
 #define XFS_DQ_GROUP		0x0004		/* a group quota */
 #define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */
-#define XFS_DQ_FREEING		0x0010		/* dquot is beeing torn down */
+#define XFS_DQ_FREEING		0x0010		/* dquot is being torn down */
 
 #define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
 
@@ -116,6 +116,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
+#define XFS_QMOPT_DQNEXT	0x0008000 /* return next dquot >= this ID */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 5dbde0d..3b93e94 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -686,6 +686,56 @@ error0:
 }
 
 /*
+ * Advance to the next id in the current chunk, or if at the
+ * end of the chunk, skip ahead to first id in next allocated chunk
+ * using the SEEK_DATA interface.
+ */
+int
+xfs_dq_get_next_id(
+	xfs_mount_t		*mp,
+	uint			type,
+	xfs_dqid_t		*id,
+	loff_t			eof)
+{
+	struct xfs_inode	*quotip;
+	xfs_fsblock_t		start;
+	loff_t			offset;
+	uint			lock;
+	xfs_dqid_t		next_id;
+	int			error = 0;
+
+	/* Simple advance */
+	next_id = *id + 1;
+
+	/* If new ID is within the current chunk, advancing it sufficed */
+	if (next_id % mp->m_quotainfo->qi_dqperchunk) {
+		*id = next_id;
+		return 0;
+	}
+
+	/* Nope, next_id is now past the current chunk, so find the next one */
+	start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
+
+	quotip = xfs_quota_inode(mp, type);
+	lock = xfs_ilock_data_map_shared(quotip);
+
+	offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
+				      eof, SEEK_DATA);
+	if (offset < 0)
+		error = offset;
+
+	xfs_iunlock(quotip, lock);
+
+	/* -ENXIO is essentially "no more data" */
+	if (error)
+		return (error == -ENXIO ? -ESRCH : error);
+
+	/* Convert next data offset back to a quota id */
+	*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
+	return 0;
+}
+
+/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -705,6 +755,7 @@ xfs_qm_dqget(
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
 	struct xfs_dquot	*dqp;
+	loff_t			eof = 0;
 	int			error;
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -732,6 +783,21 @@ xfs_qm_dqget(
 	}
 #endif
 
+	/* Get the end of the quota file if we need it */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		struct xfs_inode	*quotip;
+		xfs_fileoff_t		last;
+		uint			lock_mode;
+
+		quotip = xfs_quota_inode(mp, type);
+		lock_mode = xfs_ilock_data_map_shared(quotip);
+		error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
+		xfs_iunlock(quotip, lock_mode);
+		if (error)
+			return error;
+		eof = XFS_FSB_TO_B(mp, last);
+	}
+
 restart:
 	mutex_lock(&qi->qi_tree_lock);
 	dqp = radix_tree_lookup(tree, id);
@@ -745,6 +811,18 @@ restart:
 			goto restart;
 		}
 
+		/* uninit / unused quota found in radix tree, keep looking  */
+		if (flags & XFS_QMOPT_DQNEXT) {
+			if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+				xfs_dqunlock(dqp);
+				mutex_unlock(&qi->qi_tree_lock);
+				error = xfs_dq_get_next_id(mp, type, &id, eof);
+				if (error)
+					return error;
+				goto restart;
+			}
+		}
+
 		dqp->q_nrefs++;
 		mutex_unlock(&qi->qi_tree_lock);
 
@@ -771,6 +849,13 @@ restart:
 	if (ip)
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 
+	/* If we are asked to find next active id, keep looking */
+	if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
+		error = xfs_dq_get_next_id(mp, type, &id, eof);
+		if (!error)
+			goto restart;
+	}
+
 	if (error)
 		return error;
 
@@ -821,6 +906,17 @@ restart:
 	qi->qi_dquots++;
 	mutex_unlock(&qi->qi_tree_lock);
 
+	/* If we are asked to find next active id, keep looking */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+			xfs_qm_dqput(dqp);
+			error = xfs_dq_get_next_id(mp, type, &id, eof);
+			if (error)
+				return error;
+			goto restart;
+		}
+	}
+
  dqret:
 	ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	trace_xfs_dqget_miss(dqp);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 8901a01..c68a38f 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -164,8 +164,8 @@ extern void		xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
 
 /* quota ops */
 extern int		xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
-extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
-					uint, struct qc_dqblk *);
+extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *,
+					uint, struct qc_dqblk *, uint);
 extern int		xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
 					struct qc_dqblk *);
 extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 3640c6e..0a25286 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -635,9 +635,10 @@ out:
 int
 xfs_qm_scall_getquota(
 	struct xfs_mount	*mp,
-	xfs_dqid_t		id,
+	xfs_dqid_t		*id,
 	uint			type,
-	struct qc_dqblk		*dst)
+	struct qc_dqblk		*dst,
+	uint			dqget_flags)
 {
 	struct xfs_dquot	*dqp;
 	int			error;
@@ -647,7 +648,7 @@ xfs_qm_scall_getquota(
 	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
 	 * exist, we'll get ENOENT back.
 	 */
-	error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+	error = xfs_qm_dqget(mp, NULL, *id, type, dqget_flags, &dqp);
 	if (error)
 		return error;
 
@@ -660,6 +661,9 @@ xfs_qm_scall_getquota(
 		goto out_put;
 	}
 
+	/* Fill in the ID we actually read from disk */
+	*id = be32_to_cpu(dqp->q_core.d_id);
+
 	memset(dst, 0, sizeof(*dst));
 	dst->d_spc_hardlimit =
 		XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
@@ -701,7 +705,7 @@ xfs_qm_scall_getquota(
 	if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
 	     (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
 	     (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
-	    id != 0) {
+	    *id != 0) {
 		if ((dst->d_space > dst->d_spc_softlimit) &&
 		    (dst->d_spc_softlimit > 0)) {
 			ASSERT(dst->d_spc_timer != 0);
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 7795e0d..f82d79a 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -231,14 +231,45 @@ xfs_fs_get_dqblk(
 	struct qc_dqblk		*qdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
-				      xfs_quota_type(qid.type), qdq);
+	id = from_kqid(&init_user_ns, qid);
+	return xfs_qm_scall_getquota(mp, &id,
+				      xfs_quota_type(qid.type), qdq, 0);
+}
+
+/* Return quota info for active quota >= this qid */
+STATIC int
+xfs_fs_get_nextdqblk(
+	struct super_block	*sb,
+	struct kqid		*qid,
+	struct qc_dqblk		*qdq)
+{
+	int			ret;
+	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
+
+	if (!XFS_IS_QUOTA_RUNNING(mp))
+		return -ENOSYS;
+	if (!XFS_IS_QUOTA_ON(mp))
+		return -ESRCH;
+
+	id = from_kqid(&init_user_ns, *qid);
+	ret = xfs_qm_scall_getquota(mp, &id,
+				    xfs_quota_type(qid->type), qdq,
+				    XFS_QMOPT_DQNEXT);
+	if (ret)
+		return ret;
+
+	/* ID may be different, so convert back what we got */
+	*qid = make_kqid(current_user_ns(), qid->type, id);
+	return 0;
+	
 }
 
 STATIC int
@@ -267,5 +298,6 @@ const struct quotactl_ops xfs_quotactl_operations = {
 	.quota_disable		= xfs_quota_disable,
 	.rm_xquota		= xfs_fs_rm_xquota,
 	.get_dqblk		= xfs_fs_get_dqblk,
+	.get_nextdqblk		= xfs_fs_get_nextdqblk,
 	.set_dqblk		= xfs_fs_set_dqblk,
 };
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 7/7] xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk
@ 2016-01-22 18:25   ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-22 18:25 UTC (permalink / raw)
  To: linux-fsdevel, xfs; +Cc: jack

Add code to allow the Q_XGETNEXTQUOTA quotactl to quickly find
all active quotas by examining the quota inode, and skipping
over unallocated or uninitialized regions.

Userspace can then use this interface rather than i.e. a
getpwent() loop when asked to report all active quotas.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/libxfs/xfs_quota_defs.h |    3 +-
 fs/xfs/xfs_dquot.c             |   96 ++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_qm.h                |    4 +-
 fs/xfs/xfs_qm_syscalls.c       |   12 +++--
 fs/xfs/xfs_quotaops.c          |   36 ++++++++++++++-
 5 files changed, 142 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index f51078f..8eed512 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -37,7 +37,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_DQ_PROJ		0x0002		/* project quota */
 #define XFS_DQ_GROUP		0x0004		/* a group quota */
 #define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */
-#define XFS_DQ_FREEING		0x0010		/* dquot is beeing torn down */
+#define XFS_DQ_FREEING		0x0010		/* dquot is being torn down */
 
 #define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
 
@@ -116,6 +116,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
+#define XFS_QMOPT_DQNEXT	0x0008000 /* return next dquot >= this ID */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 5dbde0d..3b93e94 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -686,6 +686,56 @@ error0:
 }
 
 /*
+ * Advance to the next id in the current chunk, or if at the
+ * end of the chunk, skip ahead to first id in next allocated chunk
+ * using the SEEK_DATA interface.
+ */
+int
+xfs_dq_get_next_id(
+	xfs_mount_t		*mp,
+	uint			type,
+	xfs_dqid_t		*id,
+	loff_t			eof)
+{
+	struct xfs_inode	*quotip;
+	xfs_fsblock_t		start;
+	loff_t			offset;
+	uint			lock;
+	xfs_dqid_t		next_id;
+	int			error = 0;
+
+	/* Simple advance */
+	next_id = *id + 1;
+
+	/* If new ID is within the current chunk, advancing it sufficed */
+	if (next_id % mp->m_quotainfo->qi_dqperchunk) {
+		*id = next_id;
+		return 0;
+	}
+
+	/* Nope, next_id is now past the current chunk, so find the next one */
+	start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
+
+	quotip = xfs_quota_inode(mp, type);
+	lock = xfs_ilock_data_map_shared(quotip);
+
+	offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
+				      eof, SEEK_DATA);
+	if (offset < 0)
+		error = offset;
+
+	xfs_iunlock(quotip, lock);
+
+	/* -ENXIO is essentially "no more data" */
+	if (error)
+		return (error == -ENXIO ? -ESRCH : error);
+
+	/* Convert next data offset back to a quota id */
+	*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
+	return 0;
+}
+
+/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -705,6 +755,7 @@ xfs_qm_dqget(
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
 	struct xfs_dquot	*dqp;
+	loff_t			eof = 0;
 	int			error;
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -732,6 +783,21 @@ xfs_qm_dqget(
 	}
 #endif
 
+	/* Get the end of the quota file if we need it */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		struct xfs_inode	*quotip;
+		xfs_fileoff_t		last;
+		uint			lock_mode;
+
+		quotip = xfs_quota_inode(mp, type);
+		lock_mode = xfs_ilock_data_map_shared(quotip);
+		error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
+		xfs_iunlock(quotip, lock_mode);
+		if (error)
+			return error;
+		eof = XFS_FSB_TO_B(mp, last);
+	}
+
 restart:
 	mutex_lock(&qi->qi_tree_lock);
 	dqp = radix_tree_lookup(tree, id);
@@ -745,6 +811,18 @@ restart:
 			goto restart;
 		}
 
+		/* uninit / unused quota found in radix tree, keep looking  */
+		if (flags & XFS_QMOPT_DQNEXT) {
+			if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+				xfs_dqunlock(dqp);
+				mutex_unlock(&qi->qi_tree_lock);
+				error = xfs_dq_get_next_id(mp, type, &id, eof);
+				if (error)
+					return error;
+				goto restart;
+			}
+		}
+
 		dqp->q_nrefs++;
 		mutex_unlock(&qi->qi_tree_lock);
 
@@ -771,6 +849,13 @@ restart:
 	if (ip)
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 
+	/* If we are asked to find next active id, keep looking */
+	if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
+		error = xfs_dq_get_next_id(mp, type, &id, eof);
+		if (!error)
+			goto restart;
+	}
+
 	if (error)
 		return error;
 
@@ -821,6 +906,17 @@ restart:
 	qi->qi_dquots++;
 	mutex_unlock(&qi->qi_tree_lock);
 
+	/* If we are asked to find next active id, keep looking */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+			xfs_qm_dqput(dqp);
+			error = xfs_dq_get_next_id(mp, type, &id, eof);
+			if (error)
+				return error;
+			goto restart;
+		}
+	}
+
  dqret:
 	ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	trace_xfs_dqget_miss(dqp);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 8901a01..c68a38f 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -164,8 +164,8 @@ extern void		xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
 
 /* quota ops */
 extern int		xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
-extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
-					uint, struct qc_dqblk *);
+extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *,
+					uint, struct qc_dqblk *, uint);
 extern int		xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
 					struct qc_dqblk *);
 extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 3640c6e..0a25286 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -635,9 +635,10 @@ out:
 int
 xfs_qm_scall_getquota(
 	struct xfs_mount	*mp,
-	xfs_dqid_t		id,
+	xfs_dqid_t		*id,
 	uint			type,
-	struct qc_dqblk		*dst)
+	struct qc_dqblk		*dst,
+	uint			dqget_flags)
 {
 	struct xfs_dquot	*dqp;
 	int			error;
@@ -647,7 +648,7 @@ xfs_qm_scall_getquota(
 	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
 	 * exist, we'll get ENOENT back.
 	 */
-	error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+	error = xfs_qm_dqget(mp, NULL, *id, type, dqget_flags, &dqp);
 	if (error)
 		return error;
 
@@ -660,6 +661,9 @@ xfs_qm_scall_getquota(
 		goto out_put;
 	}
 
+	/* Fill in the ID we actually read from disk */
+	*id = be32_to_cpu(dqp->q_core.d_id);
+
 	memset(dst, 0, sizeof(*dst));
 	dst->d_spc_hardlimit =
 		XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
@@ -701,7 +705,7 @@ xfs_qm_scall_getquota(
 	if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
 	     (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
 	     (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
-	    id != 0) {
+	    *id != 0) {
 		if ((dst->d_space > dst->d_spc_softlimit) &&
 		    (dst->d_spc_softlimit > 0)) {
 			ASSERT(dst->d_spc_timer != 0);
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 7795e0d..f82d79a 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -231,14 +231,45 @@ xfs_fs_get_dqblk(
 	struct qc_dqblk		*qdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
-				      xfs_quota_type(qid.type), qdq);
+	id = from_kqid(&init_user_ns, qid);
+	return xfs_qm_scall_getquota(mp, &id,
+				      xfs_quota_type(qid.type), qdq, 0);
+}
+
+/* Return quota info for active quota >= this qid */
+STATIC int
+xfs_fs_get_nextdqblk(
+	struct super_block	*sb,
+	struct kqid		*qid,
+	struct qc_dqblk		*qdq)
+{
+	int			ret;
+	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
+
+	if (!XFS_IS_QUOTA_RUNNING(mp))
+		return -ENOSYS;
+	if (!XFS_IS_QUOTA_ON(mp))
+		return -ESRCH;
+
+	id = from_kqid(&init_user_ns, *qid);
+	ret = xfs_qm_scall_getquota(mp, &id,
+				    xfs_quota_type(qid->type), qdq,
+				    XFS_QMOPT_DQNEXT);
+	if (ret)
+		return ret;
+
+	/* ID may be different, so convert back what we got */
+	*qid = make_kqid(current_user_ns(), qid->type, id);
+	return 0;
+	
 }
 
 STATIC int
@@ -267,5 +298,6 @@ const struct quotactl_ops xfs_quotactl_operations = {
 	.quota_disable		= xfs_quota_disable,
 	.rm_xquota		= xfs_fs_rm_xquota,
 	.get_dqblk		= xfs_fs_get_dqblk,
+	.get_nextdqblk		= xfs_fs_get_nextdqblk,
 	.set_dqblk		= xfs_fs_set_dqblk,
 };
-- 
1.7.1

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
  2016-01-22 18:25   ` Eric Sandeen
@ 2016-01-25 14:47     ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:47 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

On Fri 22-01-16 12:25:30, Eric Sandeen wrote:
> The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
> is not used, so remove it.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/quota/quota.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 3746367..ea66670 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:
> -- 
> 1.7.1
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
@ 2016-01-25 14:47     ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:47 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

On Fri 22-01-16 12:25:30, Eric Sandeen wrote:
> The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
> is not used, so remove it.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Looks good. You can add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  fs/quota/quota.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 3746367..ea66670 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:
> -- 
> 1.7.1
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
  2016-01-25 14:47     ` Jan Kara
@ 2016-01-25 14:49       ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:49 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

On Mon 25-01-16 15:47:02, Jan Kara wrote:
> On Fri 22-01-16 12:25:30, Eric Sandeen wrote:
> > The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
> > is not used, so remove it.
> > 
> > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> 
> Looks good. You can add:
> 
> Reviewed-by: Jan Kara <jack@suse.cz>

Ah, I'm in a reviewe mode... ;) I'll just take this patch to my tree.

								Honza

> > ---
> >  fs/quota/quota.c |    4 ++--
> >  1 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> > index 3746367..ea66670 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:
> > -- 
> > 1.7.1
> > 
> -- 
> Jan Kara <jack@suse.com>
> SUSE Labs, CR
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon()
@ 2016-01-25 14:49       ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:49 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

On Mon 25-01-16 15:47:02, Jan Kara wrote:
> On Fri 22-01-16 12:25:30, Eric Sandeen wrote:
> > The cmd argument to quota_quotaon() via Q_QUOTAON quotactl
> > is not used, so remove it.
> > 
> > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> 
> Looks good. You can add:
> 
> Reviewed-by: Jan Kara <jack@suse.cz>

Ah, I'm in a reviewe mode... ;) I'll just take this patch to my tree.

								Honza

> > ---
> >  fs/quota/quota.c |    4 ++--
> >  1 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> > index 3746367..ea66670 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:
> > -- 
> > 1.7.1
> > 
> -- 
> Jan Kara <jack@suse.com>
> SUSE Labs, CR
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 3/7] quota: add new quotactl Q_GETNEXTQUOTA
  2016-01-22 18:25   ` Eric Sandeen
@ 2016-01-25 14:51     ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:51 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

On Fri 22-01-16 12:25:32, Eric Sandeen wrote:
> 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>

The patch seems to be missing addition of Q_GETNEXTQUOTA into
quotactl_cmd_write(). Otherwise it looks good to me.

							Honza

> ---
>  fs/quota/quota.c           |   30 ++++++++++++++++++++++++++++++
>  include/uapi/linux/quota.h |   14 ++++++++++++++
>  2 files changed, 44 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 0a6dd71..ffa4e0b 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:
> diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
> index 9c95b2c..38baddb 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
> -- 
> 1.7.1
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 3/7] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-25 14:51     ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:51 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

On Fri 22-01-16 12:25:32, Eric Sandeen wrote:
> 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>

The patch seems to be missing addition of Q_GETNEXTQUOTA into
quotactl_cmd_write(). Otherwise it looks good to me.

							Honza

> ---
>  fs/quota/quota.c           |   30 ++++++++++++++++++++++++++++++
>  include/uapi/linux/quota.h |   14 ++++++++++++++
>  2 files changed, 44 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 0a6dd71..ffa4e0b 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:
> diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h
> index 9c95b2c..38baddb 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
> -- 
> 1.7.1
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-22 18:25   ` Eric Sandeen
@ 2016-01-25 14:51     ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:51 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

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 <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-25 14:51     ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 14:51 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

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 <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-25 15:07   ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 15:07 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack, Dave Chinner

On Fri 22-01-16 12:25:29, Eric Sandeen wrote:
> This adds a 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 specified 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.
> 
> So if you ask for id X, you can get back quota for id X,
> id X+N, or -ESRCH if no higher id has a quota.
> 
> This allows filesystems to do efficient iteration in kernelspace,
> much like extN filesystems do in userspace when asked to report
> all active quotas.
> 
> 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.
> 
> Patches 1 and 4 are just small fixups that turned up along the way;
> 2 and 3 add the actual quota plumbing, and the rest are xfs-specific
> to allow xfs to support this new interface.
> 
> For non-xfs quota, this does require a new structure which is
> able to pass back the discovered ID along with the quota info.
> For xfs-quota, the id is already present in the structure.
> 
> V3:
> * Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
> * Require CAP_SYS_ADMIN for these calls
> * Pass back found ID in &qid passed to ->get_nextdqblk, rather
>   than modifying struct qc_dqblk
> * Munge that found ID back through user-namespace conversions
>   before returning it in the user structure.

So I've taken patch 1/7 into my tree since that is completely independent.
Patches 2/7 and 3/7 look mostly good to me (except for that small omission
in 3/7) so I can take them to my tree as well. Once I'll finish testing
some UDF changes I have pending I'll push the tree to:

git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git for_next

and Dave can pull from there to have a basis for XFS patches. I want to
implement Q_GETNEXTQUOTA for VFS quota formats as well and those will go
through my tree so that's why I want the interface changes go via my tree.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-25 15:07   ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-25 15:07 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

On Fri 22-01-16 12:25:29, Eric Sandeen wrote:
> This adds a 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 specified 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.
> 
> So if you ask for id X, you can get back quota for id X,
> id X+N, or -ESRCH if no higher id has a quota.
> 
> This allows filesystems to do efficient iteration in kernelspace,
> much like extN filesystems do in userspace when asked to report
> all active quotas.
> 
> 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.
> 
> Patches 1 and 4 are just small fixups that turned up along the way;
> 2 and 3 add the actual quota plumbing, and the rest are xfs-specific
> to allow xfs to support this new interface.
> 
> For non-xfs quota, this does require a new structure which is
> able to pass back the discovered ID along with the quota info.
> For xfs-quota, the id is already present in the structure.
> 
> V3:
> * Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
> * Require CAP_SYS_ADMIN for these calls
> * Pass back found ID in &qid passed to ->get_nextdqblk, rather
>   than modifying struct qc_dqblk
> * Munge that found ID back through user-namespace conversions
>   before returning it in the user structure.

So I've taken patch 1/7 into my tree since that is completely independent.
Patches 2/7 and 3/7 look mostly good to me (except for that small omission
in 3/7) so I can take them to my tree as well. Once I'll finish testing
some UDF changes I have pending I'll push the tree to:

git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git for_next

and Dave can pull from there to have a basis for XFS patches. I want to
implement Q_GETNEXTQUOTA for VFS quota formats as well and those will go
through my tree so that's why I want the interface changes go via my tree.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
  2016-01-25 15:07   ` Jan Kara
@ 2016-01-25 16:04     ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-25 16:04 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs, Dave Chinner

On 1/25/16 9:07 AM, Jan Kara wrote:
> On Fri 22-01-16 12:25:29, Eric Sandeen wrote:

...

> So I've taken patch 1/7 into my tree since that is completely independent.
> Patches 2/7 and 3/7 look mostly good to me (except for that small omission
> in 3/7) so I can take them to my tree as well. Once I'll finish testing
> some UDF changes I have pending I'll push the tree to:

Jan, thanks for catching & fixing those issues.

> git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git for_next
> 
> and Dave can pull from there to have a basis for XFS patches. I want to
> implement Q_GETNEXTQUOTA for VFS quota formats as well and those will go
> through my tree so that's why I want the interface changes go via my tree.

Makes sense to me.

Thanks,
-Eric


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-25 16:04     ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-25 16:04 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

On 1/25/16 9:07 AM, Jan Kara wrote:
> On Fri 22-01-16 12:25:29, Eric Sandeen wrote:

...

> So I've taken patch 1/7 into my tree since that is completely independent.
> Patches 2/7 and 3/7 look mostly good to me (except for that small omission
> in 3/7) so I can take them to my tree as well. Once I'll finish testing
> some UDF changes I have pending I'll push the tree to:

Jan, thanks for catching & fixing those issues.

> git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs.git for_next
> 
> and Dave can pull from there to have a basis for XFS patches. I want to
> implement Q_GETNEXTQUOTA for VFS quota formats as well and those will go
> through my tree so that's why I want the interface changes go via my tree.

Makes sense to me.

Thanks,
-Eric

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-22 18:25   ` Eric Sandeen
@ 2016-01-26 12:57     ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 12:57 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

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
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 12:57     ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 12:57 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

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
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
  2016-01-22 18:25 ` Eric Sandeen
@ 2016-01-26 13:10   ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 13:10 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, xfs, jack

[-- Attachment #1: Type: text/plain, Size: 1932 bytes --]

Just for reference attached are two patches that implement support for
Q_GETNEXTQUOTA and Q_XGETNEXTQUOTA in quota-tools. I have used it for
testing XFS and VFS infrastructure for these new quotactls.

								Honza
On Fri 22-01-16 12:25:29, Eric Sandeen wrote:
> This adds a 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 specified 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.
> 
> So if you ask for id X, you can get back quota for id X,
> id X+N, or -ESRCH if no higher id has a quota.
> 
> This allows filesystems to do efficient iteration in kernelspace,
> much like extN filesystems do in userspace when asked to report
> all active quotas.
> 
> 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.
> 
> Patches 1 and 4 are just small fixups that turned up along the way;
> 2 and 3 add the actual quota plumbing, and the rest are xfs-specific
> to allow xfs to support this new interface.
> 
> For non-xfs quota, this does require a new structure which is
> able to pass back the discovered ID along with the quota info.
> For xfs-quota, the id is already present in the structure.
> 
> V3:
> * Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
> * Require CAP_SYS_ADMIN for these calls
> * Pass back found ID in &qid passed to ->get_nextdqblk, rather
>   than modifying struct qc_dqblk
> * Munge that found ID back through user-namespace conversions
>   before returning it in the user structure.
> 
> Thanks,
> -Eric
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

[-- Attachment #2: 0001-Scan-dquots-using-Q_GETNEXTQUOTA.patch --]
[-- Type: text/x-patch, Size: 4029 bytes --]

>From 9ae91376373b1b0a8d4573834d0d99722a5909f6 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 26 Jan 2016 13:10:59 +0100
Subject: [PATCH 1/2] Scan dquots using Q_GETNEXTQUOTA

Check for new kernel quotactl Q_GETNEXTQUOTA and if available use it for
scanning all dquot structures.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 quota.h           | 14 ++++++++++++++
 quotaio_generic.c | 34 ++++++++++++++++++++++++++++++++++
 quotaio_generic.h |  4 ++++
 quotaio_meta.c    | 14 +++++++++++++-
 4 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/quota.h b/quota.h
index 0c3842774e6f..0607e04b1f02 100644
--- a/quota.h
+++ b/quota.h
@@ -63,6 +63,7 @@ typedef int64_t qsize_t;	/* Type in which we store size limitations */
 #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 structure used for communication with userspace via quotactl
@@ -91,6 +92,19 @@ struct if_dqblk {
 	u_int32_t dqb_valid;
 };
 
+struct if_nextdqblk {
+	u_int64_t dqb_bhardlimit;
+	u_int64_t dqb_bsoftlimit;
+	u_int64_t dqb_curspace;
+	u_int64_t dqb_ihardlimit;
+	u_int64_t dqb_isoftlimit;
+	u_int64_t dqb_curinodes;
+	u_int64_t dqb_btime;
+	u_int64_t dqb_itime;
+	u_int32_t dqb_valid;
+	u_int32_t dqb_id;
+};
+
 /*
  * Structure used for setting quota information about file via quotactl
  * Following flags are used to specify which fields are valid
diff --git a/quotaio_generic.c b/quotaio_generic.c
index 5001a56f8a6b..06b16e791624 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -161,3 +161,37 @@ int generic_scan_dquots(struct quota_handle *h,
 	free(dquot);
 	return ret;
 }
+
+int vfs_scan_dquots(struct quota_handle *h,
+		    int (*process_dquot)(struct dquot *dquot, char *dqname))
+{
+	struct dquot *dquot = get_empty_dquot();
+	qid_t id = 0;
+	struct if_nextdqblk kdqblk;
+	int ret;
+
+	dquot->dq_h = h;
+	while (1) {
+		ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type),
+			       h->qh_quotadev, id, (void *)&kdqblk);
+		if (ret < 0)
+			break;
+
+		/*
+		 * This is a slight hack but we know struct if_dqblk is a
+		 * subset of struct if_nextdqblk
+		 */
+		generic_kern2utildqblk(&dquot->dq_dqb,
+				       (struct if_dqblk *)&kdqblk);
+		dquot->dq_id = kdqblk.dqb_id;
+		ret = process_dquot(dquot, NULL);
+		if (ret < 0)
+			break;
+		id = kdqblk.dqb_id + 1;
+	}
+	free(dquot);
+
+	if (errno == ESRCH)
+		return 0;
+	return ret;
+}
diff --git a/quotaio_generic.h b/quotaio_generic.h
index 5edc11cd947e..a7930f0214bd 100644
--- a/quotaio_generic.h
+++ b/quotaio_generic.h
@@ -27,4 +27,8 @@ int generic_scan_dquots(struct quota_handle *h,
 			int (*process_dquot)(struct dquot *dquot, char *dqname),
 			int (*get_dquot)(struct dquot *dquot));
 
+/* Scan all dquots using kernel quotactl to get existing ids */
+int vfs_scan_dquots(struct quota_handle *h,
+		    int (*process_dquot)(struct dquot *dquot, char *dqname));
+
 #endif
diff --git a/quotaio_meta.c b/quotaio_meta.c
index e52b4f4322f1..ad6ff7ab2299 100644
--- a/quotaio_meta.c
+++ b/quotaio_meta.c
@@ -8,6 +8,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <sys/types.h>
 
@@ -55,7 +56,18 @@ static int meta_commit_dquot(struct dquot *dquot, int flags)
 
 static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct dquot *dquot, char *dqname))
 {
-	return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+	struct if_nextdqblk kdqblk;
+	int ret;
+
+	ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
+		       (void *)&kdqblk);
+	/*
+	 * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not
+	 * supported
+	 */
+	if (ret < 0 && (errno == ENOSYS || errno == EINVAL))
+		return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+	return vfs_scan_dquots(h, process_dquot);
 }
 
 struct quotafile_ops quotafile_ops_meta = {
-- 
2.6.2


[-- Attachment #3: 0002-Add-support-for-scanning-using-Q_XGETNEXTQUOTA.patch --]
[-- Type: text/x-patch, Size: 2463 bytes --]

>From 304bed24716fdbb7c636ea8df0462d4f979f23a0 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 26 Jan 2016 14:06:59 +0100
Subject: [PATCH 2/2] Add support for scanning using Q_XGETNEXTQUOTA

Add support for scanning of all available quota structures using
Q_XGETNEXTQUOTA quotactl.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 quotaio_xfs.c | 42 +++++++++++++++++++++++++++++++++++++++---
 quotaio_xfs.h |  1 +
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/quotaio_xfs.c b/quotaio_xfs.c
index 903c03e6d3f8..14646411dbab 100644
--- a/quotaio_xfs.c
+++ b/quotaio_xfs.c
@@ -191,15 +191,51 @@ static int xfs_get_dquot(struct dquot *dq)
 	return 0;
 }
 
+static int xfs_kernel_scan_dquots(struct quota_handle *h,
+		int (*process_dquot)(struct dquot *dquot, char *dqname))
+{
+	struct dquot *dquot = get_empty_dquot();
+	qid_t id = 0;
+	struct xfs_kern_dqblk xdqblk;
+	int ret;
+
+	dquot->dq_h = h;
+	while (1) {
+		ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type),
+			       h->qh_quotadev, id, (void *)&xdqblk);
+		if (ret < 0)
+			break;
+
+		xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk);
+		dquot->dq_id = xdqblk.d_id;
+		ret = process_dquot(dquot, NULL);
+		if (ret < 0)
+			break;
+		id = xdqblk.d_id + 1;
+	}
+	free(dquot);
+
+	if (errno == ESRCH)
+		return 0;
+	return ret;
+}
+
 /*
  *	Scan all known dquots and call callback on each
  */
 static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname))
 {
-	if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
-		return 0;
+	int ret;
+	struct xfs_kern_dqblk xdqblk;
 
-	return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+	ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
+		       (void *)&xdqblk);
+	if (ret < 0 && (errno == ENOSYS || errno == EINVAL)) {
+		if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+			return 0;
+		return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+	}
+	return xfs_kernel_scan_dquots(h, process_dquot);
 }
 
 /*
diff --git a/quotaio_xfs.h b/quotaio_xfs.h
index 54725b044d63..2236da48f832 100644
--- a/quotaio_xfs.h
+++ b/quotaio_xfs.h
@@ -46,6 +46,7 @@
 #define Q_XSETQLIM   XQM_CMD(0x4)	/* set disk limits only */
 #define Q_XGETQSTAT  XQM_CMD(0x5)	/* returns fs_quota_stat_t struct */
 #define Q_XQUOTARM   XQM_CMD(0x6)	/* free quota files' space */
+#define Q_XGETNEXTQUOTA	XQM_CMD(0x9)	/* get disk limits and usage >= ID */
 
 /*
  * fs_disk_quota structure:
-- 
2.6.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA
@ 2016-01-26 13:10   ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 13:10 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, jack, xfs

[-- Attachment #1: Type: text/plain, Size: 1932 bytes --]

Just for reference attached are two patches that implement support for
Q_GETNEXTQUOTA and Q_XGETNEXTQUOTA in quota-tools. I have used it for
testing XFS and VFS infrastructure for these new quotactls.

								Honza
On Fri 22-01-16 12:25:29, Eric Sandeen wrote:
> This adds a 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 specified 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.
> 
> So if you ask for id X, you can get back quota for id X,
> id X+N, or -ESRCH if no higher id has a quota.
> 
> This allows filesystems to do efficient iteration in kernelspace,
> much like extN filesystems do in userspace when asked to report
> all active quotas.
> 
> 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.
> 
> Patches 1 and 4 are just small fixups that turned up along the way;
> 2 and 3 add the actual quota plumbing, and the rest are xfs-specific
> to allow xfs to support this new interface.
> 
> For non-xfs quota, this does require a new structure which is
> able to pass back the discovered ID along with the quota info.
> For xfs-quota, the id is already present in the structure.
> 
> V3:
> * Remove 32-bit compat stuff (i686/x86_64 at least works w/o it...)
> * Require CAP_SYS_ADMIN for these calls
> * Pass back found ID in &qid passed to ->get_nextdqblk, rather
>   than modifying struct qc_dqblk
> * Munge that found ID back through user-namespace conversions
>   before returning it in the user structure.
> 
> Thanks,
> -Eric
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

[-- Attachment #2: 0001-Scan-dquots-using-Q_GETNEXTQUOTA.patch --]
[-- Type: text/x-patch, Size: 4029 bytes --]

>From 9ae91376373b1b0a8d4573834d0d99722a5909f6 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 26 Jan 2016 13:10:59 +0100
Subject: [PATCH 1/2] Scan dquots using Q_GETNEXTQUOTA

Check for new kernel quotactl Q_GETNEXTQUOTA and if available use it for
scanning all dquot structures.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 quota.h           | 14 ++++++++++++++
 quotaio_generic.c | 34 ++++++++++++++++++++++++++++++++++
 quotaio_generic.h |  4 ++++
 quotaio_meta.c    | 14 +++++++++++++-
 4 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/quota.h b/quota.h
index 0c3842774e6f..0607e04b1f02 100644
--- a/quota.h
+++ b/quota.h
@@ -63,6 +63,7 @@ typedef int64_t qsize_t;	/* Type in which we store size limitations */
 #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 structure used for communication with userspace via quotactl
@@ -91,6 +92,19 @@ struct if_dqblk {
 	u_int32_t dqb_valid;
 };
 
+struct if_nextdqblk {
+	u_int64_t dqb_bhardlimit;
+	u_int64_t dqb_bsoftlimit;
+	u_int64_t dqb_curspace;
+	u_int64_t dqb_ihardlimit;
+	u_int64_t dqb_isoftlimit;
+	u_int64_t dqb_curinodes;
+	u_int64_t dqb_btime;
+	u_int64_t dqb_itime;
+	u_int32_t dqb_valid;
+	u_int32_t dqb_id;
+};
+
 /*
  * Structure used for setting quota information about file via quotactl
  * Following flags are used to specify which fields are valid
diff --git a/quotaio_generic.c b/quotaio_generic.c
index 5001a56f8a6b..06b16e791624 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -161,3 +161,37 @@ int generic_scan_dquots(struct quota_handle *h,
 	free(dquot);
 	return ret;
 }
+
+int vfs_scan_dquots(struct quota_handle *h,
+		    int (*process_dquot)(struct dquot *dquot, char *dqname))
+{
+	struct dquot *dquot = get_empty_dquot();
+	qid_t id = 0;
+	struct if_nextdqblk kdqblk;
+	int ret;
+
+	dquot->dq_h = h;
+	while (1) {
+		ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type),
+			       h->qh_quotadev, id, (void *)&kdqblk);
+		if (ret < 0)
+			break;
+
+		/*
+		 * This is a slight hack but we know struct if_dqblk is a
+		 * subset of struct if_nextdqblk
+		 */
+		generic_kern2utildqblk(&dquot->dq_dqb,
+				       (struct if_dqblk *)&kdqblk);
+		dquot->dq_id = kdqblk.dqb_id;
+		ret = process_dquot(dquot, NULL);
+		if (ret < 0)
+			break;
+		id = kdqblk.dqb_id + 1;
+	}
+	free(dquot);
+
+	if (errno == ESRCH)
+		return 0;
+	return ret;
+}
diff --git a/quotaio_generic.h b/quotaio_generic.h
index 5edc11cd947e..a7930f0214bd 100644
--- a/quotaio_generic.h
+++ b/quotaio_generic.h
@@ -27,4 +27,8 @@ int generic_scan_dquots(struct quota_handle *h,
 			int (*process_dquot)(struct dquot *dquot, char *dqname),
 			int (*get_dquot)(struct dquot *dquot));
 
+/* Scan all dquots using kernel quotactl to get existing ids */
+int vfs_scan_dquots(struct quota_handle *h,
+		    int (*process_dquot)(struct dquot *dquot, char *dqname));
+
 #endif
diff --git a/quotaio_meta.c b/quotaio_meta.c
index e52b4f4322f1..ad6ff7ab2299 100644
--- a/quotaio_meta.c
+++ b/quotaio_meta.c
@@ -8,6 +8,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <sys/types.h>
 
@@ -55,7 +56,18 @@ static int meta_commit_dquot(struct dquot *dquot, int flags)
 
 static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct dquot *dquot, char *dqname))
 {
-	return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+	struct if_nextdqblk kdqblk;
+	int ret;
+
+	ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
+		       (void *)&kdqblk);
+	/*
+	 * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not
+	 * supported
+	 */
+	if (ret < 0 && (errno == ENOSYS || errno == EINVAL))
+		return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+	return vfs_scan_dquots(h, process_dquot);
 }
 
 struct quotafile_ops quotafile_ops_meta = {
-- 
2.6.2


[-- Attachment #3: 0002-Add-support-for-scanning-using-Q_XGETNEXTQUOTA.patch --]
[-- Type: text/x-patch, Size: 2463 bytes --]

>From 304bed24716fdbb7c636ea8df0462d4f979f23a0 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 26 Jan 2016 14:06:59 +0100
Subject: [PATCH 2/2] Add support for scanning using Q_XGETNEXTQUOTA

Add support for scanning of all available quota structures using
Q_XGETNEXTQUOTA quotactl.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 quotaio_xfs.c | 42 +++++++++++++++++++++++++++++++++++++++---
 quotaio_xfs.h |  1 +
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/quotaio_xfs.c b/quotaio_xfs.c
index 903c03e6d3f8..14646411dbab 100644
--- a/quotaio_xfs.c
+++ b/quotaio_xfs.c
@@ -191,15 +191,51 @@ static int xfs_get_dquot(struct dquot *dq)
 	return 0;
 }
 
+static int xfs_kernel_scan_dquots(struct quota_handle *h,
+		int (*process_dquot)(struct dquot *dquot, char *dqname))
+{
+	struct dquot *dquot = get_empty_dquot();
+	qid_t id = 0;
+	struct xfs_kern_dqblk xdqblk;
+	int ret;
+
+	dquot->dq_h = h;
+	while (1) {
+		ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type),
+			       h->qh_quotadev, id, (void *)&xdqblk);
+		if (ret < 0)
+			break;
+
+		xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk);
+		dquot->dq_id = xdqblk.d_id;
+		ret = process_dquot(dquot, NULL);
+		if (ret < 0)
+			break;
+		id = xdqblk.d_id + 1;
+	}
+	free(dquot);
+
+	if (errno == ESRCH)
+		return 0;
+	return ret;
+}
+
 /*
  *	Scan all known dquots and call callback on each
  */
 static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname))
 {
-	if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
-		return 0;
+	int ret;
+	struct xfs_kern_dqblk xdqblk;
 
-	return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+	ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
+		       (void *)&xdqblk);
+	if (ret < 0 && (errno == ENOSYS || errno == EINVAL)) {
+		if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
+			return 0;
+		return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+	}
+	return xfs_kernel_scan_dquots(h, process_dquot);
 }
 
 /*
diff --git a/quotaio_xfs.h b/quotaio_xfs.h
index 54725b044d63..2236da48f832 100644
--- a/quotaio_xfs.h
+++ b/quotaio_xfs.h
@@ -46,6 +46,7 @@
 #define Q_XSETQLIM   XQM_CMD(0x4)	/* set disk limits only */
 #define Q_XGETQSTAT  XQM_CMD(0x5)	/* returns fs_quota_stat_t struct */
 #define Q_XQUOTARM   XQM_CMD(0x6)	/* free quota files' space */
+#define Q_XGETNEXTQUOTA	XQM_CMD(0x9)	/* get disk limits and usage >= ID */
 
 /*
  * fs_disk_quota structure:
-- 
2.6.2


[-- Attachment #4: Type: text/plain, Size: 121 bytes --]

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-26 12:57     ` Jan Kara
@ 2016-01-26 15:00       ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 15:00 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 15:00       ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 15:00 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-26 15:00       ` Eric Sandeen
@ 2016-01-26 17:52         ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 17:52 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Jan Kara, linux-fsdevel, xfs

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
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 17:52         ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 17:52 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, Jan Kara, xfs

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
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-26 17:52         ` Jan Kara
@ 2016-01-26 17:57           ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 17:57 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 17:57           ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 17:57 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-26 17:52         ` Jan Kara
@ 2016-01-26 18:39           ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 18:39 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 18:39           ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 18:39 UTC (permalink / raw)
  To: Jan Kara; +Cc: linux-fsdevel, xfs

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

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 7/7 V4] xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk
  2016-01-22 18:25   ` Eric Sandeen
@ 2016-01-26 18:40     ` Eric Sandeen
  -1 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 18:40 UTC (permalink / raw)
  To: Eric Sandeen, linux-fsdevel, xfs; +Cc: jack

Add code to allow the Q_XGETNEXTQUOTA quotactl to quickly find
all active quotas by examining the quota inode, and skipping
over unallocated or uninitialized regions.

Userspace can then use this interface rather than i.e. a
getpwent() loop when asked to report all active quotas.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

V4: Return -ENOENT not -ESRCH from xfs_dq_get_next_id() when there
are no more allocated quotas to be found; this is consistent with
the normal, non-next-getquota interface in xfs.

 fs/xfs/libxfs/xfs_quota_defs.h |    3 +-
 fs/xfs/xfs_dquot.c             |   96 ++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_qm.h                |    4 +-
 fs/xfs/xfs_qm_syscalls.c       |   12 +++--
 fs/xfs/xfs_quotaops.c          |   36 ++++++++++++++-
 5 files changed, 142 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index f51078f..8eed512 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -37,7 +37,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_DQ_PROJ		0x0002		/* project quota */
 #define XFS_DQ_GROUP		0x0004		/* a group quota */
 #define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */
-#define XFS_DQ_FREEING		0x0010		/* dquot is beeing torn down */
+#define XFS_DQ_FREEING		0x0010		/* dquot is being torn down */
 
 #define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
 
@@ -116,6 +116,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
+#define XFS_QMOPT_DQNEXT	0x0008000 /* return next dquot >= this ID */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 5dbde0d..2f0502f 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -686,6 +686,56 @@ error0:
 }
 
 /*
+ * Advance to the next id in the current chunk, or if at the
+ * end of the chunk, skip ahead to first id in next allocated chunk
+ * using the SEEK_DATA interface.
+ */
+int
+xfs_dq_get_next_id(
+	xfs_mount_t		*mp,
+	uint			type,
+	xfs_dqid_t		*id,
+	loff_t			eof)
+{
+	struct xfs_inode	*quotip;
+	xfs_fsblock_t		start;
+	loff_t			offset;
+	uint			lock;
+	xfs_dqid_t		next_id;
+	int			error = 0;
+
+	/* Simple advance */
+	next_id = *id + 1;
+
+	/* If new ID is within the current chunk, advancing it sufficed */
+	if (next_id % mp->m_quotainfo->qi_dqperchunk) {
+		*id = next_id;
+		return 0;
+	}
+
+	/* Nope, next_id is now past the current chunk, so find the next one */
+	start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
+
+	quotip = xfs_quota_inode(mp, type);
+	lock = xfs_ilock_data_map_shared(quotip);
+
+	offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
+				      eof, SEEK_DATA);
+	if (offset < 0)
+		error = offset;
+
+	xfs_iunlock(quotip, lock);
+
+	/* -ENXIO is essentially "no more data" */
+	if (error)
+		return (error == -ENXIO ? -ENOENT: error);
+
+	/* Convert next data offset back to a quota id */
+	*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
+	return 0;
+}
+
+/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -705,6 +755,7 @@ xfs_qm_dqget(
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
 	struct xfs_dquot	*dqp;
+	loff_t			eof = 0;
 	int			error;
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -732,6 +783,21 @@ xfs_qm_dqget(
 	}
 #endif
 
+	/* Get the end of the quota file if we need it */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		struct xfs_inode	*quotip;
+		xfs_fileoff_t		last;
+		uint			lock_mode;
+
+		quotip = xfs_quota_inode(mp, type);
+		lock_mode = xfs_ilock_data_map_shared(quotip);
+		error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
+		xfs_iunlock(quotip, lock_mode);
+		if (error)
+			return error;
+		eof = XFS_FSB_TO_B(mp, last);
+	}
+
 restart:
 	mutex_lock(&qi->qi_tree_lock);
 	dqp = radix_tree_lookup(tree, id);
@@ -745,6 +811,18 @@ restart:
 			goto restart;
 		}
 
+		/* uninit / unused quota found in radix tree, keep looking  */
+		if (flags & XFS_QMOPT_DQNEXT) {
+			if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+				xfs_dqunlock(dqp);
+				mutex_unlock(&qi->qi_tree_lock);
+				error = xfs_dq_get_next_id(mp, type, &id, eof);
+				if (error)
+					return error;
+				goto restart;
+			}
+		}
+
 		dqp->q_nrefs++;
 		mutex_unlock(&qi->qi_tree_lock);
 
@@ -771,6 +849,13 @@ restart:
 	if (ip)
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 
+	/* If we are asked to find next active id, keep looking */
+	if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
+		error = xfs_dq_get_next_id(mp, type, &id, eof);
+		if (!error)
+			goto restart;
+	}
+
 	if (error)
 		return error;
 
@@ -821,6 +906,17 @@ restart:
 	qi->qi_dquots++;
 	mutex_unlock(&qi->qi_tree_lock);
 
+	/* If we are asked to find next active id, keep looking */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+			xfs_qm_dqput(dqp);
+			error = xfs_dq_get_next_id(mp, type, &id, eof);
+			if (error)
+				return error;
+			goto restart;
+		}
+	}
+
  dqret:
 	ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	trace_xfs_dqget_miss(dqp);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 8901a01..c68a38f 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -164,8 +164,8 @@ extern void		xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
 
 /* quota ops */
 extern int		xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
-extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
-					uint, struct qc_dqblk *);
+extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *,
+					uint, struct qc_dqblk *, uint);
 extern int		xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
 					struct qc_dqblk *);
 extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 3640c6e..0a25286 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -635,9 +635,10 @@ out:
 int
 xfs_qm_scall_getquota(
 	struct xfs_mount	*mp,
-	xfs_dqid_t		id,
+	xfs_dqid_t		*id,
 	uint			type,
-	struct qc_dqblk		*dst)
+	struct qc_dqblk		*dst,
+	uint			dqget_flags)
 {
 	struct xfs_dquot	*dqp;
 	int			error;
@@ -647,7 +648,7 @@ xfs_qm_scall_getquota(
 	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
 	 * exist, we'll get ENOENT back.
 	 */
-	error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+	error = xfs_qm_dqget(mp, NULL, *id, type, dqget_flags, &dqp);
 	if (error)
 		return error;
 
@@ -660,6 +661,9 @@ xfs_qm_scall_getquota(
 		goto out_put;
 	}
 
+	/* Fill in the ID we actually read from disk */
+	*id = be32_to_cpu(dqp->q_core.d_id);
+
 	memset(dst, 0, sizeof(*dst));
 	dst->d_spc_hardlimit =
 		XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
@@ -701,7 +705,7 @@ xfs_qm_scall_getquota(
 	if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
 	     (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
 	     (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
-	    id != 0) {
+	    *id != 0) {
 		if ((dst->d_space > dst->d_spc_softlimit) &&
 		    (dst->d_spc_softlimit > 0)) {
 			ASSERT(dst->d_spc_timer != 0);
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 7795e0d..f82d79a 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -231,14 +231,45 @@ xfs_fs_get_dqblk(
 	struct qc_dqblk		*qdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
-				      xfs_quota_type(qid.type), qdq);
+	id = from_kqid(&init_user_ns, qid);
+	return xfs_qm_scall_getquota(mp, &id,
+				      xfs_quota_type(qid.type), qdq, 0);
+}
+
+/* Return quota info for active quota >= this qid */
+STATIC int
+xfs_fs_get_nextdqblk(
+	struct super_block	*sb,
+	struct kqid		*qid,
+	struct qc_dqblk		*qdq)
+{
+	int			ret;
+	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
+
+	if (!XFS_IS_QUOTA_RUNNING(mp))
+		return -ENOSYS;
+	if (!XFS_IS_QUOTA_ON(mp))
+		return -ESRCH;
+
+	id = from_kqid(&init_user_ns, *qid);
+	ret = xfs_qm_scall_getquota(mp, &id,
+				    xfs_quota_type(qid->type), qdq,
+				    XFS_QMOPT_DQNEXT);
+	if (ret)
+		return ret;
+
+	/* ID may be different, so convert back what we got */
+	*qid = make_kqid(current_user_ns(), qid->type, id);
+	return 0;
+	
 }
 
 STATIC int
@@ -267,5 +298,6 @@ const struct quotactl_ops xfs_quotactl_operations = {
 	.quota_disable		= xfs_quota_disable,
 	.rm_xquota		= xfs_fs_rm_xquota,
 	.get_dqblk		= xfs_fs_get_dqblk,
+	.get_nextdqblk		= xfs_fs_get_nextdqblk,
 	.set_dqblk		= xfs_fs_set_dqblk,
 };


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 7/7 V4] xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk
@ 2016-01-26 18:40     ` Eric Sandeen
  0 siblings, 0 replies; 44+ messages in thread
From: Eric Sandeen @ 2016-01-26 18:40 UTC (permalink / raw)
  To: Eric Sandeen, linux-fsdevel, xfs; +Cc: jack

Add code to allow the Q_XGETNEXTQUOTA quotactl to quickly find
all active quotas by examining the quota inode, and skipping
over unallocated or uninitialized regions.

Userspace can then use this interface rather than i.e. a
getpwent() loop when asked to report all active quotas.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

V4: Return -ENOENT not -ESRCH from xfs_dq_get_next_id() when there
are no more allocated quotas to be found; this is consistent with
the normal, non-next-getquota interface in xfs.

 fs/xfs/libxfs/xfs_quota_defs.h |    3 +-
 fs/xfs/xfs_dquot.c             |   96 ++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_qm.h                |    4 +-
 fs/xfs/xfs_qm_syscalls.c       |   12 +++--
 fs/xfs/xfs_quotaops.c          |   36 ++++++++++++++-
 5 files changed, 142 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index f51078f..8eed512 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -37,7 +37,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_DQ_PROJ		0x0002		/* project quota */
 #define XFS_DQ_GROUP		0x0004		/* a group quota */
 #define XFS_DQ_DIRTY		0x0008		/* dquot is dirty */
-#define XFS_DQ_FREEING		0x0010		/* dquot is beeing torn down */
+#define XFS_DQ_FREEING		0x0010		/* dquot is being torn down */
 
 #define XFS_DQ_ALLTYPES		(XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
 
@@ -116,6 +116,7 @@ typedef __uint16_t	xfs_qwarncnt_t;
 #define XFS_QMOPT_DQREPAIR	0x0001000 /* repair dquot if damaged */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
 #define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
+#define XFS_QMOPT_DQNEXT	0x0008000 /* return next dquot >= this ID */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 5dbde0d..2f0502f 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -686,6 +686,56 @@ error0:
 }
 
 /*
+ * Advance to the next id in the current chunk, or if at the
+ * end of the chunk, skip ahead to first id in next allocated chunk
+ * using the SEEK_DATA interface.
+ */
+int
+xfs_dq_get_next_id(
+	xfs_mount_t		*mp,
+	uint			type,
+	xfs_dqid_t		*id,
+	loff_t			eof)
+{
+	struct xfs_inode	*quotip;
+	xfs_fsblock_t		start;
+	loff_t			offset;
+	uint			lock;
+	xfs_dqid_t		next_id;
+	int			error = 0;
+
+	/* Simple advance */
+	next_id = *id + 1;
+
+	/* If new ID is within the current chunk, advancing it sufficed */
+	if (next_id % mp->m_quotainfo->qi_dqperchunk) {
+		*id = next_id;
+		return 0;
+	}
+
+	/* Nope, next_id is now past the current chunk, so find the next one */
+	start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk;
+
+	quotip = xfs_quota_inode(mp, type);
+	lock = xfs_ilock_data_map_shared(quotip);
+
+	offset = __xfs_seek_hole_data(VFS_I(quotip), XFS_FSB_TO_B(mp, start),
+				      eof, SEEK_DATA);
+	if (offset < 0)
+		error = offset;
+
+	xfs_iunlock(quotip, lock);
+
+	/* -ENXIO is essentially "no more data" */
+	if (error)
+		return (error == -ENXIO ? -ENOENT: error);
+
+	/* Convert next data offset back to a quota id */
+	*id = XFS_B_TO_FSB(mp, offset) * mp->m_quotainfo->qi_dqperchunk;
+	return 0;
+}
+
+/*
  * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a
  * a locked dquot, doing an allocation (if requested) as needed.
  * When both an inode and an id are given, the inode's id takes precedence.
@@ -705,6 +755,7 @@ xfs_qm_dqget(
 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct radix_tree_root *tree = xfs_dquot_tree(qi, type);
 	struct xfs_dquot	*dqp;
+	loff_t			eof = 0;
 	int			error;
 
 	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -732,6 +783,21 @@ xfs_qm_dqget(
 	}
 #endif
 
+	/* Get the end of the quota file if we need it */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		struct xfs_inode	*quotip;
+		xfs_fileoff_t		last;
+		uint			lock_mode;
+
+		quotip = xfs_quota_inode(mp, type);
+		lock_mode = xfs_ilock_data_map_shared(quotip);
+		error = xfs_bmap_last_offset(quotip, &last, XFS_DATA_FORK);
+		xfs_iunlock(quotip, lock_mode);
+		if (error)
+			return error;
+		eof = XFS_FSB_TO_B(mp, last);
+	}
+
 restart:
 	mutex_lock(&qi->qi_tree_lock);
 	dqp = radix_tree_lookup(tree, id);
@@ -745,6 +811,18 @@ restart:
 			goto restart;
 		}
 
+		/* uninit / unused quota found in radix tree, keep looking  */
+		if (flags & XFS_QMOPT_DQNEXT) {
+			if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+				xfs_dqunlock(dqp);
+				mutex_unlock(&qi->qi_tree_lock);
+				error = xfs_dq_get_next_id(mp, type, &id, eof);
+				if (error)
+					return error;
+				goto restart;
+			}
+		}
+
 		dqp->q_nrefs++;
 		mutex_unlock(&qi->qi_tree_lock);
 
@@ -771,6 +849,13 @@ restart:
 	if (ip)
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 
+	/* If we are asked to find next active id, keep looking */
+	if (error == -ENOENT && (flags & XFS_QMOPT_DQNEXT)) {
+		error = xfs_dq_get_next_id(mp, type, &id, eof);
+		if (!error)
+			goto restart;
+	}
+
 	if (error)
 		return error;
 
@@ -821,6 +906,17 @@ restart:
 	qi->qi_dquots++;
 	mutex_unlock(&qi->qi_tree_lock);
 
+	/* If we are asked to find next active id, keep looking */
+	if (flags & XFS_QMOPT_DQNEXT) {
+		if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
+			xfs_qm_dqput(dqp);
+			error = xfs_dq_get_next_id(mp, type, &id, eof);
+			if (error)
+				return error;
+			goto restart;
+		}
+	}
+
  dqret:
 	ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	trace_xfs_dqget_miss(dqp);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 8901a01..c68a38f 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -164,8 +164,8 @@ extern void		xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
 
 /* quota ops */
 extern int		xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
-extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
-					uint, struct qc_dqblk *);
+extern int		xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *,
+					uint, struct qc_dqblk *, uint);
 extern int		xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
 					struct qc_dqblk *);
 extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 3640c6e..0a25286 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -635,9 +635,10 @@ out:
 int
 xfs_qm_scall_getquota(
 	struct xfs_mount	*mp,
-	xfs_dqid_t		id,
+	xfs_dqid_t		*id,
 	uint			type,
-	struct qc_dqblk		*dst)
+	struct qc_dqblk		*dst,
+	uint			dqget_flags)
 {
 	struct xfs_dquot	*dqp;
 	int			error;
@@ -647,7 +648,7 @@ xfs_qm_scall_getquota(
 	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
 	 * exist, we'll get ENOENT back.
 	 */
-	error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp);
+	error = xfs_qm_dqget(mp, NULL, *id, type, dqget_flags, &dqp);
 	if (error)
 		return error;
 
@@ -660,6 +661,9 @@ xfs_qm_scall_getquota(
 		goto out_put;
 	}
 
+	/* Fill in the ID we actually read from disk */
+	*id = be32_to_cpu(dqp->q_core.d_id);
+
 	memset(dst, 0, sizeof(*dst));
 	dst->d_spc_hardlimit =
 		XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
@@ -701,7 +705,7 @@ xfs_qm_scall_getquota(
 	if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
 	     (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
 	     (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
-	    id != 0) {
+	    *id != 0) {
 		if ((dst->d_space > dst->d_spc_softlimit) &&
 		    (dst->d_spc_softlimit > 0)) {
 			ASSERT(dst->d_spc_timer != 0);
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 7795e0d..f82d79a 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -231,14 +231,45 @@ xfs_fs_get_dqblk(
 	struct qc_dqblk		*qdq)
 {
 	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
 
 	if (!XFS_IS_QUOTA_RUNNING(mp))
 		return -ENOSYS;
 	if (!XFS_IS_QUOTA_ON(mp))
 		return -ESRCH;
 
-	return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
-				      xfs_quota_type(qid.type), qdq);
+	id = from_kqid(&init_user_ns, qid);
+	return xfs_qm_scall_getquota(mp, &id,
+				      xfs_quota_type(qid.type), qdq, 0);
+}
+
+/* Return quota info for active quota >= this qid */
+STATIC int
+xfs_fs_get_nextdqblk(
+	struct super_block	*sb,
+	struct kqid		*qid,
+	struct qc_dqblk		*qdq)
+{
+	int			ret;
+	struct xfs_mount	*mp = XFS_M(sb);
+	xfs_dqid_t		id;
+
+	if (!XFS_IS_QUOTA_RUNNING(mp))
+		return -ENOSYS;
+	if (!XFS_IS_QUOTA_ON(mp))
+		return -ESRCH;
+
+	id = from_kqid(&init_user_ns, *qid);
+	ret = xfs_qm_scall_getquota(mp, &id,
+				    xfs_quota_type(qid->type), qdq,
+				    XFS_QMOPT_DQNEXT);
+	if (ret)
+		return ret;
+
+	/* ID may be different, so convert back what we got */
+	*qid = make_kqid(current_user_ns(), qid->type, id);
+	return 0;
+	
 }
 
 STATIC int
@@ -267,5 +298,6 @@ const struct quotactl_ops xfs_quotactl_operations = {
 	.quota_disable		= xfs_quota_disable,
 	.rm_xquota		= xfs_fs_rm_xquota,
 	.get_dqblk		= xfs_fs_get_dqblk,
+	.get_nextdqblk		= xfs_fs_get_nextdqblk,
 	.set_dqblk		= xfs_fs_set_dqblk,
 };

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
  2016-01-26 18:39           ` Eric Sandeen
@ 2016-01-26 20:40             ` Jan Kara
  -1 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 20:40 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Jan Kara, linux-fsdevel, xfs

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
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA
@ 2016-01-26 20:40             ` Jan Kara
  0 siblings, 0 replies; 44+ messages in thread
From: Jan Kara @ 2016-01-26 20:40 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-fsdevel, Jan Kara, xfs

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
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2016-01-26 20:40 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-22 18:25 [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA Eric Sandeen
2016-01-22 18:25 ` Eric Sandeen
2016-01-22 18:25 ` [PATCH 1/7] quota: remove unused cmd argument from quota_quotaon() Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-25 14:47   ` Jan Kara
2016-01-25 14:47     ` Jan Kara
2016-01-25 14:49     ` Jan Kara
2016-01-25 14:49       ` Jan Kara
2016-01-22 18:25 ` [PATCH 2/7] quota: add new quotactl Q_XGETNEXTQUOTA Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-25 14:51   ` Jan Kara
2016-01-25 14:51     ` Jan Kara
2016-01-26 12:57   ` Jan Kara
2016-01-26 12:57     ` Jan Kara
2016-01-26 15:00     ` Eric Sandeen
2016-01-26 15:00       ` Eric Sandeen
2016-01-26 17:52       ` Jan Kara
2016-01-26 17:52         ` Jan Kara
2016-01-26 17:57         ` Eric Sandeen
2016-01-26 17:57           ` Eric Sandeen
2016-01-26 18:39         ` Eric Sandeen
2016-01-26 18:39           ` Eric Sandeen
2016-01-26 20:40           ` Jan Kara
2016-01-26 20:40             ` Jan Kara
2016-01-22 18:25 ` [PATCH 3/7] quota: add new quotactl Q_GETNEXTQUOTA Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-25 14:51   ` Jan Kara
2016-01-25 14:51     ` Jan Kara
2016-01-22 18:25 ` [PATCH 4/7] xfs: don't overflow quota ID when initializing dqblk Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-22 18:25 ` [PATCH 5/7] xfs: get quota inode from mp & flags rather than dqp Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-22 18:25 ` [PATCH 6/7] xfs: Factor xfs_seek_hole_data into helper Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-22 18:25 ` [PATCH 7/7] xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk Eric Sandeen
2016-01-22 18:25   ` Eric Sandeen
2016-01-26 18:40   ` [PATCH 7/7 V4] " Eric Sandeen
2016-01-26 18:40     ` Eric Sandeen
2016-01-25 15:07 ` [PATCH 0/7 V3] quota: add new quotactl Q_GETNEXTQUOTA Jan Kara
2016-01-25 15:07   ` Jan Kara
2016-01-25 16:04   ` Eric Sandeen
2016-01-25 16:04     ` Eric Sandeen
2016-01-26 13:10 ` Jan Kara
2016-01-26 13:10   ` Jan Kara

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.