|
|
ee7779b |
From fa920711b4bbb9e61358a7f488f0a645ef221321 Mon Sep 17 00:00:00 2001
|
|
|
ee7779b |
From: Abhijith Das <adas@redhat.com>
|
|
|
ee7779b |
Date: Fri, 4 Feb 2011 12:40:58 +0100
|
|
|
ee7779b |
Subject: [PATCH] Implement quotacheck for GFS2
|
|
|
ee7779b |
|
|
|
ee7779b |
Although GFS2 maintains quota as metadata, it sometimes might need to
|
|
|
ee7779b |
check quota usage (most notably when quota is enabled for the first time).
|
|
|
ee7779b |
So add support for GFS2 in quotacheck.
|
|
|
ee7779b |
|
|
|
ee7779b |
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
|
ee7779b |
|
|
|
ee7779b |
Petr Pisar: Remove MNTTYPE_NEXT3 test
|
|
|
ee7779b |
---
|
|
|
ee7779b |
quotacheck.c | 82 +++++++++++++++++++++++++++++++++++++++++++--------------
|
|
|
ee7779b |
quotaio_xfs.c | 12 +++++++-
|
|
|
ee7779b |
quotaio_xfs.h | 9 ++++++
|
|
|
ee7779b |
3 files changed, 82 insertions(+), 21 deletions(-)
|
|
|
ee7779b |
|
|
|
ee7779b |
diff --git a/quotacheck.c b/quotacheck.c
|
|
|
ee7779b |
index fec9ec3..7ecf62d 100644
|
|
|
ee7779b |
--- a/quotacheck.c
|
|
|
ee7779b |
+++ b/quotacheck.c
|
|
|
ee7779b |
@@ -404,10 +404,6 @@ static void parse_options(int argcnt, char **argstr)
|
|
|
ee7779b |
fputs(_("Bad number of arguments.\n"), stderr);
|
|
|
ee7779b |
usage();
|
|
|
ee7779b |
}
|
|
|
ee7779b |
- if (fmt == QF_XFS) {
|
|
|
ee7779b |
- fputs(_("XFS quota format needs no checking.\n"), stderr);
|
|
|
ee7779b |
- exit(0);
|
|
|
ee7779b |
- }
|
|
|
ee7779b |
if (flags & FL_VERBOSE && flags & FL_DEBUG)
|
|
|
ee7779b |
flags &= ~FL_VERBOSE;
|
|
|
ee7779b |
if (!(flags & FL_ALL))
|
|
|
ee7779b |
@@ -689,6 +685,9 @@ static int rename_files(struct mntent *mnt, int type)
|
|
|
ee7779b |
int fd;
|
|
|
ee7779b |
#endif
|
|
|
ee7779b |
|
|
|
ee7779b |
+ if (cfmt == QF_XFS) /* No renaming for xfs/gfs2 */
|
|
|
ee7779b |
+ return 0;
|
|
|
ee7779b |
+
|
|
|
ee7779b |
debug(FL_DEBUG, _("Renaming new files to proper names.\n"));
|
|
|
ee7779b |
if (get_qf_name(mnt, type, cfmt, 0, &filename) < 0)
|
|
|
ee7779b |
die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->mnt_dir);
|
|
|
ee7779b |
@@ -787,25 +786,42 @@ static int dump_to_file(struct mntent *mnt, int type)
|
|
|
ee7779b |
struct dquot *dquot;
|
|
|
ee7779b |
uint i;
|
|
|
ee7779b |
struct quota_handle *h;
|
|
|
ee7779b |
+ unsigned int commit = 0;
|
|
|
ee7779b |
|
|
|
ee7779b |
debug(FL_DEBUG, _("Dumping gathered data for %ss.\n"), type2name(type));
|
|
|
ee7779b |
- if (!(h = new_io(mnt, type, cfmt))) {
|
|
|
ee7779b |
- errstr(_("Cannot initialize IO on new quotafile: %s\n"),
|
|
|
ee7779b |
- strerror(errno));
|
|
|
ee7779b |
- return -1;
|
|
|
ee7779b |
- }
|
|
|
ee7779b |
- if (!(flags & FL_NEWFILE)) {
|
|
|
ee7779b |
- h->qh_info.dqi_bgrace = old_info[type].dqi_bgrace;
|
|
|
ee7779b |
- h->qh_info.dqi_igrace = old_info[type].dqi_igrace;
|
|
|
ee7779b |
- if (is_tree_qfmt(cfmt))
|
|
|
ee7779b |
- v2_merge_info(&h->qh_info, old_info + type);
|
|
|
ee7779b |
- mark_quotafile_info_dirty(h);
|
|
|
ee7779b |
+ if (cfmt == QF_XFS) {
|
|
|
ee7779b |
+ if (!(h = init_io(mnt, type, cfmt, IOI_READONLY))) {
|
|
|
ee7779b |
+ errstr(_("Cannot initialize IO on xfs/gfs2 quotafile: %s\n"),
|
|
|
ee7779b |
+ strerror(errno));
|
|
|
ee7779b |
+ return -1;
|
|
|
ee7779b |
+ }
|
|
|
ee7779b |
+ } else {
|
|
|
ee7779b |
+ if (!(h = new_io(mnt, type, cfmt))) {
|
|
|
ee7779b |
+ errstr(_("Cannot initialize IO on new quotafile: %s\n"),
|
|
|
ee7779b |
+ strerror(errno));
|
|
|
ee7779b |
+ return -1;
|
|
|
ee7779b |
+ }
|
|
|
ee7779b |
+ if (!(flags & FL_NEWFILE)) {
|
|
|
ee7779b |
+ h->qh_info.dqi_bgrace = old_info[type].dqi_bgrace;
|
|
|
ee7779b |
+ h->qh_info.dqi_igrace = old_info[type].dqi_igrace;
|
|
|
ee7779b |
+ if (is_tree_qfmt(cfmt))
|
|
|
ee7779b |
+ v2_merge_info(&h->qh_info, old_info + type);
|
|
|
ee7779b |
+ mark_quotafile_info_dirty(h);
|
|
|
ee7779b |
+ }
|
|
|
ee7779b |
}
|
|
|
ee7779b |
for (i = 0; i < DQUOTHASHSIZE; i++)
|
|
|
ee7779b |
for (dquot = dquot_hash[type][i]; dquot; dquot = dquot->dq_next) {
|
|
|
ee7779b |
dquot->dq_h = h;
|
|
|
ee7779b |
+ /* For XFS/GFS2, we don't bother with actually checking
|
|
|
ee7779b |
+ * what the usage value is in the internal quota file.
|
|
|
ee7779b |
+ * We simply attempt to update the usage for every quota
|
|
|
ee7779b |
+ * we find in the fs scan. The filesystem decides in the
|
|
|
ee7779b |
+ * quotactl handler whether to update the usage in the
|
|
|
ee7779b |
+ * quota file or not.
|
|
|
ee7779b |
+ */
|
|
|
ee7779b |
+ commit = cfmt == QF_XFS ? COMMIT_USAGE : COMMIT_ALL;
|
|
|
ee7779b |
update_grace_times(dquot);
|
|
|
ee7779b |
- h->qh_ops->commit_dquot(dquot, COMMIT_ALL);
|
|
|
ee7779b |
+ h->qh_ops->commit_dquot(dquot, commit);
|
|
|
ee7779b |
}
|
|
|
ee7779b |
if (end_io(h) < 0) {
|
|
|
ee7779b |
errstr(_("Cannot finish IO on new quotafile: %s\n"), strerror(errno));
|
|
|
ee7779b |
@@ -893,6 +909,14 @@ static void check_dir(struct mntent *mnt)
|
|
|
ee7779b |
die(2, _("Mountpoint %s is not a directory?!\n"), mnt->mnt_dir);
|
|
|
ee7779b |
cur_dev = st.st_dev;
|
|
|
ee7779b |
files_done = dirs_done = 0;
|
|
|
ee7779b |
+ /*
|
|
|
ee7779b |
+ * For gfs2, we scan the fs first and then tell the kernel about the new usage.
|
|
|
ee7779b |
+ * So, there's no need to load any information. We also don't remount the
|
|
|
ee7779b |
+ * filesystem read-only because for a clustering filesystem it won't stop
|
|
|
ee7779b |
+ * modifications from other nodes anyway.
|
|
|
ee7779b |
+ */
|
|
|
ee7779b |
+ if (cfmt == QF_XFS)
|
|
|
ee7779b |
+ goto start_scan;
|
|
|
ee7779b |
if (ucheck)
|
|
|
ee7779b |
if (process_file(mnt, USRQUOTA) < 0)
|
|
|
ee7779b |
ucheck = 0;
|
|
|
ee7779b |
@@ -923,6 +947,7 @@ Please stop all programs writing to filesystem or use -m flag to force checking.
|
|
|
ee7779b |
remounted = 1;
|
|
|
ee7779b |
debug(FL_DEBUG, _("Filesystem remounted read-only\n"));
|
|
|
ee7779b |
}
|
|
|
ee7779b |
+start_scan:
|
|
|
ee7779b |
debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->mnt_fsname, mnt->mnt_dir);
|
|
|
ee7779b |
#if defined(EXT2_DIRECT)
|
|
|
ee7779b |
if (!strcmp(mnt->mnt_type, MNTTYPE_EXT2) || !strcmp(mnt->mnt_type, MNTTYPE_EXT3)) {
|
|
|
ee7779b |
@@ -973,6 +998,10 @@ static int detect_filename_format(struct mntent *mnt, int type)
|
|
|
ee7779b |
int journal = 0;
|
|
|
ee7779b |
int fmt;
|
|
|
ee7779b |
|
|
|
ee7779b |
+ if (strcmp(mnt->mnt_type, MNTTYPE_XFS) == 0 ||
|
|
|
ee7779b |
+ strcmp(mnt->mnt_type, MNTTYPE_GFS2) == 0)
|
|
|
ee7779b |
+ return QF_XFS;
|
|
|
ee7779b |
+
|
|
|
ee7779b |
if (type == USRQUOTA) {
|
|
|
ee7779b |
if ((option = hasmntopt(mnt, MNTOPT_USRQUOTA)))
|
|
|
ee7779b |
option += strlen(MNTOPT_USRQUOTA);
|
|
|
ee7779b |
@@ -1040,6 +1069,22 @@ jquota_err:
|
|
|
ee7779b |
return -1;
|
|
|
ee7779b |
}
|
|
|
ee7779b |
|
|
|
ee7779b |
+static int compatible_fs_qfmt(char *fstype, int fmt)
|
|
|
ee7779b |
+{
|
|
|
ee7779b |
+ /* We never check XFS, NFS, and filesystems supporting VFS metaformat */
|
|
|
ee7779b |
+ if (!strcmp(fstype, MNTTYPE_XFS) || nfs_fstype(fstype) ||
|
|
|
ee7779b |
+ meta_qf_fstype(fstype))
|
|
|
ee7779b |
+ return 0;
|
|
|
ee7779b |
+ /* In all other cases we can pick a format... */
|
|
|
ee7779b |
+ if (fmt == -1)
|
|
|
ee7779b |
+ return 1;
|
|
|
ee7779b |
+ /* XFS format is supported only by GFS2 */
|
|
|
ee7779b |
+ if (fmt == QF_XFS)
|
|
|
ee7779b |
+ return !strcmp(fstype, MNTTYPE_GFS2);
|
|
|
ee7779b |
+ /* Anything but GFS2 supports all other formats */
|
|
|
ee7779b |
+ return !!strcmp(fstype, MNTTYPE_GFS2);
|
|
|
ee7779b |
+}
|
|
|
ee7779b |
+
|
|
|
ee7779b |
static void check_all(void)
|
|
|
ee7779b |
{
|
|
|
ee7779b |
struct mntent *mnt;
|
|
|
ee7779b |
@@ -1051,10 +1096,7 @@ static void check_all(void)
|
|
|
ee7779b |
while ((mnt = get_next_mount())) {
|
|
|
ee7779b |
if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->mnt_dir, "/"))
|
|
|
ee7779b |
continue;
|
|
|
ee7779b |
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) ||
|
|
|
ee7779b |
- !strcmp(mnt->mnt_type, MNTTYPE_GFS2) ||
|
|
|
ee7779b |
- nfs_fstype(mnt->mnt_type) ||
|
|
|
ee7779b |
- meta_qf_fstype(mnt->mnt_type)) {
|
|
|
ee7779b |
+ if (!compatible_fs_qfmt(mnt->mnt_type, fmt)) {
|
|
|
ee7779b |
debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->mnt_fsname, mnt->mnt_dir);
|
|
|
ee7779b |
continue;
|
|
|
ee7779b |
}
|
|
|
ee7779b |
diff --git a/quotaio_xfs.c b/quotaio_xfs.c
|
|
|
ee7779b |
index 4729317..62075b5 100644
|
|
|
ee7779b |
--- a/quotaio_xfs.c
|
|
|
ee7779b |
+++ b/quotaio_xfs.c
|
|
|
ee7779b |
@@ -151,7 +151,17 @@ static int xfs_commit_dquot(struct dquot *dquot, int flags)
|
|
|
ee7779b |
return 0;
|
|
|
ee7779b |
|
|
|
ee7779b |
xfs_util2kerndqblk(&xdqblk, &dquot->dq_dqb);
|
|
|
ee7779b |
- xdqblk.d_fieldmask |= FS_DQ_LIMIT_MASK;
|
|
|
ee7779b |
+ xdqblk.d_flags |= XFS_USRQUOTA(h) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
|
|
|
ee7779b |
+ xdqblk.d_id = id;
|
|
|
ee7779b |
+ if (strcmp(h->qh_fstype, MNTTYPE_GFS2) == 0) {
|
|
|
ee7779b |
+ if (flags & COMMIT_LIMITS) /* warn/limit */
|
|
|
ee7779b |
+ xdqblk.d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
|
|
|
ee7779b |
+ if (flags & COMMIT_USAGE) /* block usage */
|
|
|
ee7779b |
+ xdqblk.d_fieldmask |= FS_DQ_BCOUNT;
|
|
|
ee7779b |
+ } else {
|
|
|
ee7779b |
+ xdqblk.d_fieldmask |= FS_DQ_LIMIT_MASK;
|
|
|
ee7779b |
+ }
|
|
|
ee7779b |
+
|
|
|
ee7779b |
qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type);
|
|
|
ee7779b |
if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) {
|
|
|
ee7779b |
;
|
|
|
ee7779b |
diff --git a/quotaio_xfs.h b/quotaio_xfs.h
|
|
|
ee7779b |
index cf89973..54725b0 100644
|
|
|
ee7779b |
--- a/quotaio_xfs.h
|
|
|
ee7779b |
+++ b/quotaio_xfs.h
|
|
|
ee7779b |
@@ -105,6 +105,15 @@ typedef struct fs_disk_quota {
|
|
|
ee7779b |
#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
|
|
|
ee7779b |
|
|
|
ee7779b |
/*
|
|
|
ee7779b |
+ * Accounting values. These can only be set for filesystem with
|
|
|
ee7779b |
+ * non-transactional quotas that require quotacheck(8) in userspace.
|
|
|
ee7779b |
+ */
|
|
|
ee7779b |
+#define FS_DQ_BCOUNT (1<<12)
|
|
|
ee7779b |
+#define FS_DQ_ICOUNT (1<<13)
|
|
|
ee7779b |
+#define FS_DQ_RTBCOUNT (1<<14)
|
|
|
ee7779b |
+#define FS_DQ_ACCT_MASK (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
|
|
|
ee7779b |
+
|
|
|
ee7779b |
+/*
|
|
|
ee7779b |
* Various flags related to quotactl(2). Only relevant to XFS filesystems.
|
|
|
ee7779b |
*/
|
|
|
ee7779b |
#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */
|
|
|
ee7779b |
--
|
|
|
ee7779b |
1.7.4
|
|
|
ee7779b |
|