Commit 34d38666 authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'reconstruct-defer-cleanups-6.8_2023-12-06' of...

Merge tag 'reconstruct-defer-cleanups-6.8_2023-12-06' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.8-mergeA

xfs: continue removing defer item boilerplate

Now that we've restructured log intent item recovery to reconstruct the
incore deferred work state, apply further cleanups to that code to
remove boilerplate that is duplicated across all the _item.c files.
Having done that, collapse a bunch of trivial helpers to reduce the
overall call chain.  That enables us to refactor the relog code so that
the ->relog_item implementations only have to know how to format the
implementation-specific data encoded in an intent item and don't
themselves have to handle the log item juggling.

This has been lightly tested with fstests.  Enjoy!
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'reconstruct-defer-cleanups-6.8_2023-12-06' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: move ->iop_relog to struct xfs_defer_op_type
  xfs: collapse the ->create_done functions
  xfs: hoist xfs_trans_add_item calls to defer ops functions
  xfs: clean out XFS_LI_DIRTY setting boilerplate from ->iop_relog
  xfs: use xfs_defer_create_done for the relogging operation
  xfs: hoist ->create_intent boilerplate to its callsite
  xfs: collapse the ->finish_item helpers
  xfs: hoist intent done flag setting to ->finish_item callsite
  xfs: don't set XFS_TRANS_HAS_INTENT_DONE when there's no ATTRD log item
