summaryrefslogtreecommitdiff
path: root/quotasys.c
diff options
context:
space:
mode:
authorCarlos Maiolino <cem@kernel.org>2024-01-26 19:02:10 +0100
committerJan Kara <jack@suse.cz>2024-01-29 11:59:49 +0100
commitded570b1fffbeaefbecb6c191f0b5168f3b8ad0d (patch)
treed28a6006fd798d28a93dd8b511df392876d2c226 /quotasys.c
parentc18e5a1b1e51c0382f5d1431120fe65f7e9c982c (diff)
Add quotactl_fd() support
To be able to set quotas on filesystems without a backing device, quota tools should be able to use quotactl_fd(). To achieve that, add a new helper, do_quotactl(), to select between quotactl() and quotactl_fd(). This shouldn't change the semantics of current code. quotactl_fd() will be called if and only if the handlers contain an empty device, and a valid mountpoint. All current calls containing a value device should be still handled by quotactl(). The same is true for calls passing a NULL device on purpose, aiming to sync active quotas. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'quotasys.c')
-rw-r--r--quotasys.c55
1 files changed, 43 insertions, 12 deletions
diff --git a/quotasys.c b/quotasys.c
index 9af9932..903816b 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -25,6 +25,7 @@
#include <sys/vfs.h>
#include <stdint.h>
#include <sys/utsname.h>
+#include <sys/syscall.h>
#include "pot.h"
#include "bylabel.h"
@@ -671,6 +672,36 @@ const char *str2number(const char *string, qsize_t *inodes)
}
/*
+ * Wrappers for quotactl syscalls
+ */
+#ifdef SYS_quotactl_fd
+int do_quotactl(int cmd, const char *dev, const char *mnt, int id, caddr_t addr)
+{
+ int ret = -EINVAL;
+
+ if (mnt && !dev) {
+ int fd = open(mnt, O_DIRECTORY | O_PATH);
+
+ if (fd < 0) {
+ errstr(_("Unable to get a filedescriptor from mountpoint: %s\n"), mnt);
+ return fd;
+ }
+
+ ret = syscall(SYS_quotactl_fd, fd, cmd, id, addr);
+ close(fd);
+ return ret;
+ }
+
+ return quotactl(cmd, dev, id, addr);
+}
+#else
+int do_quotactl(int cmd, const char *dev, const char *mnt, int id, caddr_t addr)
+{
+ return quotactl(cmd, dev, id, addr);
+}
+#endif
+
+/*
* Wrappers for mount options processing functions
*/
@@ -685,7 +716,7 @@ static int hasxfsquota(const char *dev, struct mntent *mnt, int type, int flags)
return QF_XFS;
memset(&info, 0, sizeof(struct xfs_mem_dqinfo));
- if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) {
+ if (!do_quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, mnt->mnt_dir, 0, (void *)&info)) {
#ifdef XFS_ROOTHACK
int sbflags = (info.qs_flags & 0xff00) >> 8;
#endif /* XFS_ROOTHACK */
@@ -719,7 +750,7 @@ static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int fl
{
uint32_t fmt;
- if (!quotactl(QCMD(Q_GETFMT, type), dev, 0, (void *)&fmt))
+ if (!do_quotactl(QCMD(Q_GETFMT, type), dev, mnt->mnt_dir, 0, (void *)&fmt))
return QF_META;
return QF_ERROR;
}
@@ -796,7 +827,7 @@ static int hasquota(const char *dev, struct mntent *mnt, int type, int flags)
if (!strcmp(mnt->mnt_type, MNTTYPE_EXT4) || !strcmp(mnt->mnt_type, MNTTYPE_F2FS)) {
struct if_dqinfo kinfo;
- if (quotactl(QCMD(Q_GETINFO, type), dev, 0, (void *)&kinfo) == 0) {
+ if (do_quotactl(QCMD(Q_GETINFO, type), dev, mnt->mnt_dir, 0, (void *)&kinfo) == 0) {
if (kinfo.dqi_flags & DQF_SYS_FILE)
return QF_META;
}
@@ -1069,11 +1100,11 @@ void init_kernel_interface(void)
else {
fs_quota_stat_t dummy;
- if (!quotactl(QCMD(Q_XGETQSTAT, 0), "/dev/root", 0, (void *)&dummy) ||
+ if (!do_quotactl(QCMD(Q_XGETQSTAT, 0), "/dev/root", NULL, 0, (void *)&dummy) ||
(errno != EINVAL && errno != ENOSYS))
kernel_qfmt[kernel_qfmt_num++] = QF_XFS;
}
- if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) {
+ if (do_quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, NULL, 0, (void *)&v2_stats) >= 0) {
kernel_qfmt[kernel_qfmt_num++] = QF_VFSV0;
kernel_iface = IFACE_VFSV0;
}
@@ -1085,9 +1116,9 @@ void init_kernel_interface(void)
int err_quota = 0;
char tmp[1024]; /* Just temporary buffer */
- if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, tmp))
+ if (do_quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, NULL, 0, tmp))
err_stat = errno;
- if (quotactl(QCMD(Q_V1_GETQUOTA, 0), "/dev/null", 0, tmp))
+ if (do_quotactl(QCMD(Q_V1_GETQUOTA, 0), "/dev/null", NULL, 0, tmp))
err_quota = errno;
/* On a RedHat 2.4.2-2 we expect 0, EINVAL
@@ -1127,7 +1158,7 @@ static int v1_kern_quota_on(const char *dev, int type)
char tmp[1024]; /* Just temporary buffer */
qid_t id = (type == USRQUOTA) ? getuid() : getgid();
- if (!quotactl(QCMD(Q_V1_GETQUOTA, type), dev, id, tmp)) /* OK? */
+ if (!do_quotactl(QCMD(Q_V1_GETQUOTA, type), dev, NULL, id, tmp)) /* OK? */
return 1;
return 0;
}
@@ -1138,7 +1169,7 @@ static int v2_kern_quota_on(const char *dev, int type)
char tmp[1024]; /* Just temporary buffer */
qid_t id = (type == USRQUOTA) ? getuid() : getgid();
- if (!quotactl(QCMD(Q_V2_GETQUOTA, type), dev, id, tmp)) /* OK? */
+ if (!do_quotactl(QCMD(Q_V2_GETQUOTA, type), dev, NULL, id, tmp)) /* OK? */
return 1;
return 0;
}
@@ -1155,7 +1186,7 @@ int kern_quota_state_xfs(const char *dev, int type)
{
struct xfs_mem_dqinfo info;
- if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) {
+ if (!do_quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, NULL, 0, (void *)&info)) {
if (type == USRQUOTA) {
return !!(info.qs_flags & XFS_QUOTA_UDQ_ACCT) +
!!(info.qs_flags & XFS_QUOTA_UDQ_ENFD);
@@ -1199,8 +1230,8 @@ int kern_quota_on(struct mount_entry *mnt, int type, int fmt)
if (kernel_iface == IFACE_GENERIC) {
int actfmt;
- if (quotactl(QCMD(Q_GETFMT, type), mnt->me_devname, 0,
- (void *)&actfmt) >= 0) {
+ if (do_quotactl(QCMD(Q_GETFMT, type), mnt->me_devname,
+ mnt->me_dir, 0, (void *)&actfmt) >= 0) {
actfmt = kern2utilfmt(actfmt);
if (actfmt >= 0)
return actfmt;