From d0b2f91bede3bd5e3d24dd6803e56eee959c1797 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 20 Oct 2016 00:10:27 -0300 Subject: Linux-libre 4.8.2-gnu --- fs/xfs/xfs_extfree_item.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'fs/xfs/xfs_extfree_item.c') diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 4aa015321..d7bc14906 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -20,12 +20,15 @@ #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" +#include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_trans.h" #include "xfs_trans_priv.h" #include "xfs_buf_item.h" #include "xfs_extfree_item.h" #include "xfs_log.h" +#include "xfs_btree.h" +#include "xfs_rmap.h" kmem_zone_t *xfs_efi_zone; @@ -40,6 +43,7 @@ void xfs_efi_item_free( struct xfs_efi_log_item *efip) { + kmem_free(efip->efi_item.li_lv_shadow); if (efip->efi_format.efi_nextents > XFS_EFI_MAX_FAST_EXTENTS) kmem_free(efip); else @@ -300,6 +304,7 @@ static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip) STATIC void xfs_efd_item_free(struct xfs_efd_log_item *efdp) { + kmem_free(efdp->efd_item.li_lv_shadow); if (efdp->efd_format.efd_nextents > XFS_EFD_MAX_FAST_EXTENTS) kmem_free(efdp); else @@ -484,3 +489,69 @@ xfs_efd_init( return efdp; } + +/* + * Process an extent free intent item that was recovered from + * the log. We need to free the extents that it describes. + */ +int +xfs_efi_recover( + struct xfs_mount *mp, + struct xfs_efi_log_item *efip) +{ + struct xfs_efd_log_item *efdp; + struct xfs_trans *tp; + int i; + int error = 0; + xfs_extent_t *extp; + xfs_fsblock_t startblock_fsb; + struct xfs_owner_info oinfo; + + ASSERT(!test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)); + + /* + * First check the validity of the extents described by the + * EFI. If any are bad, then assume that all are bad and + * just toss the EFI. + */ + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &efip->efi_format.efi_extents[i]; + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, extp->ext_start)); + if (startblock_fsb == 0 || + extp->ext_len == 0 || + startblock_fsb >= mp->m_sb.sb_dblocks || + extp->ext_len >= mp->m_sb.sb_agblocks) { + /* + * This will pull the EFI from the AIL and + * free the memory associated with it. + */ + set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); + xfs_efi_release(efip); + return -EIO; + } + } + + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); + if (error) + return error; + efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); + + xfs_rmap_skip_owner_update(&oinfo); + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &efip->efi_format.efi_extents[i]; + error = xfs_trans_free_extent(tp, efdp, extp->ext_start, + extp->ext_len, &oinfo); + if (error) + goto abort_error; + + } + + set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); + error = xfs_trans_commit(tp); + return error; + +abort_error: + xfs_trans_cancel(tp); + return error; +} -- cgit v1.2.3-54-g00ecf