Skip to content

Commit

Permalink
xfs: add CRC checking to dir2 free blocks
Browse files Browse the repository at this point in the history
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: 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 f5f3d9b commit cbc8adf
Show file tree
Hide file tree
Showing 3 changed files with 382 additions and 162 deletions.
55 changes: 51 additions & 4 deletions fs/xfs/xfs_dir2_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

/*
Expand All @@ -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);
}

/*
Expand Down
15 changes: 8 additions & 7 deletions fs/xfs/xfs_dir2_leaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down
Loading

0 comments on commit cbc8adf

Please sign in to comment.