xfs: add CRC checking to dir2 data blocks
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_dir2_leaf.c
index 979735b0c76deef832ba7f5707567e5e6a88b0f5..c7dca950f768161f385988578522c9018f29efc3 100644 (file)
@@ -149,7 +149,7 @@ xfs_dir2_block_to_leaf(
        int                     needlog;        /* need to log block header */
        int                     needscan;       /* need to rescan bestfree */
        xfs_trans_t             *tp;            /* transaction pointer */
-       struct xfs_dir2_data_free       *bf;
+       struct xfs_dir2_data_free *bf;
 
        trace_xfs_dir2_block_to_leaf(args);
 
@@ -175,7 +175,7 @@ xfs_dir2_block_to_leaf(
        ASSERT(lbp != NULL);
        leaf = lbp->b_addr;
        hdr = dbp->b_addr;
-       xfs_dir2_data_check(dp, dbp);
+       xfs_dir3_data_check(dp, dbp);
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
        bf = xfs_dir3_data_bestfree_p(hdr);
@@ -204,8 +204,12 @@ xfs_dir2_block_to_leaf(
        /*
         * Fix up the block header, make it a data block.
         */
-       dbp->b_ops = &xfs_dir2_data_buf_ops;
-       hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
+       dbp->b_ops = &xfs_dir3_data_buf_ops;
+       if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
+               hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
+       else
+               hdr->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
+
        if (needscan)
                xfs_dir2_data_freescan(mp, hdr, &needlog);
        /*
@@ -221,7 +225,7 @@ xfs_dir2_block_to_leaf(
        if (needlog)
                xfs_dir2_data_log_header(tp, dbp);
        xfs_dir2_leaf_check(dp, lbp);
-       xfs_dir2_data_check(dp, dbp);
+       xfs_dir3_data_check(dp, dbp);
        xfs_dir2_leaf_log_bests(tp, lbp, 0, 0);
        return 0;
 }
@@ -385,6 +389,7 @@ xfs_dir2_leaf_addname(
        __be16                  *tagp;          /* end of data entry */
        xfs_trans_t             *tp;            /* transaction pointer */
        xfs_dir2_db_t           use_block;      /* data block number */
+       struct xfs_dir2_data_free *bf;          /* bestfree table */
 
        trace_xfs_dir2_leaf_addname(args);
 
@@ -568,14 +573,15 @@ xfs_dir2_leaf_addname(
                else
                        xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
                hdr = dbp->b_addr;
-               bestsp[use_block] = hdr->bestfree[0].length;
+               bf = xfs_dir3_data_bestfree_p(hdr);
+               bestsp[use_block] = bf[0].length;
                grown = 1;
        } else {
                /*
                 * Already had space in some data block.
                 * Just read that one in.
                 */
-               error = xfs_dir2_data_read(tp, dp,
+               error = xfs_dir3_data_read(tp, dp,
                                           xfs_dir2_db_to_da(mp, use_block),
                                           -1, &dbp);
                if (error) {
@@ -583,13 +589,14 @@ xfs_dir2_leaf_addname(
                        return error;
                }
                hdr = dbp->b_addr;
+               bf = xfs_dir3_data_bestfree_p(hdr);
                grown = 0;
        }
        /*
         * Point to the biggest freespace in our data block.
         */
        dup = (xfs_dir2_data_unused_t *)
-             ((char *)hdr + be16_to_cpu(hdr->bestfree[0].offset));
+             ((char *)hdr + be16_to_cpu(bf[0].offset));
        ASSERT(be16_to_cpu(dup->length) >= length);
        needscan = needlog = 0;
        /*
@@ -622,8 +629,8 @@ xfs_dir2_leaf_addname(
         * If the bests table needs to be changed, do it.
         * Log the change unless we've already done that.
         */
-       if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(hdr->bestfree[0].length)) {
-               bestsp[use_block] = hdr->bestfree[0].length;
+       if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) {
+               bestsp[use_block] = bf[0].length;
                if (!grown)
                        xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block);
        }
@@ -643,7 +650,7 @@ xfs_dir2_leaf_addname(
        xfs_dir2_leaf_log_header(tp, lbp);
        xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh);
        xfs_dir2_leaf_check(dp, lbp);
-       xfs_dir2_data_check(dp, dbp);
+       xfs_dir3_data_check(dp, dbp);
        return 0;
 }
 
@@ -967,7 +974,7 @@ xfs_dir2_leaf_readbuf(
         * Read the directory block starting at the first mapping.
         */
        mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
-       error = xfs_dir2_data_read(NULL, dp, map->br_startoff,
+       error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
                        map->br_blockcount >= mp->m_dirblkfsbs ?
                            XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
 
@@ -996,7 +1003,7 @@ xfs_dir2_leaf_readbuf(
                 */
                if (i > mip->ra_current &&
                    map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
-                       xfs_dir2_data_readahead(NULL, dp,
+                       xfs_dir3_data_readahead(NULL, dp,
                                map[mip->ra_index].br_startoff + mip->ra_offset,
                                XFS_FSB_TO_DADDR(mp,
                                        map[mip->ra_index].br_startblock +
@@ -1009,7 +1016,7 @@ xfs_dir2_leaf_readbuf(
                 * use our mapping, but this is a very rare case.
                 */
                else if (i > mip->ra_current) {
-                       xfs_dir2_data_readahead(NULL, dp,
+                       xfs_dir3_data_readahead(NULL, dp,
                                        map[mip->ra_index].br_startoff +
                                                        mip->ra_offset, -1);
                        mip->ra_current = i;
@@ -1135,17 +1142,17 @@ xfs_dir2_leaf_getdents(
                                ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
                                       map_info->curdb);
                        hdr = bp->b_addr;
-                       xfs_dir2_data_check(dp, bp);
+                       xfs_dir3_data_check(dp, bp);
                        /*
                         * Find our position in the block.
                         */
-                       ptr = (char *)(hdr + 1);
+                       ptr = (char *)xfs_dir3_data_entry_p(hdr);
                        byteoff = xfs_dir2_byte_to_off(mp, curoff);
                        /*
                         * Skip past the header.
                         */
                        if (byteoff == 0)
-                               curoff += (uint)sizeof(*hdr);
+                               curoff += xfs_dir3_data_entry_offset(hdr);
                        /*
                         * Skip past entries until we reach our offset.
                         */
@@ -1481,7 +1488,7 @@ xfs_dir2_leaf_lookup_int(
                if (newdb != curdb) {
                        if (dbp)
                                xfs_trans_brelse(tp, dbp);
-                       error = xfs_dir2_data_read(tp, dp,
+                       error = xfs_dir3_data_read(tp, dp,
                                                   xfs_dir2_db_to_da(mp, newdb),
                                                   -1, &dbp);
                        if (error) {
@@ -1522,7 +1529,7 @@ xfs_dir2_leaf_lookup_int(
                ASSERT(cidb != -1);
                if (cidb != curdb) {
                        xfs_trans_brelse(tp, dbp);
-                       error = xfs_dir2_data_read(tp, dp,
+                       error = xfs_dir3_data_read(tp, dp,
                                                   xfs_dir2_db_to_da(mp, cidb),
                                                   -1, &dbp);
                        if (error) {
@@ -1568,6 +1575,7 @@ xfs_dir2_leaf_removename(
        int                     needscan;       /* need to rescan data frees */
        xfs_dir2_data_off_t     oldbest;        /* old value of best free */
        xfs_trans_t             *tp;            /* transaction pointer */
+       struct xfs_dir2_data_free *bf;          /* bestfree table */
 
        trace_xfs_dir2_leaf_removename(args);
 
@@ -1582,7 +1590,8 @@ xfs_dir2_leaf_removename(
        mp = dp->i_mount;
        leaf = lbp->b_addr;
        hdr = dbp->b_addr;
-       xfs_dir2_data_check(dp, dbp);
+       bf = xfs_dir3_data_bestfree_p(hdr);
+       xfs_dir3_data_check(dp, dbp);
        /*
         * Point to the leaf entry, use that to point to the data entry.
         */
@@ -1591,7 +1600,7 @@ xfs_dir2_leaf_removename(
        dep = (xfs_dir2_data_entry_t *)
              ((char *)hdr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
        needscan = needlog = 0;
-       oldbest = be16_to_cpu(hdr->bestfree[0].length);
+       oldbest = be16_to_cpu(bf[0].length);
        ltp = xfs_dir2_leaf_tail_p(mp, leaf);
        bestsp = xfs_dir2_leaf_bests_p(ltp);
        ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
@@ -1620,16 +1629,16 @@ xfs_dir2_leaf_removename(
         * If the longest freespace in the data block has changed,
         * put the new value in the bests table and log that.
         */
-       if (be16_to_cpu(hdr->bestfree[0].length) != oldbest) {
-               bestsp[db] = hdr->bestfree[0].length;
+       if (be16_to_cpu(bf[0].length) != oldbest) {
+               bestsp[db] = bf[0].length;
                xfs_dir2_leaf_log_bests(tp, lbp, db, db);
        }
-       xfs_dir2_data_check(dp, dbp);
+       xfs_dir3_data_check(dp, dbp);
        /*
         * If the data block is now empty then get rid of the data block.
         */
-       if (be16_to_cpu(hdr->bestfree[0].length) ==
-           mp->m_dirblksize - (uint)sizeof(*hdr)) {
+       if (be16_to_cpu(bf[0].length) ==
+                       mp->m_dirblksize - xfs_dir3_data_entry_offset(hdr)) {
                ASSERT(db != mp->m_dirdatablk);
                if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {
                        /*
@@ -1809,7 +1818,7 @@ xfs_dir2_leaf_trim_data(
        /*
         * Read the offending data block.  We need its buffer.
         */
-       error = xfs_dir2_data_read(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp);
+       error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp);
        if (error)
                return error;
 
@@ -1819,10 +1828,12 @@ xfs_dir2_leaf_trim_data(
 #ifdef DEBUG
 {
        struct xfs_dir2_data_hdr *hdr = dbp->b_addr;
+       struct xfs_dir2_data_free *bf = xfs_dir3_data_bestfree_p(hdr);
 
-       ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC));
-       ASSERT(be16_to_cpu(hdr->bestfree[0].length) ==
-              mp->m_dirblksize - (uint)sizeof(*hdr));
+       ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
+              hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
+       ASSERT(be16_to_cpu(bf[0].length) ==
+              mp->m_dirblksize - xfs_dir3_data_entry_offset(hdr));
        ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
 }
 #endif