[PATCH 4/5] xfs_quota: utilize XFS_GETNEXTQUOTA for ranged calls in report/dump

Andrey Albershteyn
2022-03-28T22:27:11Z

The implementation based on XFS_GETQUOTA call for each ID in range,
specified with -L/-U, is quite slow for wider ranges.

If kernel supports XFS_GETNEXTQUOTA, report_*_mount/dump_any_file
will use that to obtain quota list for the mount. XFS_GETNEXTQUOTA
returns quota of the requested ID and next ID with non-empty quota.

Otherwise, XFS_GETQUOTA will be used for each user/group/project ID
known from password/group/project database.

Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com>
---
quota/report.c | 113 +++++++++++++++----------------------------------
1 file changed, 35 insertions(+), 78 deletions(-)

diff --git a/quota/report.c b/quota/report.c
index 14b7f458..074abbc1 100644
--- a/quota/report.c
+++ b/quota/report.c
@@ -135,7 +135,7 @@ dump_limits_any_type(
{
fs_path_t *mount;
fs_disk_quota_t d;
- uint id = 0, oid;
+ uint id = lower, oid, flags = 0;

if ((mount = fs_table_lookup(dir, FS_MOUNT_POINT)) == NULL) {
exitcode = 1;
@@ -144,27 +144,17 @@ dump_limits_any_type(
return;
}

- /* Range was specified; query everything in it */
- if (upper) {
- for (id = lower; id <= upper; id++) {
- get_quota(&d, id, &oid, type, mount->fs_name, 0);
- dump_file(fp, &d, mount->fs_name);
- }
- return;
- }
-
- /* Use GETNEXTQUOTA if it's available */
- if (get_quota(&d, id, &oid, type, mount->fs_name, GETNEXTQUOTA_FLAG)) {
+ while (get_quota(&d, id, &oid, type,
+ mount->fs_name, flags|GETNEXTQUOTA_FLAG) &&
+ !(upper && (d.d_id > upper))) {
dump_file(fp, &d, mount->fs_name);
id = oid + 1;
- while (get_quota(&d, id, &oid, type, mount->fs_name,
- GETNEXTQUOTA_FLAG)) {
- dump_file(fp, &d, mount->fs_name);
- id = oid + 1;
- }
- return;
+ flags |= GETNEXTQUOTA_FLAG;
}

+ if (flags & GETNEXTQUOTA_FLAG)
+ return;
+
/* Otherwise fall back to iterating over each uid/gid/prjid */
switch (type) {
case XFS_GROUP_QUOTA: {
@@ -469,31 +459,19 @@ report_user_mount(
{
struct passwd *u;
fs_disk_quota_t d;
- uint id = 0, oid;
+ uint id = lower, oid;

- if (upper) { /* identifier range specified */
- for (id = lower; id <= upper; id++) {
- if (get_quota(&d, id, NULL, XFS_USER_QUOTA,
- mount->fs_name, flags)) {
- report_mount(fp, &d, NULL, form, XFS_USER_QUOTA, mount,
- flags);
- flags |= NO_HEADER_FLAG;
- }
- }
- } else if (get_quota(&d, id, &oid, XFS_USER_QUOTA, mount->fs_name,
- flags|GETNEXTQUOTA_FLAG)) {
- report_mount(fp, &d, NULL, form, XFS_USER_QUOTA, mount,
- flags|GETNEXTQUOTA_FLAG);
+ while (get_quota(&d, id, &oid, XFS_USER_QUOTA,
+ mount->fs_name, flags|GETNEXTQUOTA_FLAG) &&
+ !(upper && (d.d_id > upper))) {
+ report_mount(fp, &d, NULL, form, XFS_USER_QUOTA, mount, flags);
id = oid + 1;
flags |= GETNEXTQUOTA_FLAG;
flags |= NO_HEADER_FLAG;
- while (get_quota(&d, id, &oid, XFS_USER_QUOTA, mount->fs_name,
- flags)) {
- report_mount(fp, &d, NULL, form, XFS_USER_QUOTA,
- mount, flags);
- id = oid + 1;
- }
- } else {
+ }
+
+ /* No GETNEXTQUOTA support, iterate over all from password file */
+ if (!(flags & GETNEXTQUOTA_FLAG)) {
setpwent();
while ((u = getpwent()) != NULL) {
if (get_quota(&d, u->pw_uid, NULL, XFS_USER_QUOTA, mount->fs_name,
@@ -521,30 +499,19 @@ report_group_mount(
{
struct group *g;
fs_disk_quota_t d;
- uint id = 0, oid;
+ uint id = lower, oid;

- if (upper) { /* identifier range specified */
- for (id = lower; id <= upper; id++) {
- if (get_quota(&d, id, NULL, XFS_GROUP_QUOTA,
- mount->fs_name, flags)) {
- report_mount(fp, &d, NULL, form, XFS_GROUP_QUOTA, mount, flags);
- flags |= NO_HEADER_FLAG;
- }
- }
- } else if (get_quota(&d, id, &oid, XFS_GROUP_QUOTA,
- mount->fs_name, flags|GETNEXTQUOTA_FLAG)) {
- report_mount(fp, &d, NULL, form, XFS_GROUP_QUOTA, mount,
- flags|GETNEXTQUOTA_FLAG);
+ while (get_quota(&d, id, &oid, XFS_GROUP_QUOTA,
+ mount->fs_name, flags|GETNEXTQUOTA_FLAG) &&
+ !(upper && (oid > upper))) {
+ report_mount(fp, &d, NULL, form, XFS_GROUP_QUOTA, mount, flags);
id = oid + 1;
flags |= GETNEXTQUOTA_FLAG;
flags |= NO_HEADER_FLAG;
- while (get_quota(&d, id, &oid, XFS_GROUP_QUOTA,
- mount->fs_name, flags)) {
- report_mount(fp, &d, NULL, form, XFS_GROUP_QUOTA, mount,
- flags);
- id = oid + 1;
- }
- } else {
+ }
+
+ /* No GETNEXTQUOTA support, iterate over all from password file */
+ if (!(flags & GETNEXTQUOTA_FLAG)) {
setgrent();
while ((g = getgrent()) != NULL) {
if (get_quota(&d, g->gr_gid, NULL, XFS_GROUP_QUOTA,
@@ -571,29 +538,19 @@ report_project_mount(
{
fs_project_t *p;
fs_disk_quota_t d;
- uint id = 0, oid;
+ uint id = lower, oid;

- if (upper) { /* identifier range specified */
- for (id = lower; id <= upper; id++) {
- if (get_quota(&d, id, NULL, XFS_PROJ_QUOTA,
- mount->fs_name, flags)) {
- report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA, mount, flags);
- flags |= NO_HEADER_FLAG;
- }
- }
- } else if (get_quota(&d, id, &oid, XFS_PROJ_QUOTA,
- mount->fs_name, flags|GETNEXTQUOTA_FLAG)) {
- report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA, mount,
- flags|GETNEXTQUOTA_FLAG);
+ while (get_quota(&d, id, &oid, XFS_PROJ_QUOTA,
+ mount->fs_name, flags|GETNEXTQUOTA_FLAG) &&
+ !(upper && (d.d_id > upper))) {
+ report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA, mount, flags);
id = oid + 1;
flags |= GETNEXTQUOTA_FLAG;
flags |= NO_HEADER_FLAG;
- while (get_quota(&d, id, &oid, XFS_PROJ_QUOTA,
- mount->fs_name, flags)) {
- report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA, mount, flags);
- id = oid + 1;
- }
- } else {
+ }
+
+ /* No GETNEXTQUOTA support, iterate over all */
+ if (!(flags & GETNEXTQUOTA_FLAG)) {
if (!getprprid(0)) {
/*
* Print default project quota, even if projid 0
--
2.27.0