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

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

xfs: add CRC checking to dir2 free blocks



This addition follows the same pattern as the dir2 block CRCs, but
with a few differences. The main difference is that the free block
header is different between the v2 and v3 formats, so an "in-core"
free block header has been added and _todisk/_from_disk functions
used to abstract the differences in structure format from the code.
This is similar to the on-disk superblock versus the in-core
superblock setup. The in-core strucutre is populated when the buffer
is read from disk, all the in memory checks and modifications are
done on the in-core version of the structure which is written back
to the buffer before the buffer is logged.

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 f5f3d9b0
Loading
Loading
Loading
Loading
+51 −4
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@

#define	XFS_DIR3_BLOCK_MAGIC	0x58444233	/* XDB3: single block dirs */
#define	XFS_DIR3_DATA_MAGIC	0x58444433	/* XDD3: multiblock dirs */
#define	XFS_DIR3_FREE_MAGIC	0x58444633	/* XDF3: free index blocks */

/*
 * Byte offset in data block and shortform entry.
@@ -663,19 +664,65 @@ typedef struct xfs_dir2_free {
						/* unused entries are -1 */
} xfs_dir2_free_t;

static inline int xfs_dir2_free_max_bests(struct xfs_mount *mp)
struct xfs_dir3_free_hdr {
	struct xfs_dir3_blk_hdr	hdr;
	__be32			firstdb;	/* db of first entry */
	__be32			nvalid;		/* count of valid entries */
	__be32			nused;		/* count of used entries */
};

struct xfs_dir3_free {
	struct xfs_dir3_free_hdr hdr;
	__be16			bests[];	/* best free counts */
						/* unused entries are -1 */
};

#define XFS_DIR3_FREE_CRC_OFF  offsetof(struct xfs_dir3_free, hdr.hdr.crc)

/*
 * In core version of the free block header, abstracted away from on-disk format
 * differences. Use this in the code, and convert to/from the disk version using
 * xfs_dir3_free_hdr_from_disk/xfs_dir3_free_hdr_to_disk.
 */
struct xfs_dir3_icfree_hdr {
	__uint32_t	magic;
	__uint32_t	firstdb;
	__uint32_t	nvalid;
	__uint32_t	nused;

};

void xfs_dir3_free_hdr_from_disk(struct xfs_dir3_icfree_hdr *to,
				 struct xfs_dir2_free *from);

static inline int
xfs_dir3_free_hdr_size(struct xfs_mount *mp)
{
	return (mp->m_dirblksize - sizeof(struct xfs_dir2_free_hdr)) /
	if (xfs_sb_version_hascrc(&mp->m_sb))
		return sizeof(struct xfs_dir3_free_hdr);
	return sizeof(struct xfs_dir2_free_hdr);
}

static inline int
xfs_dir3_free_max_bests(struct xfs_mount *mp)
{
	return (mp->m_dirblksize - xfs_dir3_free_hdr_size(mp)) /
		sizeof(xfs_dir2_data_off_t);
}

static inline __be16 *
xfs_dir3_free_bests_p(struct xfs_mount *mp, struct xfs_dir2_free *free)
{
	return (__be16 *)((char *)free + xfs_dir3_free_hdr_size(mp));
}

/*
 * Convert data space db to the corresponding free db.
 */
static inline xfs_dir2_db_t
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
{
	return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir2_free_max_bests(mp);
	return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir3_free_max_bests(mp);
}

/*
@@ -684,7 +731,7 @@ xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
static inline int
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
{
	return db % xfs_dir2_free_max_bests(mp);
	return db % xfs_dir3_free_max_bests(mp);
}

/*
+8 −7
Original line number Diff line number Diff line
@@ -1881,6 +1881,7 @@ xfs_dir2_node_to_leaf(
	xfs_mount_t		*mp;		/* filesystem mount point */
	int			rval;		/* successful free trim? */
	xfs_trans_t		*tp;		/* transaction pointer */
	struct xfs_dir3_icfree_hdr freehdr;

	/*
	 * There's more than a leaf level in the btree, so there must
@@ -1938,15 +1939,15 @@ xfs_dir2_node_to_leaf(
	if (error)
		return error;
	free = fbp->b_addr;
	ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
	ASSERT(!free->hdr.firstdb);
	xfs_dir3_free_hdr_from_disk(&freehdr, free);

	ASSERT(!freehdr.firstdb);

	/*
	 * Now see if the leafn and free data will fit in a leaf1.
	 * If not, release the buffer and give up.
	 */
	if (xfs_dir2_leaf_size(&leaf->hdr, be32_to_cpu(free->hdr.nvalid)) >
			mp->m_dirblksize) {
	if (xfs_dir2_leaf_size(&leaf->hdr, freehdr.nvalid) > mp->m_dirblksize) {
		xfs_trans_brelse(tp, fbp);
		return 0;
	}
@@ -1967,12 +1968,12 @@ xfs_dir2_node_to_leaf(
	 * Set up the leaf tail from the freespace block.
	 */
	ltp = xfs_dir2_leaf_tail_p(mp, leaf);
	ltp->bestcount = free->hdr.nvalid;
	ltp->bestcount = cpu_to_be32(freehdr.nvalid);
	/*
	 * Set up the leaf bests table.
	 */
	memcpy(xfs_dir2_leaf_bests_p(ltp), free->bests,
		be32_to_cpu(ltp->bestcount) * sizeof(xfs_dir2_data_off_t));
	memcpy(xfs_dir2_leaf_bests_p(ltp), xfs_dir3_free_bests_p(mp, free),
		freehdr.nvalid * sizeof(xfs_dir2_data_off_t));
	xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
	xfs_dir2_leaf_log_tail(tp, lbp);
	xfs_dir2_leaf_check(dp, lbp);
+323 −151

File changed.

Preview size limit exceeded, changes collapsed.