Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24df33b4 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

xfs: add CRC checking to dir2 leaf blocks



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: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 33363fee
Loading
Loading
Loading
Loading
+35 −10
Original line number Diff line number Diff line
@@ -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:
@@ -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);

@@ -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 &&
@@ -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));
@@ -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) {
@@ -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;
			}
		}
@@ -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;
@@ -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_);
+23 −0
Original line number Diff line number Diff line
@@ -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.
+12 −7
Original line number Diff line number Diff line
@@ -1013,6 +1013,8 @@ 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);

@@ -1020,8 +1022,12 @@ xfs_dir2_leaf_to_block(
	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
@@ -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.
	 */
@@ -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);
+53 −7
Original line number Diff line number Diff line
@@ -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.
 */
@@ -490,19 +505,46 @@ typedef struct xfs_dir2_leaf_tail {
 */
typedef struct xfs_dir2_leaf {
	xfs_dir2_leaf_hdr_t	hdr;			/* leaf header */
	xfs_dir2_leaf_entry_t	ents[];		/* entries */
	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.
 */
@@ -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
 */
+504 −288

File changed.

Preview size limit exceeded, changes collapsed.

Loading