@@ -99,6 +99,7 @@ xfs-y += xfs_aops.o \
xfs_message.o \
xfs_mount.o \
xfs_mru_cache.o \
+ xfs_notify_failure.o \
xfs_pwork.o \
xfs_reflink.o \
xfs_stats.o \
@@ -149,11 +150,6 @@ xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o
xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o
xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o
-# notify failure
-ifeq ($(CONFIG_MEMORY_FAILURE),y)
-xfs-$(CONFIG_FS_DAX) += xfs_notify_failure.o
-endif
-
xfs-$(CONFIG_XFS_DRAIN_INTENTS) += xfs_drain.o
xfs-$(CONFIG_XFS_LIVE_HOOKS) += xfs_hooks.o
xfs-$(CONFIG_XFS_MEMORY_BUFS) += xfs_buf_mem.o
@@ -1115,6 +1115,20 @@ struct xfs_health_monitor {
/* Return events in JSON format */
#define XFS_HEALTH_MONITOR_FMT_JSON (1)
+struct xfs_media_error {
+ __u64 flags; /* flags */
+ __u64 daddr; /* disk address of range */
+ __u64 bbcount; /* length, in 512b blocks */
+ __u64 pad; /* zero */
+};
+
+#define XFS_MEDIA_ERROR_DATADEV (1) /* data device */
+#define XFS_MEDIA_ERROR_LOGDEV (2) /* external log device */
+#define XFS_MEDIA_ERROR_RTDEV (3) /* realtime device */
+
+/* bottom byte of flags is the device code */
+#define XFS_MEDIA_ERROR_DEVMASK (0xFF)
+
/*
* ioctl commands that are used by Linux filesystems
*/
@@ -1157,6 +1171,7 @@ struct xfs_health_monitor {
#define XFS_IOC_GETFSREFCOUNTS _IOWR('X', 66, struct xfs_getfsrefs_head)
#define XFS_IOC_MAP_FREESP _IOW ('X', 67, struct xfs_map_freesp)
#define XFS_IOC_HEALTH_MONITOR _IOW ('X', 68, struct xfs_health_monitor)
+#define XFS_IOC_MEDIA_ERROR _IOW ('X', 69, struct xfs_media_error)
/*
* ioctl commands that replace IRIX syssgi()'s
@@ -429,7 +429,6 @@ xfs_healthmon_shutdown_hook(
return NOTIFY_DONE;
}
-#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
/* Add a media error event to the reporting queue. */
STATIC int
xfs_healthmon_media_error_hook(
@@ -480,7 +479,6 @@ xfs_healthmon_media_error_hook(
mutex_unlock(&hm->lock);
return NOTIFY_DONE;
}
-#endif
/* Add a file io error event to the reporting queue. */
STATIC int
@@ -43,6 +43,7 @@
#include "xfs_handle.h"
#include "xfs_rtgroup.h"
#include "xfs_healthmon.h"
+#include "xfs_notify_failure.h"
#include <linux/mount.h>
#include <linux/fileattr.h>
@@ -1437,6 +1438,8 @@ xfs_file_ioctl(
case XFS_IOC_HEALTH_MONITOR:
return xfs_ioc_health_monitor(mp, arg);
+ case XFS_IOC_MEDIA_ERROR:
+ return xfs_ioc_media_error(mp, arg);
default:
return -ENOTTY;
@@ -91,9 +91,19 @@ xfs_media_error_hook_setup(
xfs_hook_setup(&hook->error_hook, mod_fn);
}
#else
-# define xfs_media_error_hook(...) ((void)0)
+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)
+{
+ /* empty */
+}
#endif /* CONFIG_XFS_LIVE_HOOKS */
+#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
struct xfs_failure_info {
xfs_agblock_t startblock;
xfs_extlen_t blockcount;
@@ -463,3 +473,44 @@ xfs_dax_notify_failure(
const struct dax_holder_operations xfs_dax_holder_operations = {
.notify_failure = xfs_dax_notify_failure,
};
+#endif /* CONFIG_MEMORY_FAILURE && CONFIG_FS_DAX */
+
+#define XFS_VALID_MEDIA_ERROR_FLAGS (XFS_MEDIA_ERROR_DATADEV | \
+ XFS_MEDIA_ERROR_LOGDEV | \
+ XFS_MEDIA_ERROR_RTDEV)
+int
+xfs_ioc_media_error(
+ struct xfs_mount *mp,
+ struct xfs_media_error __user *arg)
+{
+ struct xfs_media_error me;
+ enum xfs_failed_device fdev;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&me, arg, sizeof(me)))
+ return -EFAULT;
+
+ if (me.pad)
+ return -EINVAL;
+ if (me.flags & ~XFS_VALID_MEDIA_ERROR_FLAGS)
+ return -EINVAL;
+
+ switch (me.flags & XFS_MEDIA_ERROR_DEVMASK) {
+ case XFS_MEDIA_ERROR_DATADEV:
+ fdev = XFS_FAILED_DATADEV;
+ break;
+ case XFS_MEDIA_ERROR_LOGDEV:
+ fdev = XFS_FAILED_LOGDEV;
+ break;
+ case XFS_MEDIA_ERROR_RTDEV:
+ fdev = XFS_FAILED_RTDEV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ xfs_media_error_hook(mp, fdev, me.daddr, me.bbcount, false);
+ return 0;
+}
@@ -6,7 +6,9 @@
#ifndef __XFS_NOTIFY_FAILURE_H__
#define __XFS_NOTIFY_FAILURE_H__
+#if defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
extern const struct dax_holder_operations xfs_dax_holder_operations;
+#endif
enum xfs_failed_device {
XFS_FAILED_DATADEV,
@@ -14,7 +16,7 @@ enum xfs_failed_device {
XFS_FAILED_RTDEV,
};
-#if defined(CONFIG_XFS_LIVE_HOOKS) && defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
+#if defined(CONFIG_XFS_LIVE_HOOKS)
struct xfs_media_error_params {
struct xfs_mount *mp;
enum xfs_failed_device fdev;
@@ -46,4 +48,8 @@ struct xfs_media_error_hook { };
# define xfs_media_error_hook_setup(...) ((void)0)
#endif /* CONFIG_XFS_LIVE_HOOKS */
+struct xfs_media_error;
+int xfs_ioc_media_error(struct xfs_mount *mp,
+ struct xfs_media_error __user *arg);
+
#endif /* __XFS_NOTIFY_FAILURE_H__ */
@@ -6348,7 +6348,6 @@ TRACE_EVENT(xfs_healthmon_metadata_hook,
__entry->lost_prev)
);
-#if defined(CONFIG_XFS_LIVE_HOOKS) && defined(CONFIG_MEMORY_FAILURE) && defined(CONFIG_FS_DAX)
TRACE_EVENT(xfs_healthmon_media_error_hook,
TP_PROTO(const struct xfs_media_error_params *p,
unsigned int events, bool lost_prev),
@@ -6396,7 +6395,6 @@ TRACE_EVENT(xfs_healthmon_media_error_hook,
__entry->events,
__entry->lost_prev)
);
-#endif
#define XFS_FILE_IOERROR_STRINGS \
{ XFS_FILE_IOERROR_BUFFERED_READ, "readahead" }, \