Skip to content

Commit

Permalink
xfs: recreate work items when recovering intent items
Browse files Browse the repository at this point in the history
Recreate work items for each xfs_defer_pending object when we are
recovering intent items.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Darrick J. Wong committed Dec 7, 2023
1 parent deb4cd8 commit e70fb32
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 163 deletions.
3 changes: 1 addition & 2 deletions fs/xfs/libxfs/xfs_defer.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,9 +676,8 @@ xfs_defer_add(
list_add_tail(&dfp->dfp_list, &tp->t_dfops);
}

list_add_tail(li, &dfp->dfp_work);
xfs_defer_add_item(dfp, li);
trace_xfs_defer_add_item(tp->t_mountp, dfp, li);
dfp->dfp_count++;
}

/*
Expand Down
9 changes: 9 additions & 0 deletions fs/xfs/libxfs/xfs_defer.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,15 @@ void xfs_defer_start_recovery(struct xfs_log_item *lip,
void xfs_defer_cancel_recovery(struct xfs_mount *mp,
struct xfs_defer_pending *dfp);

static inline void
xfs_defer_add_item(
struct xfs_defer_pending *dfp,
struct list_head *work)
{
list_add_tail(work, &dfp->dfp_work);
dfp->dfp_count++;
}

int __init xfs_defer_init_item_caches(void);
void xfs_defer_destroy_item_caches(void);

Expand Down
90 changes: 51 additions & 39 deletions fs/xfs/xfs_attr_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,42 +539,17 @@ xfs_attri_validate(
return xfs_verify_ino(mp, attrp->alfi_ino);
}

/*
* Process an attr intent item that was recovered from the log. We need to
* delete the attr that it describes.
*/
STATIC int
xfs_attri_item_recover(
static inline struct xfs_attr_intent *
xfs_attri_recover_work(
struct xfs_mount *mp,
struct xfs_defer_pending *dfp,
struct list_head *capture_list)
struct xfs_attri_log_format *attrp,
struct xfs_inode *ip,
struct xfs_attri_log_nameval *nv)
{
struct xfs_log_item *lip = dfp->dfp_intent;
struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
struct xfs_attr_intent *attr;
struct xfs_mount *mp = lip->li_log->l_mp;
struct xfs_inode *ip;
struct xfs_da_args *args;
struct xfs_trans *tp;
struct xfs_trans_res resv;
struct xfs_attri_log_format *attrp;
struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
int error;
int total;
int local;
struct xfs_attrd_log_item *done_item = NULL;

/*
* First check the validity of the attr described by the ATTRI. If any
* are bad, then assume that all are bad and just toss the ATTRI.
*/
attrp = &attrip->attri_format;
if (!xfs_attri_validate(mp, attrp) ||
!xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len))
return -EFSCORRUPTED;

error = xlog_recover_iget(mp, attrp->alfi_ino, &ip);
if (error)
return error;

attr = kmem_zalloc(sizeof(struct xfs_attr_intent) +
sizeof(struct xfs_da_args), KM_NOFS);
Expand Down Expand Up @@ -618,19 +593,58 @@ xfs_attri_item_recover(
case XFS_ATTRI_OP_FLAGS_REMOVE:
attr->xattri_dela_state = xfs_attr_init_remove_state(args);
break;
default:
ASSERT(0);
error = -EFSCORRUPTED;
goto out;
}

xfs_defer_add_item(dfp, &attr->xattri_list);
return attr;
}

/*
* Process an attr intent item that was recovered from the log. We need to
* delete the attr that it describes.
*/
STATIC int
xfs_attri_item_recover(
struct xfs_defer_pending *dfp,
struct list_head *capture_list)
{
struct xfs_log_item *lip = dfp->dfp_intent;
struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip);
struct xfs_attr_intent *attr;
struct xfs_mount *mp = lip->li_log->l_mp;
struct xfs_inode *ip;
struct xfs_da_args *args;
struct xfs_trans *tp;
struct xfs_trans_res resv;
struct xfs_attri_log_format *attrp;
struct xfs_attri_log_nameval *nv = attrip->attri_nameval;
int error;
int total;
struct xfs_attrd_log_item *done_item = NULL;

