1e06536a6SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
2e06536a6SDarrick J. Wong /*
3e06536a6SDarrick J. Wong  * Copyright (C) 2020 Oracle.  All Rights Reserved.
4e06536a6SDarrick J. Wong  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5e06536a6SDarrick J. Wong  */
6e06536a6SDarrick J. Wong #include "xfs.h"
7e06536a6SDarrick J. Wong #include "xfs_fs.h"
8e06536a6SDarrick J. Wong #include "xfs_shared.h"
9e06536a6SDarrick J. Wong #include "xfs_format.h"
10e06536a6SDarrick J. Wong #include "xfs_log_format.h"
11e06536a6SDarrick J. Wong #include "xfs_trans_resv.h"
12e06536a6SDarrick J. Wong #include "xfs_bit.h"
13e06536a6SDarrick J. Wong #include "xfs_mount.h"
14e06536a6SDarrick J. Wong #include "xfs_inode.h"
15e06536a6SDarrick J. Wong #include "xfs_trans.h"
16e06536a6SDarrick J. Wong #include "xfs_btree.h"
17e06536a6SDarrick J. Wong #include "xfs_trace.h"
18e06536a6SDarrick J. Wong #include "xfs_btree_staging.h"
19e06536a6SDarrick J. Wong 
20e06536a6SDarrick J. Wong /*
21e06536a6SDarrick J. Wong  * Staging Cursors and Fake Roots for Btrees
22e06536a6SDarrick J. Wong  * =========================================
23e06536a6SDarrick J. Wong  *
24e06536a6SDarrick J. Wong  * A staging btree cursor is a special type of btree cursor that callers must
25e06536a6SDarrick J. Wong  * use to construct a new btree index using the btree bulk loader code.  The
26e06536a6SDarrick J. Wong  * bulk loading code uses the staging btree cursor to abstract the details of
27e06536a6SDarrick J. Wong  * initializing new btree blocks and filling them with records or key/ptr
28e06536a6SDarrick J. Wong  * pairs.  Regular btree operations (e.g. queries and modifications) are not
29e06536a6SDarrick J. Wong  * supported with staging cursors, and callers must not invoke them.
30e06536a6SDarrick J. Wong  *
31e06536a6SDarrick J. Wong  * Fake root structures contain all the information about a btree that is under
32e06536a6SDarrick J. Wong  * construction by the bulk loading code.  Staging btree cursors point to fake
33e06536a6SDarrick J. Wong  * root structures instead of the usual AG header or inode structure.
34e06536a6SDarrick J. Wong  *
35e06536a6SDarrick J. Wong  * Callers are expected to initialize a fake root structure and pass it into
36e06536a6SDarrick J. Wong  * the _stage_cursor function for a specific btree type.  When bulk loading is
37e06536a6SDarrick J. Wong  * complete, callers should call the _commit_staged_btree function for that
38e06536a6SDarrick J. Wong  * specific btree type to commit the new btree into the filesystem.
39e06536a6SDarrick J. Wong  */
40e06536a6SDarrick J. Wong 
41e06536a6SDarrick J. Wong /*
42e06536a6SDarrick J. Wong  * Don't allow staging cursors to be duplicated because they're supposed to be
43e06536a6SDarrick J. Wong  * kept private to a single thread.
44e06536a6SDarrick J. Wong  */
45e06536a6SDarrick J. Wong STATIC struct xfs_btree_cur *
46e06536a6SDarrick J. Wong xfs_btree_fakeroot_dup_cursor(
47e06536a6SDarrick J. Wong 	struct xfs_btree_cur	*cur)
48e06536a6SDarrick J. Wong {
49e06536a6SDarrick J. Wong 	ASSERT(0);
50e06536a6SDarrick J. Wong 	return NULL;
51e06536a6SDarrick J. Wong }
52e06536a6SDarrick J. Wong 
53e06536a6SDarrick J. Wong /*
54e06536a6SDarrick J. Wong  * Don't allow block allocation for a staging cursor, because staging cursors
55e06536a6SDarrick J. Wong  * do not support regular btree modifications.
56e06536a6SDarrick J. Wong  *
57e06536a6SDarrick J. Wong  * Bulk loading uses a separate callback to obtain new blocks from a
58e06536a6SDarrick J. Wong  * preallocated list, which prevents ENOSPC failures during loading.
59e06536a6SDarrick J. Wong  */
60e06536a6SDarrick J. Wong STATIC int
61e06536a6SDarrick J. Wong xfs_btree_fakeroot_alloc_block(
62e06536a6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
63e06536a6SDarrick J. Wong 	union xfs_btree_ptr	*start_bno,
64e06536a6SDarrick J. Wong 	union xfs_btree_ptr	*new_bno,
65e06536a6SDarrick J. Wong 	int			*stat)
66e06536a6SDarrick J. Wong {
67e06536a6SDarrick J. Wong 	ASSERT(0);
68e06536a6SDarrick J. Wong 	return -EFSCORRUPTED;
69e06536a6SDarrick J. Wong }
70e06536a6SDarrick J. Wong 
71e06536a6SDarrick J. Wong /*
72e06536a6SDarrick J. Wong  * Don't allow block freeing for a staging cursor, because staging cursors
73e06536a6SDarrick J. Wong  * do not support regular btree modifications.
74e06536a6SDarrick J. Wong  */
75e06536a6SDarrick J. Wong STATIC int
76e06536a6SDarrick J. Wong xfs_btree_fakeroot_free_block(
77e06536a6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
78e06536a6SDarrick J. Wong 	struct xfs_buf		*bp)
79e06536a6SDarrick J. Wong {
80e06536a6SDarrick J. Wong 	ASSERT(0);
81e06536a6SDarrick J. Wong 	return -EFSCORRUPTED;
82e06536a6SDarrick J. Wong }
83e06536a6SDarrick J. Wong 
84e06536a6SDarrick J. Wong /* Initialize a pointer to the root block from the fakeroot. */
85e06536a6SDarrick J. Wong STATIC void
86e06536a6SDarrick J. Wong xfs_btree_fakeroot_init_ptr_from_cur(
87e06536a6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
88e06536a6SDarrick J. Wong 	union xfs_btree_ptr	*ptr)
89e06536a6SDarrick J. Wong {
90e06536a6SDarrick J. Wong 	struct xbtree_afakeroot	*afake;
91e06536a6SDarrick J. Wong 
92e06536a6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
93e06536a6SDarrick J. Wong 
94e06536a6SDarrick J. Wong 	afake = cur->bc_ag.afake;
95e06536a6SDarrick J. Wong 	ptr->s = cpu_to_be32(afake->af_root);
96e06536a6SDarrick J. Wong }
97e06536a6SDarrick J. Wong 
98e06536a6SDarrick J. Wong /*
99e06536a6SDarrick J. Wong  * Bulk Loading for AG Btrees
100e06536a6SDarrick J. Wong  * ==========================
101e06536a6SDarrick J. Wong  *
102e06536a6SDarrick J. Wong  * For a btree rooted in an AG header, pass a xbtree_afakeroot structure to the
103e06536a6SDarrick J. Wong  * staging cursor.  Callers should initialize this to zero.
104e06536a6SDarrick J. Wong  *
105e06536a6SDarrick J. Wong  * The _stage_cursor() function for a specific btree type should call
106e06536a6SDarrick J. Wong  * xfs_btree_stage_afakeroot to set up the in-memory cursor as a staging
107e06536a6SDarrick J. Wong  * cursor.  The corresponding _commit_staged_btree() function should log the
108e06536a6SDarrick J. Wong  * new root and call xfs_btree_commit_afakeroot() to transform the staging
109e06536a6SDarrick J. Wong  * cursor into a regular btree cursor.
110e06536a6SDarrick J. Wong  */
111e06536a6SDarrick J. Wong 
112e06536a6SDarrick J. Wong /* Update the btree root information for a per-AG fake root. */
113e06536a6SDarrick J. Wong STATIC void
114e06536a6SDarrick J. Wong xfs_btree_afakeroot_set_root(
115e06536a6SDarrick J. Wong 	struct xfs_btree_cur	*cur,
116e06536a6SDarrick J. Wong 	union xfs_btree_ptr	*ptr,
117e06536a6SDarrick J. Wong 	int			inc)
118e06536a6SDarrick J. Wong {
119e06536a6SDarrick J. Wong 	struct xbtree_afakeroot	*afake = cur->bc_ag.afake;
120e06536a6SDarrick J. Wong 
121e06536a6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
122e06536a6SDarrick J. Wong 	afake->af_root = be32_to_cpu(ptr->s);
123e06536a6SDarrick J. Wong 	afake->af_levels += inc;
124e06536a6SDarrick J. Wong }
125e06536a6SDarrick J. Wong 
126e06536a6SDarrick J. Wong /*
127e06536a6SDarrick J. Wong  * Initialize a AG-rooted btree cursor with the given AG btree fake root.
128e06536a6SDarrick J. Wong  * The btree cursor's bc_ops will be overridden as needed to make the staging
129e06536a6SDarrick J. Wong  * functionality work.
130e06536a6SDarrick J. Wong  */
131e06536a6SDarrick J. Wong void
132e06536a6SDarrick J. Wong xfs_btree_stage_afakeroot(
133e06536a6SDarrick J. Wong 	struct xfs_btree_cur		*cur,
134e06536a6SDarrick J. Wong 	struct xbtree_afakeroot		*afake)
135e06536a6SDarrick J. Wong {
136e06536a6SDarrick J. Wong 	struct xfs_btree_ops		*nops;
137e06536a6SDarrick J. Wong 
138e06536a6SDarrick J. Wong 	ASSERT(!(cur->bc_flags & XFS_BTREE_STAGING));
139e06536a6SDarrick J. Wong 	ASSERT(!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE));
140e06536a6SDarrick J. Wong 	ASSERT(cur->bc_tp == NULL);
141e06536a6SDarrick J. Wong 
142e06536a6SDarrick J. Wong 	nops = kmem_alloc(sizeof(struct xfs_btree_ops), KM_NOFS);
143e06536a6SDarrick J. Wong 	memcpy(nops, cur->bc_ops, sizeof(struct xfs_btree_ops));
144e06536a6SDarrick J. Wong 	nops->alloc_block = xfs_btree_fakeroot_alloc_block;
145e06536a6SDarrick J. Wong 	nops->free_block = xfs_btree_fakeroot_free_block;
146e06536a6SDarrick J. Wong 	nops->init_ptr_from_cur = xfs_btree_fakeroot_init_ptr_from_cur;
147e06536a6SDarrick J. Wong 	nops->set_root = xfs_btree_afakeroot_set_root;
148e06536a6SDarrick J. Wong 	nops->dup_cursor = xfs_btree_fakeroot_dup_cursor;
149e06536a6SDarrick J. Wong 
150e06536a6SDarrick J. Wong 	cur->bc_ag.afake = afake;
151e06536a6SDarrick J. Wong 	cur->bc_nlevels = afake->af_levels;
152e06536a6SDarrick J. Wong 	cur->bc_ops = nops;
153e06536a6SDarrick J. Wong 	cur->bc_flags |= XFS_BTREE_STAGING;
154e06536a6SDarrick J. Wong }
155e06536a6SDarrick J. Wong 
156e06536a6SDarrick J. Wong /*
157e06536a6SDarrick J. Wong  * Transform an AG-rooted staging btree cursor back into a regular cursor by
158e06536a6SDarrick J. Wong  * substituting a real btree root for the fake one and restoring normal btree
159e06536a6SDarrick J. Wong  * cursor ops.  The caller must log the btree root change prior to calling
160e06536a6SDarrick J. Wong  * this.
161e06536a6SDarrick J. Wong  */
162e06536a6SDarrick J. Wong void
163e06536a6SDarrick J. Wong xfs_btree_commit_afakeroot(
164e06536a6SDarrick J. Wong 	struct xfs_btree_cur		*cur,
165e06536a6SDarrick J. Wong 	struct xfs_trans		*tp,
166e06536a6SDarrick J. Wong 	struct xfs_buf			*agbp,
167e06536a6SDarrick J. Wong 	const struct xfs_btree_ops	*ops)
168e06536a6SDarrick J. Wong {
169e06536a6SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
170e06536a6SDarrick J. Wong 	ASSERT(cur->bc_tp == NULL);
171e06536a6SDarrick J. Wong 
172e06536a6SDarrick J. Wong 	trace_xfs_btree_commit_afakeroot(cur);
173e06536a6SDarrick J. Wong 
174e06536a6SDarrick J. Wong 	kmem_free((void *)cur->bc_ops);
175e06536a6SDarrick J. Wong 	cur->bc_ag.agbp = agbp;
176e06536a6SDarrick J. Wong 	cur->bc_ops = ops;
177e06536a6SDarrick J. Wong 	cur->bc_flags &= ~XFS_BTREE_STAGING;
178e06536a6SDarrick J. Wong 	cur->bc_tp = tp;
179e06536a6SDarrick J. Wong }
180349e1c03SDarrick J. Wong 
181349e1c03SDarrick J. Wong /*
182349e1c03SDarrick J. Wong  * Bulk Loading for Inode-Rooted Btrees
183349e1c03SDarrick J. Wong  * ====================================
184349e1c03SDarrick J. Wong  *
185349e1c03SDarrick J. Wong  * For a btree rooted in an inode fork, pass a xbtree_ifakeroot structure to
186349e1c03SDarrick J. Wong  * the staging cursor.  This structure should be initialized as follows:
187349e1c03SDarrick J. Wong  *
188349e1c03SDarrick J. Wong  * - if_fork_size field should be set to the number of bytes available to the
189349e1c03SDarrick J. Wong  *   fork in the inode.
190349e1c03SDarrick J. Wong  *
191349e1c03SDarrick J. Wong  * - if_fork should point to a freshly allocated struct xfs_ifork.
192349e1c03SDarrick J. Wong  *
193349e1c03SDarrick J. Wong  * - if_format should be set to the appropriate fork type (e.g.
194349e1c03SDarrick J. Wong  *   XFS_DINODE_FMT_BTREE).
195349e1c03SDarrick J. Wong  *
196349e1c03SDarrick J. Wong  * All other fields must be zero.
197349e1c03SDarrick J. Wong  *
198349e1c03SDarrick J. Wong  * The _stage_cursor() function for a specific btree type should call
199349e1c03SDarrick J. Wong  * xfs_btree_stage_ifakeroot to set up the in-memory cursor as a staging
200349e1c03SDarrick J. Wong  * cursor.  The corresponding _commit_staged_btree() function should log the
201349e1c03SDarrick J. Wong  * new root and call xfs_btree_commit_ifakeroot() to transform the staging
202349e1c03SDarrick J. Wong  * cursor into a regular btree cursor.
203349e1c03SDarrick J. Wong  */
204349e1c03SDarrick J. Wong 
205349e1c03SDarrick J. Wong /*
206349e1c03SDarrick J. Wong  * Initialize an inode-rooted btree cursor with the given inode btree fake
207349e1c03SDarrick J. Wong  * root.  The btree cursor's bc_ops will be overridden as needed to make the
208349e1c03SDarrick J. Wong  * staging functionality work.  If new_ops is not NULL, these new ops will be
209349e1c03SDarrick J. Wong  * passed out to the caller for further overriding.
210349e1c03SDarrick J. Wong  */
211349e1c03SDarrick J. Wong void
212349e1c03SDarrick J. Wong xfs_btree_stage_ifakeroot(
213349e1c03SDarrick J. Wong 	struct xfs_btree_cur		*cur,
214349e1c03SDarrick J. Wong 	struct xbtree_ifakeroot		*ifake,
215349e1c03SDarrick J. Wong 	struct xfs_btree_ops		**new_ops)
216349e1c03SDarrick J. Wong {
217349e1c03SDarrick J. Wong 	struct xfs_btree_ops		*nops;
218349e1c03SDarrick J. Wong 
219349e1c03SDarrick J. Wong 	ASSERT(!(cur->bc_flags & XFS_BTREE_STAGING));
220349e1c03SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
221349e1c03SDarrick J. Wong 	ASSERT(cur->bc_tp == NULL);
222349e1c03SDarrick J. Wong 
223349e1c03SDarrick J. Wong 	nops = kmem_alloc(sizeof(struct xfs_btree_ops), KM_NOFS);
224349e1c03SDarrick J. Wong 	memcpy(nops, cur->bc_ops, sizeof(struct xfs_btree_ops));
225349e1c03SDarrick J. Wong 	nops->alloc_block = xfs_btree_fakeroot_alloc_block;
226349e1c03SDarrick J. Wong 	nops->free_block = xfs_btree_fakeroot_free_block;
227349e1c03SDarrick J. Wong 	nops->init_ptr_from_cur = xfs_btree_fakeroot_init_ptr_from_cur;
228349e1c03SDarrick J. Wong 	nops->dup_cursor = xfs_btree_fakeroot_dup_cursor;
229349e1c03SDarrick J. Wong 
230349e1c03SDarrick J. Wong 	cur->bc_ino.ifake = ifake;
231349e1c03SDarrick J. Wong 	cur->bc_nlevels = ifake->if_levels;
232349e1c03SDarrick J. Wong 	cur->bc_ops = nops;
233349e1c03SDarrick J. Wong 	cur->bc_flags |= XFS_BTREE_STAGING;
234349e1c03SDarrick J. Wong 
235349e1c03SDarrick J. Wong 	if (new_ops)
236349e1c03SDarrick J. Wong 		*new_ops = nops;
237349e1c03SDarrick J. Wong }
238349e1c03SDarrick J. Wong 
239349e1c03SDarrick J. Wong /*
240349e1c03SDarrick J. Wong  * Transform an inode-rooted staging btree cursor back into a regular cursor by
241349e1c03SDarrick J. Wong  * substituting a real btree root for the fake one and restoring normal btree
242349e1c03SDarrick J. Wong  * cursor ops.  The caller must log the btree root change prior to calling
243349e1c03SDarrick J. Wong  * this.
244349e1c03SDarrick J. Wong  */
245349e1c03SDarrick J. Wong void
246349e1c03SDarrick J. Wong xfs_btree_commit_ifakeroot(
247349e1c03SDarrick J. Wong 	struct xfs_btree_cur		*cur,
248349e1c03SDarrick J. Wong 	struct xfs_trans		*tp,
249349e1c03SDarrick J. Wong 	int				whichfork,
250349e1c03SDarrick J. Wong 	const struct xfs_btree_ops	*ops)
251349e1c03SDarrick J. Wong {
252349e1c03SDarrick J. Wong 	ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
253349e1c03SDarrick J. Wong 	ASSERT(cur->bc_tp == NULL);
254349e1c03SDarrick J. Wong 
255349e1c03SDarrick J. Wong 	trace_xfs_btree_commit_ifakeroot(cur);
256349e1c03SDarrick J. Wong 
257349e1c03SDarrick J. Wong 	kmem_free((void *)cur->bc_ops);
258349e1c03SDarrick J. Wong 	cur->bc_ino.ifake = NULL;
259349e1c03SDarrick J. Wong 	cur->bc_ino.whichfork = whichfork;
260349e1c03SDarrick J. Wong 	cur->bc_ops = ops;
261349e1c03SDarrick J. Wong 	cur->bc_flags &= ~XFS_BTREE_STAGING;
262349e1c03SDarrick J. Wong 	cur->bc_tp = tp;
263349e1c03SDarrick J. Wong }
264