/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2021-2024 Oracle. All Rights Reserved. * Author: Darrick J. Wong <djwong@kernel.org>
*/ #include"xfs.h" #include"xfs_fs.h" #include"xfs_shared.h" #include"xfs_format.h" #include"xfs_log_format.h" #include"xfs_trans_resv.h" #include"xfs_mount.h" #include"xfs_trans.h" #include"xfs_btree.h" #include"xfs_error.h" #include"xfs_buf_mem.h" #include"xfs_btree_mem.h" #include"xfs_ag.h" #include"xfs_buf_item.h" #include"xfs_trace.h" #include"xfs_rtgroup.h"
/* Set the root of an in-memory btree. */ void
xfbtree_set_root( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *ptr, int inc)
{
ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
/* Close the btree xfile and release all resources. */ void
xfbtree_destroy( struct xfbtree *xfbt)
{
xfs_buftarg_drain(xfbt->target);
}
/* Compute the number of bytes available for records. */ staticinlineunsignedint
xfbtree_rec_bytes( struct xfs_mount *mp, conststruct xfs_btree_ops *ops)
{ return XMBUF_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
}
/* Initialize an empty leaf block as the btree root. */ STATICint
xfbtree_init_leaf_block( struct xfs_mount *mp, struct xfbtree *xfbt, conststruct xfs_btree_ops *ops)
{ struct xfs_buf *bp;
xfbno_t bno = xfbt->highest_bno++; int error;
error = xfs_buf_get(xfbt->target, xfbno_to_daddr(bno), XFBNO_BBSIZE,
&bp); if (error) return error;
/* * Create an in-memory btree root that can be used with the given xmbuf. * Callers must set xfbt->owner.
*/ int
xfbtree_init( struct xfs_mount *mp, struct xfbtree *xfbt, struct xfs_buftarg *btp, conststruct xfs_btree_ops *ops)
{ unsignedint blocklen = xfbtree_rec_bytes(mp, ops); unsignedint keyptr_len; int error;
/* Requires a long-format CRC-format btree */ if (!xfs_has_crc(mp)) {
ASSERT(xfs_has_crc(mp)); return -EINVAL;
} if (ops->ptr_len != XFS_BTREE_LONG_PTR_LEN) {
ASSERT(ops->ptr_len == XFS_BTREE_LONG_PTR_LEN); return -EINVAL;
}
/* Allocate a block to our in-memory btree. */ int
xfbtree_alloc_block( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat)
{ struct xfbtree *xfbt = cur->bc_mem.xfbtree;
xfbno_t bno = xfbt->highest_bno++;
ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
trace_xfbtree_alloc_block(xfbt, cur, bno);
/* Fail if the block address exceeds the maximum for the buftarg. */ if (!xfbtree_verify_bno(xfbt, bno)) {
ASSERT(xfbtree_verify_bno(xfbt, bno));
*stat = 0; return 0;
}
if (bno + 1 == xfbt->highest_bno)
xfbt->highest_bno--;
return 0;
}
/* Return the minimum number of records for a btree block. */ int
xfbtree_get_minrecs( struct xfs_btree_cur *cur, int level)
{ struct xfbtree *xfbt = cur->bc_mem.xfbtree;
return xfbt->minrecs[level != 0];
}
/* Return the maximum number of records for a btree block. */ int
xfbtree_get_maxrecs( struct xfs_btree_cur *cur, int level)
{ struct xfbtree *xfbt = cur->bc_mem.xfbtree;
return xfbt->maxrecs[level != 0];
}
/* If this log item is a buffer item that came from the xfbtree, return it. */ staticinlinestruct xfs_buf *
xfbtree_buf_match( struct xfbtree *xfbt, conststruct xfs_log_item *lip)
{ conststruct xfs_buf_log_item *bli; struct xfs_buf *bp;
if (lip->li_type != XFS_LI_BUF) return NULL;
bli = container_of(lip, struct xfs_buf_log_item, bli_item);
bp = bli->bli_buf; if (bp->b_target != xfbt->target) return NULL;
return bp;
}
/* * Commit changes to the incore btree immediately by writing all dirty xfbtree * buffers to the backing xfile. This detaches all xfbtree buffers from the * transaction, even on failure. The buffer locks are dropped between the * delwri queue and submit, so the caller must synchronize btree access. * * Normally we'd let the buffers commit with the transaction and get written to * the xfile via the log, but online repair stages ephemeral btrees in memory * and uses the btree_staging functions to write new btrees to disk atomically. * The in-memory btree (and its backing store) are discarded at the end of the * repair phase, which means that xfbtree buffers cannot commit with the rest * of a transaction. * * In other words, online repair only needs the transaction to collect buffer * pointers and to avoid buffer deadlocks, not to guarantee consistency of * updates.
*/ int
xfbtree_trans_commit( struct xfbtree *xfbt, struct xfs_trans *tp)
{ struct xfs_log_item *lip, *n; bool tp_dirty = false; int error = 0;
/* * For each xfbtree buffer attached to the transaction, write the dirty * buffers to the xfile and release them.
*/
list_for_each_entry_safe(lip, n, &tp->t_items, li_trans) { struct xfs_buf *bp = xfbtree_buf_match(xfbt, lip);
if (!bp) { if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
tp_dirty |= true; continue;
}
trace_xfbtree_trans_commit_buf(xfbt, bp);
xmbuf_trans_bdetach(tp, bp);
/* * If the buffer fails verification, note the failure but * continue walking the transaction items so that we remove all * ephemeral btree buffers.
*/ if (!error)
error = xmbuf_finalize(bp);
xfs_buf_relse(bp);
}
/* * Reset the transaction's dirty flag to reflect the dirty state of the * log items that are still attached.
*/
tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
(tp_dirty ? XFS_TRANS_DIRTY : 0);
return error;
}
/* * Cancel changes to the incore btree by detaching all the xfbtree buffers. * Changes are not undone, so callers must not access the btree ever again.
*/ void
xfbtree_trans_cancel( struct xfbtree *xfbt, struct xfs_trans *tp)
{ struct xfs_log_item *lip, *n; bool tp_dirty = false;
if (!bp) { if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
tp_dirty |= true; continue;
}
trace_xfbtree_trans_cancel_buf(xfbt, bp);
xmbuf_trans_bdetach(tp, bp);
xfs_buf_relse(bp);
}
/* * Reset the transaction's dirty flag to reflect the dirty state of the * log items that are still attached.
*/
tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
(tp_dirty ? XFS_TRANS_DIRTY : 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.