xfs
[Top] [All Lists]

[PATCH 08/12] libxfs: introduce new superblock format

To: xfs@xxxxxxxxxxx
Subject: [PATCH 08/12] libxfs: introduce new superblock format
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Tue, 22 Jan 2013 00:53:07 +1100
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1358776391-22140-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1358776391-22140-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 include/xfs_buf_item.h |    4 +-
 include/xfs_mount.h    |    1 +
 include/xfs_sb.h       |  102 ++++++++++++++++++++++++++++++++++--------------
 libxfs/xfs_mount.c     |   81 ++++++++++++++++++++++++++++++++------
 4 files changed, 147 insertions(+), 41 deletions(-)

diff --git a/include/xfs_buf_item.h b/include/xfs_buf_item.h
index abae8c8..d1eeeab 100644
--- a/include/xfs_buf_item.h
+++ b/include/xfs_buf_item.h
@@ -49,6 +49,7 @@ extern kmem_zone_t    *xfs_buf_item_zone;
 #define XFS_BLF_AGFL_BUF       (1<<7)
 #define XFS_BLF_AGI_BUF                (1<<8)
 #define XFS_BLF_DINO_BUF       (1<<9)
+#define XFS_BLF_SB_BUF         (1<<10)
 
 #define XFS_BLF_TYPE_MASK      \
                (XFS_BLF_UDQUOT_BUF | \
@@ -58,7 +59,8 @@ extern kmem_zone_t    *xfs_buf_item_zone;
                 XFS_BLF_AGF_BUF | \
                 XFS_BLF_AGFL_BUF | \
                 XFS_BLF_AGI_BUF | \
-                XFS_BLF_DINO_BUF)
+                XFS_BLF_DINO_BUF | \
+                XFS_BLF_SB_BUF)
 
 #define        XFS_BLF_CHUNK           128
 #define        XFS_BLF_SHIFT           7
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 655866e..6cc1626 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -385,6 +385,7 @@ struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, 
xfs_agnumber_t agno,
                                        int tag);
 void   xfs_perag_put(struct xfs_perag *pag);
 
+extern void    xfs_sb_calc_crc(struct xfs_buf  *);
 extern void    xfs_mod_sb(struct xfs_trans *, __int64_t);
 extern int     xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
                                        xfs_agnumber_t *);
diff --git a/include/xfs_sb.h b/include/xfs_sb.h
index 6a7f8b0..1f8c1cd 100644
--- a/include/xfs_sb.h
+++ b/include/xfs_sb.h
@@ -32,6 +32,7 @@ struct xfs_mount;
 #define        XFS_SB_VERSION_2        2               /* 6.2 - attributes */
 #define        XFS_SB_VERSION_3        3               /* 6.2 - new inode 
version */
 #define        XFS_SB_VERSION_4        4               /* 6.2+ - bitmask 
version */
+#define        XFS_SB_VERSION_5        5               /* CRC enabled 
filesystem */
 #define        XFS_SB_VERSION_NUMBITS          0x000f
 #define        XFS_SB_VERSION_ALLFBITS         0xfff0
 #define        XFS_SB_VERSION_SASHFBITS        0xf000
@@ -161,6 +162,18 @@ typedef struct xfs_sb {
         */
        __uint32_t      sb_bad_features2;
 
+       /* version 5 superblock fields start here */
+
+       /* feature masks */
+       __uint32_t      sb_features_compat;
+       __uint32_t      sb_features_ro_compat;
+       __uint32_t      sb_features_incompat;
+
+       __uint32_t      sb_crc;         /* superblock crc */
+
+       xfs_ino_t       sb_pquotino;    /* project quota inode */
+       xfs_lsn_t       sb_lsn;         /* last write sequence */
+
        /* must be padded to 64 bit alignment */
 } xfs_sb_t;
 
@@ -229,7 +242,19 @@ typedef struct xfs_dsb {
         * for features2 bits. Easiest just to mark it bad and not use
         * it for anything else.
         */
-       __be32  sb_bad_features2;
+       __be32          sb_bad_features2;
+
+       /* version 5 superblock fields start here */
+
+       /* feature masks */
+       __be32          sb_features_compat;
+       __be32          sb_features_ro_compat;
+       __be32          sb_features_incompat;
+
+       __le32          sb_crc;         /* superblock crc */
+
+       __be64          sb_pquotino;    /* project quota inode */
+       __be64          sb_lsn;         /* last write sequence */
 
        /* must be padded to 64 bit alignment */
 } xfs_dsb_t;
