summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_icache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_icache.c')
-rw-r--r--fs/xfs/xfs_icache.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 999b8eee02c2..640cbcbd5f21 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, void *args);
STATIC int xfs_inode_free_cowblocks(struct xfs_inode *ip, void *args);
@@ -2246,8 +2247,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. */
@@ -2277,6 +2282,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);
}
@@ -2355,3 +2361,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();
+ }
+}