--- quota-tools/Changelog +++ quota-tools/Changelog @@ -1,3 +1,6 @@ +* fixed bug in error reporting when quota reading fails (Jan Kara) +* added support for quota formats with hidden quota files (Jan Kara) + Changes in quota-tools from 3.15 to 3.16 * added information message about journaled quota to quotacheck (Jan Kara, Alex Tomas) * added pointers to quota_nld and warnquota to some manpages (Jan Kara) --- quota-tools/Makefile.in +++ quota-tools/Makefile.in @@ -1,5 +1,5 @@ PROGS = quotacheck quotaon quota quot repquota warnquota quotastats xqmstats edquota setquota convertquota rpc.rquotad @QUOTA_NETLINK_PROG@ -SOURCES = bylabel.c common.c convertquota.c edquota.c pot.c quot.c quota.c quotacheck.c quotacheck_v1.c quotacheck_v2.c quotaio.c quotaio_rpc.c quotaio_v1.c quotaio_v2.c quotaio_xfs.c quotaio_generic.c quotaon.c quotaon_xfs.c quotaops.c quotastats.c quotasys.c repquota.c rquota_client.c rquota_server.c rquota_svc.c setquota.c warnquota.c xqmstats.c svc_socket.c +SOURCES = bylabel.c common.c convertquota.c edquota.c pot.c quot.c quota.c quotacheck.c quotacheck_v1.c quotacheck_v2.c quotaio.c quotaio_rpc.c quotaio_v1.c quotaio_v2.c quotaio_xfs.c quotaio_meta.c quotaio_generic.c quotaon.c quotaon_xfs.c quotaops.c quotastats.c quotasys.c repquota.c rquota_client.c rquota_server.c rquota_svc.c setquota.c warnquota.c xqmstats.c svc_socket.c VERSIONDEF = -DQUOTA_VERSION=\"3.16\" CFLAGS = @CFLAGS@ @EXT2_DIRECT@ -D_GNU_SOURCE -Wall -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(VERSIONDEF) -DCOMPILE_OPTS="\"@COMPILE_OPTS@\"" CPPFLAGS = @CPPFLAGS@ @@ -39,7 +39,7 @@ sysconfdir = @sysconfdir@ RPCCLNTOBJS = rquota_xdr.o rquota_client.o rquota_clnt.o -IOOBJS = quotaio.o quotaio_v1.o quotaio_v2.o quotaio_rpc.o quotaio_xfs.o quotaio_generic.o +IOOBJS = quotaio.o quotaio_v1.o quotaio_v2.o quotaio_rpc.o quotaio_xfs.o quotaio_meta.o quotaio_generic.o IOOBJS += $(RPCCLNTOBJS) LIBOBJS = bylabel.o common.o quotasys.o pot.o $(IOOBJS) LIBOBJS += @LIBMALLOC@ --- quota-tools/mntopt.h +++ quota-tools/mntopt.h @@ -16,6 +16,7 @@ #define MNTTYPE_JFS "jfs" /* JFS file system */ #define MNTTYPE_NFS4 "nfs4" /* NFSv4 filesystem */ #define MNTTYPE_MPFS "mpfs" /* EMC Celerra MPFS filesystem */ +#define MNTTYPE_OCFS2 "ocfs2" /* Oracle Cluster filesystem */ /* mount options */ #define MNTOPT_NOQUOTA "noquota" /* don't enforce quota */ --- quota-tools/quota.h +++ quota-tools/quota.h @@ -4,7 +4,7 @@ #include typedef u_int32_t qid_t; /* Type in which we store ids in memory */ -typedef u_int64_t qsize_t; /* Type in which we store size limitations */ +typedef int64_t qsize_t; /* Type in which we store size limitations */ #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ @@ -135,6 +135,7 @@ /* Quota format identifiers */ #define QFMT_VFS_OLD 1 #define QFMT_VFS_V0 2 +#define QFMT_OCFS2 3 /* Flags supported by kernel */ #define V1_DQF_RSQUASH 1 --- quota-tools/quotacheck.c +++ quota-tools/quotacheck.c @@ -1036,7 +1036,8 @@ while ((mnt = get_next_mount())) { if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->mnt_dir, "/")) continue; - if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) || nfs_fstype(mnt->mnt_type)) { + if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) || nfs_fstype(mnt->mnt_type) || + meta_qf_fstype(mnt->mnt_type)) { debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->mnt_fsname, mnt->mnt_dir); continue; } --- quota-tools/quotaio.c +++ quota-tools/quotaio.c @@ -97,8 +97,26 @@ fmt = kernfmt; /* Default is kernel used format */ } } - if ((fmt = get_qf_name(mnt, type, (fmt == -1) ? ((1 << QF_VFSOLD) | (1 << QF_VFSV0)) : (1 << fmt), - (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0, &qfname)) < 0) { + + if (meta_qf_fstype(mnt->mnt_type)) { + if (!QIO_ENABLED(h)) { + errstr(_("Quota not supported by the filesystem.\n")); + goto out_handle; + } + if (flags & IOI_OPENFILE) { + errstr(_("Operation not supported for filesystems with hidden quota files!\n")); + goto out_handle; + } + h->qh_fd = -1; + h->qh_fmt = fmt; + goto set_ops; + } + + fmt = get_qf_name(mnt, type, + (fmt == -1) ? ((1 << QF_VFSOLD) | (1 << QF_VFSV0)) : (1 << fmt), + (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0, + &qfname); + if (fmt < 0) { errstr(_("Quota file not found or has wrong format.\n")); goto out_handle; } @@ -121,10 +139,13 @@ free(qfname); /* We don't need it anymore */ qfname = NULL; +set_ops: if (h->qh_fmt == QF_VFSOLD) h->qh_ops = "afile_ops_1; else if (h->qh_fmt == QF_VFSV0) h->qh_ops = "afile_ops_2; + else if (h->qh_fmt == QF_META) + h->qh_ops = "afile_ops_meta; memset(&h->qh_info, 0, sizeof(h->qh_info)); if (h->qh_ops->init_io && h->qh_ops->init_io(h) < 0) { @@ -155,7 +176,7 @@ if (fmt == -1) fmt = QF_VFSV0; /* Use the newest format */ - else if (fmt == QF_RPC || fmt == QF_XFS) { + else if (fmt == QF_RPC || fmt == QF_XFS || meta_qf_fstype(mnt->mnt_type)) { errstr(_("Creation of %s quota format is not supported.\n"), fmt == QF_RPC ? "RPC" : "XFS"); return NULL; --- quota-tools/quotaio.h +++ quota-tools/quotaio.h @@ -50,6 +50,7 @@ #define QF_VFSV0 1 /* New quota format - version 0 */ #define QF_RPC 2 /* RPC should be used on given filesystem */ #define QF_XFS 3 /* XFS quota format */ +#define QF_META 4 /* Quota files are hidden, we don't care about the format */ /* * Definitions for disk quotas imposed on the average user @@ -153,6 +154,9 @@ int (*report) (struct quota_handle * h, int verbose); /* Function called after 'repquota' to print format specific file information */ }; +/* This might go into a special header file but that sounds a bit silly... */ +extern struct quotafile_ops quotafile_ops_meta; + static inline void mark_quotafile_info_dirty(struct quota_handle *h) { h->qh_io_flags |= IOFL_INFODIRTY; --- quota-tools/quotaio_meta.c +++ quota-tools/quotaio_meta.c @@ -0,0 +1,58 @@ +/* + * Implementation of handling of quotafiles which are hidden + * + * Jan Kara + */ +#include +#include + +#include + +#include "pot.h" +#include "common.h" +#include "quotasys.h" +#include "quotaio_generic.h" + +static int meta_init_io(struct quota_handle *h) +{ + if (!QIO_ENABLED(h)) { + errstr(_("Metadata init_io called when kernel support is not enabled.\n")); + return -1; + } + if (kernel_iface != IFACE_GENERIC) { + errstr(_("Metadata init_io called when kernel does not support generic quota interface!\n")); + return -1; + } + return vfs_get_info(h); +} + +static int meta_write_info(struct quota_handle *h) +{ + return vfs_set_info(h, IIF_BGRACE | IIF_IGRACE); +} + +static struct dquot *meta_read_dquot(struct quota_handle *h, qid_t id) +{ + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_id = id; + dquot->dq_h = h; + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + if (vfs_get_dquot(dquot) < 0) { + free(dquot); + return NULL; + } + return dquot; +} + +static int meta_commit_dquot(struct dquot *dquot, int flags) +{ + return vfs_set_dquot(dquot, flags); +} + +struct quotafile_ops quotafile_ops_meta = { +init_io: meta_init_io, +write_info: meta_write_info, +read_dquot: meta_read_dquot, +commit_dquot: meta_commit_dquot, +}; --- quota-tools/quotaon.c +++ quota-tools/quotaon.c @@ -173,6 +173,12 @@ || (!(flags & FL_OFF) && kern_quota_on(mnt->mnt_fsname, type, 1 << QF_XFS)))) ret = xfs_newstate(mnt, type, extra, sflags); } + else if (meta_qf_fstype(mnt->mnt_type)) { + if (!hasquota(mnt, type, 0)) + return 0; + /* Must be non-empty because empty path is always invalid. */ + ret = v2_newstate(mnt, type, ".", sflags); + } else { if (!hasquota(mnt, type, 0)) return 0; --- quota-tools/quotaops.c +++ quota-tools/quotaops.c @@ -154,9 +154,11 @@ if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) { /* If rpc.rquotad is not running filesystem might be just without quotas... */ if (errno != ENOENT && (errno != ECONNREFUSED || !quiet)) { + int olderrno = errno; + id2name(id, handles[i]->qh_type, name); errstr(_("error while getting quota from %s for %s (id %u): %s\n"), - handles[i]->qh_quotadev, name, id, strerror(errno)); + handles[i]->qh_quotadev, name, id, strerror(olderrno)); } continue; } --- quota-tools/quotasys.c +++ quota-tools/quotasys.c @@ -48,6 +48,15 @@ } /* + * Check whether filesystem has hidden quota files which is handles + * as metadata (and thus always tracks usage). + */ +int meta_qf_fstype(char *type) +{ + return !strcmp(type, MNTTYPE_OCFS2); +} + +/* * Check whether give filesystem type is supported */ @@ -71,6 +80,7 @@ !strcmp(type, MNTTYPE_XFS) || !strcmp(type, MNTTYPE_NFS) || !strcmp(type, MNTTYPE_NFS4) || + !strcmp(type, MNTTYPE_OCFS2) || !strcmp(type, MNTTYPE_MPFS)) { free(mtype); return 1; @@ -267,6 +277,8 @@ return QF_VFSOLD; case QFMT_VFS_V0: return QF_VFSV0; + case QFMT_OCFS2: + return QF_META; } return -1; } @@ -700,7 +712,7 @@ /* Detect new kernel interface; Assume generic interface unless we can prove there is not one... */ if (!stat("/proc/sys/fs/quota", &st) || errno != ENOENT) { kernel_iface = IFACE_GENERIC; - kernel_formats |= (1 << QF_VFSOLD) | (1 << QF_VFSV0); + kernel_formats |= (1 << QF_VFSOLD) | (1 << QF_VFSV0) | (1 << QF_META); } else { struct v2_dqstats v2_stats; --- quota-tools/quotasys.h +++ quota-tools/quotasys.h @@ -41,6 +41,8 @@ */ /* Check whether type is one of the NFS filesystems */ int nfs_fstype(char *); +/* Quota file is treated as metadata? */ +int meta_qf_fstype(char *type); /* Convert quota type to written form */ char *type2name(int);