* [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible
@ 2026-09-14 5:48 Darrick J. Wong
2026-09-14 5:49 ` [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota Darrick J. Wong
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Darrick J. Wong @ 2026-09-14 5:48 UTC (permalink / raw)
To: aalbersh, djwong; +Cc: linux-xfs
Hi all,
xfs_quota (really, quotactl()) has an interesting interface quirk in
that one passes a path to a block device in order to administer quotas
on a mounted filesystem. Linux 5.17 added a new quotactl_fd syscall
so that one only has to have an open fd to the target filesystem.
Let's port xfsprogs to this new syscall because repeated path lookups
in xfs_quota mean that it's prone to failure if the device gets renamed
while it's running (e.g. lvm). Weirder still, you can unmount the
filesystem while xfs_quota is running.
If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.
With a bit of luck, this should all go splendidly.
Comments and questions are, as always, welcome.
--D
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=quotactl-fd
---
Commits in this patchset:
* libfrog: hoist xfsquotactl out of xfs_quota
* libfrog: clean up xfsquotactl a little bit
* libfrog: enhance struct fs_path to store optional mount fd
* libfrog: try to pass struct fs_path objects to quotactl wrapper
* libfrog: add quotactl_fd support to xfsquotactl
* xfs_quota: open the filesystem mountpoint for quota operations
* xfs_spaceman: port makecfg to use xfsquotactl
---
libfrog/paths.h | 1 +
libfrog/quotactl.h | 30 ++++++++++++++++++++++++
quota/init.h | 2 ++
quota/quota.h | 18 +-------------
configure.ac | 1 +
include/builddefs.in | 1 +
libfrog/Makefile | 6 +++++
libfrog/paths.c | 3 ++
libfrog/quotactl.c | 45 +++++++++++++++++++++++++++---------
m4/package_libcdev.m4 | 19 +++++++++++++++
quota/Makefile | 2 +-
quota/edit.c | 36 +++++++++++++++++------------
quota/free.c | 11 +++++----
quota/init.c | 15 ++++++++++++
quota/path.c | 4 ++-
quota/project.c | 7 ++++++
quota/quota.c | 6 +++--
quota/report.c | 61 ++++++++++++++++++++++++-------------------------
quota/state.c | 38 ++++++++++++++++++-------------
spaceman/info.c | 7 ++----
20 files changed, 208 insertions(+), 105 deletions(-)
create mode 100644 libfrog/quotactl.h
rename quota/linux.c => libfrog/quotactl.c (53%)
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong @ 2026-09-14 5:49 ` Darrick J. Wong 2026-09-15 12:24 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 2/7] libfrog: clean up xfsquotactl a little bit Darrick J. Wong ` (5 subsequent siblings) 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:49 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Hoist this generic function to libfrog so that we can share it with xfs_spaceman later on. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- libfrog/quotactl.h | 28 ++++++++++++++++++++++++++++ quota/quota.h | 18 +----------------- libfrog/Makefile | 2 ++ libfrog/quotactl.c | 2 +- quota/Makefile | 2 +- 5 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 libfrog/quotactl.h rename quota/linux.c => libfrog/quotactl.c (97%) diff --git a/libfrog/quotactl.h b/libfrog/quotactl.h new file mode 100644 index 00000000000000..f76d02567408a0 --- /dev/null +++ b/libfrog/quotactl.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2005 Silicon Graphics, Inc. + * All Rights Reserved. + */ +#ifndef LIBFROG_QUOTACTL_H_ +#define LIBFROG_QUOTACTL_H_ + +#include "xqm.h" + +/* + * System call definitions mapping to platform-specific quotactl + */ +extern int xfsquotactl(int __cmd, const char *__device, + uint __type, uint __id, void * __addr); +enum { + XFS_QUOTAON, /* enable accounting/enforcement */ + XFS_QUOTAOFF, /* disable accounting/enforcement */ + XFS_GETQUOTA, /* get disk limits and usage */ + XFS_SETQLIM, /* set disk limits */ + XFS_GETQSTAT, /* get quota subsystem status */ + XFS_QUOTARM, /* free disk space used by dquots */ + XFS_QSYNC, /* flush delayed allocate space */ + XFS_GETQSTATV, /* newer version of quota stats */ + XFS_GETNEXTQUOTA, /* get disk limits and usage */ +}; + +#endif /* LIBFROG_QUOTACTL_H_ */ diff --git a/quota/quota.h b/quota/quota.h index ece920ef6c1b46..82132e88c671c7 100644 --- a/quota/quota.h +++ b/quota/quota.h @@ -9,6 +9,7 @@ #include "xqm.h" #include "libfrog/paths.h" #include "libfrog/projects.h" +#include "libfrog/quotactl.h" #include <stdbool.h> /* @@ -20,23 +21,6 @@ enum { XFS_RTBLOCK_QUOTA = 0x4, }; -/* - * System call definitions mapping to platform-specific quotactl - */ -extern int xfsquotactl(int __cmd, const char *__device, - uint __type, uint __id, void * __addr); -enum { - XFS_QUOTAON, /* enable accounting/enforcement */ - XFS_QUOTAOFF, /* disable accounting/enforcement */ - XFS_GETQUOTA, /* get disk limits and usage */ - XFS_SETQLIM, /* set disk limits */ - XFS_GETQSTAT, /* get quota subsystem status */ - XFS_QUOTARM, /* free disk space used by dquots */ - XFS_QSYNC, /* flush delayed allocate space */ - XFS_GETQSTATV, /* newer version of quota stats */ - XFS_GETNEXTQUOTA, /* get disk limits and usage */ -}; - /* * Utility routines */ diff --git a/libfrog/Makefile b/libfrog/Makefile index 6ada83407e48c5..b0e8d1a10cd0c7 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -33,6 +33,7 @@ logging.c \ paths.c \ projects.c \ ptvar.c \ +quotactl.c \ radix-tree.c \ randbytes.c \ scrub.c \ @@ -67,6 +68,7 @@ logging.h \ paths.h \ projects.h \ ptvar.h \ +quotactl.h \ radix-tree.h \ randbytes.h \ scrub.h \ diff --git a/quota/linux.c b/libfrog/quotactl.c similarity index 97% rename from quota/linux.c rename to libfrog/quotactl.c index 63e0d34ce28c4e..ffef72b44eeadf 100644 --- a/quota/linux.c +++ b/libfrog/quotactl.c @@ -4,7 +4,7 @@ * All Rights Reserved. */ -#include "quota.h" +#include "libfrog/quotactl.h" #include <sys/quota.h> #ifndef PRJQUOTA diff --git a/quota/Makefile b/quota/Makefile index da5a1489e468b2..296cea44129e7f 100644 --- a/quota/Makefile +++ b/quota/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_quota HFILES = init.h quota.h CFILES = init.c util.c \ - edit.c free.c linux.c path.c project.c quot.c quota.c report.c state.c + edit.c free.c path.c project.c quot.c quota.c report.c state.c LLDLIBS = $(LIBXCMD) $(LIBFROG) LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota 2026-09-14 5:49 ` [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota Darrick J. Wong @ 2026-09-15 12:24 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:24 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 2/7] libfrog: clean up xfsquotactl a little bit 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong 2026-09-14 5:49 ` [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota Darrick J. Wong @ 2026-09-14 5:50 ` Darrick J. Wong 2026-09-15 12:25 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd Darrick J. Wong ` (4 subsequent siblings) 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:50 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Clean up this function so that we actually take advantage of enums for the quota command, and get ready for adding quotactl_fd in the next patch. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- libfrog/quotactl.h | 10 ++++------ libfrog/quotactl.c | 22 ++++++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/libfrog/quotactl.h b/libfrog/quotactl.h index f76d02567408a0..5e351d53bb4b1e 100644 --- a/libfrog/quotactl.h +++ b/libfrog/quotactl.h @@ -8,12 +8,7 @@ #include "xqm.h" -/* - * System call definitions mapping to platform-specific quotactl - */ -extern int xfsquotactl(int __cmd, const char *__device, - uint __type, uint __id, void * __addr); -enum { +enum xfs_quota_cmd { XFS_QUOTAON, /* enable accounting/enforcement */ XFS_QUOTAOFF, /* disable accounting/enforcement */ XFS_GETQUOTA, /* get disk limits and usage */ @@ -25,4 +20,7 @@ enum { XFS_GETNEXTQUOTA, /* get disk limits and usage */ }; +int xfsquotactl(enum xfs_quota_cmd xcommand, const char *device, + unsigned int xtype, unsigned int id, void *addr); + #endif /* LIBFROG_QUOTACTL_H_ */ diff --git a/libfrog/quotactl.c b/libfrog/quotactl.c index ffef72b44eeadf..81df2baf4a76b4 100644 --- a/libfrog/quotactl.c +++ b/libfrog/quotactl.c @@ -28,9 +28,9 @@ xtype_to_qtype( static int xcommand_to_qcommand( - uint command) + enum xfs_quota_cmd xcommand) { - switch (command) { + switch (xcommand) { case XFS_QUOTAON: return Q_XQUOTAON; case XFS_QUOTAOFF: @@ -55,16 +55,14 @@ xcommand_to_qcommand( int xfsquotactl( - int command, - const char *device, - uint type, - uint id, - void *addr) + enum xfs_quota_cmd xcommand, + const char *device, + uint xtype, + uint id, + void *addr) { - int qcommand, qtype; + const int op = QCMD(xcommand_to_qcommand(xcommand), + xtype_to_qtype(xtype)); - qtype = xtype_to_qtype(type); - qcommand = xcommand_to_qcommand(command); - - return quotactl(QCMD(qcommand, qtype), device, id, addr); + return quotactl(op, device, id, addr); } ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 2/7] libfrog: clean up xfsquotactl a little bit 2026-09-14 5:50 ` [PATCH 2/7] libfrog: clean up xfsquotactl a little bit Darrick J. Wong @ 2026-09-15 12:25 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:25 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong 2026-09-14 5:49 ` [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota Darrick J. Wong 2026-09-14 5:50 ` [PATCH 2/7] libfrog: clean up xfsquotactl a little bit Darrick J. Wong @ 2026-09-14 5:50 ` Darrick J. Wong 2026-09-15 12:25 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper Darrick J. Wong ` (3 subsequent siblings) 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:50 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> The fs_path object stores information about various mounted XFS(?) filesystems. We'd like to be able to store an fd to an open file on each mounted filesystem, so add a mnt_fd field to fs_path for that purpose. Users can store a fd in here if they want, and it'll get cleaned up when the fs_table is destroyed. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- libfrog/paths.h | 1 + libfrog/paths.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/libfrog/paths.h b/libfrog/paths.h index 306fd3cb8fde57..90689e7ab69fe8 100644 --- a/libfrog/paths.h +++ b/libfrog/paths.h @@ -29,6 +29,7 @@ typedef struct fs_path { char *fs_dir; /* Directory / mount point */ uint fs_flags; /* FS_{MOUNT_POINT,PROJECT_PATH}*/ uint fs_prid; /* Project ID for tree root */ + int mnt_fd; /* optional fd for mountpoint */ } fs_path_t; extern int fs_count; /* number of entries in fs table */ diff --git a/libfrog/paths.c b/libfrog/paths.c index a5dfab48ec1e2a..d4cf65810c0029 100644 --- a/libfrog/paths.c +++ b/libfrog/paths.c @@ -206,6 +206,7 @@ fs_table_insert( fs_path->fs_datadev = datadev; fs_path->fs_logdev = logdev; fs_path->fs_rtdev = rtdev; + fs_path->mnt_fd = -1; fs_count++; if (!(flags & FS_FOREIGN)) xfs_fs_count++; @@ -232,6 +233,8 @@ fs_table_destroy(void) struct fs_path *fsp; for (i = 0, fsp = fs_table; i < fs_count; i++, fsp++) { + if (fsp->mnt_fd >= 0) + close(fsp->mnt_fd); free(fsp->fs_name); free(fsp->fs_dir); free(fsp->fs_log); ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd 2026-09-14 5:50 ` [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd Darrick J. Wong @ 2026-09-15 12:25 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:25 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong ` (2 preceding siblings ...) 2026-09-14 5:50 ` [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd Darrick J. Wong @ 2026-09-14 5:50 ` Darrick J. Wong 2026-09-15 10:34 ` Andrey Albershteyn 2026-09-14 5:50 ` [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl Darrick J. Wong ` (2 subsequent siblings) 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:50 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> We're going to adapt xfs_quota to use quotactl_fd(), so to prepare for that, we need to pass fs_path pointers as deep into the stack as we can so that xfs_quota can open the associated mountpoint(s) and stash the fds in the fs_path objects; and then pass that to our quotactl wrapper. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- libfrog/quotactl.h | 4 +++ libfrog/quotactl.c | 12 ++++++++++ quota/edit.c | 29 ++++++++++++++----------- quota/free.c | 11 +++++---- quota/path.c | 4 ++- quota/quota.c | 6 +++-- quota/report.c | 61 ++++++++++++++++++++++++++-------------------------- quota/state.c | 38 +++++++++++++++++++------------- 8 files changed, 97 insertions(+), 68 deletions(-) diff --git a/libfrog/quotactl.h b/libfrog/quotactl.h index 5e351d53bb4b1e..dae03b787b7663 100644 --- a/libfrog/quotactl.h +++ b/libfrog/quotactl.h @@ -23,4 +23,8 @@ enum xfs_quota_cmd { int xfsquotactl(enum xfs_quota_cmd xcommand, const char *device, unsigned int xtype, unsigned int id, void *addr); +struct fs_path; +int xfrog_quotactl(const struct fs_path *mount, enum xfs_quota_cmd xcommand, + uint xtype, uint id, void *addr); + #endif /* LIBFROG_QUOTACTL_H_ */ diff --git a/libfrog/quotactl.c b/libfrog/quotactl.c index 81df2baf4a76b4..6129fa155ce75e 100644 --- a/libfrog/quotactl.c +++ b/libfrog/quotactl.c @@ -4,6 +4,7 @@ * All Rights Reserved. */ +#include "libfrog/paths.h" #include "libfrog/quotactl.h" #include <sys/quota.h> @@ -66,3 +67,14 @@ xfsquotactl( return quotactl(op, device, id, addr); } + +int +xfrog_quotactl( + const struct fs_path *mount, + enum xfs_quota_cmd xcommand, + uint xtype, + uint id, + void *addr) +{ + return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); +} diff --git a/quota/edit.c b/quota/edit.c index 1a3b2d9f959be8..d28a4319024038 100644 --- a/quota/edit.c +++ b/quota/edit.c @@ -469,11 +469,12 @@ set_timer( uint32_t id, uint type, uint mask, - char *dev, + const struct fs_path *mount, time64_t value) { struct fs_disk_quota d; time64_t btimer, itimer, rtbtimer; + int ret; memset(&d, 0, sizeof(d)); @@ -485,7 +486,8 @@ set_timer( time_t now; /* Get quota to find out whether user is past soft limits */ - if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) { + ret = xfrog_quotactl(mount, XFS_GETQUOTA, type, id, &d); + if (ret < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot get quota: %s\n"), progname, strerror(errno)); @@ -517,7 +519,8 @@ set_timer( d.d_id = id; encode_timers(&d, btimer, itimer, rtbtimer); - if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) { + ret = xfrog_quotactl(mount, XFS_SETQLIM, type, id, &d); + if (ret < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set timer: %s\n"), progname, strerror(errno)); @@ -601,19 +604,20 @@ timer_f( if (id == -1) return 0; - set_timer(id, type, mask, fs_path->fs_name, value); + set_timer(id, type, mask, fs_path, value); return 0; } static void set_warnings( - uint32_t id, - uint type, - uint mask, - char *dev, - uint value) + uint32_t id, + uint type, + uint mask, + const struct fs_path *mount, + uint value) { - fs_disk_quota_t d; + struct fs_disk_quota d; + int ret; memset(&d, 0, sizeof(d)); d.d_version = FS_DQUOT_VERSION; @@ -624,7 +628,8 @@ set_warnings( d.d_bwarns = value; d.d_rtbwarns = value; - if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) { + ret = xfrog_quotactl(mount, XFS_SETQLIM, type, id, &d); + if (ret < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set warnings: %s\n"), progname, strerror(errno)); @@ -699,7 +704,7 @@ warn_f( if (id == -1) return 0; - set_warnings(id, type, mask, fs_path->fs_name, value); + set_warnings(id, type, mask, fs_path, value); return 0; } diff --git a/quota/free.c b/quota/free.c index ea9c112f314a12..5793885c44fd1e 100644 --- a/quota/free.c +++ b/quota/free.c @@ -136,11 +136,11 @@ projects_free_space_data( fs_disk_quota_t d; struct fsxattr fsx; uint type = XFS_PROJ_QUOTA; - char *dev = path->fs_name; int fd; + int ret; - if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, &qfs) < 0 || - !(qfs.qs_flags & XFS_QUOTA_PDQ_ACCT)) + ret = xfrog_quotactl(path, XFS_GETQSTAT, type, 0, &qfs); + if (ret < 0 || !(qfs.qs_flags & XFS_QUOTA_PDQ_ACCT)) return 0; if ((fd = open(path->fs_dir, O_RDONLY)) < 0) { @@ -174,8 +174,9 @@ projects_free_space_data( return 0; } - xfsquotactl(XFS_QSYNC, dev, type, fsx.fsx_projid, NULL); - if (xfsquotactl(XFS_GETQUOTA, dev, type, fsx.fsx_projid, &d) < 0) { + xfrog_quotactl(path, XFS_QSYNC, type, fsx.fsx_projid, NULL); + ret = xfrog_quotactl(path, XFS_GETQUOTA, type, fsx.fsx_projid, &d); + if (ret < 0) { perror("XFS_GETQUOTA"); close(fd); return 0; diff --git a/quota/path.c b/quota/path.c index 16b8bec4d883c0..4654f1553c65e0 100644 --- a/quota/path.c +++ b/quota/path.c @@ -39,8 +39,8 @@ printpath( if (prj) printf(_(", %s"), prj->pr_name); printf(")"); - } else if (xfsquotactl(XFS_GETQSTAT, path->fs_name, 0, 0, - (void *)&qstat) == 0 && qstat.qs_flags) { + } else if (xfrog_quotactl(path, XFS_GETQSTAT, 0, 0, &qstat) == 0 && + qstat.qs_flags) { c = 0; printf(" ("); if (qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) diff --git a/quota/quota.c b/quota/quota.c index 08a07b2088817b..e1dfad62b9d762 100644 --- a/quota/quota.c +++ b/quota/quota.c @@ -53,9 +53,11 @@ quota_mount( char c[8], h[8], s[8]; uint qflags; int count; + int ret; - xfsquotactl(XFS_QSYNC, dev, type, 0, NULL); - if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) + xfrog_quotactl(mount, XFS_QSYNC, type, id, NULL); + ret = xfrog_quotactl(mount, XFS_GETQUOTA, type, id, &d); + if (ret < 0) return 0; dquot_fudge_numbers(&d); diff --git a/quota/report.c b/quota/report.c index 2acf81b81ba612..86eaa50f84c20b 100644 --- a/quota/report.c +++ b/quota/report.c @@ -61,13 +61,14 @@ report_help(void) static int get_dquot( - struct fs_disk_quota *d, - uint id, - uint type, - char *dev, - int flags) + struct fs_disk_quota *d, + uint id, + uint type, + const struct fs_path *mount, + int flags) { - int cmd; + int cmd; + int ret; if (flags & GETNEXTQUOTA_FLAG) cmd = XFS_GETNEXTQUOTA; @@ -75,7 +76,8 @@ get_dquot( cmd = XFS_GETQUOTA; /* Fall back silently if XFS_GETNEXTQUOTA fails, warn on XFS_GETQUOTA */ - if (xfsquotactl(cmd, dev, type, id, (void *)d) < 0) { + ret = xfrog_quotactl(mount, cmd, type, id, d); + if (ret < 0) { if (errno != ENOENT && errno != ENOSYS && errno != ESRCH && cmd == XFS_GETQUOTA) perror("XFS_GETQUOTA"); @@ -140,8 +142,7 @@ dump_limits_any_type( return; } - while (get_dquot(&d, id, type, mount->fs_name, - flags | GETNEXTQUOTA_FLAG) && + while (get_dquot(&d, id, type, mount, flags | GETNEXTQUOTA_FLAG) && !(upper && (d.d_id > upper))) { dump_file(fp, &d, mount->fs_name); id = d.d_id + 1; @@ -157,8 +158,7 @@ dump_limits_any_type( struct group *g; setgrent(); while ((g = getgrent()) != NULL) { - if (get_dquot(&d, g->gr_gid, type, - mount->fs_name, 0) && + if (get_dquot(&d, g->gr_gid, type, mount, 0) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) dump_file(fp, &d, mount->fs_name); @@ -170,8 +170,7 @@ dump_limits_any_type( struct fs_project *p; setprent(); while ((p = getprent()) != NULL) { - if (get_dquot(&d, p->pr_prid, type, - mount->fs_name, 0) && + if (get_dquot(&d, p->pr_prid, type, mount, 0) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) dump_file(fp, &d, mount->fs_name); @@ -183,8 +182,7 @@ dump_limits_any_type( struct passwd *u; setpwent(); while ((u = getpwent()) != NULL) { - if (get_dquot(&d, u->pw_uid, type, - mount->fs_name, 0) && + if (get_dquot(&d, u->pw_uid, type, mount, 0) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) dump_file(fp, &d, mount->fs_name); @@ -466,7 +464,7 @@ report_user_mount( struct fs_disk_quota d; uint id = lower; - while (get_dquot(&d, id, XFS_USER_QUOTA, mount->fs_name, + while (get_dquot(&d, id, XFS_USER_QUOTA, mount, flags | GETNEXTQUOTA_FLAG) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, NULL, form, XFS_USER_QUOTA, mount, flags); @@ -480,7 +478,7 @@ report_user_mount( setpwent(); while ((u = getpwent()) != NULL) { if (get_dquot(&d, u->pw_uid, XFS_USER_QUOTA, - mount->fs_name, flags) && + mount, flags) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, u->pw_name, form, @@ -508,7 +506,7 @@ report_group_mount( struct fs_disk_quota d; uint id = lower; - while (get_dquot(&d, id, XFS_GROUP_QUOTA, mount->fs_name, + while (get_dquot(&d, id, XFS_GROUP_QUOTA, mount, flags | GETNEXTQUOTA_FLAG) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, NULL, form, XFS_GROUP_QUOTA, mount, flags); @@ -522,7 +520,7 @@ report_group_mount( setgrent(); while ((g = getgrent()) != NULL) { if (get_dquot(&d, g->gr_gid, XFS_GROUP_QUOTA, - mount->fs_name, flags) && + mount, flags) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, g->gr_name, form, @@ -549,7 +547,7 @@ report_project_mount( struct fs_disk_quota d; uint id = lower; - while (get_dquot(&d, id, XFS_PROJ_QUOTA, mount->fs_name, + while (get_dquot(&d, id, XFS_PROJ_QUOTA, mount, flags | GETNEXTQUOTA_FLAG) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, NULL, form, XFS_PROJ_QUOTA, mount, flags); @@ -565,7 +563,7 @@ report_project_mount( * Print default project quota, even if projid 0 * isn't defined */ - if (get_dquot(&d, 0, XFS_PROJ_QUOTA, mount->fs_name, + if (get_dquot(&d, 0, XFS_PROJ_QUOTA, mount, flags) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) { @@ -578,7 +576,7 @@ report_project_mount( setprent(); while ((p = getprent()) != NULL) { if (get_dquot(&d, p->pr_prid, XFS_PROJ_QUOTA, - mount->fs_name, flags) && + mount, flags) && !(lower && (d.d_id < lower)) && !(upper && (d.d_id > upper))) { report_mount(fp, &d, p->pr_name, form, @@ -605,15 +603,16 @@ report_any_type( { fs_cursor_t cursor; fs_path_t *mount; + int ret; if (type & XFS_USER_QUOTA) { fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor); while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; - if (xfsquotactl(XFS_QSYNC, mount->fs_name, - XFS_USER_QUOTA, 0, NULL) < 0 - && errno != ENOENT && errno != ENOSYS) + ret = xfrog_quotactl(mount, XFS_QSYNC, XFS_USER_QUOTA, + 0, NULL); + if (ret < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC user quota"); report_user_mount(fp, form, mount, lower, upper, flags); @@ -624,9 +623,9 @@ report_any_type( while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; - if (xfsquotactl(XFS_QSYNC, mount->fs_name, - XFS_GROUP_QUOTA, 0, NULL) < 0 - && errno != ENOENT && errno != ENOSYS) + ret = xfrog_quotactl(mount, XFS_QSYNC, XFS_GROUP_QUOTA, + 0, NULL); + if (ret < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC group quota"); report_group_mount(fp, form, mount, lower, upper, flags); @@ -637,9 +636,9 @@ report_any_type( while ((mount = fs_cursor_next_entry(&cursor))) { if (!foreign_allowed && (mount->fs_flags & FS_FOREIGN)) continue; - if (xfsquotactl(XFS_QSYNC, mount->fs_name, - XFS_PROJ_QUOTA, 0, NULL) < 0 - && errno != ENOENT && errno != ENOSYS) + ret = xfrog_quotactl(mount, XFS_QSYNC, XFS_PROJ_QUOTA, + 0, NULL); + if (ret < 0 && errno != ENOENT && errno != ENOSYS) perror("XFS_QSYNC proj quota"); report_project_mount(fp, form, mount, lower, upper, flags); diff --git a/quota/state.c b/quota/state.c index 43fb700f9a7317..3679c247ea6204 100644 --- a/quota/state.c +++ b/quota/state.c @@ -202,9 +202,12 @@ state_quotafile_stat( bool accounting, enforcing; struct fs_qfilestatv *qsv; char *dev = mount->fs_name; + int ret; - if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)sv) < 0) { - if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)s) < 0) { + ret = xfrog_quotactl(mount, XFS_GETQSTATV, type, 0, sv); + if (ret < 0) { + ret = xfrog_quotactl(mount, XFS_GETQSTAT, type, 0, sv); + if (ret < 0) { if (flags & VERBOSE_FLAG) fprintf(fp, _("%s quota are not enabled on %s\n"), @@ -351,6 +354,7 @@ enable_enforcement( uint flags) { fs_path_t *mount; + int ret; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { @@ -358,8 +362,8 @@ enable_enforcement( fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } - dir = mount->fs_name; - if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qflags) < 0) { + ret = xfrog_quotactl(mount, XFS_QUOTAON, type, 0, &qflags); + if (ret < 0) { if (errno == EEXIST) fprintf(stderr, _("Quota enforcement already enabled.\n")); @@ -381,6 +385,7 @@ disable_enforcement( uint flags) { fs_path_t *mount; + int ret; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { @@ -388,8 +393,8 @@ disable_enforcement( fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } - dir = mount->fs_name; - if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) { + ret = xfrog_quotactl(mount, XFS_QUOTAOFF, type, 0, &qflags); + if (ret < 0) { if (errno == EEXIST) fprintf(stderr, _("Quota enforcement already disabled.\n")); @@ -411,6 +416,7 @@ quotaoff( uint flags) { fs_path_t *mount; + int ret; mount = fs_table_lookup(dir, FS_MOUNT_POINT); if (!mount) { @@ -418,8 +424,8 @@ quotaoff( fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } - dir = mount->fs_name; - if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qflags) < 0) { + ret = xfrog_quotactl(mount, XFS_QUOTAOFF, type, 0, &qflags); + if (ret) { if (errno == EEXIST || errno == ENOSYS) fprintf(stderr, _("Quota already off.\n")); else @@ -431,12 +437,13 @@ quotaoff( static int remove_qtype_extents( - char *dir, - uint type) + const struct fs_path *mount, + uint type) { - int error = 0; + int error; - if ((error = xfsquotactl(XFS_QUOTARM, dir, type, 0, (void *)&type)) < 0) + error = xfrog_quotactl(mount, XFS_QUOTARM, type, 0, &type); + if (error < 0) perror("XFS_QUOTARM"); return error; } @@ -455,17 +462,16 @@ remove_extents( fprintf(stderr, "%s: unknown mount point %s\n", progname, dir); return; } - dir = mount->fs_name; if (type & XFS_USER_QUOTA) { - if (remove_qtype_extents(dir, XFS_USER_QUOTA) < 0) + if (remove_qtype_extents(mount, XFS_USER_QUOTA) < 0) return; } if (type & XFS_GROUP_QUOTA) { - if (remove_qtype_extents(dir, XFS_GROUP_QUOTA) < 0) + if (remove_qtype_extents(mount, XFS_GROUP_QUOTA) < 0) return; } if (type & XFS_PROJ_QUOTA) { - if (remove_qtype_extents(dir, XFS_PROJ_QUOTA) < 0) + if (remove_qtype_extents(mount, XFS_PROJ_QUOTA) < 0) return; } if (flags & VERBOSE_FLAG) ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper 2026-09-14 5:50 ` [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper Darrick J. Wong @ 2026-09-15 10:34 ` Andrey Albershteyn 2026-09-15 12:26 ` Christoph Hellwig 0 siblings, 1 reply; 18+ messages in thread From: Andrey Albershteyn @ 2026-09-15 10:34 UTC (permalink / raw) To: Darrick J. Wong; +Cc: linux-xfs On 2026-09-13 22:50:37, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@kernel.org> > > We're going to adapt xfs_quota to use quotactl_fd(), so to prepare for > that, we need to pass fs_path pointers as deep into the stack as we can > so that xfs_quota can open the associated mountpoint(s) and stash the > fds in the fs_path objects; and then pass that to our quotactl wrapper. > > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> > --- > libfrog/quotactl.h | 4 +++ > libfrog/quotactl.c | 12 ++++++++++ > quota/edit.c | 29 ++++++++++++++----------- > quota/free.c | 11 +++++---- > quota/path.c | 4 ++- > quota/quota.c | 6 +++-- > quota/report.c | 61 ++++++++++++++++++++++++++-------------------------- > quota/state.c | 38 +++++++++++++++++++------------- > 8 files changed, 97 insertions(+), 68 deletions(-) > > > diff --git a/libfrog/quotactl.h b/libfrog/quotactl.h > index 5e351d53bb4b1e..dae03b787b7663 100644 > --- a/libfrog/quotactl.h > +++ b/libfrog/quotactl.h > @@ -23,4 +23,8 @@ enum xfs_quota_cmd { > int xfsquotactl(enum xfs_quota_cmd xcommand, const char *device, > unsigned int xtype, unsigned int id, void *addr); > > +struct fs_path; > +int xfrog_quotactl(const struct fs_path *mount, enum xfs_quota_cmd xcommand, > + uint xtype, uint id, void *addr); > + > #endif /* LIBFROG_QUOTACTL_H_ */ > diff --git a/libfrog/quotactl.c b/libfrog/quotactl.c > index 81df2baf4a76b4..6129fa155ce75e 100644 > --- a/libfrog/quotactl.c > +++ b/libfrog/quotactl.c > @@ -4,6 +4,7 @@ > * All Rights Reserved. > */ > > +#include "libfrog/paths.h" > #include "libfrog/quotactl.h" > #include <sys/quota.h> > > @@ -66,3 +67,14 @@ xfsquotactl( > > return quotactl(op, device, id, addr); > } > + > +int > +xfrog_quotactl( > + const struct fs_path *mount, > + enum xfs_quota_cmd xcommand, > + uint xtype, > + uint id, > + void *addr) > +{ > + return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); The xfsquotactl() can be unfolded here and calls may be replaced with xfrog_quotactl(), no? -- - Andrey ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper 2026-09-15 10:34 ` Andrey Albershteyn @ 2026-09-15 12:26 ` Christoph Hellwig 2026-09-15 16:15 ` Darrick J. Wong 0 siblings, 1 reply; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:26 UTC (permalink / raw) To: Andrey Albershteyn; +Cc: Darrick J. Wong, linux-xfs On Tue, Sep 15, 2026 at 12:34:33PM +0200, Andrey Albershteyn wrote: > > + const struct fs_path *mount, > > + enum xfs_quota_cmd xcommand, > > + uint xtype, > > + uint id, > > + void *addr) > > +{ > > + return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); > > The xfsquotactl() can be unfolded here and calls may be replaced > with xfrog_quotactl(), no? Yeah, looks like we should be able to kill it. But maybe do that as a follow on cleanup? ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper 2026-09-15 12:26 ` Christoph Hellwig @ 2026-09-15 16:15 ` Darrick J. Wong 2026-09-16 8:33 ` Andrey Albershteyn 0 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-15 16:15 UTC (permalink / raw) To: Christoph Hellwig; +Cc: Andrey Albershteyn, linux-xfs On Tue, Sep 15, 2026 at 05:26:40AM -0700, Christoph Hellwig wrote: > On Tue, Sep 15, 2026 at 12:34:33PM +0200, Andrey Albershteyn wrote: > > > + const struct fs_path *mount, > > > + enum xfs_quota_cmd xcommand, > > > + uint xtype, > > > + uint id, > > > + void *addr) > > > +{ > > > + return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); > > > > The xfsquotactl() can be unfolded here and calls may be replaced > > with xfrog_quotactl(), no? > > Yeah, looks like we should be able to kill it. But maybe do that > as a follow on cleanup? Hrm. There are two xfsquotactl() callers remaining after this patch. One of them is set_limits() in quota/edit.c. One of the callers of set_limits is limit_f, which could very well pass through the fs_path like everywhere else: set_limits(id, type, mask, fs_path->mnt_fd, fs_path->fs_name, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); Obviously a good candidate for passing the fs_path instead of the raw pieces. The other set_limits caller is restore_file: static void restore_file( FILE *fp, uint type) { char buffer[512]; char dev[512]; uint mask; int cnt; uint32_t id; uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard; while (fgets(buffer, sizeof(buffer), fp) != NULL) { if (strncmp("fs = ", buffer, 5) == 0) { /* * Copy the device name to dev, strip off the trailing * newline, and move on to the next line. */ strncpy(dev, buffer + 5, sizeof(dev) - 1); dev[strlen(dev) - 1] = '\0'; continue; } rtbsoft = rtbhard = 0; cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n", &id, (unsigned long long *)&bsoft, (unsigned long long *)&bhard, (unsigned long long *)&isoft, (unsigned long long *)&ihard, (unsigned long long *)&rtbsoft, (unsigned long long *)&rtbhard); if (cnt == 5 || cnt == 7) { mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD; if (cnt == 7) mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD; set_limits(id, type, mask, -1, dev, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); } } } Here, we have a device string, but no open fd to it. I could construct a fake fs_path object to use the xfrog_quotactl() interface, but that's kinda nasty so I'd rather just leave it as an xfsquotactl() site. The second caller is makecfg_f -> get_qflags, which is added in a couple of patches. That one I could just pass it through mount = fs_table_lookup_mount(file->name); if (!mount) { fprintf(stderr, _("%s: Not a XFS mount point.\n"), file->name); return 1; } mount->mnt_fd = file->xfd.fd; ret = get_qflags(mount, &qflags); mount->mnt_fd = -1; Regrettably, struct fileio in spaceman/ is private to xfs_spaceman so there's no general way to pass that to a libfrog function, which is why we have to play switcheroo games with mount->mnt_fd here. --D ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper 2026-09-15 16:15 ` Darrick J. Wong @ 2026-09-16 8:33 ` Andrey Albershteyn 0 siblings, 0 replies; 18+ messages in thread From: Andrey Albershteyn @ 2026-09-16 8:33 UTC (permalink / raw) To: Darrick J. Wong; +Cc: Christoph Hellwig, linux-xfs On 2026-09-15 09:15:33, Darrick J. Wong wrote: > On Tue, Sep 15, 2026 at 05:26:40AM -0700, Christoph Hellwig wrote: > > On Tue, Sep 15, 2026 at 12:34:33PM +0200, Andrey Albershteyn wrote: > > > > + const struct fs_path *mount, > > > > + enum xfs_quota_cmd xcommand, > > > > + uint xtype, > > > > + uint id, > > > > + void *addr) > > > > +{ > > > > + return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); > > > > > > The xfsquotactl() can be unfolded here and calls may be replaced > > > with xfrog_quotactl(), no? > > > > Yeah, looks like we should be able to kill it. But maybe do that > > as a follow on cleanup? > > Hrm. There are two xfsquotactl() callers remaining after this patch. > One of them is set_limits() in quota/edit.c. One of the callers of > set_limits is limit_f, which could very well pass through the fs_path > like everywhere else: > > set_limits(id, type, mask, fs_path->mnt_fd, fs_path->fs_name, > &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); > > Obviously a good candidate for passing the fs_path instead of the raw > pieces. > > The other set_limits caller is restore_file: > > static void > restore_file( > FILE *fp, > uint type) > { > char buffer[512]; > char dev[512]; > uint mask; > int cnt; > uint32_t id; > uint64_t bsoft, bhard, isoft, ihard, rtbsoft, rtbhard; > > while (fgets(buffer, sizeof(buffer), fp) != NULL) { > if (strncmp("fs = ", buffer, 5) == 0) { > /* > * Copy the device name to dev, strip off the trailing > * newline, and move on to the next line. > */ > strncpy(dev, buffer + 5, sizeof(dev) - 1); > dev[strlen(dev) - 1] = '\0'; > continue; > } > rtbsoft = rtbhard = 0; > cnt = sscanf(buffer, "%u %llu %llu %llu %llu %llu %llu\n", > &id, > (unsigned long long *)&bsoft, > (unsigned long long *)&bhard, > (unsigned long long *)&isoft, > (unsigned long long *)&ihard, > (unsigned long long *)&rtbsoft, > (unsigned long long *)&rtbhard); > if (cnt == 5 || cnt == 7) { > mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD; > if (cnt == 7) > mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD; > set_limits(id, type, mask, -1, dev, &bsoft, &bhard, > &isoft, &ihard, &rtbsoft, &rtbhard); > } > } > } > > Here, we have a device string, but no open fd to it. I could construct > a fake fs_path object to use the xfrog_quotactl() interface, but that's > kinda nasty so I'd rather just leave it as an xfsquotactl() site. > > The second caller is makecfg_f -> get_qflags, which is added in a couple > of patches. That one I could just pass it through > > mount = fs_table_lookup_mount(file->name); > if (!mount) { > fprintf(stderr, _("%s: Not a XFS mount point.\n"), file->name); > return 1; > } > > mount->mnt_fd = file->xfd.fd; > ret = get_qflags(mount, &qflags); > mount->mnt_fd = -1; > > Regrettably, struct fileio in spaceman/ is private to xfs_spaceman so > there's no general way to pass that to a libfrog function, which is why > we have to play switcheroo games with mount->mnt_fd here. aha Looks good to me then Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org> -- - Andrey ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong ` (3 preceding siblings ...) 2026-09-14 5:50 ` [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper Darrick J. Wong @ 2026-09-14 5:50 ` Darrick J. Wong 2026-09-15 12:27 ` Christoph Hellwig 2026-09-14 5:51 ` [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations Darrick J. Wong 2026-09-14 5:51 ` [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl Darrick J. Wong 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:50 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Add support for the quotactl_fd syscall to the xfsquotactl call in libfrog. I rearranged the function arguments so that the fs connection point (either an open fd or the fs source) come first. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- libfrog/quotactl.h | 2 +- configure.ac | 1 + include/builddefs.in | 1 + libfrog/Makefile | 4 ++++ libfrog/quotactl.c | 15 +++++++++++++-- m4/package_libcdev.m4 | 19 +++++++++++++++++++ quota/edit.c | 7 ++++--- 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/libfrog/quotactl.h b/libfrog/quotactl.h index dae03b787b7663..9df9327402726d 100644 --- a/libfrog/quotactl.h +++ b/libfrog/quotactl.h @@ -20,7 +20,7 @@ enum xfs_quota_cmd { XFS_GETNEXTQUOTA, /* get disk limits and usage */ }; -int xfsquotactl(enum xfs_quota_cmd xcommand, const char *device, +int xfsquotactl(int mnt_fd, const char *device, enum xfs_quota_cmd xcommand, unsigned int xtype, unsigned int id, void *addr); struct fs_path; diff --git a/configure.ac b/configure.ac index 40ccd88aa2a950..8a2505e37c70ab 100644 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,7 @@ if test "$have_listmount" = "yes"; then fi AC_HAVE_STATMOUNT_SUPPORTED_MASK AC_HAVE_FANOTIFY_MOUNTINFO +AC_HAVE_QUOTACTL_FD if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then AC_PACKAGE_CHECK_UBSAN diff --git a/include/builddefs.in b/include/builddefs.in index 3b52d1afd7031c..5d2e6c1b90ddbe 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -126,6 +126,7 @@ HAVE_LISTMOUNT_NS_FD = @have_listmount_ns_fd@ HAVE_STATMOUNT_SUPPORTED_MASK = @have_statmount_supported_mask@ NEED_INTERNAL_STATMOUNT = @need_internal_statmount@ HAVE_FANOTIFY_MOUNTINFO = @have_fanotify_mountinfo@ +HAVE_QUOTACTL_FD = @have_quotactl_fd@ GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall # -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl diff --git a/libfrog/Makefile b/libfrog/Makefile index b0e8d1a10cd0c7..c7bcd6a778d702 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -108,6 +108,10 @@ ifeq ($(HAVE_LISTMOUNT_NS_FD),yes) CFLAGS+=-DHAVE_LISTMOUNT_NS_FD endif +ifeq ($(HAVE_QUOTACTL_FD),yes) +CFLAGS += -DHAVE_QUOTACTL_FD +endif + default: ltdepend $(LTLIBRARY) $(GETTEXT_PY) crc32table.h: gen_crc32table.c crc32defs.h diff --git a/libfrog/quotactl.c b/libfrog/quotactl.c index 6129fa155ce75e..19b5405be47946 100644 --- a/libfrog/quotactl.c +++ b/libfrog/quotactl.c @@ -56,14 +56,24 @@ xcommand_to_qcommand( int xfsquotactl( - enum xfs_quota_cmd xcommand, + int mnt_fd, const char *device, + enum xfs_quota_cmd xcommand, uint xtype, uint id, void *addr) { const int op = QCMD(xcommand_to_qcommand(xcommand), xtype_to_qtype(xtype)); + int ret = -1; + + errno = ENOSYS; +#ifdef HAVE_QUOTACTL_FD + if (mnt_fd >= 0) + ret = syscall(SYS_quotactl_fd, mnt_fd, op, id, addr); +#endif + if (ret != -1 || errno != ENOSYS) + return ret; return quotactl(op, device, id, addr); } @@ -76,5 +86,6 @@ xfrog_quotactl( uint id, void *addr) { - return xfsquotactl(xcommand, mount->fs_name, xtype, id, addr); + return xfsquotactl(mount->mnt_fd, mount->fs_name, xcommand, xtype, id, + addr); } diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4 index 9586bc01fe0f25..5c1b6e4667d0ee 100644 --- a/m4/package_libcdev.m4 +++ b/m4/package_libcdev.m4 @@ -476,3 +476,22 @@ AC_DEFUN([AC_HAVE_FANOTIFY_MOUNTINFO], AC_MSG_RESULT(no)) AC_SUBST(have_fanotify_mountinfo) ]) + +# +# Check if we have a quotactl_fd system call (5.14). +# +AC_DEFUN([AC_HAVE_QUOTACTL_FD], + [AC_MSG_CHECKING([for quotactl_fd]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#define _GNU_SOURCE +#include <sys/syscall.h> +#include <unistd.h> + ]], [[ + return syscall(SYS_quotactl_fd); + ]]) + ], have_quotactl_fd=yes + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no)) + AC_SUBST(have_quotactl_fd) + ]) diff --git a/quota/edit.c b/quota/edit.c index d28a4319024038..cf4f8cdaeead63 100644 --- a/quota/edit.c +++ b/quota/edit.c @@ -140,6 +140,7 @@ set_limits( uint32_t id, uint type, uint mask, + int mnt_fd, char *dev, uint64_t *bsoft, uint64_t *bhard, @@ -162,7 +163,7 @@ set_limits( d.d_rtb_hardlimit = *rtbhard; d.d_rtb_softlimit = *rtbsoft; - if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) { + if (xfsquotactl(mnt_fd, dev, XFS_SETQLIM, type, id, (void *)&d) < 0) { exitcode = 1; fprintf(stderr, _("%s: cannot set limits: %s\n"), progname, strerror(errno)); @@ -310,7 +311,7 @@ limit_f( if (id == -1) return 0; - set_limits(id, type, mask, fs_path->fs_name, + set_limits(id, type, mask, fs_path->mnt_fd, fs_path->fs_name, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); return 0; } @@ -356,7 +357,7 @@ restore_file( mask = FS_DQ_ISOFT|FS_DQ_IHARD|FS_DQ_BSOFT|FS_DQ_BHARD; if (cnt == 7) mask |= FS_DQ_RTBSOFT|FS_DQ_RTBHARD; - set_limits(id, type, mask, dev, &bsoft, &bhard, + set_limits(id, type, mask, -1, dev, &bsoft, &bhard, &isoft, &ihard, &rtbsoft, &rtbhard); } } ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl 2026-09-14 5:50 ` [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl Darrick J. Wong @ 2026-09-15 12:27 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:27 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong ` (4 preceding siblings ...) 2026-09-14 5:50 ` [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl Darrick J. Wong @ 2026-09-14 5:51 ` Darrick J. Wong 2026-09-15 12:27 ` Christoph Hellwig 2026-09-14 5:51 ` [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl Darrick J. Wong 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:51 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Change xfs_quota's behavior so that it tries to open the filesystem mountpoint when it's starting up. This enables it to use the quotactl_fd system call instead of the kernel having to do a path lookup of the data device. Doing so adds robustness against the data device getting renamed (e.g. lvm rename) while xfs_quota is running. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- quota/init.h | 2 ++ quota/init.c | 15 +++++++++++++++ quota/project.c | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/quota/init.h b/quota/init.h index 9191d822e55819..e85cfa45580cb2 100644 --- a/quota/init.h +++ b/quota/init.h @@ -19,3 +19,5 @@ extern void report_init(void); extern void state_init(void); extern void init_cvtnum(unsigned int *, unsigned int *); + +void open_mnt_fds(void); diff --git a/quota/init.c b/quota/init.c index 9425827591c798..e7fae917d641b7 100644 --- a/quota/init.c +++ b/quota/init.c @@ -128,6 +128,19 @@ init_check_command( return 0; } +void +open_mnt_fds(void) +{ + int c; + + for (c = 0; c < fs_count; c++) { + if (fs_table[c].mnt_fd < 0) { + /* if this fails, we fall back to path-based quotactl */ + fs_table[c].mnt_fd = open(fs_table[c].fs_dir, O_RDONLY); + } + } +} + static void init( int argc, @@ -189,6 +202,8 @@ init( fs_path = fs_table_lookup(argv[optind], FS_MOUNT_POINT); else fs_path = &fs_table[0]; + + open_mnt_fds(); } int diff --git a/quota/project.c b/quota/project.c index 33449e01ef4dbb..9b057df75b6aed 100644 --- a/quota/project.c +++ b/quota/project.c @@ -296,6 +296,13 @@ _("%s: cannot setup path for project dir %s: %s\n"), progname, optarg, strerror(error)); return 0; } + + /* + * fs_table could have been arbitrarily rearranged by + * fs_table_insert, so we need to try to open any new + * mounts. + */ + open_mnt_fds(); break; case 's': type = SETUP_PROJECT; ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations 2026-09-14 5:51 ` [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations Darrick J. Wong @ 2026-09-15 12:27 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:27 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong ` (5 preceding siblings ...) 2026-09-14 5:51 ` [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations Darrick J. Wong @ 2026-09-14 5:51 ` Darrick J. Wong 2026-09-15 12:28 ` Christoph Hellwig 6 siblings, 1 reply; 18+ messages in thread From: Darrick J. Wong @ 2026-09-14 5:51 UTC (permalink / raw) To: aalbersh, djwong; +Cc: linux-xfs From: Darrick J. Wong <djwong@kernel.org> Port this code to use our xfsquotactl function, which means that we can call quotactl_fd/quotactl in the same manner as xfs_quota does. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- spaceman/info.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spaceman/info.c b/spaceman/info.c index bacc48e8aa796f..56c7a05c3f81ec 100644 --- a/spaceman/info.c +++ b/spaceman/info.c @@ -3,7 +3,6 @@ * Copyright (C) 2018 Oracle. All Rights Reserved. * Author: Darrick J. Wong <darrick.wong@oracle.com> */ -#include <sys/quota.h> #include "libxfs.h" #include "command.h" #include "init.h" @@ -11,8 +10,8 @@ #include "libfrog/fsgeom.h" #include "libfrog/fsproperties.h" #include "libfrog/fsprops.h" +#include "libfrog/quotactl.h" #include "space.h" -#include "include/xqm.h" static void info_help(void) @@ -126,8 +125,8 @@ get_qflags( *qflags = 0; /* GETQSTAT returns qflags for all quota types, not just user */ - ret = quotactl(QCMD(Q_XGETQSTAT, USRQUOTA), f->fs_path.fs_name, 0, - (void *)&qstat); + ret = xfsquotactl(f->xfd.fd, f->fs_path.fs_name, XFS_GETQSTAT, + XFS_USER_QUOTA, 0, (void *)&qstat); if (ret) { /* * ENOSYS means quota is not enabled or compiled in; ENODEV ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl 2026-09-14 5:51 ` [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl Darrick J. Wong @ 2026-09-15 12:28 ` Christoph Hellwig 0 siblings, 0 replies; 18+ messages in thread From: Christoph Hellwig @ 2026-09-15 12:28 UTC (permalink / raw) To: Darrick J. Wong; +Cc: aalbersh, linux-xfs Looks good: Reviewed-by: Christoph Hellwig <hch@lst.de> ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-09-16 8:33 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-14 5:48 [PATCHSET 2/2] xfsprogs: use quotactl_fd when possible Darrick J. Wong 2026-09-14 5:49 ` [PATCH 1/7] libfrog: hoist xfsquotactl out of xfs_quota Darrick J. Wong 2026-09-15 12:24 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 2/7] libfrog: clean up xfsquotactl a little bit Darrick J. Wong 2026-09-15 12:25 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 3/7] libfrog: enhance struct fs_path to store optional mount fd Darrick J. Wong 2026-09-15 12:25 ` Christoph Hellwig 2026-09-14 5:50 ` [PATCH 4/7] libfrog: try to pass struct fs_path objects to quotactl wrapper Darrick J. Wong 2026-09-15 10:34 ` Andrey Albershteyn 2026-09-15 12:26 ` Christoph Hellwig 2026-09-15 16:15 ` Darrick J. Wong 2026-09-16 8:33 ` Andrey Albershteyn 2026-09-14 5:50 ` [PATCH 5/7] libfrog: add quotactl_fd support to xfsquotactl Darrick J. Wong 2026-09-15 12:27 ` Christoph Hellwig 2026-09-14 5:51 ` [PATCH 6/7] xfs_quota: open the filesystem mountpoint for quota operations Darrick J. Wong 2026-09-15 12:27 ` Christoph Hellwig 2026-09-14 5:51 ` [PATCH 7/7] xfs_spaceman: port makecfg to use xfsquotactl Darrick J. Wong 2026-09-15 12:28 ` Christoph Hellwig
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox