diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_icache.c | 52 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 3 |
5 files changed, 61 insertions, 4 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 5240e9e517d7..892bb789dcbf 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -25,6 +25,7 @@ #include "xfs_health.h" #include <linux/iversion.h> +#include <linux/nmi.h> STATIC int xfs_inode_free_eofblocks(struct xfs_inode *ip, struct xfs_perag *pag, void *args); @@ -2284,8 +2285,12 @@ static int xfs_inactive_inodes_pag( struct xfs_perag *pag) { - return xfs_ici_walk_ag(pag, &xfs_inactive_iwalk_ops, 0, NULL, + int error; + + error = xfs_ici_walk_ag(pag, &xfs_inactive_iwalk_ops, 0, NULL, XFS_ICI_INACTIVE_TAG); + wake_up(&pag->pag_mount->m_inactive_wait); + return error; } /* @@ -2298,8 +2303,12 @@ xfs_inactive_inodes( struct xfs_mount *mp, struct xfs_eofblocks *eofb) { - return xfs_ici_walk_fns(mp, &xfs_inactive_iwalk_ops, 0, eofb, + int error; + + error = xfs_ici_walk_fns(mp, &xfs_inactive_iwalk_ops, 0, eofb, XFS_ICI_INACTIVE_TAG); + wake_up(&mp->m_inactive_wait); + return error; } /* Try to get inode inactivation moving. */ @@ -2406,3 +2415,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(); + } +} diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index a82b473b88a2..75332d4450ba 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h @@ -89,4 +89,6 @@ void xfs_inactive_shutdown(struct xfs_mount *mp); void xfs_inactive_cancel_work(struct xfs_mount *mp); void xfs_inactive_schedule_now(struct xfs_mount *mp); +void xfs_inactive_force_poll(struct xfs_mount *mp); + #endif diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index b9b37eff4063..5e2ce91f4ab8 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1066,7 +1066,7 @@ xfs_unmountfs( * Since this can involve finobt updates, do it now before we lose the * per-AG space reservations. */ - xfs_inactive_force(mp); + xfs_inactive_force_poll(mp); xfs_blockgc_stop(mp); xfs_fs_unreserve_ag_blocks(mp); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 87a62b0543ec..237a15a136c8 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -206,6 +206,12 @@ typedef struct xfs_mount { * into a single flush. */ struct work_struct m_flush_inodes_work; + + /* + * Use this to wait for the inode inactivation workqueue to finish + * inactivating all the inodes. + */ + struct wait_queue_head m_inactive_wait; } xfs_mount_t; #define M_IGEO(mp) (&(mp)->m_ino_geo) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 47d1a0f4b00d..233fa695d9c8 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1725,7 +1725,7 @@ xfs_remount_ro( * Since this can involve finobt updates, do it now before we lose the * per-AG space reservations. */ - xfs_inactive_force(mp); + xfs_inactive_force_poll(mp); /* Free the per-AG metadata reservation pool. */ error = xfs_fs_unreserve_ag_blocks(mp); @@ -1848,6 +1848,7 @@ static int xfs_init_fs_context( INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker); INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); mp->m_kobj.kobject.kset = xfs_kset; + init_waitqueue_head(&mp->m_inactive_wait); /* * We don't create the finobt per-ag space reservation until after log * recovery, so we must set this to true so that an ifree transaction |