Commit e70fb328 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: recreate work items when recovering intent items

Recreate work items for each xfs_defer_pending object when we are
recovering intent items.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent deb4cd8b
......@@ -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++;
}
/*
......
......@@ -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);
......
......@@ -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);
......@@ -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);
......@@ -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;
}
......
......@@ -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.
......@@ -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);
......@@ -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;
......@@ -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)
......@@ -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);
}
/*
......
......@@ -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.
......@@ -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;
......@@ -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);
......@@ -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);
}
/*
......@@ -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;
......@@ -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;
......
......@@ -468,6 +468,23 @@ xfs_cui_validate_phys(
return xfs_verify_fsbext(mp, pmap->pe_startblock, pmap->pe_len);
}
static inline void
xfs_cui_recover_work(
struct xfs_mount *mp,
struct xfs_defer_pending *dfp,
struct xfs_phys_extent *pmap)
{
struct xfs_refcount_intent *ri;
ri = kmem_cache_alloc(xfs_refcount_intent_cache,
GFP_NOFS | __GFP_NOFAIL);
ri->ri_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK;
ri->ri_startblock = pmap->pe_startblock;
ri->ri_blockcount = pmap->pe_len;
xfs_defer_add_item(dfp, &ri->ri_list);
}
/*
* Process a refcount update intent item that was recovered from the log.
* We need to update the refcountbt.
......@@ -484,7 +501,7 @@ xfs_cui_item_recover(
struct xfs_trans *tp;
struct xfs_btree_cur *rcur = NULL;
struct xfs_mount *mp = lip->li_log->l_mp;
unsigned int refc_type;
struct xfs_refcount_intent *fake;
bool requeue_only = false;
int i;
int error = 0;
......@@ -502,6 +519,8 @@ xfs_cui_item_recover(
sizeof(cuip->cui_format));
return -EFSCORRUPTED;
}
xfs_cui_recover_work(mp, dfp, &cuip->cui_format.cui_extents[i]);
}
/*
......@@ -525,35 +544,12 @@ xfs_cui_item_recover(
cudp = xfs_trans_get_cud(tp, cuip);
xlog_recover_transfer_intent(tp, dfp);
for (i = 0; i < cuip->cui_format.cui_nextents; i++) {
struct xfs_refcount_intent fake = { };
struct xfs_phys_extent *pmap;
pmap = &cuip->cui_format.cui_extents[i];
refc_type = pmap->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK;
switch (refc_type) {
case XFS_REFCOUNT_INCREASE:
case XFS_REFCOUNT_DECREASE:
case XFS_REFCOUNT_ALLOC_COW:
case XFS_REFCOUNT_FREE_COW:
fake.ri_type = refc_type;
break;
default:
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
&cuip->cui_format,
sizeof(cuip->cui_format));
error = -EFSCORRUPTED;
goto abort_error;
}
fake.ri_startblock = pmap->pe_startblock;
fake.ri_blockcount = pmap->pe_len;
list_for_each_entry(fake, &dfp->dfp_work, ri_list) {
if (!requeue_only) {
xfs_refcount_update_get_group(mp, &fake);
xfs_refcount_update_get_group(mp, fake);
error = xfs_trans_log_finish_refcount_update(tp, cudp,
&fake, &rcur);
xfs_refcount_update_put_group(&fake);
fake, &rcur);
xfs_refcount_update_put_group(fake);
}
if (error == -EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
......@@ -563,13 +559,13 @@ xfs_cui_item_recover(
goto abort_error;
/* Requeue what we didn't finish. */
if (fake.ri_blockcount > 0) {
if (fake->ri_blockcount > 0) {
struct xfs_bmbt_irec irec = {
.br_startblock = fake.ri_startblock,
.br_blockcount = fake.ri_blockcount,
.br_startblock = fake->ri_startblock,
.br_blockcount = fake->ri_blockcount,
};
switch (fake.ri_type) {
switch (fake->ri_type) {
case XFS_REFCOUNT_INCREASE:
xfs_refcount_increase_extent(tp, &irec);
break;
......
......@@ -498,6 +498,58 @@ xfs_rui_validate_map(
return xfs_verify_fsbext(mp, map->me_startblock, map->me_len);
}
static inline void
xfs_rui_recover_work(
struct xfs_mount *mp,
struct xfs_defer_pending *dfp,
const struct xfs_map_extent *map)
{
struct xfs_rmap_intent *ri;
ri = kmem_cache_alloc(xfs_rmap_intent_cache, GFP_NOFS | __GFP_NOFAIL);
switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) {
case XFS_RMAP_EXTENT_MAP:
ri->ri_type = XFS_RMAP_MAP;
break;
case XFS_RMAP_EXTENT_MAP_SHARED:
ri->ri_type = XFS_RMAP_MAP_SHARED;
break;
case XFS_RMAP_EXTENT_UNMAP:
ri->ri_type = XFS_RMAP_UNMAP;
break;
case XFS_RMAP_EXTENT_UNMAP_SHARED:
ri->ri_type = XFS_RMAP_UNMAP_SHARED;
break;
case XFS_RMAP_EXTENT_CONVERT:
ri->ri_type = XFS_RMAP_CONVERT;
break;
case XFS_RMAP_EXTENT_CONVERT_SHARED:
ri->ri_type = XFS_RMAP_CONVERT_SHARED;
break;
case XFS_RMAP_EXTENT_ALLOC:
ri->ri_type = XFS_RMAP_ALLOC;
break;
case XFS_RMAP_EXTENT_FREE:
ri->ri_type = XFS_RMAP_FREE;
break;
default:
ASSERT(0);
return;
}
ri->ri_owner = map->me_owner;
ri->ri_whichfork = (map->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
ri->ri_bmap.br_startblock = map->me_startblock;
ri->ri_bmap.br_startoff = map->me_startoff;
ri->ri_bmap.br_blockcount = map->me_len;
ri->ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ?
XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
xfs_defer_add_item(dfp, &ri->ri_list);
}
/*
* Process an rmap update intent item that was recovered from the log.
* We need to update the rmapbt.
......@@ -514,6 +566,7 @@ xfs_rui_item_recover(
struct xfs_trans *tp;
struct xfs_btree_cur *rcur = NULL;
struct xfs_mount *mp = lip->li_log->l_mp;
struct xfs_rmap_intent *fake;
int i;
int error = 0;
......@@ -530,6 +583,8 @@ xfs_rui_item_recover(
sizeof(ruip->rui_format));
return -EFSCORRUPTED;
}
xfs_rui_recover_work(mp, dfp, &ruip->rui_format.rui_extents[i]);
}
resv = xlog_recover_resv(&M_RES(mp)->tr_itruncate);
......@@ -541,60 +596,15 @@ xfs_rui_item_recover(
rudp = xfs_trans_get_rud(tp, ruip);
xlog_recover_transfer_intent(tp, dfp);
for (i = 0; i < ruip->rui_format.rui_nextents; i++) {
struct xfs_rmap_intent fake = { };
struct xfs_map_extent *map;
map = &ruip->rui_format.rui_extents[i];
switch (map->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) {
case XFS_RMAP_EXTENT_MAP:
fake.ri_type = XFS_RMAP_MAP;
break;
case XFS_RMAP_EXTENT_MAP_SHARED:
fake.ri_type = XFS_RMAP_MAP_SHARED;
break;
case XFS_RMAP_EXTENT_UNMAP:
fake.ri_type = XFS_RMAP_UNMAP;
break;
case XFS_RMAP_EXTENT_UNMAP_SHARED:
fake.ri_type = XFS_RMAP_UNMAP_SHARED;
break;
case XFS_RMAP_EXTENT_CONVERT:
fake.ri_type = XFS_RMAP_CONVERT;
break;
case XFS_RMAP_EXTENT_CONVERT_SHARED:
fake.ri_type = XFS_RMAP_CONVERT_SHARED;
break;
case XFS_RMAP_EXTENT_ALLOC:
fake.ri_type = XFS_RMAP_ALLOC;
break;
case XFS_RMAP_EXTENT_FREE:
fake.ri_type = XFS_RMAP_FREE;
break;
default:
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
&ruip->rui_format,
sizeof(ruip->rui_format));
error = -EFSCORRUPTED;
goto abort_error;
}
fake.ri_owner = map->me_owner;
fake.ri_whichfork = (map->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ?
XFS_ATTR_FORK : XFS_DATA_FORK;
fake.ri_bmap.br_startblock = map->me_startblock;
fake.ri_bmap.br_startoff = map->me_startoff;
fake.ri_bmap.br_blockcount = map->me_len;
fake.ri_bmap.br_state = (map->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ?
XFS_EXT_UNWRITTEN : XFS_EXT_NORM;
xfs_rmap_update_get_group(mp, &fake);
error = xfs_trans_log_finish_rmap_update(tp, rudp, &fake,
list_for_each_entry(fake, &dfp->dfp_work, ri_list) {
xfs_rmap_update_get_group(mp, fake);
error = xfs_trans_log_finish_rmap_update(tp, rudp, fake,
&rcur);
if (error == -EFSCORRUPTED)
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
map, sizeof(*map));
xfs_rmap_update_put_group(&fake);
&ruip->rui_format,
sizeof(ruip->rui_format));
xfs_rmap_update_put_group(fake);
if (error)
goto abort_error;
......
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