@@ -250,7 +275,9 @@ typedef enum {
        XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
        XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
        XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
-       XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2,
+       XFS_SBS_FEATURES2, XFS_SBS_BAD_FEATURES2, XFS_SBS_FEATURES_COMPAT,
+       XFS_SBS_FEATURES_RO_COMPAT, XFS_SBS_FEATURES_INCOMPAT, XFS_SBS_CRC,
+       XFS_SBS_PQUOTINO, XFS_SBS_LSN,
        XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -276,6 +303,11 @@ typedef enum {
 #define XFS_SB_FDBLOCKS                XFS_SB_MVAL(FDBLOCKS)
 #define XFS_SB_FEATURES2       XFS_SB_MVAL(FEATURES2)
 #define XFS_SB_BAD_FEATURES2   XFS_SB_MVAL(BAD_FEATURES2)
+#define XFS_SB_FEATURES_COMPAT XFS_SB_MVAL(FEATURES_COMPAT)
+#define XFS_SB_FEATURES_RO_COMPAT XFS_SB_MVAL(FEATURES_RO_COMPAT)
+#define XFS_SB_FEATURES_INCOMPAT XFS_SB_MVAL(FEATURES_INCOMPAT)
+#define XFS_SB_CRC             XFS_SB_MVAL(CRC)
+#define XFS_SB_PQUOTINO                XFS_SB_MVAL(PQUOTINO)
 #define        XFS_SB_NUM_BITS         ((int)XFS_SBS_FIELDCOUNT)
 #define        XFS_SB_ALL_BITS         ((1LL << XFS_SB_NUM_BITS) - 1)
 #define        XFS_SB_MOD_BITS         \
@@ -283,7 +315,8 @@ typedef enum {
         XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
         XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
         XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2 | \
-        XFS_SB_BAD_FEATURES2)
+        XFS_SB_BAD_FEATURES2 | XFS_SB_FEATURES_COMPAT | \
+        XFS_SB_FEATURES_RO_COMPAT | XFS_SB_FEATURES_INCOMPAT | XFS_SB_PQUOTINO)
 
 
 /*
@@ -325,6 +358,10 @@ static inline int xfs_sb_good_version(xfs_sb_t *sbp)
 
                return 1;
        }
+#ifdef REMOVE_TO_ENABLE_CRC_SUPPORT
+       if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
+               return 1;
+#endif
 
        return 0;
 }
@@ -365,7 +402,7 @@ static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
 {
        return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
                sbp->sb_versionnum == XFS_SB_VERSION_3 ||
-               (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+               (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                 (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
 }
 
@@ -373,7 +410,7 @@ static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
 {
        if (sbp->sb_versionnum == XFS_SB_VERSION_1)
                sbp->sb_versionnum = XFS_SB_VERSION_2;
-       else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+       else if (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4)
                sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
        else
                sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
@@ -382,7 +419,7 @@ static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
 static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
 {
        return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
-                (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+                (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                  (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
 }
 
@@ -396,13 +433,13 @@ static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
 
 static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+       return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
 }
 
 static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
 {
-       if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
+       if (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4)
                sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
        else
                sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
@@ -411,13 +448,14 @@ static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
 
 static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
-               (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
+               (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT));
 }
 
 static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+       return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
 }
 
@@ -429,38 +467,42 @@ static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
 
 static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
-               (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+               (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT));
 }
 
 static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
-               (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
+               (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT));
 }
 
 static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
-               (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+               (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT));
 }
 
 static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+       return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
 }
 
 static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+       return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
                (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
 }
 
 static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
-               (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
+               (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT));
 }
 
 /*
@@ -475,14 +517,16 @@ static inline int xfs_sb_version_hasmorebits(xfs_sb_t 
*sbp)
 
 static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
 {
-       return xfs_sb_version_hasmorebits(sbp) &&
-               (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (xfs_sb_version_hasmorebits(sbp) &&
+               (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT));
 }
 
 static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
 {
-       return xfs_sb_version_hasmorebits(sbp) &&
-               (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (xfs_sb_version_hasmorebits(sbp) &&
+               (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT));
 }
 
 static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
@@ -500,8 +544,9 @@ static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
 
 static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
 {
-       return xfs_sb_version_hasmorebits(sbp) &&
-               (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT);
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
+              (xfs_sb_version_hasmorebits(sbp) &&
+               (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT));
 }
 
 static inline void xfs_sb_version_addprojid32bit(xfs_sb_t *sbp)
@@ -513,8 +558,7 @@ static inline void xfs_sb_version_addprojid32bit(xfs_sb_t 
*sbp)
 
 static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
 {
-       return (xfs_sb_version_hasmorebits(sbp) &&
-               (sbp->sb_features2 & XFS_SB_VERSION2_CRCBIT));
+       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
 }
 
 /*
diff --git a/libxfs/xfs_mount.c b/libxfs/xfs_mount.c
index e59ea78..ed8c770 100644
--- a/libxfs/xfs_mount.c
+++ b/libxfs/xfs_mount.c
@@ -70,6 +70,12 @@ static const struct {
     { offsetof(xfs_sb_t, sb_logsunit),  0 },
     { offsetof(xfs_sb_t, sb_features2),         0 },
     { offsetof(xfs_sb_t, sb_bad_features2), 0 },
+    { offsetof(xfs_sb_t, sb_features_compat), 0 },
+    { offsetof(xfs_sb_t, sb_features_ro_compat), 0 },
+    { offsetof(xfs_sb_t, sb_features_incompat), 0 },
+    { offsetof(xfs_sb_t, sb_crc),       0 },
+    { offsetof(xfs_sb_t, sb_pquotino),  0 },
+    { offsetof(xfs_sb_t, sb_lsn),       0 },
     { sizeof(xfs_sb_t),                         0 }
 };
 
@@ -264,6 +270,12 @@ xfs_sb_from_disk(
        to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
        to->sb_features2 = be32_to_cpu(from->sb_features2);
        to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
+       to->sb_features_compat = be32_to_cpu(from->sb_features_compat);
+       to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat);
+       to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
+       to->sb_crc = be32_to_cpu(from->sb_crc);
+       to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
+       to->sb_lsn = be64_to_cpu(from->sb_lsn);
 }
 
 /*
@@ -319,13 +331,12 @@ xfs_sb_to_disk(
        }
 }
 
-static void
+static int
 xfs_sb_verify(
        struct xfs_buf  *bp)
 {
        struct xfs_mount *mp = bp->b_target->bt_mount;
        struct xfs_sb   sb;
-       int             error;
 
        xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
 
@@ -333,16 +344,46 @@ xfs_sb_verify(
         * Only check the in progress field for the primary superblock as
         * mkfs.xfs doesn't clear it from secondary superblocks.
         */
-       error = xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR);
-       if (error)
-               xfs_buf_ioerror(bp, error);
+       return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR);
 }
 
