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