summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_icache.c52
-rw-r--r--fs/xfs/xfs_icache.h2
-rw-r--r--fs/xfs/xfs_mount.c2
-rw-r--r--fs/xfs/xfs_mount.h6
-rw-r--r--fs/xfs/xfs_super.c3
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