diff options
Diffstat (limited to 'fs/xfs/xfs_icache.c')
-rw-r--r-- | fs/xfs/xfs_icache.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 426e63c7718a..a2096ca82504 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -26,6 +26,7 @@ #include "xfs_health.h" #include <linux/iversion.h> +#include <linux/nmi.h> STATIC int xfs_inode_free_eofblocks(struct xfs_inode *ip, void *args); STATIC int xfs_inode_free_cowblocks(struct xfs_inode *ip, void *args); @@ -2114,8 +2115,12 @@ xfs_inactive_inodes( struct xfs_mount *mp, struct xfs_eofblocks *eofb) { - return __xfs_inode_walk(mp, XFS_INODE_WALK_INACTIVE, + int error; + + error = __xfs_inode_walk(mp, XFS_INODE_WALK_INACTIVE, xfs_inactive_inode, eofb, XFS_ICI_INACTIVE_TAG); + wake_up(&mp->m_inactive_wait); + return error; } /* Try to get inode inactivation moving. */ @@ -2145,6 +2150,7 @@ xfs_inactive_worker( if (error && error != -EAGAIN) xfs_err(mp, "inode inactivation failed, error %d", error); + wake_up(&mp->m_inactive_wait); sb_end_write(mp->m_super); xfs_inactive_work_queue(pag); } @@ -2237,3 +2243,42 @@ xfs_inactive_schedule_now( spin_unlock(&pag->pag_ici_lock); } } + +/* Return true if there are inodes still being inactivated. */ +static bool +xfs_inactive_pending( + struct xfs_mount *mp) +{ + struct xfs_perag *pag; + xfs_agnumber_t agno = 0; + bool ret = false; + + while (!ret && + (pag = xfs_perag_get_tag(mp, agno, XFS_ICI_INACTIVE_TAG))) { + agno = pag->pag_agno + 1; + spin_lock(&pag->pag_ici_lock); + if (pag->pag_ici_inactive) + ret = true; + spin_unlock(&pag->pag_ici_lock); + xfs_perag_put(pag); + } + + return ret; +} + +/* + * Flush all pending inactivation work and poll until finished. This function + * is for callers that must flush with vfs locks held, such as unmount, + * remount, and iunlinks processing during mount. + */ +void +xfs_inactive_force_poll( + struct xfs_mount *mp) +{ + xfs_inactive_schedule_now(mp); + + while (!wait_event_timeout(mp->m_inactive_wait, + xfs_inactive_pending(mp) == false, HZ)) { + touch_softlockup_watchdog(); + } +} |