[PATCH v8 3/5] xfs: Start using pquotaino from the superblock

Chandra Seetharaman
2013-05-10T21:21:48Z

Define a macro to check if the superblock has pquotino.

Keep backward compatibilty by alowing mount of older superblock
with no separate pquota inode.
---
fs/xfs/xfs_itable.c | 3 +-
fs/xfs/xfs_mount.c | 117 ++++++++++++++++++++++++++++++----------
fs/xfs/xfs_qm.c | 29 +++++-----
fs/xfs/xfs_qm_syscalls.c | 32 +++++++++---
fs/xfs/xfs_quota.h | 8 ---
fs/xfs/xfs_sb.h | 5 ++
fs/xfs/xfs_super.c | 14 +++--
fs/xfs/xfs_trans_dquot.c | 4 +-
include/uapi/linux/dqblk_xfs.h | 1 +
9 files changed, 148 insertions(+), 65 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 2ea7d40..d80d58c 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -43,7 +43,8 @@ xfs_internal_inum(
{
return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
(xfs_sb_version_hasquota(&mp->m_sb) &&
- (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
+ (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino ||
+ ino == mp->m_sb.sb_pquotino)));
}

/*
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 1b79906..233f88e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -601,21 +601,6 @@ xfs_sb_from_disk(
to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
to->sb_qflags = be16_to_cpu(from->sb_qflags);
- if ((to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
- (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
- XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
- xfs_notice(NULL, "Super block has XFS_OQUOTA bits along with "
- "XFS_PQUOTA and/or XFS_GQUOTA bits. Quota check forced.\n");
- force_quota_check = true;
- }
- if (to->sb_qflags & XFS_OQUOTA_ENFD)
- to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
- XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
- if (to->sb_qflags & XFS_OQUOTA_CHKD)
- to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
- XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
- to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
-
to->sb_flags = from->sb_flags;
to->sb_shared_vn = from->sb_shared_vn;
to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
@@ -636,6 +621,44 @@ xfs_sb_from_disk(
to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
to->sb_lsn = be64_to_cpu(from->sb_lsn);

+ if (xfs_sb_version_has_pquota(to)) {
+ if (to->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
+ xfs_notice(NULL, "Super block has XFS_OQUOTA bits "
+ "with version PQUOTINO. Quota check forced.\n");
+ to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+ force_quota_check = true;
+ }
+ to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
+ } else {
+ if (to->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+ XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
+ xfs_notice(NULL, "Super block has XFS_[G|P]UOTA "
+ "bits in version older than PQUOTINO. "
+ "Quota check forced.\n");
+
+ to->sb_qflags &= ~(XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+ XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD);
+ force_quota_check = true;
+ }
+
+ /*
+ * On disk superblock qflags uses XFS_OQUOTA.* to support
+ * either PQUOTA or GQUOTA. But, in memory qflags uses
+ * XFS_PQUOTA.* or XFS_GQUOTA.* depending on which quota
+ * is used.
+ * Following block translates XFS_OQUOTA.* to either
+ * GQUOTA or PQUOTA.
+ */
+ if (to->sb_qflags & XFS_OQUOTA_ENFD)
+ to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+ XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
+ if (to->sb_qflags & XFS_OQUOTA_CHKD)
+ to->sb_qflags |= (to->sb_qflags & XFS_PQUOTA_ACCT) ?
+ XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
+ to->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+
+ }
+
if (force_quota_check)
to->sb_qflags &= ~(XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD);
}
@@ -657,27 +680,51 @@ xfs_sb_to_disk(
int first;
int size;
__uint16_t qflags = from->sb_qflags;
+ xfs_ino_t gquotino = from->sb_gquotino;

ASSERT(fields);
if (!fields)
return;

- if (fields & XFS_SB_QFLAGS) {
+ if (!xfs_sb_version_has_pquota(from)) {
+ if (fields & XFS_SB_QFLAGS) {
+ /*
+ * The in-core version of sb_qflags do not have
+ * XFS_OQUOTA_* flags, whereas the on-disk version
+ * does. So, convert incore XFS_{PG}QUOTA_* flags
+ * to on-disk XFS_OQUOTA_* flags.
+ */
+ qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+ XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+
+ if (from->sb_qflags &
+ (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
+ qflags |= XFS_OQUOTA_ENFD;
+ if (from->sb_qflags &
+ (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
+ qflags |= XFS_OQUOTA_CHKD;
+ }
+
/*
- * The in-core version of sb_qflags do not have
- * XFS_OQUOTA_* flags, whereas the on-disk version
- * does. So, convert incore XFS_{PG}QUOTA_* flags
- * to on-disk XFS_OQUOTA_* flags.
+ * On-disk version earlier than pquota doesn't have
+ * sb_pquotino. so, we need to copy the value to gquotino.
*/
- qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
- XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+ if (fields & XFS_SB_PQUOTINO) {
+ fields &= (__int64_t)~XFS_SB_PQUOTINO;
+ fields |= (__int64_t)XFS_SB_GQUOTINO;
+ gquotino = from->sb_pquotino;
+ }

- if (from->sb_qflags &
- (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
- qflags |= XFS_OQUOTA_ENFD;
- if (from->sb_qflags &
- (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
- qflags |= XFS_OQUOTA_CHKD;
+ /* If any quota inodes are written, write all quota inodes */
+ if (fields & (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO))
+ fields |= (XFS_SB_UQUOTINO|XFS_SB_GQUOTINO);
+
+ } else {
+ /* If any quota inodes are written, write all quota inodes */
+ if (fields & (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
+ | XFS_SB_PQUOTINO))
+ fields |= (XFS_SB_UQUOTINO | XFS_SB_GQUOTINO
+ | XFS_SB_PQUOTINO);
}

while (fields) {
@@ -691,6 +738,8 @@ xfs_sb_to_disk(
memcpy(to_ptr + first, from_ptr + first, size);
} else if (f == XFS_SBS_QFLAGS) {
*(__be16 *)(to_ptr + first) = cpu_to_be16(qflags);
+ } else if (f == XFS_SBS_GQUOTINO) {
+ *(__be64 *)(to_ptr + first) = cpu_to_be64(gquotino);
} else {
switch (size) {
case 2:
@@ -872,6 +921,18 @@ reread:
*/
xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));

+ if (!xfs_sb_version_has_pquota(&mp->m_sb) && XFS_IS_PQUOTA_ON(mp)) {
+ /*
+ * On disk superblock only has sb_gquotino, and in memory
+ * superblock has both sb_gquotino and sb_pquotino. But,
+ * only one them is supported at any point of time.
+ * So, if PQUOTA is set in disk superblock, copy over
+ * sb_gquotino to sb_pquotino.
+ */
+ mp->m_sb.sb_pquotino = mp->m_sb.sb_gquotino;
+ mp->m_sb.sb_gquotino = NULLFSINO;
+ }
+
/*
* We must be able to do sector-sized and sector-aligned IO.
*/
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 97912cb..41ccc3c 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -516,7 +516,8 @@ xfs_qm_need_dqattach(
if (!XFS_NOT_DQATTACHED(mp, ip))
return false;
if (ip->i_ino == mp->m_sb.sb_uquotino ||
- ip->i_ino == mp->m_sb.sb_gquotino)
+ ip->i_ino == mp->m_sb.sb_gquotino ||
+ ip->i_ino == mp->m_sb.sb_pquotino)
return false;
return true;
}
@@ -651,6 +652,7 @@ xfs_qm_dqdetach(

ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
+ ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_pquotino);
if (ip->i_udquot) {
xfs_qm_dqrele(ip->i_udquot);
ip->i_udquot = NULL;
@@ -858,22 +860,21 @@ xfs_qm_qino_alloc(
spin_lock(&mp->m_sb_lock);
if (flags & XFS_QMOPT_SBVERSION) {
ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
- ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
- XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
- (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
- XFS_SB_GQUOTINO | XFS_SB_QFLAGS));

xfs_sb_version_addquota(&mp->m_sb);
mp->m_sb.sb_uquotino = NULLFSINO;
mp->m_sb.sb_gquotino = NULLFSINO;
+ mp->m_sb.sb_pquotino = NULLFSINO;

/* qflags will get updated _after_ quotacheck */
mp->m_sb.sb_qflags = 0;
}
if (flags & XFS_QMOPT_UQUOTA)
mp->m_sb.sb_uquotino = (*ip)->i_ino;
- else
+ else if (flags & XFS_QMOPT_GQUOTA)
mp->m_sb.sb_gquotino = (*ip)->i_ino;
+ else
+ mp->m_sb.sb_pquotino = (*ip)->i_ino;
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, sbfields);

@@ -1185,7 +1186,9 @@ xfs_qm_dqusage_adjust(
* rootino must have its resources accounted for, not so with the quota
* inodes.
*/
- if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
+ if (ino == mp->m_sb.sb_uquotino ||
+ ino == mp->m_sb.sb_gquotino ||
+ ino == mp->m_sb.sb_pquotino) {
*res = BULKSTAT_RV_NOTHING;
return XFS_ERROR(EINVAL);
}
@@ -1466,19 +1469,17 @@ xfs_qm_init_quotainos(
if (error)
goto error_rele;
}
- /* Use sb_gquotino for now */
if (XFS_IS_PQUOTA_ON(mp) &&
- mp->m_sb.sb_gquotino != NULLFSINO) {
- ASSERT(mp->m_sb.sb_gquotino > 0);
- error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+ mp->m_sb.sb_pquotino != NULLFSINO) {
+ ASSERT(mp->m_sb.sb_pquotino > 0);
+ error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
0, 0, &pip);
if (error)
goto error_rele;
}
} else {
flags |= XFS_QMOPT_SBVERSION;
- sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
- XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+ sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_QFLAGS);
}

/*
@@ -1505,7 +1506,7 @@ xfs_qm_init_quotainos(
}
if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
error = xfs_qm_qino_alloc(mp, &pip,
- sbflags | XFS_SB_GQUOTINO,
+ sbflags | XFS_SB_PQUOTINO,
flags | XFS_QMOPT_PQUOTA);
if (error)
goto error_rele;
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 9bec772..65c0a7d 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -201,8 +201,7 @@ xfs_qm_scall_quotaoff(
/*
* If quotas is completely disabled, close shop.
*/
- if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
- ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
+ if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) {
mutex_unlock(&q->qi_quotaofflock);
xfs_qm_destroy_quotainfo(mp);
return (0);
@@ -297,8 +296,10 @@ xfs_qm_scall_trunc_qfiles(

if (flags & XFS_DQ_USER)
error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
- if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+ if (flags & XFS_DQ_GROUP)
error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
+ if (flags & XFS_DQ_PROJ)
+ error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);

return error ? error : error2;
}
@@ -412,17 +413,20 @@ xfs_qm_scall_getqstat(
struct fs_quota_stat *out)
{
struct xfs_quotainfo *q = mp->m_quotainfo;
- struct xfs_inode *uip, *gip;
- bool tempuqip, tempgqip;
+ struct xfs_inode *uip = NULL;
+ struct xfs_inode *gip = NULL;
+ struct xfs_inode *pip = NULL;
+ bool tempuqip = false;
+ bool tempgqip = false;
+ bool temppqip = false;

- uip = gip = NULL;
- tempuqip = tempgqip = false;
memset(out, 0, sizeof(fs_quota_stat_t));

out->qs_version = FS_QSTAT_VERSION;
if (!xfs_sb_version_hasquota(&mp->m_sb)) {
out->qs_uquota.qfs_ino = NULLFSINO;
out->qs_gquota.qfs_ino = NULLFSINO;
+ out->qs_pquota.qfs_ino = NULLFSINO;
return (0);
}
out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
@@ -431,10 +435,13 @@ xfs_qm_scall_getqstat(
out->qs_pad = 0;
out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+ if (&out->qs_gquota != &out->qs_pquota)
+ out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;

if (q) {
uip = q->qi_uquotaip;
gip = q->qi_gquotaip;
+ pip = q->qi_pquotaip;
}
if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
@@ -446,6 +453,11 @@ xfs_qm_scall_getqstat(
0, 0, &gip) == 0)
tempgqip = true;
}
+ if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+ if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+ 0, 0, &pip) == 0)
+ temppqip = true;
+ }
if (uip) {
out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
@@ -458,6 +470,12 @@ xfs_qm_scall_getqstat(
if (tempgqip)
IRELE(gip);
}
+ if (pip) {
+ out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
+ out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
+ if (temppqip)
+ IRELE(pip);
+ }
if (q) {
out->qs_incoredqs = q->qi_dquots;
out->qs_btimelimit = q->qi_btimelimit;
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index fe46c0c..be51581 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -285,14 +285,6 @@ typedef struct xfs_qoff_logformat {
(XFS_IS_PQUOTA_ON(mp) && \
(mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))

-#define XFS_MOUNT_QUOTA_SET1 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
- XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
- XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD)
-
-#define XFS_MOUNT_QUOTA_SET2 (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
- XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
- XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)
-
#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
XFS_PQUOTA_ENFD|XFS_PQUOTA_CHKD|\
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index 2de58a8..3745b73 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -618,6 +618,11 @@ xfs_sb_has_incompat_log_feature(
return (sbp->sb_features_log_incompat & feature) != 0;
}

+static inline int xfs_sb_version_has_pquota(xfs_sb_t *sbp)
+{
+ return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
+}
+
/*
* end of superblock version macros
*/
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 5feac04..01019d9 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -420,12 +420,6 @@ xfs_parseargs(
}
#endif

- if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
- (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
- xfs_warn(mp, "cannot mount with both project and group quota");
- return EINVAL;
- }
-
if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
xfs_warn(mp, "sunit and swidth must be specified together");
return EINVAL;
@@ -1388,6 +1382,14 @@ xfs_finish_flags(
return XFS_ERROR(EROFS);
}

+ if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
+ (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
+ !xfs_sb_version_has_pquota(&mp->m_sb)) {
+ xfs_warn(mp, "Super block does not support "
+ "project and group quota together");
+ return XFS_ERROR(EINVAL);
+ }
+
return 0;
}

diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 2bbad13..fee905b 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -157,7 +157,8 @@ xfs_trans_mod_dquot_byino(
if (!XFS_IS_QUOTA_RUNNING(mp) ||
!XFS_IS_QUOTA_ON(mp) ||
ip->i_ino == mp->m_sb.sb_uquotino ||
- ip->i_ino == mp->m_sb.sb_gquotino)
+ ip->i_ino == mp->m_sb.sb_gquotino ||
+ ip->i_ino == mp->m_sb.sb_pquotino)
return;

if (tp->t_dqinfo == NULL)
@@ -825,6 +826,7 @@ xfs_trans_reserve_quota_nblks(

ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
+ ASSERT(ip->i_ino != mp->m_sb.sb_pquotino);

ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
diff --git a/include/uapi/linux/dqblk_xfs.h b/include/uapi/linux/dqblk_xfs.h
index 8655280..f17e3bb 100644
--- a/include/uapi/linux/dqblk_xfs.h
+++ b/include/uapi/linux/dqblk_xfs.h
@@ -155,6 +155,7 @@ typedef struct fs_quota_stat {
__s8 qs_pad; /* unused */
fs_qfilestat_t qs_uquota; /* user quota storage information */
fs_qfilestat_t qs_gquota; /* group quota storage information */
+#define qs_pquota qs_gquota
__u32 qs_incoredqs; /* number of dquots incore */
__s32 qs_btimelimit; /* limit for blks timer */
__s32 qs_itimelimit; /* limit for inodes timer */
--
1.7.1