/*
* First check the validity of the attr described by the ATTRI. If any
* are bad, then assume that all are bad and just toss the ATTRI.
*/
attrp = &attrip->attri_format;
if (!xfs_attri_validate(mp, attrp) ||
!xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len))
return -EFSCORRUPTED;

error = xlog_recover_iget(mp, attrp->alfi_ino, &ip);
if (error)
return error;

attr = xfs_attri_recover_work(mp, dfp, attrp, ip, nv);
args = attr->xattri_da_args;

xfs_init_attr_trans(args, &resv, &total);
resv = xlog_recover_resv(&resv);
error = xfs_trans_alloc(mp, &resv, total, 0, XFS_TRANS_RESERVE, &tp);
if (error)
goto out;

return error;
args->trans = tp;

done_item = xfs_trans_get_attrd(tp, attrip);
xlog_recover_transfer_intent(tp, dfp);

Expand Down Expand Up @@ -661,8 +675,6 @@ xfs_attri_item_recover(
out_unlock:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_irele(ip);
out:
xfs_attr_free_item(attr);
return error;
}

Expand Down
55 changes: 35 additions & 20 deletions fs/xfs/xfs_bmap_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,28 @@ xfs_bui_validate(
return xfs_verify_fsbext(mp, map->me_startblock, map->me_len);
}

