@@ -346,6 +346,9 @@ typedef struct xfs_mount {
/* Hook to feed shutdown events to a daemon. */
struct xfs_hooks m_shutdown_hooks;
+
+ /* Hook to feed media error events to a daemon. */
+ struct xfs_hooks m_media_error_hooks;
} xfs_mount_t;
#define M_IGEO(mp) (&(mp)->m_ino_geo)
@@ -27,6 +27,73 @@
#include <linux/dax.h>
#include <linux/fs.h>
+#ifdef CONFIG_XFS_LIVE_HOOKS
+DEFINE_STATIC_XFS_HOOK_SWITCH(xfs_media_error_hooks_switch);
+
+void
+xfs_media_error_hook_disable(void)
+{
+ xfs_hooks_switch_off(&xfs_media_error_hooks_switch);
+}
+
+void
+xfs_media_error_hook_enable(void)
+{
+ xfs_hooks_switch_on(&xfs_media_error_hooks_switch);
+}
+
+/* Call downstream hooks for a media error. */
+static inline void
+xfs_media_error_hook(
+ struct xfs_mount *mp,
+ enum xfs_failed_device fdev,
+ xfs_daddr_t daddr,
+ uint64_t bbcount,
+ bool pre_remove)
+{
+ if (xfs_hooks_switched_on(&xfs_media_error_hooks_switch)) {
+ struct xfs_media_error_params p = {
+ .mp = mp,
+ .fdev = fdev,
+ .daddr = daddr,
+ .bbcount = bbcount,
+ .pre_remove = pre_remove,
+ };
+
+ xfs_hooks_call(&mp->m_media_error_hooks, 0, &p);
+ }
+}
+
+/* Call the specified function during a media error. */
+int
+xfs_media_error_hook_add(
+ struct xfs_mount *mp,
+ struct xfs_media_error_hook *hook)
+{
+ return xfs_hooks_add(&mp->m_media_error_hooks, &hook->error_hook);
+}
+
+/* Stop calling the specified function during a media error. */
+void
+xfs_media_error_hook_del(
+ struct xfs_mount *mp,
+ struct xfs_media_error_hook *hook)
+{
+ xfs_hooks_del(&mp->m_media_error_hooks, &hook->error_hook);
+}
+
+/* Configure media error hook functions. */
+void
+xfs_media_error_hook_setup(
+ struct xfs_media_error_hook *hook,
+ notifier_fn_t mod_fn)
+{
+ xfs_hook_setup(&hook->error_hook, mod_fn);
+}
+#else
+# define xfs_media_error_hook(...) ((void)0)
+#endif /* CONFIG_XFS_LIVE_HOOKS */
+
struct xfs_failure_info {
xfs_agblock_t startblock;
xfs_extlen_t blockcount;
@@ -215,6 +282,9 @@ xfs_dax_notify_logdev_failure(
if (error)
return error;
+ xfs_media_error_hook(mp, XFS_FAILED_LOGDEV, daddr, bblen,
+ mf_flags & MF_MEM_PRE_REMOVE);
+
/*
* In the pre-remove case the failure notification is attempting to
* trigger a force unmount. The expectation is that the device is
@@ -248,17 +318,21 @@ xfs_dax_notify_dev_failure(
uint64_t bblen;
struct xfs_group *xg = NULL;
+ error = xfs_dax_translate_range(type == XG_TYPE_RTG ?
+ mp->m_rtdev_targp : mp->m_ddev_targp,
+ offset, len, &daddr, &bblen);
+ if (error)
+ return error;
+
+ xfs_media_error_hook(mp, type == XG_TYPE_RTG ?
+ XFS_FAILED_RTDEV : XFS_FAILED_DATADEV,
+ daddr, bblen, mf_flags & MF_MEM_PRE_REMOVE);
+
if (!xfs_has_rmapbt(mp)) {
xfs_debug(mp, "notify_failure() needs rmapbt enabled!");
return -EOPNOTSUPP;
}
- error = xfs_dax_translate_range(type == XG_TYPE_RTG ?
- mp->m_rtdev_targp : mp->m_ddev_targp,
- offset, len, &daddr, &bblen);
- if (error)
- return error;
-
if (type == XG_TYPE_RTG) {
start_bno = xfs_daddr_to_rtb(mp, daddr);
end_bno = xfs_daddr_to_rtb(mp, daddr + bblen - 1);
@@ -8,4 +8,42 @@
extern const struct dax_holder_operations xfs_dax_holder_operations;
+enum xfs_failed_device {
+ XFS_FAILED_DATADEV,
+ XFS_FAILED_LOGDEV,
+ XFS_FAILED_RTDEV,
+};
+
+#if defined(CONFIG_XFS_LIVE_HOOKS) && defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
+struct xfs_media_error_params {
+ struct xfs_mount *mp;
+ enum xfs_failed_device fdev;
+ xfs_daddr_t daddr;
+ uint64_t bbcount;
+ bool pre_remove;
+};
+
+struct xfs_media_error_hook {
+ struct xfs_hook error_hook;
+};
+
+void xfs_media_error_hook_disable(void);
+void xfs_media_error_hook_enable(void);
+
+int xfs_media_error_hook_add(struct xfs_mount *mp,
+ struct xfs_media_error_hook *hook);
+void xfs_media_error_hook_del(struct xfs_mount *mp,
+ struct xfs_media_error_hook *hook);
+void xfs_media_error_hook_setup(struct xfs_media_error_hook *hook,
+ notifier_fn_t mod_fn);
+#else
+struct xfs_media_error_params { };
+struct xfs_media_error_hook { };
+# define xfs_media_error_hook_disable() ((void)0)
+# define xfs_media_error_hook_enable() ((void)0)
+# define xfs_media_error_hook_add(...) (0)
+# define xfs_media_error_hook_del(...) ((void)0)
+# define xfs_media_error_hook_setup(...) ((void)0)
+#endif /* CONFIG_XFS_LIVE_HOOKS */
+
#endif /* __XFS_NOTIFY_FAILURE_H__ */
@@ -2184,6 +2184,7 @@ xfs_init_fs_context(
xfs_hooks_init(&mp->m_dir_update_hooks);
xfs_hooks_init(&mp->m_shutdown_hooks);
xfs_hooks_init(&mp->m_health_update_hooks);
+ xfs_hooks_init(&mp->m_media_error_hooks);
fc->s_fs_info = mp;
fc->ops = &xfs_context_ops;