Skip to content

Commit

Permalink
xfs: add CRC checking to dir2 leaf blocks
Browse files Browse the repository at this point in the history
This addition follows the same pattern as the dir2 block CRCs.
Seeing as both LEAF1 and LEAFN types need to changed at the same
time, this is a pretty large amount of change. leaf block headers
need to be abstracted away from the on-disk structures (struct
xfs_dir3_icleaf_hdr), as do the base leaf entry locations.

This header abstract allows the in-core header and leaf entry
location to be passed around instead of the leaf block itself. This
saves a lot of converting individual variables from on-disk format
to host format where they are used, so there's a good chance that
the compiler will be able to produce much more optimal code as it's
not having to byteswap variables all over the place.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Apr 27, 2013
1 parent 33363fe commit 24df33b
Show file tree
Hide file tree
Showing 7 changed files with 924 additions and 522 deletions.
45 changes: 35 additions & 10 deletions fs/xfs/xfs_da_btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ xfs_da_node_read_verify(
bp->b_ops->verify_read(bp);
return;
case XFS_DIR2_LEAFN_MAGIC:
bp->b_ops = &xfs_dir2_leafn_buf_ops;
case XFS_DIR3_LEAFN_MAGIC:
bp->b_ops = &xfs_dir3_leafn_buf_ops;
bp->b_ops->verify_read(bp);
return;
default:
Expand Down Expand Up @@ -396,11 +397,18 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] -
(char *)oldroot);
} else {
ASSERT(oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC));
struct xfs_dir3_icleaf_hdr leafhdr;
struct xfs_dir2_leaf_entry *ents;

leaf = (xfs_dir2_leaf_t *)oldroot;
size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] -
(char *)leaf);
xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
ents = xfs_dir3_leaf_ents_p(leaf);

ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC ||
leafhdr.magic == XFS_DIR3_LEAFN_MAGIC);
size = (int)((char *)&ents[leafhdr.count] - (char *)leaf);
}
/* XXX: can't just copy CRC headers from one block to another */
memcpy(node, oldroot, size);
xfs_trans_log_buf(tp, bp, 0, size - 1);

Expand All @@ -424,7 +432,8 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
node->hdr.count = cpu_to_be16(2);

