diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_rmap_btree.c')
| -rw-r--r-- | fs/xfs/libxfs/xfs_rmap_btree.c | 102 | 
1 files changed, 76 insertions, 26 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c index d3285684bb5e..6c81b20e97d2 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.c +++ b/fs/xfs/libxfs/xfs_rmap_btree.c @@ -156,6 +156,16 @@ xfs_rmapbt_get_maxrecs(  	return cur->bc_mp->m_rmap_mxr[level != 0];  } +/* + * Convert the ondisk record's offset field into the ondisk key's offset field. + * Fork and bmbt are significant parts of the rmap record key, but written + * status is merely a record attribute. + */ +static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec) +{ +	return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN); +} +  STATIC void  xfs_rmapbt_init_key_from_rec(  	union xfs_btree_key		*key, @@ -163,7 +173,7 @@ xfs_rmapbt_init_key_from_rec(  {  	key->rmap.rm_startblock = rec->rmap.rm_startblock;  	key->rmap.rm_owner = rec->rmap.rm_owner; -	key->rmap.rm_offset = rec->rmap.rm_offset; +	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);  }  /* @@ -186,7 +196,7 @@ xfs_rmapbt_init_high_key_from_rec(  	key->rmap.rm_startblock = rec->rmap.rm_startblock;  	be32_add_cpu(&key->rmap.rm_startblock, adj);  	key->rmap.rm_owner = rec->rmap.rm_owner; -	key->rmap.rm_offset = rec->rmap.rm_offset; +	key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);  	if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||  	    XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))  		return; @@ -219,6 +229,16 @@ xfs_rmapbt_init_ptr_from_cur(  	ptr->s = agf->agf_roots[cur->bc_btnum];  } +/* + * Mask the appropriate parts of the ondisk key field for a key comparison. + * Fork and bmbt are significant parts of the rmap record key, but written + * status is merely a record attribute. + */ +static inline uint64_t offset_keymask(uint64_t offset) +{ +	return offset & ~XFS_RMAP_OFF_UNWRITTEN; +} +  STATIC int64_t  xfs_rmapbt_key_diff(  	struct xfs_btree_cur		*cur, @@ -240,8 +260,8 @@ xfs_rmapbt_key_diff(  	else if (y > x)  		return -1; -	x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset)); -	y = rec->rm_offset; +	x = offset_keymask(be64_to_cpu(kp->rm_offset)); +	y = offset_keymask(xfs_rmap_irec_offset_pack(rec));  	if (x > y)  		return 1;  	else if (y > x) @@ -253,31 +273,43 @@ STATIC int64_t  xfs_rmapbt_diff_two_keys(  	struct xfs_btree_cur		*cur,  	const union xfs_btree_key	*k1, -	const union xfs_btree_key	*k2) +	const union xfs_btree_key	*k2, +	const union xfs_btree_key	*mask)  {  	const struct xfs_rmap_key	*kp1 = &k1->rmap;  	const struct xfs_rmap_key	*kp2 = &k2->rmap;  	int64_t				d;  	__u64				x, y; +	/* Doesn't make sense to mask off the physical space part */ +	ASSERT(!mask || mask->rmap.rm_startblock); +  	d = (int64_t)be32_to_cpu(kp1->rm_startblock) - -		       be32_to_cpu(kp2->rm_startblock); +		     be32_to_cpu(kp2->rm_startblock);  	if (d)  		return d; -	x = be64_to_cpu(kp1->rm_owner); -	y = be64_to_cpu(kp2->rm_owner); -	if (x > y) -		return 1; -	else if (y > x) -		return -1; +	if (!mask || mask->rmap.rm_owner) { +		x = be64_to_cpu(kp1->rm_owner); +		y = be64_to_cpu(kp2->rm_owner); +		if (x > y) +			return 1; +		else if (y > x) +			return -1; +	} + +	if (!mask || mask->rmap.rm_offset) { +		/* Doesn't make sense to allow offset but not owner */ +		ASSERT(!mask || mask->rmap.rm_owner); + +		x = offset_keymask(be64_to_cpu(kp1->rm_offset)); +		y = offset_keymask(be64_to_cpu(kp2->rm_offset)); +		if (x > y) +			return 1; +		else if (y > x) +			return -1; +	} -	x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset)); -	y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset)); -	if (x > y) -		return 1; -	else if (y > x) -		return -1;  	return 0;  } @@ -387,8 +419,8 @@ xfs_rmapbt_keys_inorder(  		return 1;  	else if (a > b)  		return 0; -	a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset)); -	b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset)); +	a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset)); +	b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));  	if (a <= b)  		return 1;  	return 0; @@ -417,13 +449,33 @@ xfs_rmapbt_recs_inorder(  		return 1;  	else if (a > b)  		return 0; -	a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset)); -	b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset)); +	a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset)); +	b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));  	if (a <= b)  		return 1;  	return 0;  } +STATIC enum xbtree_key_contig +xfs_rmapbt_keys_contiguous( +	struct xfs_btree_cur		*cur, +	const union xfs_btree_key	*key1, +	const union xfs_btree_key	*key2, +	const union xfs_btree_key	*mask) +{ +	ASSERT(!mask || mask->rmap.rm_startblock); + +	/* +	 * We only support checking contiguity of the physical space component. +	 * If any callers ever need more specificity than that, they'll have to +	 * implement it here. +	 */ +	ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset)); + +	return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock), +				 be32_to_cpu(key2->rmap.rm_startblock)); +} +  static const struct xfs_btree_ops xfs_rmapbt_ops = {  	.rec_len		= sizeof(struct xfs_rmap_rec),  	.key_len		= 2 * sizeof(struct xfs_rmap_key), @@ -443,6 +495,7 @@ static const struct xfs_btree_ops xfs_rmapbt_ops = {  	.diff_two_keys		= xfs_rmapbt_diff_two_keys,  	.keys_inorder		= xfs_rmapbt_keys_inorder,  	.recs_inorder		= xfs_rmapbt_recs_inorder, +	.keys_contiguous	= xfs_rmapbt_keys_contiguous,  };  static struct xfs_btree_cur * @@ -460,10 +513,7 @@ xfs_rmapbt_init_common(  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);  	cur->bc_ops = &xfs_rmapbt_ops; -	/* take a reference for the cursor */ -	atomic_inc(&pag->pag_ref); -	cur->bc_ag.pag = pag; - +	cur->bc_ag.pag = xfs_perag_hold(pag);  	return cur;  }  |