Message ID | 20240109134651.869887-3-cem@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Enable tmpfs quotas | expand |
On Tue 09-01-24 14:46:04, cem@kernel.org wrote: > From: Carlos Maiolino <cem@kernel.org> > > 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> quota-tools work on mounted filesystems so ideally we could switch all the places to use quotactl_fd() (if the kernel supports it - we probably have to keep the fallback for some time yet). But for now what you do is fine and we can clean that up later. Honza > --- > 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 ++++---- > quotastats.c | 4 ++-- > quotasync.c | 2 +- > quotasys.c | 55 ++++++++++++++++++++++++++++++++++++----------- > quotasys.h | 3 +++ > 14 files changed, 98 insertions(+), 59 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/quotastats.c b/quotastats.c > index a059812..ee23afd 100644 > --- a/quotastats.c > +++ b/quotastats.c > @@ -72,7 +72,7 @@ static int get_stats(struct util_dqstats *dqstats) > dqstats->free_dquots = get_proc_num("free_dquots"); > dqstats->syncs = get_proc_num("syncs"); > } > - else if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, (caddr_t)&old_dqstats) >= 0) { > + else if (do_quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&old_dqstats) >= 0) { > /* Structures are currently the same */ > memcpy(dqstats, &old_dqstats, sizeof(old_dqstats)); > dqstats->version = 0; > @@ -83,7 +83,7 @@ static int get_stats(struct util_dqstats *dqstats) > errstr(_("Error while getting quota statistics from kernel: %s\n"), strerror(errno)); > goto out; > } > - if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (caddr_t)&v0_dqstats) < 0) { > + if (do_quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&v0_dqstats) < 0) { > errstr(_("Error while getting old quota statistics from kernel: %s\n"), strerror(errno)); > goto out; > } > 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 <sys/vfs.h> > #include <stdint.h> > #include <sys/utsname.h> > +#include <sys/syscall.h> > > #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.43.0 >
On Wed, Jan 17, 2024 at 07:08:33PM +0100, Jan Kara wrote: > On Tue 09-01-24 14:46:04, cem@kernel.org wrote: > > From: Carlos Maiolino <cem@kernel.org> > > > > 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> > > quota-tools work on mounted filesystems so ideally we could switch all the > places to use quotactl_fd() (if the kernel supports it - we probably have > to keep the fallback for some time yet). But for now what you do is fine > and we can clean that up later. Thanks for the review! I do agree with you. I can work on such cleanup later for sure. Carlos > > Honza > > > --- > > 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 ++++---- > > quotastats.c | 4 ++-- > > quotasync.c | 2 +- > > quotasys.c | 55 ++++++++++++++++++++++++++++++++++++----------- > > quotasys.h | 3 +++ > > 14 files changed, 98 insertions(+), 59 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/quotastats.c b/quotastats.c > > index a059812..ee23afd 100644 > > --- a/quotastats.c > > +++ b/quotastats.c > > @@ -72,7 +72,7 @@ static int get_stats(struct util_dqstats *dqstats) > > dqstats->free_dquots = get_proc_num("free_dquots"); > > dqstats->syncs = get_proc_num("syncs"); > > } > > - else if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, (caddr_t)&old_dqstats) >= 0) { > > + else if (do_quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&old_dqstats) >= 0) { > > /* Structures are currently the same */ > > memcpy(dqstats, &old_dqstats, sizeof(old_dqstats)); > > dqstats->version = 0; > > @@ -83,7 +83,7 @@ static int get_stats(struct util_dqstats *dqstats) > > errstr(_("Error while getting quota statistics from kernel: %s\n"), strerror(errno)); > > goto out; > > } > > - if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (caddr_t)&v0_dqstats) < 0) { > > + if (do_quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&v0_dqstats) < 0) { > > errstr(_("Error while getting old quota statistics from kernel: %s\n"), strerror(errno)); > > goto out; > > } > > 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 <sys/vfs.h> > > #include <stdint.h> > > #include <sys/utsname.h> > > +#include <sys/syscall.h> > > > > #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.43.0 > > > -- > Jan Kara <jack@suse.com> > SUSE Labs, CR
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/quotastats.c b/quotastats.c index a059812..ee23afd 100644 --- a/quotastats.c +++ b/quotastats.c @@ -72,7 +72,7 @@ static int get_stats(struct util_dqstats *dqstats) dqstats->free_dquots = get_proc_num("free_dquots"); dqstats->syncs = get_proc_num("syncs"); } - else if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, (caddr_t)&old_dqstats) >= 0) { + else if (do_quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&old_dqstats) >= 0) { /* Structures are currently the same */ memcpy(dqstats, &old_dqstats, sizeof(old_dqstats)); dqstats->version = 0; @@ -83,7 +83,7 @@ static int get_stats(struct util_dqstats *dqstats) errstr(_("Error while getting quota statistics from kernel: %s\n"), strerror(errno)); goto out; } - if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (caddr_t)&v0_dqstats) < 0) { + if (do_quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, NULL, 0, (caddr_t)&v0_dqstats) < 0) { errstr(_("Error while getting old quota statistics from kernel: %s\n"), strerror(errno)); goto out; } 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 <sys/vfs.h> #include <stdint.h> #include <sys/utsname.h> +#include <sys/syscall.h> #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