#ifdef DEBUG
if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)) {
if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
ASSERT(blk1->blkno >= mp->m_dirleafblk &&
blk1->blkno < mp->m_dirfreeblk);
ASSERT(blk2->blkno >= mp->m_dirleafblk &&
Expand Down Expand Up @@ -782,6 +791,7 @@ xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level)

if (level == 1) {
ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
} else
ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
Expand Down Expand Up @@ -1565,6 +1575,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
info = blk->bp->b_addr;
ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) ||
info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) ||
info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
blk->magic = be16_to_cpu(info->magic);
if (blk->magic == XFS_DA_NODE_MAGIC) {
Expand All @@ -1584,12 +1595,13 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path,
NULL);
break;
case XFS_DIR2_LEAFN_MAGIC:
case XFS_DIR3_LEAFN_MAGIC:
blk->magic = XFS_DIR2_LEAFN_MAGIC;
blk->hashval = xfs_dir2_leafn_lasthash(blk->bp,
NULL);
break;
default:
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC ||
blk->magic == XFS_DIR2_LEAFN_MAGIC);
ASSERT(0);
break;
}
}
Expand Down Expand Up @@ -1833,10 +1845,16 @@ xfs_da_swap_lastblock(
/*
* Get values from the moved block.
*/
if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC)) {
if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
struct xfs_dir3_icleaf_hdr leafhdr;
struct xfs_dir2_leaf_entry *ents;

dead_leaf2 = (xfs_dir2_leaf_t *)dead_info;
xfs_dir3_leaf_hdr_from_disk(&leafhdr, dead_leaf2);
ents = xfs_dir3_leaf_ents_p(dead_leaf2);
dead_level = 0;
dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval);
dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval);
} else {
ASSERT(dead_info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
dead_node = (xfs_da_intnode_t *)dead_info;
Expand Down Expand Up @@ -2281,10 +2299,17 @@ xfs_da_read_buf(
XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
(magic != XFS_ATTR_LEAF_MAGIC) &&
(magic != XFS_DIR2_LEAF1_MAGIC) &&
(magic != XFS_DIR3_LEAF1_MAGIC) &&
(magic != XFS_DIR2_LEAFN_MAGIC) &&
(magic != XFS_DIR3_LEAFN_MAGIC) &&
(magic1 != XFS_DIR2_BLOCK_MAGIC) &&
(magic1 != XFS_DIR3_BLOCK_MAGIC) &&
(magic1 != XFS_DIR2_DATA_MAGIC) &&
(free->hdr.magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)),
(magic1 != XFS_DIR3_DATA_MAGIC) &&
(free->hdr.magic !=
cpu_to_be32(XFS_DIR2_FREE_MAGIC)) &&
(free->hdr.magic !=
cpu_to_be32(XFS_DIR3_FREE_MAGIC)),
mp, XFS_ERRTAG_DA_READ_BUF,
XFS_RANDOM_DA_READ_BUF))) {
trace_xfs_da_btree_corrupt(bp, _RET_IP_);
Expand Down
23 changes: 23 additions & 0 deletions fs/xfs/xfs_da_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,29 @@ typedef struct xfs_da_blkinfo {
__be16 pad; /* unused */
} xfs_da_blkinfo_t;

/*
* CRC enabled directory structure types
*
* The headers change size for the additional verification information, but
* otherwise the tree layouts and contents are unchanged.
*/
#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */
#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */

struct xfs_da3_blkinfo {
/*
* the node link manipulation code relies on the fact that the first
* element of this structure is the struct xfs_da_blkinfo so it can
* ignore the differences in the rest of the structures.
*/
struct xfs_da_blkinfo hdr;
__be32 crc; /* CRC of block */
__be64 blkno; /* first block of the buffer */
__be64 lsn; /* sequence number of last write */
uuid_t uuid; /* filesystem we belong to */
__be64 owner; /* inode that owns the block */
};

/*
* This is the structure of the root and intermediate nodes in the Btree.
* The leaf nodes are defined above.
Expand Down
19 changes: 12 additions & 7 deletions fs/xfs/xfs_dir2_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1013,15 +1013,21 @@ xfs_dir2_leaf_to_block(
__be16 *tagp; /* end of entry (tag) */
int to; /* block/leaf to index */
xfs_trans_t *tp; /* transaction pointer */
struct xfs_dir2_leaf_entry *ents;
struct xfs_dir3_icleaf_hdr leafhdr;

trace_xfs_dir2_leaf_to_block(args);

dp = args->dp;
tp = args->trans;
mp = dp->i_mount;
leaf = lbp->b_addr;
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC));
xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
ents = xfs_dir3_leaf_ents_p(leaf);
ltp = xfs_dir2_leaf_tail_p(mp, leaf);

ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
leafhdr.magic == XFS_DIR3_LEAF1_MAGIC);
/*
* If there are data blocks other than the first one, take this
* opportunity to remove trailing empty data blocks that may have
Expand Down Expand Up @@ -1058,7 +1064,7 @@ xfs_dir2_leaf_to_block(
* Size of the "leaf" area in the block.
*/
size = (uint)sizeof(xfs_dir2_block_tail_t) +
(uint)sizeof(*lep) * (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
(uint)sizeof(*lep) * (leafhdr.count - leafhdr.stale);
/*
* Look at the last data entry.
*/
Expand Down Expand Up @@ -1087,18 +1093,17 @@ xfs_dir2_leaf_to_block(
* Initialize the block tail.
*/
btp = xfs_dir2_block_tail_p(mp, hdr);
btp->count = cpu_to_be32(be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale);
btp->stale = 0;
xfs_dir2_block_log_tail(tp, dbp);
/*
* Initialize the block leaf area. We compact out stale entries.
*/
lep = xfs_dir2_block_leaf_p(btp);
for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
if (leaf->ents[from].address ==
cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
for (from = to = 0; from < leafhdr.count; from++) {
if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
continue;
lep[to++] = leaf->ents[from];
lep[to++] = ents[from];
}
ASSERT(to == be32_to_cpu(btp->count));
xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1);
Expand Down
60 changes: 53 additions & 7 deletions fs/xfs/xfs_dir2_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,21 @@ typedef struct xfs_dir2_leaf_hdr {
__be16 stale; /* count of stale entries */
} xfs_dir2_leaf_hdr_t;

struct xfs_dir3_leaf_hdr {
struct xfs_da3_blkinfo info; /* header for da routines */
__be16 count; /* count of entries */
__be16 stale; /* count of stale entries */
__be32 pad;
};

struct xfs_dir3_icleaf_hdr {
__uint32_t forw;
__uint32_t back;
__uint16_t magic;
__uint16_t count;
__uint16_t stale;
};

/*
* Leaf block entry.
*/
Expand All @@ -489,20 +504,47 @@ typedef struct xfs_dir2_leaf_tail {
* Leaf block.
*/
typedef struct xfs_dir2_leaf {
xfs_dir2_leaf_hdr_t hdr; /* leaf header */
xfs_dir2_leaf_entry_t ents[]; /* entries */
xfs_dir2_leaf_hdr_t hdr; /* leaf header */
xfs_dir2_leaf_entry_t __ents[]; /* entries */
} xfs_dir2_leaf_t;

/*
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/
struct xfs_dir3_leaf {
struct xfs_dir3_leaf_hdr hdr; /* leaf header */
struct xfs_dir2_leaf_entry __ents[]; /* entries */
};

#define XFS_DIR3_LEAF_CRC_OFF offsetof(struct xfs_dir3_leaf_hdr, info.crc)

static inline int
xfs_dir3_leaf_hdr_size(struct xfs_dir2_leaf *lp)
{
if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC))
return sizeof(struct xfs_dir3_leaf_hdr);
return sizeof(struct xfs_dir2_leaf_hdr);
}

static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
static inline int
xfs_dir3_max_leaf_ents(struct xfs_mount *mp, struct xfs_dir2_leaf *lp)
{
return (mp->m_dirblksize - (uint)sizeof(struct xfs_dir2_leaf_hdr)) /
return (mp->m_dirblksize - xfs_dir3_leaf_hdr_size(lp)) /
(uint)sizeof(struct xfs_dir2_leaf_entry);
}

/*
* Get address of the bestcount field in the single-leaf block.
*/
static inline struct xfs_dir2_leaf_entry *
xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp)
{
if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp;
return lp3->__ents;
}
return lp->__ents;
}

/*
* Get address of the bestcount field in the single-leaf block.
*/
Expand All @@ -523,6 +565,10 @@ xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp)
return (__be16 *)ltp - be32_to_cpu(ltp->bestcount);
}

/*
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/

/*
* Convert dataptr to byte in file space
*/
Expand Down
Loading

0 comments on commit 24df33b

Please sign in to comment.