From ee7779bd8a7630c6415eb34c4fca07c8ca0969cd Mon Sep 17 00:00:00 2001 From: Petr Písař Date: Feb 04 2011 12:36:53 +0000 Subject: Implement quotacheck for GFS2 --- diff --git a/quota-4.00_pre1-Implement-quotacheck-for-GFS2.patch b/quota-4.00_pre1-Implement-quotacheck-for-GFS2.patch new file mode 100644 index 0000000..fddbfc4 --- /dev/null +++ b/quota-4.00_pre1-Implement-quotacheck-for-GFS2.patch @@ -0,0 +1,213 @@ +From fa920711b4bbb9e61358a7f488f0a645ef221321 Mon Sep 17 00:00:00 2001 +From: Abhijith Das +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 + +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 + diff --git a/quota.spec b/quota.spec index e7f18db..e47963a 100644 --- a/quota.spec +++ b/quota.spec @@ -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 - 1:4.00-0.5.pre1 - Correct manual pages