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