]> Git Repo - J-linux.git/blob - fs/xfs/libxfs/xfs_btree_mem.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / fs / xfs / libxfs / xfs_btree_mem.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (c) 2021-2024 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <[email protected]>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_trans_resv.h"
12 #include "xfs_mount.h"
13 #include "xfs_trans.h"
14 #include "xfs_btree.h"
15 #include "xfs_error.h"
16 #include "xfs_buf_mem.h"
17 #include "xfs_btree_mem.h"
18 #include "xfs_ag.h"
19 #include "xfs_buf_item.h"
20 #include "xfs_trace.h"
21
22 /* Set the root of an in-memory btree. */
23 void
24 xfbtree_set_root(
25         struct xfs_btree_cur            *cur,
26         const union xfs_btree_ptr       *ptr,
27         int                             inc)
28 {
29         ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
30
31         cur->bc_mem.xfbtree->root = *ptr;
32         cur->bc_mem.xfbtree->nlevels += inc;
33 }
34
35 /* Initialize a pointer from the in-memory btree header. */
36 void
37 xfbtree_init_ptr_from_cur(
38         struct xfs_btree_cur            *cur,
39         union xfs_btree_ptr             *ptr)
40 {
41         ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
42
43         *ptr = cur->bc_mem.xfbtree->root;
44 }
45
46 /* Duplicate an in-memory btree cursor. */
47 struct xfs_btree_cur *
48 xfbtree_dup_cursor(
49         struct xfs_btree_cur            *cur)
50 {
51         struct xfs_btree_cur            *ncur;
52
53         ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
54
55         ncur = xfs_btree_alloc_cursor(cur->bc_mp, cur->bc_tp, cur->bc_ops,
56                         cur->bc_maxlevels, cur->bc_cache);
57         ncur->bc_flags = cur->bc_flags;
58         ncur->bc_nlevels = cur->bc_nlevels;
59         ncur->bc_mem.xfbtree = cur->bc_mem.xfbtree;
60         if (cur->bc_group)
61                 ncur->bc_group = xfs_group_hold(cur->bc_group);
62         return ncur;
63 }
64
65 /* Close the btree xfile and release all resources. */
66 void
67 xfbtree_destroy(
68         struct xfbtree          *xfbt)
69 {
70         xfs_buftarg_drain(xfbt->target);
71 }
72
73 /* Compute the number of bytes available for records. */
74 static inline unsigned int
75 xfbtree_rec_bytes(
76         struct xfs_mount                *mp,
77         const struct xfs_btree_ops      *ops)
78 {
79         return XMBUF_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
80 }
81
82 /* Initialize an empty leaf block as the btree root. */
83 STATIC int
84 xfbtree_init_leaf_block(
85         struct xfs_mount                *mp,
86         struct xfbtree                  *xfbt,
87         const struct xfs_btree_ops      *ops)
88 {
89         struct xfs_buf                  *bp;
90         xfbno_t                         bno = xfbt->highest_bno++;
91         int                             error;
92
93         error = xfs_buf_get(xfbt->target, xfbno_to_daddr(bno), XFBNO_BBSIZE,
94                         &bp);
95         if (error)
96                 return error;
97
98         trace_xfbtree_create_root_buf(xfbt, bp);
99
100         bp->b_ops = ops->buf_ops;
101         xfs_btree_init_buf(mp, bp, ops, 0, 0, xfbt->owner);
102         xfs_buf_relse(bp);
103
104         xfbt->root.l = cpu_to_be64(bno);
105         return 0;
106 }
107
108 /*
109  * Create an in-memory btree root that can be used with the given xmbuf.
110  * Callers must set xfbt->owner.
111  */
112 int
113 xfbtree_init(
114         struct xfs_mount                *mp,
115         struct xfbtree                  *xfbt,
116         struct xfs_buftarg              *btp,
117         const struct xfs_btree_ops      *ops)
118 {
119         unsigned int                    blocklen = xfbtree_rec_bytes(mp, ops);
120         unsigned int                    keyptr_len;
121         int                             error;
122
123         /* Requires a long-format CRC-format btree */
124         if (!xfs_has_crc(mp)) {
125                 ASSERT(xfs_has_crc(mp));
126                 return -EINVAL;
127         }
128         if (ops->ptr_len != XFS_BTREE_LONG_PTR_LEN) {
129                 ASSERT(ops->ptr_len == XFS_BTREE_LONG_PTR_LEN);
130                 return -EINVAL;
131         }
132
133         memset(xfbt, 0, sizeof(*xfbt));
134         xfbt->target = btp;
135
136         /* Set up min/maxrecs for this btree. */
137         keyptr_len = ops->key_len + sizeof(__be64);
138         xfbt->maxrecs[0] = blocklen / ops->rec_len;
139         xfbt->maxrecs[1] = blocklen / keyptr_len;
140         xfbt->minrecs[0] = xfbt->maxrecs[0] / 2;
141         xfbt->minrecs[1] = xfbt->maxrecs[1] / 2;
142         xfbt->highest_bno = 0;
143         xfbt->nlevels = 1;
144
145         /* Initialize the empty btree. */
146         error = xfbtree_init_leaf_block(mp, xfbt, ops);
147         if (error)
148                 goto err_freesp;
149
150         trace_xfbtree_init(mp, xfbt, ops);
151
152         return 0;
153
154 err_freesp:
155         xfs_buftarg_drain(xfbt->target);
156         return error;
157 }
158
159 /* Allocate a block to our in-memory btree. */
160 int
161 xfbtree_alloc_block(
162         struct xfs_btree_cur            *cur,
163         const union xfs_btree_ptr       *start,
164         union xfs_btree_ptr             *new,
165         int                             *stat)
166 {
167         struct xfbtree                  *xfbt = cur->bc_mem.xfbtree;
168         xfbno_t                         bno = xfbt->highest_bno++;
169
170         ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
171
172         trace_xfbtree_alloc_block(xfbt, cur, bno);
173
174         /* Fail if the block address exceeds the maximum for the buftarg. */
175         if (!xfbtree_verify_bno(xfbt, bno)) {
176                 ASSERT(xfbtree_verify_bno(xfbt, bno));
177                 *stat = 0;
178                 return 0;
179         }
180
181         new->l = cpu_to_be64(bno);
182         *stat = 1;
183         return 0;
184 }
185
186 /* Free a block from our in-memory btree. */
187 int
188 xfbtree_free_block(
189         struct xfs_btree_cur    *cur,
190         struct xfs_buf          *bp)
191 {
192         struct xfbtree          *xfbt = cur->bc_mem.xfbtree;
193         xfs_daddr_t             daddr = xfs_buf_daddr(bp);
194         xfbno_t                 bno = xfs_daddr_to_xfbno(daddr);
195
196         ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
197
198         trace_xfbtree_free_block(xfbt, cur, bno);
199
200         if (bno + 1 == xfbt->highest_bno)
201                 xfbt->highest_bno--;
202
203         return 0;
204 }
205
206 /* Return the minimum number of records for a btree block. */
207 int
208 xfbtree_get_minrecs(
209         struct xfs_btree_cur    *cur,
210         int                     level)
211 {
212         struct xfbtree          *xfbt = cur->bc_mem.xfbtree;
213
214         return xfbt->minrecs[level != 0];
215 }
216
217 /* Return the maximum number of records for a btree block. */
218 int
219 xfbtree_get_maxrecs(
220         struct xfs_btree_cur    *cur,
221         int                     level)
222 {
223         struct xfbtree          *xfbt = cur->bc_mem.xfbtree;
224
225         return xfbt->maxrecs[level != 0];
226 }
227
228 /* If this log item is a buffer item that came from the xfbtree, return it. */
229 static inline struct xfs_buf *
230 xfbtree_buf_match(
231         struct xfbtree                  *xfbt,
232         const struct xfs_log_item       *lip)
233 {
234         const struct xfs_buf_log_item   *bli;
235         struct xfs_buf                  *bp;
236
237         if (lip->li_type != XFS_LI_BUF)
238                 return NULL;
239
240         bli = container_of(lip, struct xfs_buf_log_item, bli_item);
241         bp = bli->bli_buf;
242         if (bp->b_target != xfbt->target)
243                 return NULL;
244
245         return bp;
246 }
247
248 /*
249  * Commit changes to the incore btree immediately by writing all dirty xfbtree
250  * buffers to the backing xfile.  This detaches all xfbtree buffers from the
251  * transaction, even on failure.  The buffer locks are dropped between the
252  * delwri queue and submit, so the caller must synchronize btree access.
253  *
254  * Normally we'd let the buffers commit with the transaction and get written to
255  * the xfile via the log, but online repair stages ephemeral btrees in memory
256  * and uses the btree_staging functions to write new btrees to disk atomically.
257  * The in-memory btree (and its backing store) are discarded at the end of the
258  * repair phase, which means that xfbtree buffers cannot commit with the rest
259  * of a transaction.
260  *
261  * In other words, online repair only needs the transaction to collect buffer
262  * pointers and to avoid buffer deadlocks, not to guarantee consistency of
263  * updates.
264  */
265 int
266 xfbtree_trans_commit(
267         struct xfbtree          *xfbt,
268         struct xfs_trans        *tp)
269 {
270         struct xfs_log_item     *lip, *n;
271         bool                    tp_dirty = false;
272         int                     error = 0;
273
274         /*
275          * For each xfbtree buffer attached to the transaction, write the dirty
276          * buffers to the xfile and release them.
277          */
278         list_for_each_entry_safe(lip, n, &tp->t_items, li_trans) {
279                 struct xfs_buf  *bp = xfbtree_buf_match(xfbt, lip);
280
281                 if (!bp) {
282                         if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
283                                 tp_dirty |= true;
284                         continue;
285                 }
286
287                 trace_xfbtree_trans_commit_buf(xfbt, bp);
288
289                 xmbuf_trans_bdetach(tp, bp);
290
291                 /*
292                  * If the buffer fails verification, note the failure but
293                  * continue walking the transaction items so that we remove all
294                  * ephemeral btree buffers.
295                  */
296                 if (!error)
297                         error = xmbuf_finalize(bp);
298
299                 xfs_buf_relse(bp);
300         }
301
302         /*
303          * Reset the transaction's dirty flag to reflect the dirty state of the
304          * log items that are still attached.
305          */
306         tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
307                         (tp_dirty ? XFS_TRANS_DIRTY : 0);
308
309         return error;
310 }
311
312 /*
313  * Cancel changes to the incore btree by detaching all the xfbtree buffers.
314  * Changes are not undone, so callers must not access the btree ever again.
315  */
316 void
317 xfbtree_trans_cancel(
318         struct xfbtree          *xfbt,
319         struct xfs_trans        *tp)
320 {
321         struct xfs_log_item     *lip, *n;
322         bool                    tp_dirty = false;
323
324         list_for_each_entry_safe(lip, n, &tp->t_items, li_trans) {
325                 struct xfs_buf  *bp = xfbtree_buf_match(xfbt, lip);
326
327                 if (!bp) {
328                         if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
329                                 tp_dirty |= true;
330                         continue;
331                 }
332
333                 trace_xfbtree_trans_cancel_buf(xfbt, bp);
334
335                 xmbuf_trans_bdetach(tp, bp);
336                 xfs_buf_relse(bp);
337         }
338
339         /*
340          * Reset the transaction's dirty flag to reflect the dirty state of the
341          * log items that are still attached.
342          */
343         tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
344                         (tp_dirty ? XFS_TRANS_DIRTY : 0);
345 }
This page took 0.044753 seconds and 4 git commands to generate.