You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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: Dave Chinner <dchinner@redhat.com> Reviewed-by: Ben Myers <bpm@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
@@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */
|
#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */
|
||||||
#define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock 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.
|
* Byte offset in data block and shortform entry.
|
||||||
@@ -663,19 +664,65 @@ typedef struct xfs_dir2_free {
|
|||||||
/* unused entries are -1 */
|
/* unused entries are -1 */
|
||||||
} xfs_dir2_free_t;
|
} 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);
|
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.
|
* Convert data space db to the corresponding free db.
|
||||||
*/
|
*/
|
||||||
static inline xfs_dir2_db_t
|
static inline xfs_dir2_db_t
|
||||||
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
|
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
|
static inline int
|
||||||
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1881,6 +1881,7 @@ xfs_dir2_node_to_leaf(
|
|||||||
xfs_mount_t *mp; /* filesystem mount point */
|
xfs_mount_t *mp; /* filesystem mount point */
|
||||||
int rval; /* successful free trim? */
|
int rval; /* successful free trim? */
|
||||||
xfs_trans_t *tp; /* transaction pointer */
|
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
|
* There's more than a leaf level in the btree, so there must
|
||||||
@@ -1938,15 +1939,15 @@ xfs_dir2_node_to_leaf(
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
free = fbp->b_addr;
|
free = fbp->b_addr;
|
||||||
ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC));
|
xfs_dir3_free_hdr_from_disk(&freehdr, free);
|
||||||
ASSERT(!free->hdr.firstdb);
|
|
||||||
|
ASSERT(!freehdr.firstdb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now see if the leafn and free data will fit in a leaf1.
|
* Now see if the leafn and free data will fit in a leaf1.
|
||||||
* If not, release the buffer and give up.
|
* If not, release the buffer and give up.
|
||||||
*/
|
*/
|
||||||
if (xfs_dir2_leaf_size(&leaf->hdr, be32_to_cpu(free->hdr.nvalid)) >
|
if (xfs_dir2_leaf_size(&leaf->hdr, freehdr.nvalid) > mp->m_dirblksize) {
|
||||||
mp->m_dirblksize) {
|
|
||||||
xfs_trans_brelse(tp, fbp);
|
xfs_trans_brelse(tp, fbp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1967,12 +1968,12 @@ xfs_dir2_node_to_leaf(
|
|||||||
* Set up the leaf tail from the freespace block.
|
* Set up the leaf tail from the freespace block.
|
||||||
*/
|
*/
|
||||||
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
|
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.
|
* Set up the leaf bests table.
|
||||||
*/
|
*/
|
||||||
memcpy(xfs_dir2_leaf_bests_p(ltp), free->bests,
|
memcpy(xfs_dir2_leaf_bests_p(ltp), xfs_dir3_free_bests_p(mp, free),
|
||||||
be32_to_cpu(ltp->bestcount) * sizeof(xfs_dir2_data_off_t));
|
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_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
|
||||||
xfs_dir2_leaf_log_tail(tp, lbp);
|
xfs_dir2_leaf_log_tail(tp, lbp);
|
||||||
xfs_dir2_leaf_check(dp, lbp);
|
xfs_dir2_leaf_check(dp, lbp);
|
||||||
|
|||||||
+330
-158
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user