brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 709356d Raw
371 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2022-2024 Oracle.  All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_trans_resv.h"11#include "xfs_mount.h"12#include "xfs_defer.h"13#include "xfs_btree.h"14#include "xfs_buf_mem.h"15#include "xfs_btree_mem.h"16#include "xfs_error.h"17#include "scrub/rcbag_btree.h"18#include "scrub/trace.h"19 20static struct kmem_cache	*rcbagbt_cur_cache;21 22STATIC void23rcbagbt_init_key_from_rec(24	union xfs_btree_key		*key,25	const union xfs_btree_rec	*rec)26{27	struct rcbag_key	*bag_key = (struct rcbag_key *)key;28	const struct rcbag_rec	*bag_rec = (const struct rcbag_rec *)rec;29 30	BUILD_BUG_ON(sizeof(struct rcbag_key) > sizeof(union xfs_btree_key));31	BUILD_BUG_ON(sizeof(struct rcbag_rec) > sizeof(union xfs_btree_rec));32 33	bag_key->rbg_startblock = bag_rec->rbg_startblock;34	bag_key->rbg_blockcount = bag_rec->rbg_blockcount;35}36 37STATIC void38rcbagbt_init_rec_from_cur(39	struct xfs_btree_cur	*cur,40	union xfs_btree_rec	*rec)41{42	struct rcbag_rec	*bag_rec = (struct rcbag_rec *)rec;43	struct rcbag_rec	*bag_irec = (struct rcbag_rec *)&cur->bc_rec;44 45	bag_rec->rbg_startblock = bag_irec->rbg_startblock;46	bag_rec->rbg_blockcount = bag_irec->rbg_blockcount;47	bag_rec->rbg_refcount = bag_irec->rbg_refcount;48}49 50STATIC int64_t51rcbagbt_key_diff(52	struct xfs_btree_cur		*cur,53	const union xfs_btree_key	*key)54{55	struct rcbag_rec		*rec = (struct rcbag_rec *)&cur->bc_rec;56	const struct rcbag_key		*kp = (const struct rcbag_key *)key;57 58	if (kp->rbg_startblock > rec->rbg_startblock)59		return 1;60	if (kp->rbg_startblock < rec->rbg_startblock)61		return -1;62 63	if (kp->rbg_blockcount > rec->rbg_blockcount)64		return 1;65	if (kp->rbg_blockcount < rec->rbg_blockcount)66		return -1;67 68	return 0;69}70 71STATIC int64_t72rcbagbt_diff_two_keys(73	struct xfs_btree_cur		*cur,74	const union xfs_btree_key	*k1,75	const union xfs_btree_key	*k2,76	const union xfs_btree_key	*mask)77{78	const struct rcbag_key		*kp1 = (const struct rcbag_key *)k1;79	const struct rcbag_key		*kp2 = (const struct rcbag_key *)k2;80 81	ASSERT(mask == NULL);82 83	if (kp1->rbg_startblock > kp2->rbg_startblock)84		return 1;85	if (kp1->rbg_startblock < kp2->rbg_startblock)86		return -1;87 88	if (kp1->rbg_blockcount > kp2->rbg_blockcount)89		return 1;90	if (kp1->rbg_blockcount < kp2->rbg_blockcount)91		return -1;92 93	return 0;94}95 96STATIC int97rcbagbt_keys_inorder(98	struct xfs_btree_cur		*cur,99	const union xfs_btree_key	*k1,100	const union xfs_btree_key	*k2)101{102	const struct rcbag_key		*kp1 = (const struct rcbag_key *)k1;103	const struct rcbag_key		*kp2 = (const struct rcbag_key *)k2;104 105	if (kp1->rbg_startblock > kp2->rbg_startblock)106		return 0;107	if (kp1->rbg_startblock < kp2->rbg_startblock)108		return 1;109 110	if (kp1->rbg_blockcount > kp2->rbg_blockcount)111		return 0;112	if (kp1->rbg_blockcount < kp2->rbg_blockcount)113		return 1;114 115	return 0;116}117 118STATIC int119rcbagbt_recs_inorder(120	struct xfs_btree_cur		*cur,121	const union xfs_btree_rec	*r1,122	const union xfs_btree_rec	*r2)123{124	const struct rcbag_rec		*rp1 = (const struct rcbag_rec *)r1;125	const struct rcbag_rec		*rp2 = (const struct rcbag_rec *)r2;126 127	if (rp1->rbg_startblock > rp2->rbg_startblock)128		return 0;129	if (rp1->rbg_startblock < rp2->rbg_startblock)130		return 1;131 132	if (rp1->rbg_blockcount > rp2->rbg_blockcount)133		return 0;134	if (rp1->rbg_blockcount < rp2->rbg_blockcount)135		return 1;136 137	return 0;138}139 140static xfs_failaddr_t141rcbagbt_verify(142	struct xfs_buf		*bp)143{144	struct xfs_mount	*mp = bp->b_mount;145	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);146	xfs_failaddr_t		fa;147	unsigned int		level;148	unsigned int		maxrecs;149 150	if (!xfs_verify_magic(bp, block->bb_magic))151		return __this_address;152 153	fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);154	if (fa)155		return fa;156 157	level = be16_to_cpu(block->bb_level);158	if (level >= rcbagbt_maxlevels_possible())159		return __this_address;160 161	maxrecs = rcbagbt_maxrecs(mp, XFBNO_BLOCKSIZE, level == 0);162	return xfs_btree_memblock_verify(bp, maxrecs);163}164 165static void166rcbagbt_rw_verify(167	struct xfs_buf	*bp)168{169	xfs_failaddr_t	fa = rcbagbt_verify(bp);170 171	if (fa)172		xfs_verifier_error(bp, -EFSCORRUPTED, fa);173}174 175/* skip crc checks on in-memory btrees to save time */176static const struct xfs_buf_ops rcbagbt_mem_buf_ops = {177	.name			= "rcbagbt_mem",178	.magic			= { 0, cpu_to_be32(RCBAG_MAGIC) },179	.verify_read		= rcbagbt_rw_verify,180	.verify_write		= rcbagbt_rw_verify,181	.verify_struct		= rcbagbt_verify,182};183 184static const struct xfs_btree_ops rcbagbt_mem_ops = {185	.name			= "rcbag",186	.type			= XFS_BTREE_TYPE_MEM,187 188	.rec_len		= sizeof(struct rcbag_rec),189	.key_len		= sizeof(struct rcbag_key),190	.ptr_len		= XFS_BTREE_LONG_PTR_LEN,191 192	.lru_refs		= 1,193	.statoff		= XFS_STATS_CALC_INDEX(xs_rcbag_2),194 195	.dup_cursor		= xfbtree_dup_cursor,196	.set_root		= xfbtree_set_root,197	.alloc_block		= xfbtree_alloc_block,198	.free_block		= xfbtree_free_block,199	.get_minrecs		= xfbtree_get_minrecs,200	.get_maxrecs		= xfbtree_get_maxrecs,201	.init_key_from_rec	= rcbagbt_init_key_from_rec,202	.init_rec_from_cur	= rcbagbt_init_rec_from_cur,203	.init_ptr_from_cur	= xfbtree_init_ptr_from_cur,204	.key_diff		= rcbagbt_key_diff,205	.buf_ops		= &rcbagbt_mem_buf_ops,206	.diff_two_keys		= rcbagbt_diff_two_keys,207	.keys_inorder		= rcbagbt_keys_inorder,208	.recs_inorder		= rcbagbt_recs_inorder,209};210 211/* Create a cursor for an in-memory btree. */212struct xfs_btree_cur *213rcbagbt_mem_cursor(214	struct xfs_mount	*mp,215	struct xfs_trans	*tp,216	struct xfbtree		*xfbtree)217{218	struct xfs_btree_cur	*cur;219 220	cur = xfs_btree_alloc_cursor(mp, tp, &rcbagbt_mem_ops,221			rcbagbt_maxlevels_possible(), rcbagbt_cur_cache);222 223	cur->bc_mem.xfbtree = xfbtree;224	cur->bc_nlevels = xfbtree->nlevels;225	return cur;226}227 228/* Create an in-memory refcount bag btree. */229int230rcbagbt_mem_init(231	struct xfs_mount	*mp,232	struct xfbtree		*xfbt,233	struct xfs_buftarg	*btp)234{235	xfbt->owner = 0;236	return xfbtree_init(mp, xfbt, btp, &rcbagbt_mem_ops);237}238 239/* Calculate number of records in a refcount bag btree block. */240static inline unsigned int241rcbagbt_block_maxrecs(242	unsigned int		blocklen,243	bool			leaf)244{245	if (leaf)246		return blocklen / sizeof(struct rcbag_rec);247	return blocklen /248		(sizeof(struct rcbag_key) + sizeof(rcbag_ptr_t));249}250 251/*252 * Calculate number of records in an refcount bag btree block.253 */254unsigned int255rcbagbt_maxrecs(256	struct xfs_mount	*mp,257	unsigned int		blocklen,258	bool			leaf)259{260	blocklen -= RCBAG_BLOCK_LEN;261	return rcbagbt_block_maxrecs(blocklen, leaf);262}263 264/* Compute the max possible height for refcount bag btrees. */265unsigned int266rcbagbt_maxlevels_possible(void)267{268	unsigned int		minrecs[2];269	unsigned int		blocklen;270 271	blocklen = XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;272 273	minrecs[0] = rcbagbt_block_maxrecs(blocklen, true) / 2;274	minrecs[1] = rcbagbt_block_maxrecs(blocklen, false) / 2;275 276	return xfs_btree_space_to_height(minrecs, ULLONG_MAX);277}278 279/* Calculate the refcount bag btree size for some records. */280unsigned long long281rcbagbt_calc_size(282	unsigned long long	nr_records)283{284	unsigned int		minrecs[2];285	unsigned int		blocklen;286 287	blocklen = XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;288 289	minrecs[0] = rcbagbt_block_maxrecs(blocklen, true) / 2;290	minrecs[1] = rcbagbt_block_maxrecs(blocklen, false) / 2;291 292	return xfs_btree_calc_size(minrecs, nr_records);293}294 295int __init296rcbagbt_init_cur_cache(void)297{298	rcbagbt_cur_cache = kmem_cache_create("xfs_rcbagbt_cur",299			xfs_btree_cur_sizeof(rcbagbt_maxlevels_possible()),300			0, 0, NULL);301 302	if (!rcbagbt_cur_cache)303		return -ENOMEM;304	return 0;305}306 307void308rcbagbt_destroy_cur_cache(void)309{310	kmem_cache_destroy(rcbagbt_cur_cache);311	rcbagbt_cur_cache = NULL;312}313 314/* Look up the refcount bag record corresponding to this reverse mapping. */315int316rcbagbt_lookup_eq(317	struct xfs_btree_cur		*cur,318	const struct xfs_rmap_irec	*rmap,319	int				*success)320{321	struct rcbag_rec		*rec = (struct rcbag_rec *)&cur->bc_rec;322 323	rec->rbg_startblock = rmap->rm_startblock;324	rec->rbg_blockcount = rmap->rm_blockcount;325 326	return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, success);327}328 329/* Get the data from the pointed-to record. */330int331rcbagbt_get_rec(332	struct xfs_btree_cur	*cur,333	struct rcbag_rec	*rec,334	int			*has)335{336	union xfs_btree_rec	*btrec;337	int			error;338 339	error = xfs_btree_get_rec(cur, &btrec, has);340	if (error || !(*has))341		return error;342 343	memcpy(rec, btrec, sizeof(struct rcbag_rec));344	return 0;345}346 347/* Update the record referred to by cur to the value given. */348int349rcbagbt_update(350	struct xfs_btree_cur	*cur,351	const struct rcbag_rec	*rec)352{353	union xfs_btree_rec	btrec;354 355	memcpy(&btrec, rec, sizeof(struct rcbag_rec));356	return xfs_btree_update(cur, &btrec);357}358 359/* Update the record referred to by cur to the value given. */360int361rcbagbt_insert(362	struct xfs_btree_cur	*cur,363	const struct rcbag_rec	*rec,364	int			*success)365{366	struct rcbag_rec	*btrec = (struct rcbag_rec *)&cur->bc_rec;367 368	memcpy(btrec, rec, sizeof(struct rcbag_rec));369	return xfs_btree_insert(cur, success);370}371