diff options
-rw-r--r-- | fs/xfs/Kconfig | 33 | ||||
-rw-r--r-- | fs/xfs/xfs_hooks.c | 41 | ||||
-rw-r--r-- | fs/xfs/xfs_hooks.h | 6 |
3 files changed, 78 insertions, 2 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_hooks.c b/fs/xfs/xfs_hooks.c index 3f958ece0dc0..653fc1f82516 100644 --- a/fs/xfs/xfs_hooks.c +++ b/fs/xfs/xfs_hooks.c @@ -12,6 +12,7 @@ #include "xfs_ag.h" #include "xfs_trace.h" +#if defined(CONFIG_XFS_LIVE_HOOKS_SRCU) /* Initialize a notifier chain. */ void xfs_hooks_init( @@ -51,3 +52,43 @@ xfs_hooks_call( { return srcu_notifier_call_chain(&chain->head, val, priv); } +#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_hooks.h b/fs/xfs/xfs_hooks.h index 9cd3f6e07751..7e5ef53f5829 100644 --- a/fs/xfs/xfs_hooks.h +++ b/fs/xfs/xfs_hooks.h @@ -6,10 +6,14 @@ #ifndef XFS_HOOKS_H_ #define XFS_HOOKS_H_ -#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 |