From 99673271fc8a04120c1f367d52891d4f56248fb6 Mon Sep 17 00:00:00 2001 From: wenjie2025 Date: Thu, 29 Jan 2026 08:49:12 +0800 Subject: [PATCH] Update code from upstream --- quota-4.10-Add-quotactl_fd-support.patch | 580 +++++++++ ...4.10-Enable-support-for-tmpfs-quotas.patch | 336 +++++ ...name-searched_dir-sd_dir-to-sd_isdir.patch | 52 + ...Fix-error-handling-in-xfs_read_dquot.patch | 36 + ...0-quotaio_xfs-Fix-quota-tools-on-XFS.patch | 64 + quota-upstream-2944f3c9.patch | 1135 +++++++++++++++++ quota.spec | 14 +- 7 files changed, 2216 insertions(+), 1 deletion(-) create mode 100644 quota-4.10-Add-quotactl_fd-support.patch create mode 100644 quota-4.10-Enable-support-for-tmpfs-quotas.patch create mode 100644 quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch create mode 100644 quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch create mode 100644 quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch create mode 100644 quota-upstream-2944f3c9.patch diff --git a/quota-4.10-Add-quotactl_fd-support.patch b/quota-4.10-Add-quotactl_fd-support.patch new file mode 100644 index 0000000..973cdfb --- /dev/null +++ b/quota-4.10-Add-quotactl_fd-support.patch @@ -0,0 +1,580 @@ +From ded570b1fffbeaefbecb6c191f0b5168f3b8ad0d Mon Sep 17 00:00:00 2001 +From: Carlos Maiolino +Date: Fri, 26 Jan 2024 19:02:10 +0100 +Subject: [PATCH 2/3] 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 +Signed-off-by: Lukas Czerner +Signed-off-by: Jan Kara +Signed-off-by: Pavel Reichl +--- + Makefile.am | 1 + + quotacheck.c | 12 +++++------ + quotaio.c | 4 ++-- + quotaio_generic.c | 12 +++++------ + quotaio_meta.c | 4 ++-- + quotaio_v1.c | 10 ++++----- + quotaio_v2.c | 12 +++++------ + quotaio_xfs.c | 21 ++++++++++-------- + quotaon.c | 8 +++---- + quotaon_xfs.c | 9 ++++---- + quotasync.c | 2 +- + quotasys.c | 55 ++++++++++++++++++++++++++++++++++++----------- + quotasys.h | 3 +++ + 13 files changed, 96 insertions(+), 57 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 372eafb..13a0f06 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -207,6 +207,7 @@ quotastats_SOURCES = \ + pot.h + + quotastats_LDADD = \ ++ libquota.a \ + $(INTLLIBS) + + xqmstats_SOURCES = \ +diff --git a/quotacheck.c b/quotacheck.c +index bd62d9a..e2c3bbd 100644 +--- a/quotacheck.c ++++ b/quotacheck.c +@@ -648,8 +648,8 @@ Please turn quotas off or use -f to force checking.\n"), + type2name(type), mnt->me_dir); + } + /* At least sync quotas so damage will be smaller */ +- if (quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type), +- mnt->me_devname, 0, NULL) < 0) ++ if (do_quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type), ++ mnt->me_devname, mnt->me_dir, 0, NULL) < 0) + die(4, _("Error while syncing quotas on %s: %s\n"), mnt->me_devname, strerror(errno)); + } + +@@ -848,8 +848,8 @@ static int dump_to_file(struct mount_entry *mnt, int type) + if (get_qf_name(mnt, type, cfmt, NF_FORMAT, &filename) < 0) + errstr(_("Cannot find checked quota file for %ss on %s!\n"), _(type2name(type)), mnt->me_devname); + else { +- if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type), +- mnt->me_devname, 0, NULL) < 0) ++ if (do_quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type), ++ mnt->me_devname, mnt->me_dir, 0, NULL) < 0) + errstr(_("Cannot turn %s quotas off on %s: %s\nKernel won't know about changes quotacheck did.\n"), + _(type2name(type)), mnt->me_devname, strerror(errno)); + else { +@@ -859,9 +859,9 @@ static int dump_to_file(struct mount_entry *mnt, int type) + rename_files(mnt, type); + + if (kernel_iface == IFACE_GENERIC) +- ret = quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, util2kernfmt(cfmt), filename); ++ ret = do_quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, mnt->me_dir, util2kernfmt(cfmt), filename); + else +- ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, 0, filename); ++ ret = do_quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, mnt->me_dir, 0, filename); + if (ret < 0) + errstr(_("Cannot turn %s quotas on on %s: %s\nKernel won't know about changes quotacheck did.\n"), + _(type2name(type)), mnt->me_devname, strerror(errno)); +diff --git a/quotaio.c b/quotaio.c +index 94ae458..9bebb5e 100644 +--- a/quotaio.c ++++ b/quotaio.c +@@ -140,8 +140,8 @@ struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int fla + if (QIO_ENABLED(h)) { /* Kernel uses same file? */ + unsigned int cmd = + (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC; +- if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, +- 0, NULL) < 0) { ++ if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, ++ h->qh_dir, 0, NULL) < 0) { + die(4, _("Cannot sync quotas on device %s: %s\n"), + h->qh_quotadev, strerror(errno)); + } +diff --git a/quotaio_generic.c b/quotaio_generic.c +index 5b23955..3c95872 100644 +--- a/quotaio_generic.c ++++ b/quotaio_generic.c +@@ -50,7 +50,7 @@ int vfs_get_info(struct quota_handle *h) + { + struct if_dqinfo kinfo; + +- if (quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kinfo) < 0) { ++ if (do_quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { + errstr(_("Cannot get info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -68,7 +68,7 @@ int vfs_set_info(struct quota_handle *h, int flags) + kinfo.dqi_igrace = h->qh_info.dqi_igrace; + kinfo.dqi_valid = flags; + +- if (quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kinfo) < 0) { ++ if (do_quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { + errstr(_("Cannot set info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -80,7 +80,7 @@ int vfs_get_dquot(struct dquot *dquot) + { + struct if_dqblk kdqblk; + +- if (quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_id, (void *)&kdqblk) < 0) { ++ if (do_quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { + errstr(_("Cannot get quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -95,7 +95,7 @@ int vfs_set_dquot(struct dquot *dquot, int flags) + + generic_util2kerndqblk(&kdqblk, &dquot->dq_dqb); + kdqblk.dqb_valid = flags; +- if (quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_id, (void *)&kdqblk) < 0) { ++ if (do_quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { + errstr(_("Cannot set quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -188,8 +188,8 @@ int vfs_scan_dquots(struct quota_handle *h, + + dquot->dq_h = h; + while (1) { +- ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), +- h->qh_quotadev, id, (void *)&kdqblk); ++ ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), ++ h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk); + if (ret < 0) + break; + +diff --git a/quotaio_meta.c b/quotaio_meta.c +index ad6ff7a..51ebbcf 100644 +--- a/quotaio_meta.c ++++ b/quotaio_meta.c +@@ -59,8 +59,8 @@ static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct + struct if_nextdqblk kdqblk; + int ret; + +- ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0, +- (void *)&kdqblk); ++ ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, ++ h->qh_dir, 0, (void *)&kdqblk); + /* + * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not + * supported +diff --git a/quotaio_v1.c b/quotaio_v1.c +index 6a6dc78..187a5a5 100644 +--- a/quotaio_v1.c ++++ b/quotaio_v1.c +@@ -118,7 +118,7 @@ static int v1_init_io(struct quota_handle *h) + else { + struct v1_kern_dqblk kdqblk; + +- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) { ++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) { + if (errno == EPERM) { /* We have no permission to get this information? */ + h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */ + } +@@ -193,11 +193,11 @@ static int v1_write_info(struct quota_handle *h) + else { + struct v1_kern_dqblk kdqblk; + +- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) ++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) + return -1; + kdqblk.dqb_btime = h->qh_info.dqi_bgrace; + kdqblk.dqb_itime = h->qh_info.dqi_igrace; +- if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) ++ if (do_quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) + return -1; + } + } +@@ -237,7 +237,7 @@ static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id) + else { + struct v1_kern_dqblk kdqblk; + +- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) { ++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { + free(dquot); + return NULL; + } +@@ -299,7 +299,7 @@ static int v1_commit_dquot(struct dquot *dquot, int flags) + else + cmd = Q_V1_SETQUOTA; + v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb); +- if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id, ++ if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, h->qh_dir, dquot->dq_id, + (void *)&kdqblk) < 0) + return -1; + } +diff --git a/quotaio_v2.c b/quotaio_v2.c +index 56a549f..b0fe7bf 100644 +--- a/quotaio_v2.c ++++ b/quotaio_v2.c +@@ -275,7 +275,7 @@ static int v2_init_io(struct quota_handle *h) + else { + struct v2_kern_dqinfo kdqinfo; + +- if (quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) { ++ if (do_quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) { + /* Temporary check just before fix gets to kernel */ + if (errno == EPERM) /* Don't have permission to get information? */ + return 0; +@@ -403,8 +403,8 @@ static int v2_write_info(struct quota_handle *h) + kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks; + kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk; + kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry; +- if (quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0 || +- quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) ++ if (do_quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0 || ++ do_quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) + return -1; + } + } +@@ -441,7 +441,7 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) + else { + struct v2_kern_dqblk kdqblk; + +- if (quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) { ++ if (do_quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { + free(dquot); + return NULL; + } +@@ -485,8 +485,8 @@ static int v2_commit_dquot(struct dquot *dquot, int flags) + else + cmd = Q_V2_SETQUOTA; + v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb); +- if (quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, +- dquot->dq_id, (void *)&kdqblk) < 0) ++ if (do_quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, ++ dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) + return -1; + } + return 0; +diff --git a/quotaio_xfs.c b/quotaio_xfs.c +index 5abb2c2..0bf6f34 100644 +--- a/quotaio_xfs.c ++++ b/quotaio_xfs.c +@@ -128,7 +128,7 @@ static int xfs_init_io(struct quota_handle *h) + + qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); + memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); +- if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&info) < 0) ++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&info) < 0) + return -1; + h->qh_info.dqi_bgrace = info.qs_btimelimit; + h->qh_info.dqi_igrace = info.qs_itimelimit; +@@ -153,7 +153,7 @@ static int xfs_write_info(struct quota_handle *h) + xdqblk.d_itimer = h->qh_info.dqi_igrace; + xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; + qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); +- if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&xdqblk) < 0) ++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&xdqblk) < 0) + return -1; + return 0; + } +@@ -174,7 +174,8 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) + return dquot; + + qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); +- if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) { ++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, ++ id, (void *)&xdqblk) < 0) { + ; + } + else { +@@ -219,7 +220,7 @@ static int xfs_commit_dquot(struct dquot *dquot, int flags) + } + + qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); +- if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) ++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, id, (void *)&xdqblk) < 0) + return -1; + return 0; + } +@@ -234,7 +235,9 @@ static int xfs_get_dquot(struct dquot *dq) + int ret; + + memset(&d, 0, sizeof(d)); +- ret = quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_id, (void *)&d); ++ ret = do_quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_h->qh_dir, ++ dq->dq_id, (void *)&d); ++ + if (ret < 0) { + if (errno == ENOENT) + return 0; +@@ -254,8 +257,8 @@ static int xfs_kernel_scan_dquots(struct quota_handle *h, + + dquot->dq_h = h; + while (1) { +- ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), +- h->qh_quotadev, id, (void *)&xdqblk); ++ ret = do_quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), ++ h->qh_quotadev, h->qh_dir, id, (void *)&xdqblk); + if (ret < 0) + break; + +@@ -286,8 +289,8 @@ static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct + int ret; + struct xfs_kern_dqblk xdqblk; + +- ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0, +- (void *)&xdqblk); ++ ret = do_quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, ++ h->qh_dir, 0, (void *)&xdqblk); + if (ret < 0 && (errno == ENOSYS || errno == EINVAL)) { + if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h)) + return 0; +diff --git a/quotaon.c b/quotaon.c +index 125b934..351c851 100644 +--- a/quotaon.c ++++ b/quotaon.c +@@ -152,13 +152,13 @@ static int quotarsquashonoff(const char *quotadev, int type, int flags) + + info.dqi_flags = V1_DQF_RSQUASH; + info.dqi_valid = IIF_FLAGS; +- ret = quotactl(qcmd, quotadev, 0, (void *)&info); ++ ret = do_quotactl(qcmd, quotadev, NULL, 0, (void *)&info); + } + else { + int mode = (flags & STATEFLAG_OFF) ? 0 : 1; + int qcmd = QCMD(Q_V1_RSQUASH, type); + +- ret = quotactl(qcmd, quotadev, 0, (void *)&mode); ++ ret = do_quotactl(qcmd, quotadev, NULL, 0, (void *)&mode); + } + if (ret < 0) { + errstr(_("set root_squash on %s: %s\n"), quotadev, strerror(errno)); +@@ -184,7 +184,7 @@ static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafil + qcmd = QCMD(Q_QUOTAOFF, type); + else + qcmd = QCMD(Q_6_5_QUOTAOFF, type); +- if (quotactl(qcmd, quotadev, 0, NULL) < 0) { ++ if (do_quotactl(qcmd, quotadev, quotadir, 0, NULL) < 0) { + errstr(_("quotactl on %s [%s]: %s\n"), quotadev, quotadir, strerror(errno)); + return 1; + } +@@ -199,7 +199,7 @@ static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafil + qcmd = QCMD(Q_6_5_QUOTAON, type); + kqf = 0; + } +- if (quotactl(qcmd, quotadev, kqf, (void *)quotafile) < 0) { ++ if (do_quotactl(qcmd, quotadev, quotadir, kqf, (void *)quotafile) < 0) { + if (errno == ENOENT) + errstr(_("cannot find %s on %s [%s]\n"), quotafile, quotadev, quotadir); + else +diff --git a/quotaon_xfs.c b/quotaon_xfs.c +index d137240..dda3023 100644 +--- a/quotaon_xfs.c ++++ b/quotaon_xfs.c +@@ -32,7 +32,7 @@ static int xfs_state_check(int qcmd, int type, int flags, const char *dev, int r + if (flags & STATEFLAG_ALL) + return 0; /* noop */ + +- if (quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info) < 0) { ++ if (do_quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, NULL, 0, (void *)&info) < 0) { + errstr(_("quotactl() on %s: %s\n"), dev, strerror(errno)); + return -1; + } +@@ -156,7 +156,7 @@ static int xfs_onoff(const char *dev, int type, int flags, int roothack, int xop + if (check != 1) + return (check < 0); + +- if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { ++ if (do_quotactl(QCMD(qcmd, type), dev, NULL, 0, (void *)&xopts) < 0) { + errstr(_("quotactl on %s: %s\n"), dev, strerror(errno)); + return 1; + } +@@ -176,7 +176,7 @@ static int xfs_delete(const char *dev, int type, int flags, int roothack, int xo + if (check != 1) + return (check < 0); + +- if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { ++ if (do_quotactl(QCMD(qcmd, type), dev, NULL, 0, (void *)&xopts) < 0) { + errstr(_("Failed to delete quota: %s\n"), + strerror(errno)); + return 1; +@@ -208,7 +208,8 @@ int xfs_newstate(struct mount_entry *mnt, int type, char *xarg, int flags) + struct xfs_mem_dqinfo info; + u_int16_t sbflags = 0; + +- if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, 0, (void *)&info)) ++ if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, ++ mnt->me_dir, 0, (void *)&info)) + sbflags = (info.qs_flags & 0xff00) >> 8; + + if ((type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) && +diff --git a/quotasync.c b/quotasync.c +index 80f7e9e..cad2a20 100644 +--- a/quotasync.c ++++ b/quotasync.c +@@ -100,7 +100,7 @@ static int sync_one(int type, char *dev) + { + int qcmd = QCMD(Q_SYNC, type); + +- return quotactl(qcmd, dev, 0, NULL); ++ return do_quotactl(qcmd, dev, NULL, 0, NULL); + } + + static int syncquotas(int type) +diff --git a/quotasys.c b/quotasys.c +index 9af9932..903816b 100644 +--- a/quotasys.c ++++ b/quotasys.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "pot.h" + #include "bylabel.h" +@@ -670,6 +671,36 @@ const char *str2number(const char *string, qsize_t *inodes) + return NULL; + } + ++/* ++ * 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; +diff --git a/quotasys.h b/quotasys.h +index 841251e..b166ad2 100644 +--- a/quotasys.h ++++ b/quotasys.h +@@ -206,6 +206,9 @@ void end_mounts_scan(void); + /* Parse kernel version and return 1 if ext4 supports quota feature */ + int ext4_supports_quota_feature(void); + ++/* Wrapper around quota syscalls, either call quotactl or quotactl_fd */ ++int do_quotactl(int cmd, const char *dev, const char *mnt, int id, caddr_t addr); ++ + /* Quota output formats */ + #define QOF_ERROR -1 + #define QOF_DEFAULT 0 +-- +2.45.2 + diff --git a/quota-4.10-Enable-support-for-tmpfs-quotas.patch b/quota-4.10-Enable-support-for-tmpfs-quotas.patch new file mode 100644 index 0000000..023dc68 --- /dev/null +++ b/quota-4.10-Enable-support-for-tmpfs-quotas.patch @@ -0,0 +1,336 @@ +From 00534e79856c8ce385ea1fdcdc2dcb32b1ed5de6 Mon Sep 17 00:00:00 2001 +From: Carlos Maiolino +Date: Fri, 26 Jan 2024 19:02:11 +0100 +Subject: [PATCH 3/3] Enable support for tmpfs quotas + +To achieve so, add a new function quotactl_handle() to the quotaio subsystem, +this will call do_quotactl() with or without a valid quotadev, according to the +filesystem type. + +Signed-off-by: Carlos Maiolino +Signed-off-by: Lukas Czerner +Signed-off-by: Jan Kara +Signed-off-by: Pavel Reichl +--- + mntopt.h | 1 + + quotaio.c | 19 +++++++++++++++++-- + quotaio.h | 2 ++ + quotaio_generic.c | 11 +++++------ + quotaio_meta.c | 3 +-- + quotaio_v1.c | 11 +++++------ + quotaio_v2.c | 11 +++++------ + quotaio_xfs.c | 4 ++-- + quotasys.c | 27 +++++++++++++++++++++------ + 9 files changed, 59 insertions(+), 30 deletions(-) + +diff --git a/mntopt.h b/mntopt.h +index 0f3b0c5..9b71990 100644 +--- a/mntopt.h ++++ b/mntopt.h +@@ -22,6 +22,7 @@ + #define MNTTYPE_MPFS "mpfs" /* EMC Celerra MPFS filesystem */ + #define MNTTYPE_OCFS2 "ocfs2" /* Oracle Cluster filesystem */ + #define MNTTYPE_GFS2 "gfs2" /* Red Hat Global filesystem 2 */ ++#define MNTTYPE_TMPFS "tmpfs" /* tmpfs filesystem */ + + #ifndef MNTTYPE_NFS + #define MNTTYPE_NFS "nfs" /* Network file system. */ +diff --git a/quotaio.c b/quotaio.c +index 9bebb5e..ae40d2a 100644 +--- a/quotaio.c ++++ b/quotaio.c +@@ -34,6 +34,22 @@ struct disk_dqheader { + u_int32_t dqh_version; + } __attribute__ ((packed)); + ++int quotactl_handle(int cmd, struct quota_handle *h, int id, void *addr) ++{ ++ int err = -EINVAL; ++ ++ if (!h) ++ return err; ++ ++ if (!strcmp(h->qh_fstype, MNTTYPE_TMPFS)) ++ err = do_quotactl(QCMD(cmd, h->qh_type), NULL, h->qh_dir, ++ id, addr); ++ else ++ err = do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, ++ h->qh_dir, id, addr); ++ ++ return err; ++} + /* + * Detect quota format and initialize quota IO + */ +@@ -140,8 +156,7 @@ struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int fla + if (QIO_ENABLED(h)) { /* Kernel uses same file? */ + unsigned int cmd = + (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC; +- if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, +- h->qh_dir, 0, NULL) < 0) { ++ if (quotactl_handle(cmd, h, 0, NULL) < 0) { + die(4, _("Cannot sync quotas on device %s: %s\n"), + h->qh_quotadev, strerror(errno)); + } +diff --git a/quotaio.h b/quotaio.h +index 2c373b2..91689d9 100644 +--- a/quotaio.h ++++ b/quotaio.h +@@ -182,4 +182,6 @@ struct dquot *get_empty_dquot(void); + /* Check whether values in current dquot can be stored on disk */ + int check_dquot_range(struct dquot *dquot); + ++/* Uses do_quotactl() to call quotactl() or quotactl_fd() */ ++int quotactl_handle(int cmd, struct quota_handle *h, int id, void *addr); + #endif /* GUARD_QUOTAIO_H */ +diff --git a/quotaio_generic.c b/quotaio_generic.c +index 3c95872..cf03b59 100644 +--- a/quotaio_generic.c ++++ b/quotaio_generic.c +@@ -50,7 +50,7 @@ int vfs_get_info(struct quota_handle *h) + { + struct if_dqinfo kinfo; + +- if (do_quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { ++ if (quotactl_handle(Q_GETINFO, h, 0, (void *)&kinfo) < 0) { + errstr(_("Cannot get info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -68,7 +68,7 @@ int vfs_set_info(struct quota_handle *h, int flags) + kinfo.dqi_igrace = h->qh_info.dqi_igrace; + kinfo.dqi_valid = flags; + +- if (do_quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { ++ if (quotactl_handle(Q_SETINFO, h, 0, (void *)&kinfo) < 0) { + errstr(_("Cannot set info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -80,7 +80,7 @@ int vfs_get_dquot(struct dquot *dquot) + { + struct if_dqblk kdqblk; + +- if (do_quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { ++ if (quotactl_handle(Q_GETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) { + errstr(_("Cannot get quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -95,7 +95,7 @@ int vfs_set_dquot(struct dquot *dquot, int flags) + + generic_util2kerndqblk(&kdqblk, &dquot->dq_dqb); + kdqblk.dqb_valid = flags; +- if (do_quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { ++ if (quotactl_handle(Q_SETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) { + errstr(_("Cannot set quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); + return -1; + } +@@ -188,8 +188,7 @@ int vfs_scan_dquots(struct quota_handle *h, + + dquot->dq_h = h; + while (1) { +- ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), +- h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk); ++ ret = quotactl_handle(Q_GETNEXTQUOTA, h, id, (void *)&kdqblk); + if (ret < 0) + break; + +diff --git a/quotaio_meta.c b/quotaio_meta.c +index 51ebbcf..99fdaf8 100644 +--- a/quotaio_meta.c ++++ b/quotaio_meta.c +@@ -59,8 +59,7 @@ static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct + struct if_nextdqblk kdqblk; + int ret; + +- ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, +- h->qh_dir, 0, (void *)&kdqblk); ++ ret = quotactl_handle(Q_GETNEXTQUOTA, h, 0, (void *)&kdqblk); + /* + * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not + * supported +diff --git a/quotaio_v1.c b/quotaio_v1.c +index 187a5a5..0b88d0c 100644 +--- a/quotaio_v1.c ++++ b/quotaio_v1.c +@@ -118,7 +118,7 @@ static int v1_init_io(struct quota_handle *h) + else { + struct v1_kern_dqblk kdqblk; + +- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) { ++ if (quotactl_handle(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0) { + if (errno == EPERM) { /* We have no permission to get this information? */ + h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */ + } +@@ -193,11 +193,11 @@ static int v1_write_info(struct quota_handle *h) + else { + struct v1_kern_dqblk kdqblk; + +- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) ++ if (quotactl_handle(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0) + return -1; + kdqblk.dqb_btime = h->qh_info.dqi_bgrace; + kdqblk.dqb_itime = h->qh_info.dqi_igrace; +- if (do_quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) ++ if (quotactl_handle(Q_V1_SETQUOTA, h, 0, (void *)&kdqblk) < 0) + return -1; + } + } +@@ -237,7 +237,7 @@ static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id) + else { + struct v1_kern_dqblk kdqblk; + +- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { ++ if (quotactl_handle(Q_V1_GETQUOTA, h, id, (void *)&kdqblk) < 0) { + free(dquot); + return NULL; + } +@@ -299,8 +299,7 @@ static int v1_commit_dquot(struct dquot *dquot, int flags) + else + cmd = Q_V1_SETQUOTA; + v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb); +- if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, h->qh_dir, dquot->dq_id, +- (void *)&kdqblk) < 0) ++ if (quotactl_handle(cmd, h, dquot->dq_id, (void *)&kdqblk) < 0) + return -1; + } + } +diff --git a/quotaio_v2.c b/quotaio_v2.c +index b0fe7bf..9927cad 100644 +--- a/quotaio_v2.c ++++ b/quotaio_v2.c +@@ -275,7 +275,7 @@ static int v2_init_io(struct quota_handle *h) + else { + struct v2_kern_dqinfo kdqinfo; + +- if (do_quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) { ++ if (quotactl_handle(Q_V2_GETINFO, h, 0, (void *)&kdqinfo) < 0) { + /* Temporary check just before fix gets to kernel */ + if (errno == EPERM) /* Don't have permission to get information? */ + return 0; +@@ -403,8 +403,8 @@ static int v2_write_info(struct quota_handle *h) + kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks; + kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk; + kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry; +- if (do_quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0 || +- do_quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) ++ if (quotactl_handle(Q_V2_SETGRACE, h, 0, (void *)&kdqinfo) < 0 || ++ quotactl_handle(Q_V2_SETFLAGS, h, 0, (void *)&kdqinfo) < 0) + return -1; + } + } +@@ -441,7 +441,7 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) + else { + struct v2_kern_dqblk kdqblk; + +- if (do_quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { ++ if (quotactl_handle(Q_V2_GETQUOTA, h, id, (void *)&kdqblk) < 0) { + free(dquot); + return NULL; + } +@@ -485,8 +485,7 @@ static int v2_commit_dquot(struct dquot *dquot, int flags) + else + cmd = Q_V2_SETQUOTA; + v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb); +- if (do_quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, +- dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) ++ if (quotactl_handle(cmd, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) + return -1; + } + return 0; +diff --git a/quotaio_xfs.c b/quotaio_xfs.c +index 0bf6f34..d742f9c 100644 +--- a/quotaio_xfs.c ++++ b/quotaio_xfs.c +@@ -128,7 +128,7 @@ static int xfs_init_io(struct quota_handle *h) + + qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); + memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); +- if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&info) < 0) ++ if (quotactl_handle(qcmd, h, 0, (void *)&info) < 0) + return -1; + h->qh_info.dqi_bgrace = info.qs_btimelimit; + h->qh_info.dqi_igrace = info.qs_itimelimit; +@@ -153,7 +153,7 @@ static int xfs_write_info(struct quota_handle *h) + xdqblk.d_itimer = h->qh_info.dqi_igrace; + xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; + qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); +- if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&xdqblk) < 0) ++ if (quotactl_handle(qcmd, h, 0, (void *)&xdqblk) < 0) + return -1; + return 0; + } +diff --git a/quotasys.c b/quotasys.c +index 903816b..afe5f6d 100644 +--- a/quotasys.c ++++ b/quotasys.c +@@ -70,7 +70,15 @@ int nfs_fstype(char *type) + */ + int meta_qf_fstype(char *type) + { +- return !strcmp(type, MNTTYPE_OCFS2); ++ return !strcmp(type, MNTTYPE_OCFS2) || !strcmp(type, MNTTYPE_TMPFS); ++} ++ ++/* ++ * Check whether the filesystem is not using block device as a backing ++ */ ++int nodev_fstype(char *type) ++{ ++ return !strcmp(type, MNTTYPE_TMPFS) || nfs_fstype(type); + } + + /* +@@ -752,6 +760,7 @@ static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int fl + + if (!do_quotactl(QCMD(Q_GETFMT, type), dev, mnt->mnt_dir, 0, (void *)&fmt)) + return QF_META; ++ + return QF_ERROR; + } + +@@ -816,8 +825,13 @@ static int hasquota(const char *dev, struct mntent *mnt, int type, int flags) + !strcmp(mnt->mnt_type, MNTTYPE_XFS) || + !strcmp(mnt->mnt_type, MNTTYPE_EXFS)) + return hasxfsquota(dev, mnt, type, flags); ++ + if (!strcmp(mnt->mnt_type, MNTTYPE_OCFS2)) + return hasvfsmetaquota(dev, mnt, type, flags); ++ ++ /* tmpfs has no device, pass null here so quotactl_fd() is called */ ++ if (!strcmp(mnt->mnt_type, MNTTYPE_TMPFS)) ++ return hasvfsmetaquota(NULL, mnt, type, flags); + /* + * For ext4 we check whether it has quota in system files and if not, + * we fall back on checking standard quotas. Furthermore we cannot use +@@ -1384,7 +1398,7 @@ alloc: + continue; + } + +- if (!nfs_fstype(mnt->mnt_type)) { ++ if (!nodev_fstype(mnt->mnt_type)) { + if (stat(devname, &st) < 0) { /* Can't stat mounted device? */ + errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno)); + free((char *)devname); +@@ -1398,15 +1412,16 @@ alloc: + dev = st.st_rdev; + for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); + } +- /* Cope with network filesystems or new mountpoint */ +- if (nfs_fstype(mnt->mnt_type) || i == mnt_entries_cnt) { ++ ++ /* Cope with filesystems without a block device or new mountpoint */ ++ if (nodev_fstype(mnt->mnt_type) || i == mnt_entries_cnt) { + if (stat(mnt->mnt_dir, &st) < 0) { /* Can't stat mountpoint? We have better ignore it... */ + errstr(_("Cannot stat() mountpoint %s: %s\n"), mnt->mnt_dir, strerror(errno)); + free((char *)devname); + continue; + } +- if (nfs_fstype(mnt->mnt_type)) { +- /* For network filesystems we must get device from root */ ++ if (nodev_fstype(mnt->mnt_type)) { ++ /* For filesystems without block device we must get device from root */ + dev = st.st_dev; + if (!(flags & MS_NFS_ALL)) { + for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); +-- +2.45.2 + diff --git a/quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch b/quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch new file mode 100644 index 0000000..39c67df --- /dev/null +++ b/quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch @@ -0,0 +1,52 @@ +From c18e5a1b1e51c0382f5d1431120fe65f7e9c982c Mon Sep 17 00:00:00 2001 +From: Carlos Maiolino +Date: Fri, 26 Jan 2024 19:02:09 +0100 +Subject: [PATCH 1/3] Rename searched_dir->sd_dir to sd_isdir + +The field holds information if we are searching a directory mountpoint or a +device, rename the field to something more meaningful. + +We could switch it to bool, but it seems pointless to include a whole header +just for it, so keep the int type. + +Signed-off-by: Carlos Maiolino +Signed-off-by: Jan Kara +Signed-off-by: Pavel Reichl +--- + quotasys.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/quotasys.c b/quotasys.c +index 3f50e32..9af9932 100644 +--- a/quotasys.c ++++ b/quotasys.c +@@ -1223,7 +1223,7 @@ int kern_quota_on(struct mount_entry *mnt, int type, int fmt) + */ + + struct searched_dir { +- int sd_dir; /* Is searched dir mountpoint or in fact device? */ ++ int sd_isdir; /* Is searched dir mountpoint or in fact device? */ + dev_t sd_dev; /* Device mountpoint lies on */ + ino_t sd_ino; /* Inode number of mountpoint */ + const char *sd_name; /* Name of given dir/device */ +@@ -1454,7 +1454,7 @@ static int process_dirs(int dcnt, char **dirs, int flags) + errstr(_("Cannot stat() given mountpoint %s: %s\nSkipping...\n"), dirs[i], strerror(errno)); + continue; + } +- check_dirs[check_dirs_cnt].sd_dir = S_ISDIR(st.st_mode); ++ check_dirs[check_dirs_cnt].sd_isdir = S_ISDIR(st.st_mode); + if (S_ISDIR(st.st_mode)) { + const char *realmnt = dirs[i]; + +@@ -1538,7 +1538,7 @@ restart: + return 0; + sd = check_dirs + act_checked; + for (i = 0; i < mnt_entries_cnt; i++) { +- if (sd->sd_dir) { ++ if (sd->sd_isdir) { + if (sd->sd_dev == mnt_entries[i].me_dev && sd->sd_ino == mnt_entries[i].me_ino) + break; + } +-- +2.45.2 + diff --git a/quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch b/quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch new file mode 100644 index 0000000..6adbfc1 --- /dev/null +++ b/quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch @@ -0,0 +1,36 @@ +From dba8c5ca95516b9550fc44b2a476ceca60ee4b38 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Tue, 7 May 2024 12:55:30 +0200 +Subject: [PATCH] quotaio_xfs: Fix error handling in xfs_read_dquot() + +When quotactl(2) fails, xfs_read_dquot() will happily return zero-filled +structure. This is fine when the user structure does not exist but it is +wrong when there's other error (like EACCESS). Fix the error handling. + +Signed-off-by: Jan Kara +Signed-off-by: Pavel Reichl +--- + quotaio_xfs.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/quotaio_xfs.c b/quotaio_xfs.c +index d742f9c..040e7d8 100644 +--- a/quotaio_xfs.c ++++ b/quotaio_xfs.c +@@ -176,7 +176,12 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) + qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); + if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, + id, (void *)&xdqblk) < 0) { +- ; ++ /* ++ * ENOENT means the structure just does not exist - return all ++ * zeros. Otherwise return failure. ++ */ ++ if (errno != ENOENT) ++ return NULL; + } + else { + xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk); +-- +2.45.2 + diff --git a/quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch b/quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch new file mode 100644 index 0000000..13e6bed --- /dev/null +++ b/quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch @@ -0,0 +1,64 @@ +From bd13b74e6d181638023d8a89316417643d9e7fd8 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Tue, 7 May 2024 14:21:45 +0200 +Subject: [PATCH] quotaio_xfs: Fix quota-tools on XFS + +Patches implementing tmpfs quota support, commit 00534e79856c ("Enable +support for tmpfs quotas") in particular, broke quota-tools on XFS +because quotactl(2) syscall got called with wrong arguments. Fix it. + +Signed-off-by: Jan Kara +Signed-off-by: Pavel Reichl +--- + quotaio_xfs.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/quotaio_xfs.c b/quotaio_xfs.c +index 040e7d8..c10534d 100644 +--- a/quotaio_xfs.c ++++ b/quotaio_xfs.c +@@ -124,11 +124,9 @@ static inline int xfs_util2kerndqblk(struct xfs_kern_dqblk *k, struct util_dqblk + static int xfs_init_io(struct quota_handle *h) + { + struct xfs_mem_dqinfo info; +- int qcmd; + +- qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); + memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); +- if (quotactl_handle(qcmd, h, 0, (void *)&info) < 0) ++ if (quotactl_handle(Q_XFS_GETQSTAT, h, 0, (void *)&info) < 0) + return -1; + h->qh_info.dqi_bgrace = info.qs_btimelimit; + h->qh_info.dqi_igrace = info.qs_itimelimit; +@@ -142,7 +140,6 @@ static int xfs_init_io(struct quota_handle *h) + static int xfs_write_info(struct quota_handle *h) + { + struct xfs_kern_dqblk xdqblk; +- int qcmd; + + if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h)) + return 0; +@@ -152,8 +149,7 @@ static int xfs_write_info(struct quota_handle *h) + xdqblk.d_btimer = h->qh_info.dqi_bgrace; + xdqblk.d_itimer = h->qh_info.dqi_igrace; + xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; +- qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); +- if (quotactl_handle(qcmd, h, 0, (void *)&xdqblk) < 0) ++ if (quotactl_handle(Q_XFS_SETQLIM, h, 0, (void *)&xdqblk) < 0) + return -1; + return 0; + } +@@ -180,8 +176,9 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) + * ENOENT means the structure just does not exist - return all + * zeros. Otherwise return failure. + */ +- if (errno != ENOENT) ++ if (errno != ENOENT) { + return NULL; ++ } + } + else { + xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk); +-- +2.45.2 + diff --git a/quota-upstream-2944f3c9.patch b/quota-upstream-2944f3c9.patch new file mode 100644 index 0000000..cfa1415 --- /dev/null +++ b/quota-upstream-2944f3c9.patch @@ -0,0 +1,1135 @@ +--- a/quota-4.10-Add-quotactl_fd-support.patch ++++ b/quota-4.10-Add-quotactl_fd-support.patch +@@ -0,0 +1,580 @@ ++From ded570b1fffbeaefbecb6c191f0b5168f3b8ad0d Mon Sep 17 00:00:00 2001 ++From: Carlos Maiolino ++Date: Fri, 26 Jan 2024 19:02:10 +0100 ++Subject: [PATCH 2/3] 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 ++Signed-off-by: Lukas Czerner ++Signed-off-by: Jan Kara ++Signed-off-by: Pavel Reichl ++--- ++ Makefile.am | 1 + ++ quotacheck.c | 12 +++++------ ++ quotaio.c | 4 ++-- ++ quotaio_generic.c | 12 +++++------ ++ quotaio_meta.c | 4 ++-- ++ quotaio_v1.c | 10 ++++----- ++ quotaio_v2.c | 12 +++++------ ++ quotaio_xfs.c | 21 ++++++++++-------- ++ quotaon.c | 8 +++---- ++ quotaon_xfs.c | 9 ++++---- ++ quotasync.c | 2 +- ++ quotasys.c | 55 ++++++++++++++++++++++++++++++++++++----------- ++ quotasys.h | 3 +++ ++ 13 files changed, 96 insertions(+), 57 deletions(-) ++ ++diff --git a/Makefile.am b/Makefile.am ++index 372eafb..13a0f06 100644 ++--- a/Makefile.am +++++ b/Makefile.am ++@@ -207,6 +207,7 @@ quotastats_SOURCES = \ ++ pot.h ++ ++ quotastats_LDADD = \ +++ libquota.a \ ++ $(INTLLIBS) ++ ++ xqmstats_SOURCES = \ ++diff --git a/quotacheck.c b/quotacheck.c ++index bd62d9a..e2c3bbd 100644 ++--- a/quotacheck.c +++++ b/quotacheck.c ++@@ -648,8 +648,8 @@ Please turn quotas off or use -f to force checking.\n"), ++ type2name(type), mnt->me_dir); ++ } ++ /* At least sync quotas so damage will be smaller */ ++- if (quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type), ++- mnt->me_devname, 0, NULL) < 0) +++ if (do_quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type), +++ mnt->me_devname, mnt->me_dir, 0, NULL) < 0) ++ die(4, _("Error while syncing quotas on %s: %s\n"), mnt->me_devname, strerror(errno)); ++ } ++ ++@@ -848,8 +848,8 @@ static int dump_to_file(struct mount_entry *mnt, int type) ++ if (get_qf_name(mnt, type, cfmt, NF_FORMAT, &filename) < 0) ++ errstr(_("Cannot find checked quota file for %ss on %s!\n"), _(type2name(type)), mnt->me_devname); ++ else { ++- if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type), ++- mnt->me_devname, 0, NULL) < 0) +++ if (do_quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type), +++ mnt->me_devname, mnt->me_dir, 0, NULL) < 0) ++ errstr(_("Cannot turn %s quotas off on %s: %s\nKernel won't know about changes quotacheck did.\n"), ++ _(type2name(type)), mnt->me_devname, strerror(errno)); ++ else { ++@@ -859,9 +859,9 @@ static int dump_to_file(struct mount_entry *mnt, int type) ++ rename_files(mnt, type); ++ ++ if (kernel_iface == IFACE_GENERIC) ++- ret = quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, util2kernfmt(cfmt), filename); +++ ret = do_quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, mnt->me_dir, util2kernfmt(cfmt), filename); ++ else ++- ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, 0, filename); +++ ret = do_quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, mnt->me_dir, 0, filename); ++ if (ret < 0) ++ errstr(_("Cannot turn %s quotas on on %s: %s\nKernel won't know about changes quotacheck did.\n"), ++ _(type2name(type)), mnt->me_devname, strerror(errno)); ++diff --git a/quotaio.c b/quotaio.c ++index 94ae458..9bebb5e 100644 ++--- a/quotaio.c +++++ b/quotaio.c ++@@ -140,8 +140,8 @@ struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int fla ++ if (QIO_ENABLED(h)) { /* Kernel uses same file? */ ++ unsigned int cmd = ++ (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC; ++- if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, ++- 0, NULL) < 0) { +++ if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, +++ h->qh_dir, 0, NULL) < 0) { ++ die(4, _("Cannot sync quotas on device %s: %s\n"), ++ h->qh_quotadev, strerror(errno)); ++ } ++diff --git a/quotaio_generic.c b/quotaio_generic.c ++index 5b23955..3c95872 100644 ++--- a/quotaio_generic.c +++++ b/quotaio_generic.c ++@@ -50,7 +50,7 @@ int vfs_get_info(struct quota_handle *h) ++ { ++ struct if_dqinfo kinfo; ++ ++- if (quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kinfo) < 0) { +++ if (do_quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { ++ errstr(_("Cannot get info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -68,7 +68,7 @@ int vfs_set_info(struct quota_handle *h, int flags) ++ kinfo.dqi_igrace = h->qh_info.dqi_igrace; ++ kinfo.dqi_valid = flags; ++ ++- if (quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kinfo) < 0) { +++ if (do_quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { ++ errstr(_("Cannot set info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -80,7 +80,7 @@ int vfs_get_dquot(struct dquot *dquot) ++ { ++ struct if_dqblk kdqblk; ++ ++- if (quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_id, (void *)&kdqblk) < 0) { +++ if (do_quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { ++ errstr(_("Cannot get quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -95,7 +95,7 @@ int vfs_set_dquot(struct dquot *dquot, int flags) ++ ++ generic_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++ kdqblk.dqb_valid = flags; ++- if (quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_id, (void *)&kdqblk) < 0) { +++ if (do_quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { ++ errstr(_("Cannot set quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -188,8 +188,8 @@ int vfs_scan_dquots(struct quota_handle *h, ++ ++ dquot->dq_h = h; ++ while (1) { ++- ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), ++- h->qh_quotadev, id, (void *)&kdqblk); +++ ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), +++ h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk); ++ if (ret < 0) ++ break; ++ ++diff --git a/quotaio_meta.c b/quotaio_meta.c ++index ad6ff7a..51ebbcf 100644 ++--- a/quotaio_meta.c +++++ b/quotaio_meta.c ++@@ -59,8 +59,8 @@ static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct ++ struct if_nextdqblk kdqblk; ++ int ret; ++ ++- ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0, ++- (void *)&kdqblk); +++ ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, +++ h->qh_dir, 0, (void *)&kdqblk); ++ /* ++ * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not ++ * supported ++diff --git a/quotaio_v1.c b/quotaio_v1.c ++index 6a6dc78..187a5a5 100644 ++--- a/quotaio_v1.c +++++ b/quotaio_v1.c ++@@ -118,7 +118,7 @@ static int v1_init_io(struct quota_handle *h) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) { +++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) { ++ if (errno == EPERM) { /* We have no permission to get this information? */ ++ h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */ ++ } ++@@ -193,11 +193,11 @@ static int v1_write_info(struct quota_handle *h) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) +++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) ++ return -1; ++ kdqblk.dqb_btime = h->qh_info.dqi_bgrace; ++ kdqblk.dqb_itime = h->qh_info.dqi_igrace; ++- if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) +++ if (do_quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) ++ return -1; ++ } ++ } ++@@ -237,7 +237,7 @@ static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) { +++ if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { ++ free(dquot); ++ return NULL; ++ } ++@@ -299,7 +299,7 @@ static int v1_commit_dquot(struct dquot *dquot, int flags) ++ else ++ cmd = Q_V1_SETQUOTA; ++ v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++- if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id, +++ if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, h->qh_dir, dquot->dq_id, ++ (void *)&kdqblk) < 0) ++ return -1; ++ } ++diff --git a/quotaio_v2.c b/quotaio_v2.c ++index 56a549f..b0fe7bf 100644 ++--- a/quotaio_v2.c +++++ b/quotaio_v2.c ++@@ -275,7 +275,7 @@ static int v2_init_io(struct quota_handle *h) ++ else { ++ struct v2_kern_dqinfo kdqinfo; ++ ++- if (quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) { +++ if (do_quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) { ++ /* Temporary check just before fix gets to kernel */ ++ if (errno == EPERM) /* Don't have permission to get information? */ ++ return 0; ++@@ -403,8 +403,8 @@ static int v2_write_info(struct quota_handle *h) ++ kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks; ++ kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk; ++ kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry; ++- if (quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0 || ++- quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) +++ if (do_quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0 || +++ do_quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) ++ return -1; ++ } ++ } ++@@ -441,7 +441,7 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) ++ else { ++ struct v2_kern_dqblk kdqblk; ++ ++- if (quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) { +++ if (do_quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { ++ free(dquot); ++ return NULL; ++ } ++@@ -485,8 +485,8 @@ static int v2_commit_dquot(struct dquot *dquot, int flags) ++ else ++ cmd = Q_V2_SETQUOTA; ++ v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++- if (quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, ++- dquot->dq_id, (void *)&kdqblk) < 0) +++ if (do_quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, +++ dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) ++ return -1; ++ } ++ return 0; ++diff --git a/quotaio_xfs.c b/quotaio_xfs.c ++index 5abb2c2..0bf6f34 100644 ++--- a/quotaio_xfs.c +++++ b/quotaio_xfs.c ++@@ -128,7 +128,7 @@ static int xfs_init_io(struct quota_handle *h) ++ ++ qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); ++ memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); ++- if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&info) < 0) +++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&info) < 0) ++ return -1; ++ h->qh_info.dqi_bgrace = info.qs_btimelimit; ++ h->qh_info.dqi_igrace = info.qs_itimelimit; ++@@ -153,7 +153,7 @@ static int xfs_write_info(struct quota_handle *h) ++ xdqblk.d_itimer = h->qh_info.dqi_igrace; ++ xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; ++ qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); ++- if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&xdqblk) < 0) +++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&xdqblk) < 0) ++ return -1; ++ return 0; ++ } ++@@ -174,7 +174,8 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) ++ return dquot; ++ ++ qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); ++- if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) { +++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, +++ id, (void *)&xdqblk) < 0) { ++ ; ++ } ++ else { ++@@ -219,7 +220,7 @@ static int xfs_commit_dquot(struct dquot *dquot, int flags) ++ } ++ ++ qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); ++- if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) +++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, id, (void *)&xdqblk) < 0) ++ return -1; ++ return 0; ++ } ++@@ -234,7 +235,9 @@ static int xfs_get_dquot(struct dquot *dq) ++ int ret; ++ ++ memset(&d, 0, sizeof(d)); ++- ret = quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_id, (void *)&d); +++ ret = do_quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_h->qh_dir, +++ dq->dq_id, (void *)&d); +++ ++ if (ret < 0) { ++ if (errno == ENOENT) ++ return 0; ++@@ -254,8 +257,8 @@ static int xfs_kernel_scan_dquots(struct quota_handle *h, ++ ++ dquot->dq_h = h; ++ while (1) { ++- ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), ++- h->qh_quotadev, id, (void *)&xdqblk); +++ ret = do_quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), +++ h->qh_quotadev, h->qh_dir, id, (void *)&xdqblk); ++ if (ret < 0) ++ break; ++ ++@@ -286,8 +289,8 @@ static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct ++ int ret; ++ struct xfs_kern_dqblk xdqblk; ++ ++- ret = quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0, ++- (void *)&xdqblk); +++ ret = do_quotactl(QCMD(Q_XGETNEXTQUOTA, h->qh_type), h->qh_quotadev, +++ h->qh_dir, 0, (void *)&xdqblk); ++ if (ret < 0 && (errno == ENOSYS || errno == EINVAL)) { ++ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h)) ++ return 0; ++diff --git a/quotaon.c b/quotaon.c ++index 125b934..351c851 100644 ++--- a/quotaon.c +++++ b/quotaon.c ++@@ -152,13 +152,13 @@ static int quotarsquashonoff(const char *quotadev, int type, int flags) ++ ++ info.dqi_flags = V1_DQF_RSQUASH; ++ info.dqi_valid = IIF_FLAGS; ++- ret = quotactl(qcmd, quotadev, 0, (void *)&info); +++ ret = do_quotactl(qcmd, quotadev, NULL, 0, (void *)&info); ++ } ++ else { ++ int mode = (flags & STATEFLAG_OFF) ? 0 : 1; ++ int qcmd = QCMD(Q_V1_RSQUASH, type); ++ ++- ret = quotactl(qcmd, quotadev, 0, (void *)&mode); +++ ret = do_quotactl(qcmd, quotadev, NULL, 0, (void *)&mode); ++ } ++ if (ret < 0) { ++ errstr(_("set root_squash on %s: %s\n"), quotadev, strerror(errno)); ++@@ -184,7 +184,7 @@ static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafil ++ qcmd = QCMD(Q_QUOTAOFF, type); ++ else ++ qcmd = QCMD(Q_6_5_QUOTAOFF, type); ++- if (quotactl(qcmd, quotadev, 0, NULL) < 0) { +++ if (do_quotactl(qcmd, quotadev, quotadir, 0, NULL) < 0) { ++ errstr(_("quotactl on %s [%s]: %s\n"), quotadev, quotadir, strerror(errno)); ++ return 1; ++ } ++@@ -199,7 +199,7 @@ static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafil ++ qcmd = QCMD(Q_6_5_QUOTAON, type); ++ kqf = 0; ++ } ++- if (quotactl(qcmd, quotadev, kqf, (void *)quotafile) < 0) { +++ if (do_quotactl(qcmd, quotadev, quotadir, kqf, (void *)quotafile) < 0) { ++ if (errno == ENOENT) ++ errstr(_("cannot find %s on %s [%s]\n"), quotafile, quotadev, quotadir); ++ else ++diff --git a/quotaon_xfs.c b/quotaon_xfs.c ++index d137240..dda3023 100644 ++--- a/quotaon_xfs.c +++++ b/quotaon_xfs.c ++@@ -32,7 +32,7 @@ static int xfs_state_check(int qcmd, int type, int flags, const char *dev, int r ++ if (flags & STATEFLAG_ALL) ++ return 0; /* noop */ ++ ++- if (quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info) < 0) { +++ if (do_quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, NULL, 0, (void *)&info) < 0) { ++ errstr(_("quotactl() on %s: %s\n"), dev, strerror(errno)); ++ return -1; ++ } ++@@ -156,7 +156,7 @@ static int xfs_onoff(const char *dev, int type, int flags, int roothack, int xop ++ if (check != 1) ++ return (check < 0); ++ ++- if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { +++ if (do_quotactl(QCMD(qcmd, type), dev, NULL, 0, (void *)&xopts) < 0) { ++ errstr(_("quotactl on %s: %s\n"), dev, strerror(errno)); ++ return 1; ++ } ++@@ -176,7 +176,7 @@ static int xfs_delete(const char *dev, int type, int flags, int roothack, int xo ++ if (check != 1) ++ return (check < 0); ++ ++- if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { +++ if (do_quotactl(QCMD(qcmd, type), dev, NULL, 0, (void *)&xopts) < 0) { ++ errstr(_("Failed to delete quota: %s\n"), ++ strerror(errno)); ++ return 1; ++@@ -208,7 +208,8 @@ int xfs_newstate(struct mount_entry *mnt, int type, char *xarg, int flags) ++ struct xfs_mem_dqinfo info; ++ u_int16_t sbflags = 0; ++ ++- if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, 0, (void *)&info)) +++ if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, +++ mnt->me_dir, 0, (void *)&info)) ++ sbflags = (info.qs_flags & 0xff00) >> 8; ++ ++ if ((type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) && ++diff --git a/quotasync.c b/quotasync.c ++index 80f7e9e..cad2a20 100644 ++--- a/quotasync.c +++++ b/quotasync.c ++@@ -100,7 +100,7 @@ static int sync_one(int type, char *dev) ++ { ++ int qcmd = QCMD(Q_SYNC, type); ++ ++- return quotactl(qcmd, dev, 0, NULL); +++ return do_quotactl(qcmd, dev, NULL, 0, NULL); ++ } ++ ++ static int syncquotas(int type) ++diff --git a/quotasys.c b/quotasys.c ++index 9af9932..903816b 100644 ++--- a/quotasys.c +++++ b/quotasys.c ++@@ -25,6 +25,7 @@ ++ #include ++ #include ++ #include +++#include ++ ++ #include "pot.h" ++ #include "bylabel.h" ++@@ -670,6 +671,36 @@ const char *str2number(const char *string, qsize_t *inodes) ++ return NULL; ++ } ++ +++/* +++ * 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; ++diff --git a/quotasys.h b/quotasys.h ++index 841251e..b166ad2 100644 ++--- a/quotasys.h +++++ b/quotasys.h ++@@ -206,6 +206,9 @@ void end_mounts_scan(void); ++ /* Parse kernel version and return 1 if ext4 supports quota feature */ ++ int ext4_supports_quota_feature(void); ++ +++/* Wrapper around quota syscalls, either call quotactl or quotactl_fd */ +++int do_quotactl(int cmd, const char *dev, const char *mnt, int id, caddr_t addr); +++ ++ /* Quota output formats */ ++ #define QOF_ERROR -1 ++ #define QOF_DEFAULT 0 ++-- ++2.45.2 ++ + +--- a/quota-4.10-Enable-support-for-tmpfs-quotas.patch ++++ b/quota-4.10-Enable-support-for-tmpfs-quotas.patch +@@ -0,0 +1,336 @@ ++From 00534e79856c8ce385ea1fdcdc2dcb32b1ed5de6 Mon Sep 17 00:00:00 2001 ++From: Carlos Maiolino ++Date: Fri, 26 Jan 2024 19:02:11 +0100 ++Subject: [PATCH 3/3] Enable support for tmpfs quotas ++ ++To achieve so, add a new function quotactl_handle() to the quotaio subsystem, ++this will call do_quotactl() with or without a valid quotadev, according to the ++filesystem type. ++ ++Signed-off-by: Carlos Maiolino ++Signed-off-by: Lukas Czerner ++Signed-off-by: Jan Kara ++Signed-off-by: Pavel Reichl ++--- ++ mntopt.h | 1 + ++ quotaio.c | 19 +++++++++++++++++-- ++ quotaio.h | 2 ++ ++ quotaio_generic.c | 11 +++++------ ++ quotaio_meta.c | 3 +-- ++ quotaio_v1.c | 11 +++++------ ++ quotaio_v2.c | 11 +++++------ ++ quotaio_xfs.c | 4 ++-- ++ quotasys.c | 27 +++++++++++++++++++++------ ++ 9 files changed, 59 insertions(+), 30 deletions(-) ++ ++diff --git a/mntopt.h b/mntopt.h ++index 0f3b0c5..9b71990 100644 ++--- a/mntopt.h +++++ b/mntopt.h ++@@ -22,6 +22,7 @@ ++ #define MNTTYPE_MPFS "mpfs" /* EMC Celerra MPFS filesystem */ ++ #define MNTTYPE_OCFS2 "ocfs2" /* Oracle Cluster filesystem */ ++ #define MNTTYPE_GFS2 "gfs2" /* Red Hat Global filesystem 2 */ +++#define MNTTYPE_TMPFS "tmpfs" /* tmpfs filesystem */ ++ ++ #ifndef MNTTYPE_NFS ++ #define MNTTYPE_NFS "nfs" /* Network file system. */ ++diff --git a/quotaio.c b/quotaio.c ++index 9bebb5e..ae40d2a 100644 ++--- a/quotaio.c +++++ b/quotaio.c ++@@ -34,6 +34,22 @@ struct disk_dqheader { ++ u_int32_t dqh_version; ++ } __attribute__ ((packed)); ++ +++int quotactl_handle(int cmd, struct quota_handle *h, int id, void *addr) +++{ +++ int err = -EINVAL; +++ +++ if (!h) +++ return err; +++ +++ if (!strcmp(h->qh_fstype, MNTTYPE_TMPFS)) +++ err = do_quotactl(QCMD(cmd, h->qh_type), NULL, h->qh_dir, +++ id, addr); +++ else +++ err = do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, +++ h->qh_dir, id, addr); +++ +++ return err; +++} ++ /* ++ * Detect quota format and initialize quota IO ++ */ ++@@ -140,8 +156,7 @@ struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int fla ++ if (QIO_ENABLED(h)) { /* Kernel uses same file? */ ++ unsigned int cmd = ++ (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC; ++- if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, ++- h->qh_dir, 0, NULL) < 0) { +++ if (quotactl_handle(cmd, h, 0, NULL) < 0) { ++ die(4, _("Cannot sync quotas on device %s: %s\n"), ++ h->qh_quotadev, strerror(errno)); ++ } ++diff --git a/quotaio.h b/quotaio.h ++index 2c373b2..91689d9 100644 ++--- a/quotaio.h +++++ b/quotaio.h ++@@ -182,4 +182,6 @@ struct dquot *get_empty_dquot(void); ++ /* Check whether values in current dquot can be stored on disk */ ++ int check_dquot_range(struct dquot *dquot); ++ +++/* Uses do_quotactl() to call quotactl() or quotactl_fd() */ +++int quotactl_handle(int cmd, struct quota_handle *h, int id, void *addr); ++ #endif /* GUARD_QUOTAIO_H */ ++diff --git a/quotaio_generic.c b/quotaio_generic.c ++index 3c95872..cf03b59 100644 ++--- a/quotaio_generic.c +++++ b/quotaio_generic.c ++@@ -50,7 +50,7 @@ int vfs_get_info(struct quota_handle *h) ++ { ++ struct if_dqinfo kinfo; ++ ++- if (do_quotactl(QCMD(Q_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { +++ if (quotactl_handle(Q_GETINFO, h, 0, (void *)&kinfo) < 0) { ++ errstr(_("Cannot get info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -68,7 +68,7 @@ int vfs_set_info(struct quota_handle *h, int flags) ++ kinfo.dqi_igrace = h->qh_info.dqi_igrace; ++ kinfo.dqi_valid = flags; ++ ++- if (do_quotactl(QCMD(Q_SETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kinfo) < 0) { +++ if (quotactl_handle(Q_SETINFO, h, 0, (void *)&kinfo) < 0) { ++ errstr(_("Cannot set info for %s quota file from kernel on %s: %s\n"), type2name(h->qh_type), h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -80,7 +80,7 @@ int vfs_get_dquot(struct dquot *dquot) ++ { ++ struct if_dqblk kdqblk; ++ ++- if (do_quotactl(QCMD(Q_GETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { +++ if (quotactl_handle(Q_GETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) { ++ errstr(_("Cannot get quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -95,7 +95,7 @@ int vfs_set_dquot(struct dquot *dquot, int flags) ++ ++ generic_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++ kdqblk.dqb_valid = flags; ++- if (do_quotactl(QCMD(Q_SETQUOTA, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) { +++ if (quotactl_handle(Q_SETQUOTA, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) { ++ errstr(_("Cannot set quota for %s %d from kernel on %s: %s\n"), type2name(dquot->dq_h->qh_type), dquot->dq_id, dquot->dq_h->qh_quotadev, strerror(errno)); ++ return -1; ++ } ++@@ -188,8 +188,7 @@ int vfs_scan_dquots(struct quota_handle *h, ++ ++ dquot->dq_h = h; ++ while (1) { ++- ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), ++- h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk); +++ ret = quotactl_handle(Q_GETNEXTQUOTA, h, id, (void *)&kdqblk); ++ if (ret < 0) ++ break; ++ ++diff --git a/quotaio_meta.c b/quotaio_meta.c ++index 51ebbcf..99fdaf8 100644 ++--- a/quotaio_meta.c +++++ b/quotaio_meta.c ++@@ -59,8 +59,7 @@ static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct ++ struct if_nextdqblk kdqblk; ++ int ret; ++ ++- ret = do_quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, ++- h->qh_dir, 0, (void *)&kdqblk); +++ ret = quotactl_handle(Q_GETNEXTQUOTA, h, 0, (void *)&kdqblk); ++ /* ++ * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not ++ * supported ++diff --git a/quotaio_v1.c b/quotaio_v1.c ++index 187a5a5..0b88d0c 100644 ++--- a/quotaio_v1.c +++++ b/quotaio_v1.c ++@@ -118,7 +118,7 @@ static int v1_init_io(struct quota_handle *h) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) { +++ if (quotactl_handle(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0) { ++ if (errno == EPERM) { /* We have no permission to get this information? */ ++ h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */ ++ } ++@@ -193,11 +193,11 @@ static int v1_write_info(struct quota_handle *h) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) +++ if (quotactl_handle(Q_V1_GETQUOTA, h, 0, (void *)&kdqblk) < 0) ++ return -1; ++ kdqblk.dqb_btime = h->qh_info.dqi_bgrace; ++ kdqblk.dqb_itime = h->qh_info.dqi_igrace; ++- if (do_quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqblk) < 0) +++ if (quotactl_handle(Q_V1_SETQUOTA, h, 0, (void *)&kdqblk) < 0) ++ return -1; ++ } ++ } ++@@ -237,7 +237,7 @@ static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id) ++ else { ++ struct v1_kern_dqblk kdqblk; ++ ++- if (do_quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { +++ if (quotactl_handle(Q_V1_GETQUOTA, h, id, (void *)&kdqblk) < 0) { ++ free(dquot); ++ return NULL; ++ } ++@@ -299,8 +299,7 @@ static int v1_commit_dquot(struct dquot *dquot, int flags) ++ else ++ cmd = Q_V1_SETQUOTA; ++ v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++- if (do_quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, h->qh_dir, dquot->dq_id, ++- (void *)&kdqblk) < 0) +++ if (quotactl_handle(cmd, h, dquot->dq_id, (void *)&kdqblk) < 0) ++ return -1; ++ } ++ } ++diff --git a/quotaio_v2.c b/quotaio_v2.c ++index b0fe7bf..9927cad 100644 ++--- a/quotaio_v2.c +++++ b/quotaio_v2.c ++@@ -275,7 +275,7 @@ static int v2_init_io(struct quota_handle *h) ++ else { ++ struct v2_kern_dqinfo kdqinfo; ++ ++- if (do_quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) { +++ if (quotactl_handle(Q_V2_GETINFO, h, 0, (void *)&kdqinfo) < 0) { ++ /* Temporary check just before fix gets to kernel */ ++ if (errno == EPERM) /* Don't have permission to get information? */ ++ return 0; ++@@ -403,8 +403,8 @@ static int v2_write_info(struct quota_handle *h) ++ kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks; ++ kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk; ++ kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry; ++- if (do_quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0 || ++- do_quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, h->qh_dir, 0, (void *)&kdqinfo) < 0) +++ if (quotactl_handle(Q_V2_SETGRACE, h, 0, (void *)&kdqinfo) < 0 || +++ quotactl_handle(Q_V2_SETFLAGS, h, 0, (void *)&kdqinfo) < 0) ++ return -1; ++ } ++ } ++@@ -441,7 +441,7 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) ++ else { ++ struct v2_kern_dqblk kdqblk; ++ ++- if (do_quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, h->qh_dir, id, (void *)&kdqblk) < 0) { +++ if (quotactl_handle(Q_V2_GETQUOTA, h, id, (void *)&kdqblk) < 0) { ++ free(dquot); ++ return NULL; ++ } ++@@ -485,8 +485,7 @@ static int v2_commit_dquot(struct dquot *dquot, int flags) ++ else ++ cmd = Q_V2_SETQUOTA; ++ v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb); ++- if (do_quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev, ++- dquot->dq_h->qh_dir, dquot->dq_id, (void *)&kdqblk) < 0) +++ if (quotactl_handle(cmd, dquot->dq_h, dquot->dq_id, (void *)&kdqblk) < 0) ++ return -1; ++ } ++ return 0; ++diff --git a/quotaio_xfs.c b/quotaio_xfs.c ++index 0bf6f34..d742f9c 100644 ++--- a/quotaio_xfs.c +++++ b/quotaio_xfs.c ++@@ -128,7 +128,7 @@ static int xfs_init_io(struct quota_handle *h) ++ ++ qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); ++ memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); ++- if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&info) < 0) +++ if (quotactl_handle(qcmd, h, 0, (void *)&info) < 0) ++ return -1; ++ h->qh_info.dqi_bgrace = info.qs_btimelimit; ++ h->qh_info.dqi_igrace = info.qs_itimelimit; ++@@ -153,7 +153,7 @@ static int xfs_write_info(struct quota_handle *h) ++ xdqblk.d_itimer = h->qh_info.dqi_igrace; ++ xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; ++ qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); ++- if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, 0, (void *)&xdqblk) < 0) +++ if (quotactl_handle(qcmd, h, 0, (void *)&xdqblk) < 0) ++ return -1; ++ return 0; ++ } ++diff --git a/quotasys.c b/quotasys.c ++index 903816b..afe5f6d 100644 ++--- a/quotasys.c +++++ b/quotasys.c ++@@ -70,7 +70,15 @@ int nfs_fstype(char *type) ++ */ ++ int meta_qf_fstype(char *type) ++ { ++- return !strcmp(type, MNTTYPE_OCFS2); +++ return !strcmp(type, MNTTYPE_OCFS2) || !strcmp(type, MNTTYPE_TMPFS); +++} +++ +++/* +++ * Check whether the filesystem is not using block device as a backing +++ */ +++int nodev_fstype(char *type) +++{ +++ return !strcmp(type, MNTTYPE_TMPFS) || nfs_fstype(type); ++ } ++ ++ /* ++@@ -752,6 +760,7 @@ static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int fl ++ ++ if (!do_quotactl(QCMD(Q_GETFMT, type), dev, mnt->mnt_dir, 0, (void *)&fmt)) ++ return QF_META; +++ ++ return QF_ERROR; ++ } ++ ++@@ -816,8 +825,13 @@ static int hasquota(const char *dev, struct mntent *mnt, int type, int flags) ++ !strcmp(mnt->mnt_type, MNTTYPE_XFS) || ++ !strcmp(mnt->mnt_type, MNTTYPE_EXFS)) ++ return hasxfsquota(dev, mnt, type, flags); +++ ++ if (!strcmp(mnt->mnt_type, MNTTYPE_OCFS2)) ++ return hasvfsmetaquota(dev, mnt, type, flags); +++ +++ /* tmpfs has no device, pass null here so quotactl_fd() is called */ +++ if (!strcmp(mnt->mnt_type, MNTTYPE_TMPFS)) +++ return hasvfsmetaquota(NULL, mnt, type, flags); ++ /* ++ * For ext4 we check whether it has quota in system files and if not, ++ * we fall back on checking standard quotas. Furthermore we cannot use ++@@ -1384,7 +1398,7 @@ alloc: ++ continue; ++ } ++ ++- if (!nfs_fstype(mnt->mnt_type)) { +++ if (!nodev_fstype(mnt->mnt_type)) { ++ if (stat(devname, &st) < 0) { /* Can't stat mounted device? */ ++ errstr(_("Cannot stat() mounted device %s: %s\n"), devname, strerror(errno)); ++ free((char *)devname); ++@@ -1398,15 +1412,16 @@ alloc: ++ dev = st.st_rdev; ++ for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); ++ } ++- /* Cope with network filesystems or new mountpoint */ ++- if (nfs_fstype(mnt->mnt_type) || i == mnt_entries_cnt) { +++ +++ /* Cope with filesystems without a block device or new mountpoint */ +++ if (nodev_fstype(mnt->mnt_type) || i == mnt_entries_cnt) { ++ if (stat(mnt->mnt_dir, &st) < 0) { /* Can't stat mountpoint? We have better ignore it... */ ++ errstr(_("Cannot stat() mountpoint %s: %s\n"), mnt->mnt_dir, strerror(errno)); ++ free((char *)devname); ++ continue; ++ } ++- if (nfs_fstype(mnt->mnt_type)) { ++- /* For network filesystems we must get device from root */ +++ if (nodev_fstype(mnt->mnt_type)) { +++ /* For filesystems without block device we must get device from root */ ++ dev = st.st_dev; ++ if (!(flags & MS_NFS_ALL)) { ++ for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); ++-- ++2.45.2 ++ + +--- a/quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch ++++ b/quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch +@@ -0,0 +1,52 @@ ++From c18e5a1b1e51c0382f5d1431120fe65f7e9c982c Mon Sep 17 00:00:00 2001 ++From: Carlos Maiolino ++Date: Fri, 26 Jan 2024 19:02:09 +0100 ++Subject: [PATCH 1/3] Rename searched_dir->sd_dir to sd_isdir ++ ++The field holds information if we are searching a directory mountpoint or a ++device, rename the field to something more meaningful. ++ ++We could switch it to bool, but it seems pointless to include a whole header ++just for it, so keep the int type. ++ ++Signed-off-by: Carlos Maiolino ++Signed-off-by: Jan Kara ++Signed-off-by: Pavel Reichl ++--- ++ quotasys.c | 6 +++--- ++ 1 file changed, 3 insertions(+), 3 deletions(-) ++ ++diff --git a/quotasys.c b/quotasys.c ++index 3f50e32..9af9932 100644 ++--- a/quotasys.c +++++ b/quotasys.c ++@@ -1223,7 +1223,7 @@ int kern_quota_on(struct mount_entry *mnt, int type, int fmt) ++ */ ++ ++ struct searched_dir { ++- int sd_dir; /* Is searched dir mountpoint or in fact device? */ +++ int sd_isdir; /* Is searched dir mountpoint or in fact device? */ ++ dev_t sd_dev; /* Device mountpoint lies on */ ++ ino_t sd_ino; /* Inode number of mountpoint */ ++ const char *sd_name; /* Name of given dir/device */ ++@@ -1454,7 +1454,7 @@ static int process_dirs(int dcnt, char **dirs, int flags) ++ errstr(_("Cannot stat() given mountpoint %s: %s\nSkipping...\n"), dirs[i], strerror(errno)); ++ continue; ++ } ++- check_dirs[check_dirs_cnt].sd_dir = S_ISDIR(st.st_mode); +++ check_dirs[check_dirs_cnt].sd_isdir = S_ISDIR(st.st_mode); ++ if (S_ISDIR(st.st_mode)) { ++ const char *realmnt = dirs[i]; ++ ++@@ -1538,7 +1538,7 @@ restart: ++ return 0; ++ sd = check_dirs + act_checked; ++ for (i = 0; i < mnt_entries_cnt; i++) { ++- if (sd->sd_dir) { +++ if (sd->sd_isdir) { ++ if (sd->sd_dev == mnt_entries[i].me_dev && sd->sd_ino == mnt_entries[i].me_ino) ++ break; ++ } ++-- ++2.45.2 ++ + +--- a/quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch ++++ b/quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch +@@ -0,0 +1,36 @@ ++From dba8c5ca95516b9550fc44b2a476ceca60ee4b38 Mon Sep 17 00:00:00 2001 ++From: Jan Kara ++Date: Tue, 7 May 2024 12:55:30 +0200 ++Subject: [PATCH] quotaio_xfs: Fix error handling in xfs_read_dquot() ++ ++When quotactl(2) fails, xfs_read_dquot() will happily return zero-filled ++structure. This is fine when the user structure does not exist but it is ++wrong when there's other error (like EACCESS). Fix the error handling. ++ ++Signed-off-by: Jan Kara ++Signed-off-by: Pavel Reichl ++--- ++ quotaio_xfs.c | 7 ++++++- ++ 1 file changed, 6 insertions(+), 1 deletion(-) ++ ++diff --git a/quotaio_xfs.c b/quotaio_xfs.c ++index d742f9c..040e7d8 100644 ++--- a/quotaio_xfs.c +++++ b/quotaio_xfs.c ++@@ -176,7 +176,12 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) ++ qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type); ++ if (do_quotactl(qcmd, h->qh_quotadev, h->qh_dir, ++ id, (void *)&xdqblk) < 0) { ++- ; +++ /* +++ * ENOENT means the structure just does not exist - return all +++ * zeros. Otherwise return failure. +++ */ +++ if (errno != ENOENT) +++ return NULL; ++ } ++ else { ++ xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk); ++-- ++2.45.2 ++ + +--- a/quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch ++++ b/quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch +@@ -0,0 +1,64 @@ ++From bd13b74e6d181638023d8a89316417643d9e7fd8 Mon Sep 17 00:00:00 2001 ++From: Jan Kara ++Date: Tue, 7 May 2024 14:21:45 +0200 ++Subject: [PATCH] quotaio_xfs: Fix quota-tools on XFS ++ ++Patches implementing tmpfs quota support, commit 00534e79856c ("Enable ++support for tmpfs quotas") in particular, broke quota-tools on XFS ++because quotactl(2) syscall got called with wrong arguments. Fix it. ++ ++Signed-off-by: Jan Kara ++Signed-off-by: Pavel Reichl ++--- ++ quotaio_xfs.c | 11 ++++------- ++ 1 file changed, 4 insertions(+), 7 deletions(-) ++ ++diff --git a/quotaio_xfs.c b/quotaio_xfs.c ++index 040e7d8..c10534d 100644 ++--- a/quotaio_xfs.c +++++ b/quotaio_xfs.c ++@@ -124,11 +124,9 @@ static inline int xfs_util2kerndqblk(struct xfs_kern_dqblk *k, struct util_dqblk ++ static int xfs_init_io(struct quota_handle *h) ++ { ++ struct xfs_mem_dqinfo info; ++- int qcmd; ++ ++- qcmd = QCMD(Q_XFS_GETQSTAT, h->qh_type); ++ memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); ++- if (quotactl_handle(qcmd, h, 0, (void *)&info) < 0) +++ if (quotactl_handle(Q_XFS_GETQSTAT, h, 0, (void *)&info) < 0) ++ return -1; ++ h->qh_info.dqi_bgrace = info.qs_btimelimit; ++ h->qh_info.dqi_igrace = info.qs_itimelimit; ++@@ -142,7 +140,6 @@ static int xfs_init_io(struct quota_handle *h) ++ static int xfs_write_info(struct quota_handle *h) ++ { ++ struct xfs_kern_dqblk xdqblk; ++- int qcmd; ++ ++ if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h) && !XFS_PRJQUOTA(h)) ++ return 0; ++@@ -152,8 +149,7 @@ static int xfs_write_info(struct quota_handle *h) ++ xdqblk.d_btimer = h->qh_info.dqi_bgrace; ++ xdqblk.d_itimer = h->qh_info.dqi_igrace; ++ xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK; ++- qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type); ++- if (quotactl_handle(qcmd, h, 0, (void *)&xdqblk) < 0) +++ if (quotactl_handle(Q_XFS_SETQLIM, h, 0, (void *)&xdqblk) < 0) ++ return -1; ++ return 0; ++ } ++@@ -180,8 +176,9 @@ static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id) ++ * ENOENT means the structure just does not exist - return all ++ * zeros. Otherwise return failure. ++ */ ++- if (errno != ENOENT) +++ if (errno != ENOENT) { ++ return NULL; +++ } ++ } ++ else { ++ xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk); ++-- ++2.45.2 ++ + +--- a/quota.spec ++++ b/quota.spec +@@ -13,7 +13,7 @@ + Name: quota + Epoch: 1 + Version: 4.09 +-Release: 6%{?dist} ++Release: 7%{?dist} + Summary: System administration tools for monitoring users' disk usage + # quota_nld.c, quotaio_xfs.h: GPLv2 + # bylabel.c copied from util-linux: GPLv2+ +@@ -59,6 +59,11 @@ Source4: rpc-rquotad.sysconfig + Patch0: quota-4.06-warnquota-configuration-tunes.patch + # Fix parsing a TCP port number + Patch1: quota-4.03-Validate-upper-bound-of-RPC-port.patch ++Patch2: quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch ++Patch3: quota-4.10-Add-quotactl_fd-support.patch ++Patch4: quota-4.10-Enable-support-for-tmpfs-quotas.patch ++Patch5: quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch ++Patch6: quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch + + BuildRequires: autoconf + BuildRequires: automake +@@ -182,6 +187,11 @@ Linux/UNIX environment. + %setup -q + %patch0 -p1 + %patch1 -p1 ++%patch2 -p1 ++%patch3 -p1 ++%patch4 -p1 ++%patch5 -p1 ++%patch6 -p1 + + # Regenerate build scripts + autoreconf -f -i +@@ -332,6 +342,10 @@ make check + + + %changelog ++* Fri Jul 26 2024 Pavel Reichl - 1:4.09-7 ++- Add tmpfs quota support ++- Fix quota-tools on XFS ++ + * Mon Jun 24 2024 Troy Dawson - 1:4.09-6 + - Bump release for June 2024 mass rebuild + + diff --git a/quota.spec b/quota.spec index b49529c..7c1f738 100644 --- a/quota.spec +++ b/quota.spec @@ -1,4 +1,4 @@ -%define anolis_release 2 +%define anolis_release 3 # Scan ext file systems directly to increase the performace of a quota # initialization and check @@ -25,6 +25,11 @@ Source1: quota_nld.service Source2: quota_nld.sysconfig Source3: rpc-rquotad.service Source4: rpc-rquotad.sysconfig +Patch0: quota-4.10-Add-quotactl_fd-support.patch +Patch1: quota-4.10-Enable-support-for-tmpfs-quotas.patch +Patch2: quota-4.10-Rename-searched_dir-sd_dir-to-sd_isdir.patch +Patch3: quota-4.10-quotaio_xfs-Fix-error-handling-in-xfs_read_dquot.patch +Patch4: quota-4.10-quotaio_xfs-Fix-quota-tools-on-XFS.patch BuildRequires: autoconf automake bash coreutils gcc make BuildRequires: pkgconfig(ext2fs) pkgconfig(ldap) gettext-devel @@ -262,6 +267,13 @@ make check %doc Changelog README.ldap-support README.mailserver %changelog +* Thu Jan 29 2026 wenjie2025 - 4.09-3 +- Add tmpfs quota support +- Add quotactl_fd support for filesystems without backing devices +- Fix quota-tools on XFS +- Fix error handling in xfs_read_dquot +- Rename searched_dir sd_dir to sd_isdir + * Thu Apr 13 2023 yuanhui - 4.09-2 - Optimize the spec file -- Gitee