parents 6b4ffe97 a49c708f
......@@ -26,6 +26,7 @@
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_attr.h"
#include "xfs_trans_priv.h"
static struct kmem_cache *xfs_defer_pending_cache;
......@@ -191,6 +192,33 @@ static const struct xfs_defer_op_type *defer_op_types[] = {
[XFS_DEFER_OPS_TYPE_ATTR] = &xfs_attr_defer_type,
};
/* Create a log intent done item for a log intent item. */
static inline void
xfs_defer_create_done(
struct xfs_trans *tp,
struct xfs_defer_pending *dfp)
{
const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type];
struct xfs_log_item *lip;
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the log intent item and frees the log done item
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY;
lip = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count);
if (!lip)
return;
tp->t_flags |= XFS_TRANS_HAS_INTENT_DONE;
xfs_trans_add_item(tp, lip);
set_bit(XFS_LI_DIRTY, &lip->li_flags);
dfp->dfp_done = lip;
}
/*
* Ensure there's a log intent item associated with this deferred work item if
* the operation must be restarted on crash. Returns 1 if there's a log item;
......@@ -214,6 +242,9 @@ xfs_defer_create_intent(
if (IS_ERR(lip))
return PTR_ERR(lip);
tp->t_flags |= XFS_TRANS_DIRTY;
xfs_trans_add_item(tp, lip);
set_bit(XFS_LI_DIRTY, &lip->li_flags);
dfp->dfp_intent = lip;
return 1;
}
......@@ -428,6 +459,25 @@ xfs_defer_cancel_list(
xfs_defer_pending_cancel_work(mp, dfp);
}
static inline void
xfs_defer_relog_intent(
struct xfs_trans *tp,
struct xfs_defer_pending *dfp)
{
struct xfs_log_item *lip;
const struct xfs_defer_op_type *ops = defer_op_types[dfp->dfp_type];
xfs_defer_create_done(tp, dfp);
lip = ops->relog_intent(tp, dfp->dfp_intent, dfp->dfp_done);
if (lip) {
xfs_trans_add_item(tp, lip);
set_bit(XFS_LI_DIRTY, &lip->li_flags);
}
dfp->dfp_done = NULL;
dfp->dfp_intent = lip;
}
/*
* Prevent a log intent item from pinning the tail of the log by logging a
* done item to release the intent item; and then log a new intent item.
......@@ -472,7 +522,8 @@ xfs_defer_relog(
trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp);
XFS_STATS_INC((*tpp)->t_mountp, defer_relog);
dfp->dfp_intent = xfs_trans_item_relog(dfp->dfp_intent, *tpp);
xfs_defer_relog_intent(*tpp, dfp);
}
if ((*tpp)->t_flags & XFS_TRANS_DIRTY)
......@@ -496,7 +547,7 @@ xfs_defer_finish_one(
trace_xfs_defer_pending_finish(tp->t_mountp, dfp);
dfp->dfp_done = ops->create_done(tp, dfp->dfp_intent, dfp->dfp_count);
xfs_defer_create_done(tp, dfp);
list_for_each_safe(li, n, &dfp->dfp_work) {
list_del(li);
dfp->dfp_count--;
......
......@@ -59,6 +59,9 @@ struct xfs_defer_op_type {
void (*cancel_item)(struct list_head *item);
int (*recover_work)(struct xfs_defer_pending *dfp,
struct list_head *capture_list);
struct xfs_log_item *(*relog_intent)(struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_log_item *done_item);
unsigned int max_items;
};
......
......@@ -33,8 +33,6 @@ struct kmem_cache *xfs_attrd_cache;
static const struct xfs_item_ops xfs_attri_item_ops;
static const struct xfs_item_ops xfs_attrd_item_ops;
static struct xfs_attrd_log_item *xfs_trans_get_attrd(struct xfs_trans *tp,
struct xfs_attri_log_item *attrip);
static inline struct xfs_attri_log_item *ATTRI_ITEM(struct xfs_log_item *lip)
{
......@@ -310,54 +308,6 @@ xfs_attrd_item_intent(
return &ATTRD_ITEM(lip)->attrd_attrip->attri_item;
}
/*
* Performs one step of an attribute update intent and marks the attrd item
* dirty.. An attr operation may be a set or a remove. Note that the
* transaction is marked dirty regardless of whether the operation succeeds or
* fails to support the ATTRI/ATTRD lifecycle rules.
*/
STATIC int
xfs_xattri_finish_update(
struct xfs_attr_intent *attr,
struct xfs_attrd_log_item *attrdp)
{
struct xfs_da_args *args = attr->xattri_da_args;
int error;
if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {
error = -EIO;
goto out;
}
/* If an attr removal is trivially complete, we're done. */
if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE &&
!xfs_inode_hasattr(args->dp)) {
error = 0;
goto out;
}
error = xfs_attr_set_iter(attr);
if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
error = -EAGAIN;
out:
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the ATTRI and frees the ATTRD
* 2.) shuts down the filesystem
*/
args->trans->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
/*
* attr intent/done items are null when logged attributes are disabled
*/
if (attrdp)
set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
return error;
}
/* Log an attr to the intent item. */
STATIC void
xfs_attr_log_item(
......@@ -367,9 +317,6 @@ xfs_attr_log_item(
{
struct xfs_attri_log_format *attrp;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &attrip->attri_item.li_flags);
/*
* At this point the xfs_attr_intent has been constructed, and we've
* created the log intent. Fill in the attri log item and log format
......@@ -426,7 +373,6 @@ xfs_attr_create_intent(
}
attrip = xfs_attri_init(mp, attr->xattri_nameval);
xfs_trans_add_item(tp, &attrip->attri_item);
xfs_attr_log_item(tp, attrip, attr);
return &attrip->attri_item;
......@@ -454,23 +400,33 @@ xfs_attr_finish_item(
struct xfs_btree_cur **state)
{
struct xfs_attr_intent *attr;
struct xfs_attrd_log_item *done_item = NULL;
struct xfs_da_args *args;
int error;
attr = container_of(item, struct xfs_attr_intent, xattri_list);
if (done)
done_item = ATTRD_ITEM(done);
args = attr->xattri_da_args;
/*
* Always reset trans after EAGAIN cycle
* since the transaction is new
*/
attr->xattri_da_args->trans = tp;
/* Reset trans after EAGAIN cycle since the transaction is new */
args->trans = tp;
error = xfs_xattri_finish_update(attr, done_item);
if (error != -EAGAIN)
xfs_attr_free_item(attr);
if (XFS_TEST_ERROR(false, args->dp->i_mount, XFS_ERRTAG_LARP)) {
error = -EIO;
goto out;
}
/* If an attr removal is trivially complete, we're done. */
if (attr->xattri_op_flags == XFS_ATTRI_OP_FLAGS_REMOVE &&
!xfs_inode_hasattr(args->dp)) {
error = 0;
goto out;
}
error = xfs_attr_set_iter(attr);
if (!error && attr->xattri_dela_state != XFS_DAS_DONE)
return -EAGAIN;
out:
xfs_attr_free_item(attr);
return error;
}
......@@ -669,11 +625,11 @@ xfs_attr_recover_work(
/* Re-log an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_attri_item_relog(
xfs_attr_relog_intent(
struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_trans *tp)
struct xfs_log_item *done_item)
{
struct xfs_attrd_log_item *attrdp;
struct xfs_attri_log_item *old_attrip;
struct xfs_attri_log_item *new_attrip;
struct xfs_attri_log_format *new_attrp;
......@@ -682,10 +638,6 @@ xfs_attri_item_relog(
old_attrip = ATTRI_ITEM(intent);
old_attrp = &old_attrip->attri_format;
tp->t_flags |= XFS_TRANS_DIRTY;
attrdp = xfs_trans_get_attrd(tp, old_attrip);
set_bit(XFS_LI_DIRTY, &attrdp->attrd_item.li_flags);
/*
* Create a new log item that shares the same name/value buffer as the
* old log item.
......@@ -699,9 +651,6 @@ xfs_attri_item_relog(
new_attrp->alfi_name_len = old_attrp->alfi_name_len;
new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;
xfs_trans_add_item(tp, &new_attrip->attri_item);
set_bit(XFS_LI_DIRTY, &new_attrip->attri_item.li_flags);
return &new_attrip->attri_item;
}
......@@ -781,28 +730,6 @@ xlog_recover_attri_commit_pass2(
return 0;
}
/*
* This routine is called to allocate an "attr free done" log item.
*/
static struct xfs_attrd_log_item *
xfs_trans_get_attrd(struct xfs_trans *tp,
struct xfs_attri_log_item *attrip)
{
struct xfs_attrd_log_item *attrdp;
ASSERT(tp != NULL);
attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,
&xfs_attrd_item_ops);
attrdp->attrd_attrip = attrip;
attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
xfs_trans_add_item(tp, &attrdp->attrd_item);
return attrdp;
}
/* Get an ATTRD so we can process all the attrs. */
static struct xfs_log_item *
xfs_attr_create_done(
......@@ -810,10 +737,22 @@ xfs_attr_create_done(
struct xfs_log_item *intent,
unsigned int count)
{
struct xfs_attri_log_item *attrip;
struct xfs_attrd_log_item *attrdp;
if (!intent)
return NULL;
return &xfs_trans_get_attrd(tp, ATTRI_ITEM(intent))->attrd_item;
attrip = ATTRI_ITEM(intent);
attrdp = kmem_cache_zalloc(xfs_attrd_cache, GFP_NOFS | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &attrdp->attrd_item, XFS_LI_ATTRD,
&xfs_attrd_item_ops);
attrdp->attrd_attrip = attrip;
attrdp->attrd_format.alfd_alf_id = attrip->attri_format.alfi_id;
return &attrdp->attrd_item;
}
const struct xfs_defer_op_type xfs_attr_defer_type = {
......@@ -824,6 +763,7 @@ const struct xfs_defer_op_type xfs_attr_defer_type = {
.finish_item = xfs_attr_finish_item,
.cancel_item = xfs_attr_cancel_item,
.recover_work = xfs_attr_recover_work,
.relog_intent = xfs_attr_relog_intent,
};
/*
......@@ -861,7 +801,6 @@ static const struct xfs_item_ops xfs_attri_item_ops = {
.iop_unpin = xfs_attri_item_unpin,
.iop_release = xfs_attri_item_release,
.iop_match = xfs_attri_item_match,
.iop_relog = xfs_attri_item_relog,
};
const struct xlog_recover_item_ops xlog_attri_item_ops = {
......
......@@ -221,51 +221,6 @@ static const struct xfs_item_ops xfs_bud_item_ops = {
.iop_intent = xfs_bud_item_intent,
};
static struct xfs_bud_log_item *
xfs_trans_get_bud(
struct xfs_trans *tp,
struct xfs_bui_log_item *buip)
{
struct xfs_bud_log_item *budp;
budp = kmem_cache_zalloc(xfs_bud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD,
&xfs_bud_item_ops);
budp->bud_buip = buip;
budp->bud_format.bud_bui_id = buip->bui_format.bui_id;
xfs_trans_add_item(tp, &budp->bud_item);
return budp;
}
/*
* Finish an bmap update and log it to the BUD. Note that the
* transaction is marked dirty regardless of whether the bmap update
* succeeds or fails to support the BUI/BUD lifecycle rules.
*/
static int
xfs_trans_log_finish_bmap_update(
struct xfs_trans *tp,
struct xfs_bud_log_item *budp,
struct xfs_bmap_intent *bi)
{
int error;
error = xfs_bmap_finish_one(tp, bi);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the BUI and frees the BUD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
return error;
}
/* Sort bmap intents by inode. */
static int
xfs_bmap_update_diff_items(
......@@ -314,9 +269,6 @@ xfs_bmap_update_log_item(
uint next_extent;
struct xfs_map_extent *map;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
/*
* atomic_inc_return gives us the value after the increment;
* we want to use it as an array index so we need to subtract 1 from
......@@ -346,7 +298,6 @@ xfs_bmap_update_create_intent(
ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
xfs_trans_add_item(tp, &buip->bui_item);
if (sort)
list_sort(mp, items, xfs_bmap_update_diff_items);
list_for_each_entry(bi, items, bi_list)
......@@ -354,14 +305,23 @@ xfs_bmap_update_create_intent(
return &buip->bui_item;
}
/* Get an BUD so we can process all the deferred rmap updates. */
/* Get an BUD so we can process all the deferred bmap updates. */
static struct xfs_log_item *
xfs_bmap_update_create_done(
struct xfs_trans *tp,
struct xfs_log_item *intent,
unsigned int count)
{
return &xfs_trans_get_bud(tp, BUI_ITEM(intent))->bud_item;
struct xfs_bui_log_item *buip = BUI_ITEM(intent);
struct xfs_bud_log_item *budp;
budp = kmem_cache_zalloc(xfs_bud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &budp->bud_item, XFS_LI_BUD,
&xfs_bud_item_ops);
budp->bud_buip = buip;
budp->bud_format.bud_bui_id = buip->bui_format.bui_id;
return &budp->bud_item;
}
/* Take a passive ref to the AG containing the space we're mapping. */
......@@ -392,7 +352,7 @@ xfs_bmap_update_put_group(
xfs_perag_intent_put(bi->bi_pag);
}
/* Process a deferred rmap update. */
/* Process a deferred bmap update. */
STATIC int
xfs_bmap_update_finish_item(
struct xfs_trans *tp,
......@@ -405,7 +365,7 @@ xfs_bmap_update_finish_item(
bi = container_of(item, struct xfs_bmap_intent, bi_list);
error = xfs_trans_log_finish_bmap_update(tp, BUD_ITEM(done), bi);
error = xfs_bmap_finish_one(tp, bi);
if (!error && bi->bi_bmap.br_blockcount > 0) {
ASSERT(bi->bi_type == XFS_BMAP_UNMAP);
return -EAGAIN;
......@@ -581,6 +541,27 @@ xfs_bmap_recover_work(
return error;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_bmap_relog_intent(
struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_log_item *done_item)
{
struct xfs_bui_log_item *buip;
struct xfs_map_extent *map;
unsigned int count;
count = BUI_ITEM(intent)->bui_format.bui_nextents;
map = BUI_ITEM(intent)->bui_format.bui_extents;
buip = xfs_bui_init(tp->t_mountp);
memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map));
atomic_set(&buip->bui_next_extent, count);
return &buip->bui_item;
}
const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
.max_items = XFS_BUI_MAX_FAST_EXTENTS,
.create_intent = xfs_bmap_update_create_intent,
......@@ -589,6 +570,7 @@ const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
.finish_item = xfs_bmap_update_finish_item,
.cancel_item = xfs_bmap_update_cancel_item,
.recover_work = xfs_bmap_recover_work,
.relog_intent = xfs_bmap_relog_intent,
};
STATIC bool
......@@ -599,32 +581,6 @@ xfs_bui_item_match(
return BUI_ITEM(lip)->bui_format.bui_id == intent_id;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_bui_item_relog(
struct xfs_log_item *intent,
struct xfs_trans *tp)
{
struct xfs_bud_log_item *budp;
struct xfs_bui_log_item *buip;
struct xfs_map_extent *map;
unsigned int count;
count = BUI_ITEM(intent)->bui_format.bui_nextents;
map = BUI_ITEM(intent)->bui_format.bui_extents;
tp->t_flags |= XFS_TRANS_DIRTY;
budp = xfs_trans_get_bud(tp, BUI_ITEM(intent));
set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
buip = xfs_bui_init(tp->t_mountp);
memcpy(buip->bui_format.bui_extents, map, count * sizeof(*map));
atomic_set(&buip->bui_next_extent, count);
xfs_trans_add_item(tp, &buip->bui_item);
set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
return &buip->bui_item;
}
static const struct xfs_item_ops xfs_bui_item_ops = {
.flags = XFS_ITEM_INTENT,
.iop_size = xfs_bui_item_size,
......@@ -632,7 +588,6 @@ static const struct xfs_item_ops xfs_bui_item_ops = {
.iop_unpin = xfs_bui_item_unpin,
.iop_release = xfs_bui_item_release,
.iop_match = xfs_bui_item_match,
.iop_relog = xfs_bui_item_relog,
};
static inline void
......
......@@ -303,39 +303,6 @@ static const struct xfs_item_ops xfs_efd_item_ops = {
.iop_intent = xfs_efd_item_intent,
};
/*
* Allocate an "extent free done" log item that will hold nextents worth of
* extents. The caller must use all nextents extents, because we are not
* flexible about this at all.
*/
static struct xfs_efd_log_item *
xfs_trans_get_efd(
struct xfs_trans *tp,
struct xfs_efi_log_item *efip,
unsigned int nextents)
{
struct xfs_efd_log_item *efdp;
ASSERT(nextents > 0);
if (nextents > XFS_EFD_MAX_FAST_EXTENTS) {
efdp = kzalloc(xfs_efd_log_item_sizeof(nextents),
GFP_KERNEL | __GFP_NOFAIL);
} else {
efdp = kmem_cache_zalloc(xfs_efd_cache,
GFP_KERNEL | __GFP_NOFAIL);
}
xfs_log_item_init(tp->t_mountp, &efdp->efd_item, XFS_LI_EFD,
&xfs_efd_item_ops);
efdp->efd_efip = efip;
efdp->efd_format.efd_nextents = nextents;
efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
xfs_trans_add_item(tp, &efdp->efd_item);
return efdp;
}
/*
* Fill the EFD with all extents from the EFI when we need to roll the
* transaction and continue with a new EFI.
......@@ -364,69 +331,6 @@ xfs_efd_from_efi(
efdp->efd_next_extent = efip->efi_format.efi_nextents;
}
/*
* Free an extent and log it to the EFD. Note that the transaction is marked
* dirty regardless of whether the extent free succeeds or fails to support the
* EFI/EFD lifecycle rules.
*/
static int
xfs_trans_free_extent(
struct xfs_trans *tp,
struct xfs_efd_log_item *efdp,
struct xfs_extent_free_item *xefi)
{
struct xfs_owner_info oinfo = { };
struct xfs_mount *mp = tp->t_mountp;
struct xfs_extent *extp;
uint next_extent;
xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp,
xefi->xefi_startblock);
int error;
oinfo.oi_owner = xefi->xefi_owner;
if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK)
oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
trace_xfs_bmap_free_deferred(tp->t_mountp, xefi->xefi_pag->pag_agno, 0,
agbno, xefi->xefi_blockcount);
error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the EFI and frees the EFD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
/*
* If we need a new transaction to make progress, the caller will log a
* new EFI with the current contents. It will also log an EFD to cancel
* the existing EFI, and so we need to copy all the unprocessed extents
* in this EFI to the EFD so this works correctly.
*/
if (error == -EAGAIN) {
xfs_efd_from_efi(efdp);
return error;
}
next_extent = efdp->efd_next_extent;
ASSERT(next_extent < efdp->efd_format.efd_nextents);
extp = &(efdp->efd_format.efd_extents[next_extent]);
extp->ext_start = xefi->xefi_startblock;
extp->ext_len = xefi->xefi_blockcount;
efdp->efd_next_extent++;
return error;
}
/* Sort bmap items by AG. */
static int
xfs_extent_free_diff_items(
......@@ -453,9 +357,6 @@ xfs_extent_free_log_item(
uint next_extent;
struct xfs_extent *extp;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags);
/*
* atomic_inc_return gives us the value after the increment;
* we want to use it as an array index so we need to subtract 1 from
......@@ -481,7 +382,6 @@ xfs_extent_free_create_intent(
ASSERT(count > 0);
xfs_trans_add_item(tp, &efip->efi_item);
if (sort)
list_sort(mp, items, xfs_extent_free_diff_items);
list_for_each_entry(xefi, items, xefi_list)
......@@ -496,7 +396,26 @@ xfs_extent_free_create_done(
struct xfs_log_item *intent,
unsigned int count)
{
return &xfs_trans_get_efd(tp, EFI_ITEM(intent), count)->efd_item;
struct xfs_efi_log_item *efip = EFI_ITEM(intent);
struct xfs_efd_log_item *efdp;
ASSERT(count > 0);
if (count > XFS_EFD_MAX_FAST_EXTENTS) {
efdp = kzalloc(xfs_efd_log_item_sizeof(count),
GFP_KERNEL | __GFP_NOFAIL);
} else {
efdp = kmem_cache_zalloc(xfs_efd_cache,
GFP_KERNEL | __GFP_NOFAIL);
}
xfs_log_item_init(tp->t_mountp, &efdp->efd_item, XFS_LI_EFD,
&xfs_efd_item_ops);
efdp->efd_efip = efip;
efdp->efd_format.efd_nextents = count;
efdp->efd_format.efd_efi_id = efip->efi_format.efi_id;
return &efdp->efd_item;
}
/* Take a passive ref to the AG containing the space we're freeing. */
......@@ -527,19 +446,48 @@ xfs_extent_free_finish_item(
struct list_head *item,
struct xfs_btree_cur **state)
{
struct xfs_owner_info oinfo = { };
struct xfs_extent_free_item *xefi;
struct xfs_efd_log_item *efdp = EFD_ITEM(done);
struct xfs_mount *mp = tp->t_mountp;
struct xfs_extent *extp;
uint next_extent;
xfs_agblock_t agbno;
int error;
xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock);
error = xfs_trans_free_extent(tp, EFD_ITEM(done), xefi);
oinfo.oi_owner = xefi->xefi_owner;
if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK)
oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
trace_xfs_bmap_free_deferred(tp->t_mountp, xefi->xefi_pag->pag_agno, 0,
agbno, xefi->xefi_blockcount);
/*
* Don't free the XEFI if we need a new transaction to complete
* processing of it.
* If we need a new transaction to make progress, the caller will log a
* new EFI with the current contents. It will also log an EFD to cancel
* the existing EFI, and so we need to copy all the unprocessed extents
* in this EFI to the EFD so this works correctly.
*/
if (error == -EAGAIN)
error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
if (error == -EAGAIN) {
xfs_efd_from_efi(efdp);
return error;
}
/* Add the work we finished to the EFD, even though nobody uses that */
next_extent = efdp->efd_next_extent;
ASSERT(next_extent < efdp->efd_format.efd_nextents);
extp = &(efdp->efd_format.efd_extents[next_extent]);
extp->ext_start = xefi->xefi_startblock;
extp->ext_len = xefi->xefi_blockcount;
efdp->efd_next_extent++;
xfs_extent_free_put_group(xefi);
kmem_cache_free(xfs_extfree_item_cache, xefi);
......@@ -601,16 +549,6 @@ xfs_agfl_free_finish_item(
error = xfs_free_agfl_block(tp, xefi->xefi_pag->pag_agno,
agbno, agbp, &oinfo);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the EFI and frees the EFD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
next_extent = efdp->efd_next_extent;
ASSERT(next_extent < efdp->efd_format.efd_nextents);
extp = &(efdp->efd_format.efd_extents[next_extent]);
......@@ -705,6 +643,31 @@ xfs_extent_free_recover_work(
return error;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_extent_free_relog_intent(
struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_log_item *done_item)
{
struct xfs_efd_log_item *efdp = EFD_ITEM(done_item);
struct xfs_efi_log_item *efip;
struct xfs_extent *extp;
unsigned int count;
count = EFI_ITEM(intent)->efi_format.efi_nextents;
extp = EFI_ITEM(intent)->efi_format.efi_extents;
efdp->efd_next_extent = count;
memcpy(efdp->efd_format.efd_extents, extp, count * sizeof(*extp));
efip = xfs_efi_init(tp->t_mountp, count);
memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp));
atomic_set(&efip->efi_next_extent, count);
return &efip->efi_item;
}
const struct xfs_defer_op_type xfs_extent_free_defer_type = {
.max_items = XFS_EFI_MAX_FAST_EXTENTS,
.create_intent = xfs_extent_free_create_intent,
......@@ -713,6 +676,7 @@ const struct xfs_defer_op_type xfs_extent_free_defer_type = {
.finish_item = xfs_extent_free_finish_item,
.cancel_item = xfs_extent_free_cancel_item,
.recover_work = xfs_extent_free_recover_work,
.relog_intent = xfs_extent_free_relog_intent,
};
/* sub-type with special handling for AGFL deferred frees */
......@@ -724,6 +688,7 @@ const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
.finish_item = xfs_agfl_free_finish_item,
.cancel_item = xfs_extent_free_cancel_item,
.recover_work = xfs_extent_free_recover_work,
.relog_intent = xfs_extent_free_relog_intent,
};
STATIC bool
......@@ -734,34 +699,6 @@ xfs_efi_item_match(
return EFI_ITEM(lip)->efi_format.efi_id == intent_id;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_efi_item_relog(
struct xfs_log_item *intent,
struct xfs_trans *tp)
{
struct xfs_efd_log_item *efdp;
struct xfs_efi_log_item *efip;
struct xfs_extent *extp;
unsigned int count;
count = EFI_ITEM(intent)->efi_format.efi_nextents;
extp = EFI_ITEM(intent)->efi_format.efi_extents;
tp->t_flags |= XFS_TRANS_DIRTY;
efdp = xfs_trans_get_efd(tp, EFI_ITEM(intent), count);
efdp->efd_next_extent = count;
memcpy(efdp->efd_format.efd_extents, extp, count * sizeof(*extp));
set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
efip = xfs_efi_init(tp->t_mountp, count);
memcpy(efip->efi_format.efi_extents, extp, count * sizeof(*extp));
atomic_set(&efip->efi_next_extent, count);
xfs_trans_add_item(tp, &efip->efi_item);
set_bit(XFS_LI_DIRTY, &efip->efi_item.li_flags);
return &efip->efi_item;
}
static const struct xfs_item_ops xfs_efi_item_ops = {
.flags = XFS_ITEM_INTENT,
.iop_size = xfs_efi_item_size,
......@@ -769,7 +706,6 @@ static const struct xfs_item_ops xfs_efi_item_ops = {
.iop_unpin = xfs_efi_item_unpin,
.iop_release = xfs_efi_item_release,
.iop_match = xfs_efi_item_match,
.iop_relog = xfs_efi_item_relog,
};
/*
......
......@@ -227,52 +227,6 @@ static const struct xfs_item_ops xfs_cud_item_ops = {
.iop_intent = xfs_cud_item_intent,
};
static struct xfs_cud_log_item *
xfs_trans_get_cud(
struct xfs_trans *tp,
struct xfs_cui_log_item *cuip)
{
struct xfs_cud_log_item *cudp;
cudp = kmem_cache_zalloc(xfs_cud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD,
&xfs_cud_item_ops);
cudp->cud_cuip = cuip;
cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id;
xfs_trans_add_item(tp, &cudp->cud_item);
return cudp;
}
/*
* Finish an refcount update and log it to the CUD. Note that the
* transaction is marked dirty regardless of whether the refcount
* update succeeds or fails to support the CUI/CUD lifecycle rules.
*/
static int
xfs_trans_log_finish_refcount_update(
struct xfs_trans *tp,
struct xfs_cud_log_item *cudp,
struct xfs_refcount_intent *ri,
struct xfs_btree_cur **pcur)
{
int error;
error = xfs_refcount_finish_one(tp, ri, pcur);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the CUI and frees the CUD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags);
return error;
}
/* Sort refcount intents by AG. */
static int
xfs_refcount_update_diff_items(
......@@ -318,9 +272,6 @@ xfs_refcount_update_log_item(
uint next_extent;
struct xfs_phys_extent *pmap;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags);
/*
* atomic_inc_return gives us the value after the increment;
* we want to use it as an array index so we need to subtract 1 from
......@@ -347,7 +298,6 @@ xfs_refcount_update_create_intent(
ASSERT(count > 0);
xfs_trans_add_item(tp, &cuip->cui_item);
if (sort)
list_sort(mp, items, xfs_refcount_update_diff_items);
list_for_each_entry(ri, items, ri_list)
......@@ -362,7 +312,16 @@ xfs_refcount_update_create_done(
struct xfs_log_item *intent,
unsigned int count)
{
return &xfs_trans_get_cud(tp, CUI_ITEM(intent))->cud_item;
struct xfs_cui_log_item *cuip = CUI_ITEM(intent);
struct xfs_cud_log_item *cudp;
cudp = kmem_cache_zalloc(xfs_cud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &cudp->cud_item, XFS_LI_CUD,
&xfs_cud_item_ops);
cudp->cud_cuip = cuip;
cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id;
return &cudp->cud_item;
}
/* Take a passive ref to the AG containing the space we're refcounting. */
......@@ -397,10 +356,9 @@ xfs_refcount_update_finish_item(
int error;
ri = container_of(item, struct xfs_refcount_intent, ri_list);
error = xfs_trans_log_finish_refcount_update(tp, CUD_ITEM(done), ri,
state);
/* Did we run out of reservation? Requeue what we didn't finish. */
error = xfs_refcount_finish_one(tp, ri, state);
if (!error && ri->ri_blockcount > 0) {
ASSERT(ri->ri_type == XFS_REFCOUNT_INCREASE ||
ri->ri_type == XFS_REFCOUNT_DECREASE);
......@@ -543,6 +501,27 @@ xfs_refcount_recover_work(
return error;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_refcount_relog_intent(
struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_log_item *done_item)
{
struct xfs_cui_log_item *cuip;
struct xfs_phys_extent *pmap;
unsigned int count;
count = CUI_ITEM(intent)->cui_format.cui_nextents;
pmap = CUI_ITEM(intent)->cui_format.cui_extents;
cuip = xfs_cui_init(tp->t_mountp, count);
memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap));
atomic_set(&cuip->cui_next_extent, count);
return &cuip->cui_item;
}
const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
.max_items = XFS_CUI_MAX_FAST_EXTENTS,
.create_intent = xfs_refcount_update_create_intent,
......@@ -552,6 +531,7 @@ const struct xfs_defer_op_type xfs_refcount_update_defer_type = {
.finish_cleanup = xfs_refcount_finish_one_cleanup,
.cancel_item = xfs_refcount_update_cancel_item,
.recover_work = xfs_refcount_recover_work,
.relog_intent = xfs_refcount_relog_intent,
};
STATIC bool
......@@ -562,32 +542,6 @@ xfs_cui_item_match(
return CUI_ITEM(lip)->cui_format.cui_id == intent_id;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_cui_item_relog(
struct xfs_log_item *intent,
struct xfs_trans *tp)
{
struct xfs_cud_log_item *cudp;
struct xfs_cui_log_item *cuip;
struct xfs_phys_extent *pmap;
unsigned int count;
count = CUI_ITEM(intent)->cui_format.cui_nextents;
pmap = CUI_ITEM(intent)->cui_format.cui_extents;
tp->t_flags |= XFS_TRANS_DIRTY;
cudp = xfs_trans_get_cud(tp, CUI_ITEM(intent));
set_bit(XFS_LI_DIRTY, &cudp->cud_item.li_flags);
cuip = xfs_cui_init(tp->t_mountp, count);
memcpy(cuip->cui_format.cui_extents, pmap, count * sizeof(*pmap));
atomic_set(&cuip->cui_next_extent, count);
xfs_trans_add_item(tp, &cuip->cui_item);
set_bit(XFS_LI_DIRTY, &cuip->cui_item.li_flags);
return &cuip->cui_item;
}
static const struct xfs_item_ops xfs_cui_item_ops = {
.flags = XFS_ITEM_INTENT,
.iop_size = xfs_cui_item_size,
......@@ -595,7 +549,6 @@ static const struct xfs_item_ops xfs_cui_item_ops = {
.iop_unpin = xfs_cui_item_unpin,
.iop_release = xfs_cui_item_release,
.iop_match = xfs_cui_item_match,
.iop_relog = xfs_cui_item_relog,
};
static inline void
......
......@@ -225,23 +225,6 @@ static const struct xfs_item_ops xfs_rud_item_ops = {
.iop_intent = xfs_rud_item_intent,
};
static struct xfs_rud_log_item *
xfs_trans_get_rud(
struct xfs_trans *tp,
struct xfs_rui_log_item *ruip)
{
struct xfs_rud_log_item *rudp;
rudp = kmem_cache_zalloc(xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD,
&xfs_rud_item_ops);
rudp->rud_ruip = ruip;
rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
xfs_trans_add_item(tp, &rudp->rud_item);
return rudp;
}
/* Set the map extent flags for this reverse mapping. */
static void
xfs_trans_set_rmap_flags(
......@@ -285,35 +268,6 @@ xfs_trans_set_rmap_flags(
}
}
/*
* Finish an rmap update and log it to the RUD. Note that the transaction is
* marked dirty regardless of whether the rmap update succeeds or fails to
* support the RUI/RUD lifecycle rules.
*/
static int
xfs_trans_log_finish_rmap_update(
struct xfs_trans *tp,
struct xfs_rud_log_item *rudp,
struct xfs_rmap_intent *ri,
struct xfs_btree_cur **pcur)
{
int error;
error = xfs_rmap_finish_one(tp, ri, pcur);
/*
* Mark the transaction dirty, even on error. This ensures the
* transaction is aborted, which:
*
* 1.) releases the RUI and frees the RUD
* 2.) shuts down the filesystem
*/
tp->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE;
set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags);
return error;
}
/* Sort rmap intents by AG. */
static int
xfs_rmap_update_diff_items(
......@@ -340,9 +294,6 @@ xfs_rmap_update_log_item(
uint next_extent;
struct xfs_map_extent *map;
tp->t_flags |= XFS_TRANS_DIRTY;
set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags);
/*
* atomic_inc_return gives us the value after the increment;
* we want to use it as an array index so we need to subtract 1 from
......@@ -372,7 +323,6 @@ xfs_rmap_update_create_intent(
ASSERT(count > 0);
xfs_trans_add_item(tp, &ruip->rui_item);
if (sort)
list_sort(mp, items, xfs_rmap_update_diff_items);
list_for_each_entry(ri, items, ri_list)
......@@ -387,7 +337,16 @@ xfs_rmap_update_create_done(
struct xfs_log_item *intent,
unsigned int count)
{
return &xfs_trans_get_rud(tp, RUI_ITEM(intent))->rud_item;
struct xfs_rui_log_item *ruip = RUI_ITEM(intent);
struct xfs_rud_log_item *rudp;
rudp = kmem_cache_zalloc(xfs_rud_cache, GFP_KERNEL | __GFP_NOFAIL);
xfs_log_item_init(tp->t_mountp, &rudp->rud_item, XFS_LI_RUD,
&xfs_rud_item_ops);
rudp->rud_ruip = ruip;
rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id;
return &rudp->rud_item;
}
/* Take a passive ref to the AG containing the space we're rmapping. */
......@@ -423,8 +382,7 @@ xfs_rmap_update_finish_item(
ri = container_of(item, struct xfs_rmap_intent, ri_list);
error = xfs_trans_log_finish_rmap_update(tp, RUD_ITEM(done), ri,
state);
error = xfs_rmap_finish_one(tp, ri, state);
xfs_rmap_update_put_group(ri);
kmem_cache_free(xfs_rmap_intent_cache, ri);
......@@ -596,6 +554,27 @@ xfs_rmap_recover_work(
return error;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_rmap_relog_intent(
struct xfs_trans *tp,
struct xfs_log_item *intent,
struct xfs_log_item *done_item)
{
struct xfs_rui_log_item *ruip;
struct xfs_map_extent *map;
unsigned int count;
count = RUI_ITEM(intent)->rui_format.rui_nextents;
map = RUI_ITEM(intent)->rui_format.rui_extents;
ruip = xfs_rui_init(tp->t_mountp, count);
memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map));
atomic_set(&ruip->rui_next_extent, count);
return &ruip->rui_item;
}
const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
.max_items = XFS_RUI_MAX_FAST_EXTENTS,
.create_intent = xfs_rmap_update_create_intent,
......@@ -605,6 +584,7 @@ const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
.finish_cleanup = xfs_rmap_finish_one_cleanup,
.cancel_item = xfs_rmap_update_cancel_item,
.recover_work = xfs_rmap_recover_work,
.relog_intent = xfs_rmap_relog_intent,
};
STATIC bool
......@@ -615,32 +595,6 @@ xfs_rui_item_match(
return RUI_ITEM(lip)->rui_format.rui_id == intent_id;
}
/* Relog an intent item to push the log tail forward. */
static struct xfs_log_item *
xfs_rui_item_relog(
struct xfs_log_item *intent,
struct xfs_trans *tp)
{
struct xfs_rud_log_item *rudp;
struct xfs_rui_log_item *ruip;
struct xfs_map_extent *map;
unsigned int count;
count = RUI_ITEM(intent)->rui_format.rui_nextents;
map = RUI_ITEM(intent)->rui_format.rui_extents;
tp->t_flags |= XFS_TRANS_DIRTY;
rudp = xfs_trans_get_rud(tp, RUI_ITEM(intent));
set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags);
ruip = xfs_rui_init(tp->t_mountp, count);
memcpy(ruip->rui_format.rui_extents, map, count * sizeof(*map));
atomic_set(&ruip->rui_next_extent, count);
xfs_trans_add_item(tp, &ruip->rui_item);
set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags);
return &ruip->rui_item;
}
static const struct xfs_item_ops xfs_rui_item_ops = {
.flags = XFS_ITEM_INTENT,
.iop_size = xfs_rui_item_size,
......@@ -648,7 +602,6 @@ static const struct xfs_item_ops xfs_rui_item_ops = {
.iop_unpin = xfs_rui_item_unpin,
.iop_release = xfs_rui_item_release,
.iop_match = xfs_rui_item_match,
.iop_relog = xfs_rui_item_relog,
};
static inline void
......
......@@ -79,8 +79,6 @@ struct xfs_item_ops {
uint (*iop_push)(struct xfs_log_item *, struct list_head *);
void (*iop_release)(struct xfs_log_item *);
bool (*iop_match)(struct xfs_log_item *item, uint64_t id);
struct xfs_log_item *(*iop_relog)(struct xfs_log_item *intent,
struct xfs_trans *tp);
struct xfs_log_item *(*iop_intent)(struct xfs_log_item *intent_done);
};
......@@ -245,14 +243,6 @@ void xfs_trans_buf_copy_type(struct xfs_buf *dst_bp,
extern struct kmem_cache *xfs_trans_cache;
static inline struct xfs_log_item *
xfs_trans_item_relog(
struct xfs_log_item *lip,
struct xfs_trans *tp)
{
return lip->li_ops->iop_relog(lip, tp);
}
struct xfs_dquot;
int xfs_trans_alloc_inode(struct xfs_inode *ip, struct xfs_trans_res *resv,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment