summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-08-30 15:45:12 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2019-10-09 09:39:24 -0700
commitfbf95404d148decb0b431a730f80f34a4a043088 (patch)
tree180e256185f1d0e46473370866a8f57663cf8c91
parent6065474081094c19b7d524f49d2d1948f5a28e02 (diff)
xfs: create a polled function to force inode inactivationdeferred-inactivation_2019-10-09
Create a polled version of xfs_inactive_force so that we can force inactivation while holding a lock (usually the umount lock) without tripping over the softlockup timer. This is for callers that hold vfs locks while calling inactivation, which is currently unmount, iunlink processing during mount, and rw->ro remount. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_icache.c42
-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, 53 insertions, 2 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 4cce17eb3d6c..1c06e2c5f10f 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -24,6 +24,7 @@
#include "xfs_reflink.h"
#include <linux/iversion.h>
+#include <linux/nmi.h>
static void xfs_perag_set_inactive_tag(struct xfs_perag *pag);
static void xfs_perag_clear_inactive_tag(struct xfs_perag *pag);
@@ -2139,6 +2140,8 @@ xfs_inactive_inodes_pag(
if (inctx.kick_reclaim)
xfs_reclaim_work_queue(pag->pag_mount);
+ wake_up(&pag->pag_mount->m_inactive_wait);
+
return error;
}
@@ -2162,6 +2165,8 @@ xfs_inactive_inodes(
if (inctx.kick_reclaim)
xfs_reclaim_work_queue(mp);
+ wake_up(&mp->m_inactive_wait);
+
return error;
}
@@ -2273,3 +2278,40 @@ xfs_inactive_schedule_work(
xfs_perag_put(pag);
}
}
+
+/* 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 ag = 0;
+ bool ret = false;
+
+ while (!ret && (pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
+ ag = 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_work(mp, 0);
+ while (wait_event_timeout(mp->m_inactive_wait,
+ xfs_inactive_pending(mp) == false, HZ / 10) == 0) {
+ touch_softlockup_watchdog();
+ }
+}
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h
index f0a18238bc86..77422b2be148 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_work(struct xfs_mount *mp, unsigned long delay);
+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 060e558f44c3..f771cd6701ee 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1036,7 +1036,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_stop_block_reaping(mp);
xfs_fs_unreserve_ag_blocks(mp);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index e5170fbc98e9..3464a13b44d0 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -221,6 +221,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 90de69cfc00d..bba942a91f6c 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1402,7 +1402,7 @@ xfs_fs_remount(
* inodes. 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);
@@ -1643,6 +1643,7 @@ xfs_mount_alloc(
INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_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