+/*
+ * If the superblock has the CRC feature bit set or the CRC field is non-null,
+ * check that the CRC is valid.  We check the CRC field is non-null because a
+ * single bit error could clear the feature bit and unused parts of the
+ * superblock are supposed to be zero. Hence a non-null crc field indicates 
that
+ * we've potentially lost a feature bit and we should check it anyway.
+ */
 static void
 xfs_sb_read_verify(
        struct xfs_buf  *bp)
 {
-       xfs_sb_verify(bp);
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
+       int             error;
+
+       /*
+        * open code the version check to avoid needing to convert the entire
+        * superblock from disk order just to check the version number
+        */
+       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) &&
+           (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) ==
+                                               XFS_SB_VERSION_5) ||
+            dsb->sb_crc != 0)) {
+
+               if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
+                                     offsetof(struct xfs_sb, sb_crc))) {
+                       error = EFSCORRUPTED;
+                       goto out_error;
+               }
+       }
+       error = xfs_sb_verify(bp);
+
+out_error:
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 
bp->b_addr);
+               xfs_buf_ioerror(bp, error);
+       }
 }
 
 /*
@@ -355,11 +396,10 @@ static void
 xfs_sb_quiet_read_verify(
        struct xfs_buf  *bp)
 {
-       struct xfs_sb   sb;
+       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
 
-       xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
 
-       if (sb.sb_magicnum == XFS_SB_MAGIC) {
+       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
                /* XFS filesystem, verify noisily! */
                xfs_sb_read_verify(bp);
                return;
@@ -370,9 +410,27 @@ xfs_sb_quiet_read_verify(
 
 static void
 xfs_sb_write_verify(
-       struct xfs_buf  *bp)
+       struct xfs_buf          *bp)
 {
-       xfs_sb_verify(bp);
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       int                     error;
+
+       error = xfs_sb_verify(bp);
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 
bp->b_addr);
+               xfs_buf_ioerror(bp, error);
+               return;
+       }
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (bip)
+               XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        offsetof(struct xfs_sb, sb_crc));
 }
 
 const struct xfs_buf_ops xfs_sb_buf_ops = {
@@ -525,5 +583,6 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
        ASSERT((1LL << f) & XFS_SB_MOD_BITS);
        first = xfs_sb_info[f].offset;
 
+       xfs_trans_buf_set_type(tp, bp, XFS_BLF_SB_BUF);
        xfs_trans_log_buf(tp, bp, first, last);
 }
-- 
1.7.10

<Prev in Thread] Current Thread [Next in Thread>