On Wed, Apr 20, 2022 at 04:45:07PM +0200, Andrey Albershteyn wrote: > 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@xxxxxxxxxx> > Reviewed-by: Christoph Hellwig <hch@xxxxxx> > --- > quota/report.c | 116 +++++++++++++++---------------------------------- > 1 file changed, 35 insertions(+), 81 deletions(-) > > diff --git a/quota/report.c b/quota/report.c > index 8ca154f0..65d931f3 100644 > --- a/quota/report.c > +++ b/quota/report.c > @@ -135,7 +135,7 @@ dump_limits_any_type( > { > fs_path_t *mount; > struct fs_disk_quota 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_dquot(&d, id, &oid, type, mount->fs_name, 0); > - dump_file(fp, &d, mount->fs_name); > - } > - return; > - } > - > - /* Use GETNEXTQUOTA if it's available */ > - if (get_dquot(&d, id, &oid, type, mount->fs_name, GETNEXTQUOTA_FLAG)) { > + while (get_dquot(&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; Just out of curiosity, could this be "id = d.d_id + 1", and then you don't have to pass around &oid at all? --D > - while (get_dquot(&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: { > @@ -472,31 +462,19 @@ report_user_mount( > { > struct passwd *u; > struct fs_disk_quota d; > - uint id = 0, oid; > + uint id = lower, oid; > > - if (upper) { /* identifier range specified */ > - for (id = lower; id <= upper; id++) { > - if (get_dquot(&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_dquot(&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_dquot(&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_dquot(&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_dquot(&d, u->pw_uid, NULL, XFS_USER_QUOTA, > @@ -524,31 +502,19 @@ report_group_mount( > { > struct group *g; > struct fs_disk_quota d; > - uint id = 0, oid; > + uint id = lower, oid; > > - if (upper) { /* identifier range specified */ > - for (id = lower; id <= upper; id++) { > - if (get_dquot(&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_dquot(&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_dquot(&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_dquot(&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_dquot(&d, g->gr_gid, NULL, XFS_GROUP_QUOTA, > @@ -575,31 +541,19 @@ report_project_mount( > { > fs_project_t *p; > struct fs_disk_quota d; > - uint id = 0, oid; > + uint id = lower, oid; > > - if (upper) { /* identifier range specified */ > - for (id = lower; id <= upper; id++) { > - if (get_dquot(&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_dquot(&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_dquot(&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_dquot(&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 >