diff options
author | Alex Lyakas <alex@zadarastorage.com> | 2016-05-18 00:01:52 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-05-18 00:01:52 -0400 |
commit | 32b43ab6fb983e5a117048443e628c235cd2c5bd (patch) | |
tree | c953aa9cfd4ab662cbccbdd649238a0ea5cf7c79 | |
parent | 7d3aa7fe970791f1a674b14572a411accf2f4d4e (diff) |
xfs: optimise xfs_iext_destroy
When unmounting XFS, we call:
xfs_inode_free => xfs_idestroy_fork => xfs_iext_destroy
This goes over the whole indirection array and calls
xfs_iext_irec_remove for each one of the erps (from the last one to
the first one). As a result, we keep shrinking (reallocating
actually) the indirection array until we shrink out all of its
elements. When we have files with huge numbers of extents, umount
takes 30-80 sec, depending on the amount of files that XFS loaded
and the amount of indirection entries of each file. The unmount
stack looks like:
[<ffffffffc0b6d200>] xfs_iext_realloc_indirect+0x40/0x60 [xfs]
[<ffffffffc0b6cd8e>] xfs_iext_irec_remove+0xee/0xf0 [xfs]
[<ffffffffc0b6cdcd>] xfs_iext_destroy+0x3d/0xb0 [xfs]
[<ffffffffc0b6cef6>] xfs_idestroy_fork+0xb6/0xf0 [xfs]
[<ffffffffc0b87002>] xfs_inode_free+0xb2/0xc0 [xfs]
[<ffffffffc0b87260>] xfs_reclaim_inode+0x250/0x340 [xfs]
[<ffffffffc0b87583>] xfs_reclaim_inodes_ag+0x233/0x370 [xfs]
[<ffffffffc0b8823d>] xfs_reclaim_inodes+0x1d/0x20 [xfs]
[<ffffffffc0b96feb>] xfs_unmountfs+0x7b/0x1a0 [xfs]
[<ffffffffc0b98e4d>] xfs_fs_put_super+0x2d/0x70 [xfs]
[<ffffffff811e9e36>] generic_shutdown_super+0x76/0x100
[<ffffffff811ea207>] kill_block_super+0x27/0x70
[<ffffffff811ea519>] deactivate_locked_super+0x49/0x60
[<ffffffff811eaaee>] deactivate_super+0x4e/0x70
[<ffffffff81207593>] cleanup_mnt+0x43/0x90
[<ffffffff81207632>] __cleanup_mnt+0x12/0x20
[<ffffffff8108f8e7>] task_work_run+0xa7/0xe0
[<ffffffff81014ff7>] do_notify_resume+0x97/0xb0
[<ffffffff81717c6f>] int_signal+0x12/0x17
Further, this reallocation prevents us from freeing the extent list
from a RCU callback as allocation can block. Hence if the extent
list is in indirect format, optimise the freeing of the extent list
to only use kmem_free calls by freeing entire extent buffer pages at
a time, rather than extent by extent.
[dchinner: simplified freeing loop based on Christoph's suggestion]
Signed-off-by: Alex Lyakas <alex@zadarastorage.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/libxfs/xfs_inode_fork.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 11faf7df14c8..8fe6617a8653 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c | |||
@@ -1497,6 +1497,24 @@ xfs_iext_indirect_to_direct( | |||
1497 | } | 1497 | } |
1498 | 1498 | ||
1499 | /* | 1499 | /* |
1500 | * Remove all records from the indirection array. | ||
1501 | */ | ||
1502 | STATIC void | ||
1503 | xfs_iext_irec_remove_all( | ||
1504 | struct xfs_ifork *ifp) | ||
1505 | { | ||
1506 | int nlists; | ||
1507 | int i; | ||
1508 | |||
1509 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | ||
1510 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | ||
1511 | for (i = 0; i < nlists; i++) | ||
1512 | kmem_free(ifp->if_u1.if_ext_irec[i].er_extbuf); | ||
1513 | kmem_free(ifp->if_u1.if_ext_irec); | ||
1514 | ifp->if_flags &= ~XFS_IFEXTIREC; | ||
1515 | } | ||
1516 | |||
1517 | /* | ||
1500 | * Free incore file extents. | 1518 | * Free incore file extents. |
1501 | */ | 1519 | */ |
1502 | void | 1520 | void |
@@ -1504,14 +1522,7 @@ xfs_iext_destroy( | |||
1504 | xfs_ifork_t *ifp) /* inode fork pointer */ | 1522 | xfs_ifork_t *ifp) /* inode fork pointer */ |
1505 | { | 1523 | { |
1506 | if (ifp->if_flags & XFS_IFEXTIREC) { | 1524 | if (ifp->if_flags & XFS_IFEXTIREC) { |
1507 | int erp_idx; | 1525 | xfs_iext_irec_remove_all(ifp); |
1508 | int nlists; | ||
1509 | |||
1510 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | ||
1511 | for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) { | ||
1512 | xfs_iext_irec_remove(ifp, erp_idx); | ||
1513 | } | ||
1514 | ifp->if_flags &= ~XFS_IFEXTIREC; | ||
1515 | } else if (ifp->if_real_bytes) { | 1526 | } else if (ifp->if_real_bytes) { |
1516 | kmem_free(ifp->if_u1.if_extents); | 1527 | kmem_free(ifp->if_u1.if_extents); |
1517 | } else if (ifp->if_bytes) { | 1528 | } else if (ifp->if_bytes) { |