summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:16:47 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:16:42 -0700
commita98f81bc8c7e0924b4f1ef44d04e1d59d13ed09a (patch)
tree92c2706d8efd0da7c6ba0055212bb7440ccb37c1
parent6336dacfb5953883e193215ca510ec9740a90b16 (diff)
xfs: allow blocking notifier chains with filesystem hooksscrub-iscan_2022-10-14
Make it so that we can switch between notifier chain implementations for testing purposes. On the author's test system, calling an empty srcu notifier chain cost about 19ns per call, vs. 4ns for a blocking notifier chain. Hm. Might we actually want regular blocking notifiers? Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/Kconfig33
-rw-r--r--fs/xfs/xfs_mount.c43
-rw-r--r--fs/xfs/xfs_mount.h6
3 files changed, 78 insertions, 4 deletions
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index db60944ab3c3..54806c2b80d4 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -106,7 +106,6 @@ config XFS_ONLINE_SCRUB
default n
depends on XFS_FS
depends on TMPFS && SHMEM
- depends on SRCU
select XFS_LIVE_HOOKS
select XFS_DRAIN_INTENTS
help
@@ -122,6 +121,38 @@ config XFS_ONLINE_SCRUB
If unsure, say N.
+choice
+ prompt "XFS hook implementation"
+ depends on XFS_FS && XFS_LIVE_HOOKS && XFS_ONLINE_SCRUB
+ default XFS_LIVE_HOOKS_BLOCKING if HAVE_ARCH_JUMP_LABEL
+ default XFS_LIVE_HOOKS_SRCU if !HAVE_ARCH_JUMP_LABEL
+ help
+ Pick one
+
+config XFS_LIVE_HOOKS_SRCU
+ bool "SRCU notifier chains"
+ depends on SRCU
+ help
+ Use SRCU notifier chains for filesystem hooks. These have very low
+ overhead for event initiators (the main filesystem) and higher
+ overhead for chain modifiers (scrub waits for RCU grace). This is
+ the best option when jump labels are not supported or there are many
+ CPUs in the system.
+
+ This may cause problems with CPU hotplug invoking reclaim invoking
+ XFS.
+
+config XFS_LIVE_HOOKS_BLOCKING
+ bool "Blocking notifier chains"
+ help
+ Use blocking notifier chains for filesystem hooks. These have medium
+ overhead for event initiators (the main fs) and chain modifiers
+ (scrub) due to their use of rwsems. This is the best option when
+ jump labels can be used to eliminate overhead for the filesystem when
+ scrub is not running.
+
+endchoice
+
config XFS_ONLINE_REPAIR
bool "XFS online metadata repair support"
default n
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 38deae942ed1..e665adbb0ae3 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1491,7 +1491,7 @@ xfs_ag_intents_busy(
#endif /* CONFIG_XFS_DRAIN_INTENTS */
-#ifdef CONFIG_XFS_LIVE_HOOKS
+#if defined(CONFIG_XFS_LIVE_HOOKS_SRCU)
/* Initialize a notifier chain. */
void
xfs_hooks_init(
@@ -1531,4 +1531,43 @@ xfs_hooks_call(
{
return srcu_notifier_call_chain(&chain->head, val, priv);
}
-#endif /* CONFIG_XFS_LIVE_HOOKS */
+#elif defined(CONFIG_XFS_LIVE_HOOKS_BLOCKING)
+/* Initialize a notifier chain. */
+void
+xfs_hooks_init(
+ struct xfs_hooks *chain)
+{
+ BLOCKING_INIT_NOTIFIER_HEAD(&chain->head);
+}
+
+/* Make it so a function gets called whenever we hit a certain hook point. */
+int
+xfs_hooks_add(
+ struct xfs_hooks *chain,
+ struct xfs_hook *hook)
+{
+ ASSERT(hook->nb.notifier_call != NULL);
+ BUILD_BUG_ON(offsetof(struct xfs_hook, nb) != 0);
+
+ return blocking_notifier_chain_register(&chain->head, &hook->nb);
+}
+
+/* Remove a previously installed hook. */
+void
+xfs_hooks_del(
+ struct xfs_hooks *chain,
+ struct xfs_hook *hook)
+{
+ blocking_notifier_chain_unregister(&chain->head, &hook->nb);
+}
+
+/* Call a hook. Returns the NOTIFY_* value returned by the last hook. */
+int
+xfs_hooks_call(
+ struct xfs_hooks *chain,
+ unsigned long val,
+ void *priv)
+{
+ return blocking_notifier_call_chain(&chain->head, val, priv);
+}
+#endif /* CONFIG_XFS_LIVE_HOOKS_BLOCKING */
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index a9eb5e4cf153..b099af731535 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -56,10 +56,14 @@ struct xfs_error_cfg {
long retry_timeout; /* in jiffies, -1 = infinite */
};
-#ifdef CONFIG_XFS_LIVE_HOOKS
+#if defined(CONFIG_XFS_LIVE_HOOKS_SRCU)
struct xfs_hooks {
struct srcu_notifier_head head;
};
+#elif defined(CONFIG_XFS_LIVE_HOOKS_BLOCKING)
+struct xfs_hooks {
+ struct blocking_notifier_head head;
+};
#else
struct xfs_hooks { /* empty */ };
#endif