#include "xfs_rmap.h"
#include "xfs_refcount_btree.h"
#include "xfs_refcount.h"
+#include "xfs_btree_staging.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define xfs_alloc_fix_freelist libxfs_alloc_fix_freelist
#define xfs_alloc_min_freelist libxfs_alloc_min_freelist
#define xfs_alloc_read_agf libxfs_alloc_read_agf
+#define xfs_alloc_vextent libxfs_alloc_vextent
#define xfs_attr_get libxfs_attr_get
#define xfs_attr_leaf_newentsize libxfs_attr_leaf_newentsize
#define xfs_attr_namecheck libxfs_attr_namecheck
#define xfs_attr_set libxfs_attr_set
+#define __xfs_bmap_add_free __libxfs_bmap_add_free
#define xfs_bmapi_read libxfs_bmapi_read
#define xfs_bmapi_write libxfs_bmapi_write
#define xfs_bmap_last_offset libxfs_bmap_last_offset
LTCOMMAND = xfs_repair
-HFILES = agheader.h attr_repair.h avl.h bmap.h btree.h \
+HFILES = agheader.h attr_repair.h avl.h bulkload.h bmap.h btree.h \
da_util.h dinode.h dir2.h err_protos.h globals.h incore.h protos.h \
rt.h progress.h scan.h versions.h prefetch.h rmap.h slab.h threads.h
-CFILES = agheader.c attr_repair.c avl.c bmap.c btree.c \
+CFILES = agheader.c attr_repair.c avl.c bulkload.c bmap.c btree.c \
da_util.c dino_chunks.c dinode.c dir2.c globals.c incore.c \
incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \
phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include <libxfs.h>
+#include "bulkload.h"
+
+int bload_leaf_slack = -1;
+int bload_node_slack = -1;
+
+/* Initialize accounting resources for staging a new AG btree. */
+void
+bulkload_init_ag(
+ struct bulkload *bkl,
+ struct repair_ctx *sc,
+ const struct xfs_owner_info *oinfo)
+{
+ memset(bkl, 0, sizeof(struct bulkload));
+ bkl->sc = sc;
+ bkl->oinfo = *oinfo; /* structure copy */
+ INIT_LIST_HEAD(&bkl->resv_list);
+}
+
+/* Designate specific blocks to be used to build our new btree. */
+int
+bulkload_add_blocks(
+ struct bulkload *bkl,
+ xfs_fsblock_t fsbno,
+ xfs_extlen_t len)
+{
+ struct bulkload_resv *resv;
+
+ resv = kmem_alloc(sizeof(struct bulkload_resv), KM_MAYFAIL);
+ if (!resv)
+ return ENOMEM;
+
+ INIT_LIST_HEAD(&resv->list);
+ resv->fsbno = fsbno;
+ resv->len = len;
+ resv->used = 0;
+ list_add_tail(&resv->list, &bkl->resv_list);
+ return 0;
+}
+
+/* Free all the accounting info and disk space we reserved for a new btree. */
+void
+bulkload_destroy(
+ struct bulkload *bkl,
+ int error)
+{
+ struct bulkload_resv *resv, *n;
+
+ list_for_each_entry_safe(resv, n, &bkl->resv_list, list) {
+ list_del(&resv->list);
+ kmem_free(resv);
+ }
+}
+
+/* Feed one of the reserved btree blocks to the bulk loader. */
+int
+bulkload_claim_block(
+ struct xfs_btree_cur *cur,
+ struct bulkload *bkl,
+ union xfs_btree_ptr *ptr)
+{
+ struct bulkload_resv *resv;
+ xfs_fsblock_t fsb;
+
+ /*
+ * The first item in the list should always have a free block unless
+ * we're completely out.
+ */
+ resv = list_first_entry(&bkl->resv_list, struct bulkload_resv, list);
+ if (resv->used == resv->len)
+ return ENOSPC;
+
+ /*
+ * Peel off a block from the start of the reservation. We allocate
+ * blocks in order to place blocks on disk in increasing record or key
+ * order. The block reservations tend to end up on the list in
+ * decreasing order, which hopefully results in leaf blocks ending up
+ * together.
+ */
+ fsb = resv->fsbno + resv->used;
+ resv->used++;
+
+ /* If we used all the blocks in this reservation, move it to the end. */
+ if (resv->used == resv->len)
+ list_move_tail(&resv->list, &bkl->resv_list);
+
+ if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+ ptr->l = cpu_to_be64(fsb);
+ else
+ ptr->s = cpu_to_be32(XFS_FSB_TO_AGBNO(cur->bc_mp, fsb));
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#ifndef __XFS_REPAIR_BULKLOAD_H__
+#define __XFS_REPAIR_BULKLOAD_H__
+
+extern int bload_leaf_slack;
+extern int bload_node_slack;
+
+struct repair_ctx {
+ struct xfs_mount *mp;
+};
+
+struct bulkload_resv {
+ /* Link to list of extents that we've reserved. */
+ struct list_head list;
+
+ /* FSB of the block we reserved. */
+ xfs_fsblock_t fsbno;
+
+ /* Length of the reservation. */
+ xfs_extlen_t len;
+
+ /* How much of this reservation we've used. */
+ xfs_extlen_t used;
+};
+
+struct bulkload {
+ struct repair_ctx *sc;
+
+ /* List of extents that we've reserved. */
+ struct list_head resv_list;
+
+ /* Fake root for new btree. */
+ struct xbtree_afakeroot afake;
+
+ /* rmap owner of these blocks */
+ struct xfs_owner_info oinfo;
+
+ /* The last reservation we allocated from. */
+ struct bulkload_resv *last_resv;
+};
+
+#define for_each_bulkload_reservation(bkl, resv, n) \
+ list_for_each_entry_safe((resv), (n), &(bkl)->resv_list, list)
+
+void bulkload_init_ag(struct bulkload *bkl, struct repair_ctx *sc,
+ const struct xfs_owner_info *oinfo);
+int bulkload_add_blocks(struct bulkload *bkl, xfs_fsblock_t fsbno,
+ xfs_extlen_t len);
+void bulkload_destroy(struct bulkload *bkl, int error);
+int bulkload_claim_block(struct xfs_btree_cur *cur, struct bulkload *bkl,
+ union xfs_btree_ptr *ptr);
+
+#endif /* __XFS_REPAIR_BULKLOAD_H__ */
#include "rmap.h"
#include "libfrog/fsgeom.h"
#include "libfrog/platform.h"
+#include "bulkload.h"
/*
* option tables for getsubopt calls
AG_STRIDE,
FORCE_GEO,
PHASE2_THREADS,
+ BLOAD_LEAF_SLACK,
+ BLOAD_NODE_SLACK,
O_MAX_OPTS,
};
[AG_STRIDE] = "ag_stride",
[FORCE_GEO] = "force_geometry",
[PHASE2_THREADS] = "phase2_threads",
+ [BLOAD_LEAF_SLACK] = "debug_bload_leaf_slack",
+ [BLOAD_NODE_SLACK] = "debug_bload_node_slack",
[O_MAX_OPTS] = NULL,
};
_("-o phase2_threads requires a parameter\n"));
phase2_threads = (int)strtol(val, NULL, 0);
break;
+ case BLOAD_LEAF_SLACK:
+ if (!val)
+ do_abort(
+ _("-o debug_bload_leaf_slack requires a parameter\n"));
+ bload_leaf_slack = (int)strtol(val, NULL, 0);
+ break;
+ case BLOAD_NODE_SLACK:
+ if (!val)
+ do_abort(
+ _("-o debug_bload_node_slack requires a parameter\n"));
+ bload_node_slack = (int)strtol(val, NULL, 0);
+ break;
default:
unknown('o', val);
break;