* [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
* [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
* [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
* [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
* [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
* [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
* [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 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 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
* 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
* 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
* 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 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
* 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
* 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
* 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
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