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

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
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -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++;
}

/*
+9 −0
Original line number Diff line number Diff line
@@ -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);

+51 −39
Original line number Diff line number Diff line
@@ -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;
}

+35 −20
Original line number Diff line number Diff line
@@ -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);
	}

	/*
+30 −19
Original line number Diff line number Diff line
@@ -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;

Loading