summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-08-30 15:44:47 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2019-10-19 10:39:06 -0700
commitb72dfaae14e36135ad6c603a26df271d0e5d94b8 (patch)
treeff2a9c464cae872d6e4653615a51c66ebee62809
parentef1d515010cf53ec7d6c2bc786aa063944de7a16 (diff)
xfs: log EFIs for all btree blocks being used to stage a btreerepair-prep-for-bulk-loading_2019-10-19
We need to log EFIs for every extent that we allocate for the purpose of staging a new btree so that if we fail then the blocks will be freed during log recovery. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/scrub/repair.c37
-rw-r--r--fs/xfs/scrub/repair.h4
-rw-r--r--fs/xfs/xfs_extfree_item.c2
3 files changed, 38 insertions, 5 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index de8a991836a8..425ae4861166 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -25,6 +25,8 @@
#include "xfs_ag_resv.h"
#include "xfs_quota.h"
#include "xfs_bmap.h"
+#include "xfs_defer.h"
+#include "xfs_extfree_item.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
@@ -412,7 +414,8 @@ int
xrep_newbt_add_reservation(
struct xrep_newbt *xnr,
xfs_fsblock_t fsbno,
- xfs_extlen_t len)
+ xfs_extlen_t len,
+ void *priv)
{
struct xrep_newbt_resv *resv;
@@ -424,6 +427,7 @@ xrep_newbt_add_reservation(
resv->fsbno = fsbno;
resv->len = len;
resv->used = 0;
+ resv->priv = priv;
list_add_tail(&resv->list, &xnr->reservations);
return 0;
}
@@ -434,6 +438,7 @@ xrep_newbt_reserve_space(
struct xrep_newbt *xnr,
uint64_t nr_blocks)
{
+ const struct xfs_defer_op_type *efi_type = &xfs_extent_free_defer_type;
struct xfs_scrub *sc = xnr->sc;
xfs_alloctype_t type;
xfs_fsblock_t alloc_hint = xnr->alloc_hint;
@@ -442,6 +447,7 @@ xrep_newbt_reserve_space(
type = sc->ip ? XFS_ALLOCTYPE_START_BNO : XFS_ALLOCTYPE_NEAR_BNO;
while (nr_blocks > 0 && !error) {
+ struct xfs_extent_free_item efi_item;
struct xfs_alloc_arg args = {
.tp = sc->tp,
.mp = sc->mp,
@@ -453,6 +459,7 @@ xrep_newbt_reserve_space(
.prod = nr_blocks,
.resv = xnr->resv,
};
+ void *efi;
error = xfs_alloc_vextent(&args);
if (error)
@@ -465,7 +472,20 @@ xrep_newbt_reserve_space(
XFS_FSB_TO_AGBNO(sc->mp, args.fsbno),
args.len, xnr->oinfo.oi_owner);
- error = xrep_newbt_add_reservation(xnr, args.fsbno, args.len);
+ /*
+ * Log a deferred free item for each extent we allocate so that
+ * we can get all of the space back if we crash before we can
+ * commit the new btree.
+ */
+ efi_item.xefi_startblock = args.fsbno;
+ efi_item.xefi_blockcount = args.len;
+ efi_item.xefi_oinfo = xnr->oinfo;
+ efi_item.xefi_skip_discard = true;
+ efi = efi_type->create_intent(sc->tp, 1);
+ efi_type->log_item(sc->tp, efi, &efi_item.xefi_list);
+
+ error = xrep_newbt_add_reservation(xnr, args.fsbno, args.len,
+ efi);
if (error)
break;
@@ -487,6 +507,7 @@ xrep_newbt_destroy(
struct xrep_newbt *xnr,
int error)
{
+ const struct xfs_defer_op_type *efi_type = &xfs_extent_free_defer_type;
struct xfs_scrub *sc = xnr->sc;
struct xrep_newbt_resv *resv, *n;
@@ -494,6 +515,17 @@ xrep_newbt_destroy(
goto junkit;
list_for_each_entry_safe(resv, n, &xnr->reservations, list) {
+ struct xfs_efd_log_item *efd;
+
+ /*
+ * Log a deferred free done for each extent we allocated now
+ * that we've linked the block into the filesystem. We cheat
+ * since we know that log recovery has never looked at the
+ * extents attached to an EFD.
+ */
+ efd = efi_type->create_done(sc->tp, resv->priv, 0);
+ set_bit(XFS_LI_DIRTY, &efd->efd_item.li_flags);
+
/* Free every block we didn't use. */
resv->fsbno += resv->used;
resv->len -= resv->used;
@@ -515,6 +547,7 @@ xrep_newbt_destroy(
junkit:
list_for_each_entry_safe(resv, n, &xnr->reservations, list) {
+ efi_type->abort_intent(resv->priv);
list_del(&resv->list);
kmem_free(resv);
}
diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h
index ab6c1199ecc0..cb86281de28b 100644
--- a/fs/xfs/scrub/repair.h
+++ b/fs/xfs/scrub/repair.h
@@ -67,6 +67,8 @@ struct xrep_newbt_resv {
/* Link to list of extents that we've reserved. */
struct list_head list;
+ void *priv;
+
/* FSB of the block we reserved. */
xfs_fsblock_t fsbno;
@@ -112,7 +114,7 @@ void xrep_newbt_init_ag(struct xrep_newbt *xba, struct xfs_scrub *sc,
void xrep_newbt_init_inode(struct xrep_newbt *xba, struct xfs_scrub *sc,
int whichfork, const struct xfs_owner_info *oinfo);
int xrep_newbt_add_reservation(struct xrep_newbt *xba, xfs_fsblock_t fsbno,
- xfs_extlen_t len);
+ xfs_extlen_t len, void *priv);
int xrep_newbt_reserve_space(struct xrep_newbt *xba, uint64_t nr_blocks);
void xrep_newbt_destroy(struct xrep_newbt *xba, int error);
int xrep_newbt_alloc_block(struct xfs_btree_cur *cur, struct xrep_newbt *xba,
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index e44efc41a041..1e49936afbfb 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -328,8 +328,6 @@ xfs_trans_get_efd(
{
struct xfs_efd_log_item *efdp;
- ASSERT(nextents > 0);
-
if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
efdp = kmem_zalloc(sizeof(struct xfs_efd_log_item) +
(nextents - 1) * sizeof(struct xfs_extent),