diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_refcount.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index b177ef33cd4c..82a38d86ebad 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c | |||
@@ -1629,13 +1629,28 @@ xfs_refcount_recover_cow_leftovers( | |||
1629 | if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) | 1629 | if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) |
1630 | return -EOPNOTSUPP; | 1630 | return -EOPNOTSUPP; |
1631 | 1631 | ||
1632 | error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); | 1632 | INIT_LIST_HEAD(&debris); |
1633 | |||
1634 | /* | ||
1635 | * In this first part, we use an empty transaction to gather up | ||
1636 | * all the leftover CoW extents so that we can subsequently | ||
1637 | * delete them. The empty transaction is used to avoid | ||
1638 | * a buffer lock deadlock if there happens to be a loop in the | ||
1639 | * refcountbt because we're allowed to re-grab a buffer that is | ||
1640 | * already attached to our transaction. When we're done | ||
1641 | * recording the CoW debris we cancel the (empty) transaction | ||
1642 | * and everything goes away cleanly. | ||
1643 | */ | ||
1644 | error = xfs_trans_alloc_empty(mp, &tp); | ||
1633 | if (error) | 1645 | if (error) |
1634 | return error; | 1646 | return error; |
1635 | cur = xfs_refcountbt_init_cursor(mp, NULL, agbp, agno, NULL); | 1647 | |
1648 | error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); | ||
1649 | if (error) | ||
1650 | goto out_trans; | ||
1651 | cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); | ||
1636 | 1652 | ||
1637 | /* Find all the leftover CoW staging extents. */ | 1653 | /* Find all the leftover CoW staging extents. */ |
1638 | INIT_LIST_HEAD(&debris); | ||
1639 | memset(&low, 0, sizeof(low)); | 1654 | memset(&low, 0, sizeof(low)); |
1640 | memset(&high, 0, sizeof(high)); | 1655 | memset(&high, 0, sizeof(high)); |
1641 | low.rc.rc_startblock = XFS_REFC_COW_START; | 1656 | low.rc.rc_startblock = XFS_REFC_COW_START; |
@@ -1645,10 +1660,11 @@ xfs_refcount_recover_cow_leftovers( | |||
1645 | if (error) | 1660 | if (error) |
1646 | goto out_cursor; | 1661 | goto out_cursor; |
1647 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); | 1662 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
1648 | xfs_buf_relse(agbp); | 1663 | xfs_trans_brelse(tp, agbp); |
1664 | xfs_trans_cancel(tp); | ||
1649 | 1665 | ||
1650 | /* Now iterate the list to free the leftovers */ | 1666 | /* Now iterate the list to free the leftovers */ |
1651 | list_for_each_entry(rr, &debris, rr_list) { | 1667 | list_for_each_entry_safe(rr, n, &debris, rr_list) { |
1652 | /* Set up transaction. */ | 1668 | /* Set up transaction. */ |
1653 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); | 1669 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); |
1654 | if (error) | 1670 | if (error) |
@@ -1676,8 +1692,16 @@ xfs_refcount_recover_cow_leftovers( | |||
1676 | error = xfs_trans_commit(tp); | 1692 | error = xfs_trans_commit(tp); |
1677 | if (error) | 1693 | if (error) |
1678 | goto out_free; | 1694 | goto out_free; |
1695 | |||
1696 | list_del(&rr->rr_list); | ||
1697 | kmem_free(rr); | ||
1679 | } | 1698 | } |
1680 | 1699 | ||
1700 | return error; | ||
1701 | out_defer: | ||
1702 | xfs_defer_cancel(&dfops); | ||
1703 | out_trans: | ||
1704 | xfs_trans_cancel(tp); | ||
1681 | out_free: | 1705 | out_free: |
1682 | /* Free the leftover list */ | 1706 | /* Free the leftover list */ |
1683 | list_for_each_entry_safe(rr, n, &debris, rr_list) { | 1707 | list_for_each_entry_safe(rr, n, &debris, rr_list) { |
@@ -1688,11 +1712,6 @@ out_free: | |||
1688 | 1712 | ||
1689 | out_cursor: | 1713 | out_cursor: |
1690 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 1714 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
1691 | xfs_buf_relse(agbp); | 1715 | xfs_trans_brelse(tp, agbp); |
1692 | goto out_free; | 1716 | goto out_trans; |
1693 | |||
1694 | out_defer: | ||
1695 | xfs_defer_cancel(&dfops); | ||
1696 | xfs_trans_cancel(tp); | ||
1697 | goto out_free; | ||
1698 | } | 1717 | } |