static inline struct xfs_bmap_intent *
xfs_bui_recover_work(
struct xfs_mount *mp,
struct xfs_defer_pending *dfp,
struct xfs_map_extent *map)
{
struct xfs_bmap_intent *bi;

bi = kmem_cache_zalloc(xfs_bmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
bi->bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
bi->bi_type = map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK;
bi->bi_bmap.br_startblock = map->me_startblock;
bi->bi_bmap.br_startoff = map->me_startoff;
bi->bi_bmap.br_blockcount = map->me_len;
bi->bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ?
XFS_EXT_UNWRITTEN : XFS_EXT_NORM;

xfs_defer_add_item(dfp, &bi->bi_list);
return bi;
}

/*
* Process a bmap update intent item that was recovered from the log.
* We need to update some inode's bmbt.
Expand All @@ -489,7 +511,6 @@ xfs_bui_item_recover(
struct xfs_defer_pending *dfp,
struct list_head *capture_list)
{
struct xfs_bmap_intent fake = { };
struct xfs_trans_res resv;
struct xfs_log_item *lip = dfp->dfp_intent;
struct xfs_bui_log_item *buip = BUI_ITEM(lip);
Expand All @@ -498,6 +519,7 @@ xfs_bui_item_recover(
struct xfs_mount *mp = lip->li_log->l_mp;
struct xfs_map_extent *map;
struct xfs_bud_log_item *budp;
struct xfs_bmap_intent *fake;
int iext_delta;
int error = 0;

Expand All @@ -508,9 +530,7 @@ xfs_bui_item_recover(
}

map = &buip->bui_format.bui_extents[0];
fake.bi_whichfork = (map->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
fake.bi_type = map->me_flags & XFS_BMAP_EXTENT_TYPE_MASK;
fake = xfs_bui_recover_work(mp, dfp, map);

error = xlog_recover_iget(mp, map->me_owner, &ip);
if (error)
Expand All @@ -529,36 +549,31 @@ xfs_bui_item_recover(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);

if (fake.bi_type == XFS_BMAP_MAP)
if (fake->bi_type == XFS_BMAP_MAP)
iext_delta = XFS_IEXT_ADD_NOSPLIT_CNT;
else
iext_delta = XFS_IEXT_PUNCH_HOLE_CNT;

error = xfs_iext_count_may_overflow(ip, fake.bi_whichfork, iext_delta);
error = xfs_iext_count_may_overflow(ip, fake->bi_whichfork, iext_delta);
if (error == -EFBIG)
error = xfs_iext_count_upgrade(tp, ip, iext_delta);
if (error)
goto err_cancel;

fake.bi_owner = ip;
fake.bi_bmap.br_startblock = map->me_startblock;
fake.bi_bmap.br_startoff = map->me_startoff;
fake.bi_bmap.br_blockcount = map->me_len;
fake.bi_bmap.br_state = (map->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ?
XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
fake->bi_owner = ip;

xfs_bmap_update_get_group(mp, &fake);
error = xfs_trans_log_finish_bmap_update(tp, budp, &fake);
xfs_bmap_update_get_group(mp, fake);
error = xfs_trans_log_finish_bmap_update(tp, budp, fake);
if (error == -EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, map,
sizeof(*map));
xfs_bmap_update_put_group(&fake);
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
&buip->bui_format, sizeof(buip->bui_format));
xfs_bmap_update_put_group(fake);
if (error)
goto err_cancel;

if (fake.bi_bmap.br_blockcount > 0) {
ASSERT(fake.bi_type == XFS_BMAP_UNMAP);
xfs_bmap_unmap_extent(tp, ip, &fake.bi_bmap);
if (fake->bi_bmap.br_blockcount > 0) {
ASSERT(fake->bi_type == XFS_BMAP_UNMAP);
xfs_bmap_unmap_extent(tp, ip, &fake->bi_bmap);
}

/*
Expand Down
49 changes: 30 additions & 19 deletions fs/xfs/xfs_extfree_item.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,24 @@ xfs_efi_validate_ext(
return xfs_verify_fsbext(mp, extp->ext_start, extp->ext_len);
}

static inline void
xfs_efi_recover_work(
struct xfs_mount *mp,
struct xfs_defer_pending *dfp,
struct xfs_extent *extp)
{
struct xfs_extent_free_item *xefi;

xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
GFP_KERNEL | __GFP_NOFAIL);
xefi->xefi_startblock = extp->ext_start;
xefi->xefi_blockcount = extp->ext_len;
xefi->xefi_agresv = XFS_AG_RESV_NONE;
xefi->xefi_owner = XFS_RMAP_OWN_UNKNOWN;

xfs_defer_add_item(dfp, &xefi->xefi_list);
}

/*
* Process an extent free intent item that was recovered from
* the log. We need to free the extents that it describes.
Expand All @@ -666,6 +684,7 @@ xfs_efi_item_recover(
struct xfs_mount *mp = lip->li_log->l_mp;
struct xfs_efd_log_item *efdp;
struct xfs_trans *tp;
struct xfs_extent_free_item *fake;
int i;
int error = 0;
bool requeue_only = false;
Expand All @@ -683,6 +702,8 @@ xfs_efi_item_recover(
sizeof(efip->efi_format));
return -EFSCORRUPTED;
}

xfs_efi_recover_work(mp, dfp, &efip->efi_format.efi_extents[i]);
}

resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
Expand All @@ -693,22 +714,11 @@ xfs_efi_item_recover(
efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
xlog_recover_transfer_intent(tp, dfp);

for (i = 0; i < efip->efi_format.efi_nextents; i++) {
struct xfs_extent_free_item fake = {
.xefi_owner = XFS_RMAP_OWN_UNKNOWN,
.xefi_agresv = XFS_AG_RESV_NONE,
};
struct xfs_extent *extp;

extp = &efip->efi_format.efi_extents[i];

fake.xefi_startblock = extp->ext_start;
fake.xefi_blockcount = extp->ext_len;

list_for_each_entry(fake, &dfp->dfp_work, xefi_list) {
if (!requeue_only) {
xfs_extent_free_get_group(mp, &fake);
error = xfs_trans_free_extent(tp, efdp, &fake);
xfs_extent_free_put_group(&fake);
xfs_extent_free_get_group(mp, fake);
error = xfs_trans_free_extent(tp, efdp, fake);
xfs_extent_free_put_group(fake);
}

/*
Expand All @@ -717,10 +727,10 @@ xfs_efi_item_recover(
* run again later with a new transaction context.
*/
if (error == -EAGAIN || requeue_only) {
error = xfs_free_extent_later(tp, fake.xefi_startblock,
fake.xefi_blockcount,
error = xfs_free_extent_later(tp, fake->xefi_startblock,
fake->xefi_blockcount,
&XFS_RMAP_OINFO_ANY_OWNER,
fake.xefi_agresv);
fake->xefi_agresv);
if (!error) {
requeue_only = true;
continue;
Expand All @@ -729,7 +739,8 @@ xfs_efi_item_recover(

if (error == -EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
extp, sizeof(*extp));
&efip->efi_format,
sizeof(efip->efi_format));
if (error)
goto abort_error;

Expand Down
Loading

0 comments on commit e70fb32

Please sign in to comment.