xfs: support the XFS_BTNUM_FINOBT free inode btree type
authorBrian Foster <bfoster@redhat.com>
Thu, 24 Apr 2014 06:00:52 +0000 (16:00 +1000)
committerDave Chinner <david@fromorbit.com>
Thu, 24 Apr 2014 06:00:52 +0000 (16:00 +1000)
Define the AGI fields for the finobt root/level and add magic
numbers. Update the btree code to add support for the new
XFS_BTNUM_FINOBT inode btree.

The finobt root block is reserved immediately following the inobt
root block in the AG. Update XFS_PREALLOC_BLOCKS() to determine the
starting AG data block based on whether finobt support is enabled.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/xfs_ag.h
fs/xfs/xfs_btree.c
fs/xfs/xfs_btree.h
fs/xfs/xfs_format.h
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_ialloc_btree.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_stats.c
fs/xfs/xfs_stats.h
fs/xfs/xfs_types.h

index 0fdd410..6e247a9 100644 (file)
@@ -160,30 +160,38 @@ typedef struct xfs_agi {
         * still being referenced.
         */
        __be32          agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
-
+       /*
+        * This marks the end of logging region 1 and start of logging region 2.
+        */
        uuid_t          agi_uuid;       /* uuid of filesystem */
        __be32          agi_crc;        /* crc of agi sector */
        __be32          agi_pad32;
        __be64          agi_lsn;        /* last write sequence */
 
+       __be32          agi_free_root; /* root of the free inode btree */
+       __be32          agi_free_level;/* levels in free inode btree */
+
        /* structure must be padded to 64 bit alignment */
 } xfs_agi_t;
 
 #define XFS_AGI_CRC_OFF                offsetof(struct xfs_agi, agi_crc)
 
-#define        XFS_AGI_MAGICNUM        0x00000001
-#define        XFS_AGI_VERSIONNUM      0x00000002
-#define        XFS_AGI_SEQNO           0x00000004
-#define        XFS_AGI_LENGTH          0x00000008
-#define        XFS_AGI_COUNT           0x00000010
-#define        XFS_AGI_ROOT            0x00000020
-#define        XFS_AGI_LEVEL           0x00000040
-#define        XFS_AGI_FREECOUNT       0x00000080
-#define        XFS_AGI_NEWINO          0x00000100
-#define        XFS_AGI_DIRINO          0x00000200
-#define        XFS_AGI_UNLINKED        0x00000400
-#define        XFS_AGI_NUM_BITS        11
-#define        XFS_AGI_ALL_BITS        ((1 << XFS_AGI_NUM_BITS) - 1)
+#define        XFS_AGI_MAGICNUM        (1 << 0)
+#define        XFS_AGI_VERSIONNUM      (1 << 1)
+#define        XFS_AGI_SEQNO           (1 << 2)
+#define        XFS_AGI_LENGTH          (1 << 3)
+#define        XFS_AGI_COUNT           (1 << 4)
+#define        XFS_AGI_ROOT            (1 << 5)
+#define        XFS_AGI_LEVEL           (1 << 6)
+#define        XFS_AGI_FREECOUNT       (1 << 7)
+#define        XFS_AGI_NEWINO          (1 << 8)
+#define        XFS_AGI_DIRINO          (1 << 9)
+#define        XFS_AGI_UNLINKED        (1 << 10)
+#define        XFS_AGI_NUM_BITS_R1     11      /* end of the 1st agi logging region */
+#define        XFS_AGI_ALL_BITS_R1     ((1 << XFS_AGI_NUM_BITS_R1) - 1)
+#define        XFS_AGI_FREE_ROOT       (1 << 11)
+#define        XFS_AGI_FREE_LEVEL      (1 << 12)
+#define        XFS_AGI_NUM_BITS_R2     13
 
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGI_DADDR(mp)      ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
index e80d59f..b920745 100644 (file)
@@ -43,9 +43,10 @@ kmem_zone_t  *xfs_btree_cur_zone;
  * Btree magic numbers.
  */
 static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
-       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
+       { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
+         XFS_FIBT_MAGIC },
        { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
-         XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
+         XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
 };
 #define xfs_btree_magic(cur) \
        xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
@@ -1115,6 +1116,7 @@ xfs_btree_set_refs(
                xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
                break;
        case XFS_BTNUM_INO:
+       case XFS_BTNUM_FINO:
                xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
                break;
        case XFS_BTNUM_BMAP:
index 91e34f2..d2ac586 100644 (file)
@@ -62,6 +62,7 @@ union xfs_btree_rec {
 #define        XFS_BTNUM_CNT   ((xfs_btnum_t)XFS_BTNUM_CNTi)
 #define        XFS_BTNUM_BMAP  ((xfs_btnum_t)XFS_BTNUM_BMAPi)
 #define        XFS_BTNUM_INO   ((xfs_btnum_t)XFS_BTNUM_INOi)
+#define        XFS_BTNUM_FINO  ((xfs_btnum_t)XFS_BTNUM_FINOi)
 
 /*
  * For logging record fields.
@@ -92,6 +93,7 @@ do {    \
        case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break;   \
        case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break;  \
        case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break;    \
+       case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break;  \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;       \
        }       \
 } while (0)
@@ -105,6 +107,7 @@ do {    \
        case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
        case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
        case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
+       case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
        case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break;       \
        }       \
 } while (0)
index 9898f31..34d85ac 100644 (file)
@@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t;
  */
 #define        XFS_IBT_MAGIC           0x49414254      /* 'IABT' */
 #define        XFS_IBT_CRC_MAGIC       0x49414233      /* 'IAB3' */
+#define        XFS_FIBT_MAGIC          0x46494254      /* 'FIBT' */
+#define        XFS_FIBT_CRC_MAGIC      0x46494233      /* 'FIB3' */
 
 typedef        __uint64_t      xfs_inofree_t;
 #define        XFS_INODES_PER_CHUNK            (NBBY * sizeof(xfs_inofree_t))
@@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t;
  * block numbers in the AG.
  */
 #define        XFS_IBT_BLOCK(mp)               ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
-#define        XFS_PREALLOC_BLOCKS(mp)         ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
+#define        XFS_FIBT_BLOCK(mp)              ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
+
+/*
+ * The first data block of an AG depends on whether the filesystem was formatted
+ * with the finobt feature. If so, account for the finobt reserved root btree
+ * block.
+ */
+#define XFS_PREALLOC_BLOCKS(mp) \
+       (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
+        XFS_FIBT_BLOCK(mp) + 1 : \
+        XFS_IBT_BLOCK(mp) + 1)
 
 
 
index e676572..a0aead5 100644 (file)
@@ -1488,7 +1488,16 @@ xfs_ialloc_compute_maxlevels(
 }
 
 /*
- * Log specified fields for the ag hdr (inode section)
+ * Log specified fields for the ag hdr (inode section). The growth of the agi
+ * structure over time requires that we interpret the buffer as two logical
+ * regions delineated by the end of the unlinked list. This is due to the size
+ * of the hash table and its location in the middle of the agi.
+ *
+ * For example, a request to log a field before agi_unlinked and a field after
+ * agi_unlinked could cause us to log the entire hash table and use an excessive
+ * amount of log space. To avoid this behavior, log the region up through
+ * agi_unlinked in one call and the region after agi_unlinked through the end of
+ * the structure in another.
  */
 void
 xfs_ialloc_log_agi(
@@ -1511,6 +1520,8 @@ xfs_ialloc_log_agi(
                offsetof(xfs_agi_t, agi_newino),
                offsetof(xfs_agi_t, agi_dirino),
                offsetof(xfs_agi_t, agi_unlinked),
+               offsetof(xfs_agi_t, agi_free_root),
+               offsetof(xfs_agi_t, agi_free_level),
                sizeof(xfs_agi_t)
        };
 #ifdef DEBUG
@@ -1519,15 +1530,30 @@ xfs_ialloc_log_agi(
        agi = XFS_BUF_TO_AGI(bp);
        ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
 #endif
+
+       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
+
        /*
-        * Compute byte offsets for the first and last fields.
+        * Compute byte offsets for the first and last fields in the first
+        * region and log the agi buffer. This only logs up through
+        * agi_unlinked.
         */
-       xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last);
+       if (fields & XFS_AGI_ALL_BITS_R1) {
+               xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1,
+                                 &first, &last);
+               xfs_trans_log_buf(tp, bp, first, last);
+       }
+
        /*
-        * Log the allocation group inode header buffer.
+        * Mask off the bits in the first region and calculate the first and
+        * last field offsets for any bits in the second region.
         */
-       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
-       xfs_trans_log_buf(tp, bp, first, last);
+       fields &= ~XFS_AGI_ALL_BITS_R1;
+       if (fields) {
+               xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2,
+                                 &first, &last);
+               xfs_trans_log_buf(tp, bp, first, last);
+       }
 }
 
 #ifdef DEBUG
index 41e4883..3789c6f 100644 (file)
@@ -67,6 +67,21 @@ xfs_inobt_set_root(
        xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
 }
 
+STATIC void
+xfs_finobt_set_root(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *nptr,
+       int                     inc)    /* level change */
+{
+       struct xfs_buf          *agbp = cur->bc_private.a.agbp;
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+
+       agi->agi_free_root = nptr->s;
+       be32_add_cpu(&agi->agi_free_level, inc);
+       xfs_ialloc_log_agi(cur->bc_tp, agbp,
+                          XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
+}
+
 STATIC int
 xfs_inobt_alloc_block(
        struct xfs_btree_cur    *cur,
@@ -174,6 +189,17 @@ xfs_inobt_init_ptr_from_cur(
        ptr->s = agi->agi_root;
 }
 
+STATIC void
+xfs_finobt_init_ptr_from_cur(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr)
+{
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
+
+       ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
+       ptr->s = agi->agi_free_root;
+}
+
 STATIC __int64_t
 xfs_inobt_key_diff(
        struct xfs_btree_cur    *cur,
@@ -204,6 +230,7 @@ xfs_inobt_verify(
         */
        switch (block->bb_magic) {
        case cpu_to_be32(XFS_IBT_CRC_MAGIC):
+       case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
                if (!xfs_sb_version_hascrc(&mp->m_sb))
                        return false;
                if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
@@ -215,6 +242,7 @@ xfs_inobt_verify(
                        return false;
                /* fall through */
        case cpu_to_be32(XFS_IBT_MAGIC):
+       case cpu_to_be32(XFS_FIBT_MAGIC):
                break;
        default:
                return 0;
@@ -318,6 +346,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
 #endif
 };
 
+static const struct xfs_btree_ops xfs_finobt_ops = {
+       .rec_len                = sizeof(xfs_inobt_rec_t),
+       .key_len                = sizeof(xfs_inobt_key_t),
+
+       .dup_cursor             = xfs_inobt_dup_cursor,
+       .set_root               = xfs_finobt_set_root,
+       .alloc_block            = xfs_inobt_alloc_block,
+       .free_block             = xfs_inobt_free_block,
+       .get_minrecs            = xfs_inobt_get_minrecs,
+       .get_maxrecs            = xfs_inobt_get_maxrecs,
+       .init_key_from_rec      = xfs_inobt_init_key_from_rec,
+       .init_rec_from_key      = xfs_inobt_init_rec_from_key,
+       .init_rec_from_cur      = xfs_inobt_init_rec_from_cur,
+       .init_ptr_from_cur      = xfs_finobt_init_ptr_from_cur,
+       .key_diff               = xfs_inobt_key_diff,
+       .buf_ops                = &xfs_inobt_buf_ops,
+#if defined(DEBUG) || defined(XFS_WARN)
+       .keys_inorder           = xfs_inobt_keys_inorder,
+       .recs_inorder           = xfs_inobt_recs_inorder,
+#endif
+};
+
 /*
  * Allocate a new inode btree cursor.
  */
@@ -336,11 +386,17 @@ xfs_inobt_init_cursor(
 
        cur->bc_tp = tp;
        cur->bc_mp = mp;
-       cur->bc_nlevels = be32_to_cpu(agi->agi_level);
        cur->bc_btnum = btnum;
+       if (btnum == XFS_BTNUM_INO) {
+               cur->bc_nlevels = be32_to_cpu(agi->agi_level);
+               cur->bc_ops = &xfs_inobt_ops;
+       } else {
+               cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
+               cur->bc_ops = &xfs_finobt_ops;
+       }
+
        cur->bc_blocklog = mp->m_sb.sb_blocklog;
 
-       cur->bc_ops = &xfs_inobt_ops;
        if (xfs_sb_version_hascrc(&mp->m_sb))
                cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
index bce53ac..f7843df 100644 (file)
@@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type(
                        bp->b_ops = &xfs_allocbt_buf_ops;
                        break;
                case XFS_IBT_CRC_MAGIC:
+               case XFS_FIBT_CRC_MAGIC:
                case XFS_IBT_MAGIC:
+               case XFS_FIBT_MAGIC:
                        bp->b_ops = &xfs_inobt_buf_ops;
                        break;
                case XFS_BMAP_CRC_MAGIC:
index ce372b7..f224038 100644 (file)
@@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
                { "abtc2",              XFSSTAT_END_ABTC_V2             },
                { "bmbt2",              XFSSTAT_END_BMBT_V2             },
                { "ibt2",               XFSSTAT_END_IBT_V2              },
+               { "fibt2",              XFSSTAT_END_FIBT_V2             },
                /* we print both series of quota information together */
                { "qm",                 XFSSTAT_END_QM                  },
        };
index c03ad38..c8f238b 100644 (file)
@@ -183,7 +183,23 @@ struct xfsstats {
        __uint32_t              xs_ibt_2_alloc;
        __uint32_t              xs_ibt_2_free;
        __uint32_t              xs_ibt_2_moves;
-#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_IBT_V2+6)
+#define XFSSTAT_END_FIBT_V2            (XFSSTAT_END_IBT_V2+15)
+       __uint32_t              xs_fibt_2_lookup;
+       __uint32_t              xs_fibt_2_compare;
+       __uint32_t              xs_fibt_2_insrec;
+       __uint32_t              xs_fibt_2_delrec;
+       __uint32_t              xs_fibt_2_newroot;
+       __uint32_t              xs_fibt_2_killroot;
+       __uint32_t              xs_fibt_2_increment;
+       __uint32_t              xs_fibt_2_decrement;
+       __uint32_t              xs_fibt_2_lshift;
+       __uint32_t              xs_fibt_2_rshift;
+       __uint32_t              xs_fibt_2_split;
+       __uint32_t              xs_fibt_2_join;
+       __uint32_t              xs_fibt_2_alloc;
+       __uint32_t              xs_fibt_2_free;
+       __uint32_t              xs_fibt_2_moves;
+#define XFSSTAT_END_XQMSTAT            (XFSSTAT_END_FIBT_V2+6)
        __uint32_t              xs_qm_dqreclaims;
        __uint32_t              xs_qm_dqreclaim_misses;
        __uint32_t              xs_qm_dquot_dups;
index 82bbc34..65c6e66 100644 (file)
@@ -134,7 +134,7 @@ typedef enum {
 
 typedef enum {
        XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
-       XFS_BTNUM_MAX
+       XFS_BTNUM_FINOi, XFS_BTNUM_MAX
 } xfs_btnum_t;
 
 struct xfs_name {