#define XFS_HEALTH_MONITOR_TYPE_CORRUPT (4)
#define XFS_HEALTH_MONITOR_TYPE_HEALTHY (5)
+/* filesystem shutdown */
+#define XFS_HEALTH_MONITOR_TYPE_SHUTDOWN (6)
+
/* lost events */
struct xfs_health_monitor_lost {
__u64 count;
__u64 ino;
};
+/* shutdown reasons */
+#define XFS_HEALTH_SHUTDOWN_META_IO_ERROR (1u << 0)
+#define XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR (1u << 1)
+#define XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT (1u << 2)
+#define XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE (1u << 3)
+#define XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK (1u << 4)
+#define XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED (1u << 5)
+
+/* shutdown */
+struct xfs_health_monitor_shutdown {
+ /* XFS_HEALTH_SHUTDOWN_* flags */
+ __u32 reasons;
+};
+
struct xfs_health_monitor_event {
/* XFS_HEALTH_MONITOR_DOMAIN_* */
__u32 domain;
struct xfs_health_monitor_fs fs;
struct xfs_health_monitor_group group;
struct xfs_health_monitor_inode inode;
+ struct xfs_health_monitor_shutdown shutdown;
} e;
/* zeroes */
#include "xfs_rtrmap_btree.h"
#include "xfs_rtrefcount_btree.h"
#include "xfs_metafile.h"
+#include "xfs_healthmon.h"
#include <linux/fserror.h>
xfs_stack_trace();
fserror_report_shutdown(mp->m_super, GFP_KERNEL);
+ xfs_healthmon_report_shutdown(mp, flags);
}
/*
#include "xfs_rtgroup.h"
#include "xfs_health.h"
#include "xfs_healthmon.h"
+#include "xfs_fsops.h"
#include <linux/anon_inodes.h>
#include <linux/eventpoll.h>
return false;
}
return false;
+
+ case XFS_HEALTHMON_SHUTDOWN:
+ /* yes, we can race to shutdown */
+ existing->flags |= new->flags;
+ return true;
}
return false;
xfs_healthmon_put(hm);
}
+/* Add a shutdown event to the reporting queue. */
+void
+xfs_healthmon_report_shutdown(
+ struct xfs_mount *mp,
+ uint32_t flags)
+{
+ struct xfs_healthmon_event event = {
+ .type = XFS_HEALTHMON_SHUTDOWN,
+ .domain = XFS_HEALTHMON_MOUNT,
+ .flags = flags,
+ };
+ struct xfs_healthmon *hm = xfs_healthmon_get(mp);
+
+ if (!hm)
+ return;
+
+ trace_xfs_healthmon_report_shutdown(hm, flags);
+
+ xfs_healthmon_push(hm, &event);
+ xfs_healthmon_put(hm);
+}
+
static inline void
xfs_healthmon_reset_outbuf(
struct xfs_healthmon *hm)
hm->bufhead = 0;
}
+struct flags_map {
+ unsigned int in_mask;
+ unsigned int out_mask;
+};
+
+static const struct flags_map shutdown_map[] = {
+ { SHUTDOWN_META_IO_ERROR, XFS_HEALTH_SHUTDOWN_META_IO_ERROR },
+ { SHUTDOWN_LOG_IO_ERROR, XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR },
+ { SHUTDOWN_FORCE_UMOUNT, XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT },
+ { SHUTDOWN_CORRUPT_INCORE, XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE },
+ { SHUTDOWN_CORRUPT_ONDISK, XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK },
+ { SHUTDOWN_DEVICE_REMOVED, XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED },
+};
+
+static inline unsigned int
+__map_flags(
+ const struct flags_map *map,
+ size_t array_len,
+ unsigned int flags)
+{
+ const struct flags_map *m;
+ unsigned int ret = 0;
+
+ for (m = map; m < map + array_len; m++) {
+ if (flags & m->in_mask)
+ ret |= m->out_mask;
+ }
+
+ return ret;
+}
+
+#define map_flags(map, flags) __map_flags((map), ARRAY_SIZE(map), (flags))
+
+static inline unsigned int shutdown_mask(unsigned int in)
+{
+ return map_flags(shutdown_map, in);
+}
+
static const unsigned int domain_map[] = {
[XFS_HEALTHMON_MOUNT] = XFS_HEALTH_MONITOR_DOMAIN_MOUNT,
[XFS_HEALTHMON_FS] = XFS_HEALTH_MONITOR_DOMAIN_FS,
[XFS_HEALTHMON_CORRUPT] = XFS_HEALTH_MONITOR_TYPE_CORRUPT,
[XFS_HEALTHMON_HEALTHY] = XFS_HEALTH_MONITOR_TYPE_HEALTHY,
[XFS_HEALTHMON_UNMOUNT] = XFS_HEALTH_MONITOR_TYPE_UNMOUNT,
+ [XFS_HEALTHMON_SHUTDOWN] = XFS_HEALTH_MONITOR_TYPE_SHUTDOWN,
};
/* Render event as a V0 structure */
case XFS_HEALTHMON_LOST:
hme.e.lost.count = event->lostcount;
break;
+ case XFS_HEALTHMON_SHUTDOWN:
+ hme.e.shutdown.reasons = shutdown_mask(event->flags);
+ break;
default:
break;
}
XFS_HEALTHMON_LOST, /* message lost */
XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */
+ /* filesystem shutdown */
+ XFS_HEALTHMON_SHUTDOWN,
+
/* metadata health events */
XFS_HEALTHMON_SICK, /* runtime corruption observed */
XFS_HEALTHMON_CORRUPT, /* fsck reported corruption */
uint32_t gen;
xfs_ino_t ino;
};
+ /* shutdown */
+ struct {
+ unsigned int flags;
+ };
};
};
enum xfs_healthmon_type type, unsigned int old_mask,
unsigned int new_mask);
+void xfs_healthmon_report_shutdown(struct xfs_mount *mp, uint32_t flags);
+
long xfs_ioc_health_monitor(struct file *file,
struct xfs_health_monitor __user *arg);
{ XFS_HEALTHMON_UNMOUNT, "unmount" }, \
{ XFS_HEALTHMON_SICK, "sick" }, \
{ XFS_HEALTHMON_CORRUPT, "corrupt" }, \
- { XFS_HEALTHMON_HEALTHY, "healthy" }
+ { XFS_HEALTHMON_HEALTHY, "healthy" }, \
+ { XFS_HEALTHMON_SHUTDOWN, "shutdown" }
#define XFS_HEALTHMON_DOMAIN_STRINGS \
{ XFS_HEALTHMON_MOUNT, "mount" }, \
{ XFS_HEALTHMON_RTGROUP, "rtgroup" }
TRACE_DEFINE_ENUM(XFS_HEALTHMON_LOST);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_SHUTDOWN);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_UNMOUNT);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_SICK);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_CORRUPT);
switch (__entry->domain) {
case XFS_HEALTHMON_MOUNT:
switch (__entry->type) {
+ case XFS_HEALTHMON_SHUTDOWN:
+ __entry->mask = event->flags;
+ break;
case XFS_HEALTHMON_LOST:
__entry->lostcount = event->lostcount;
break;
__entry->gen)
);
+TRACE_EVENT(xfs_healthmon_report_shutdown,
+ TP_PROTO(const struct xfs_healthmon *hm, uint32_t shutdown_flags),
+ TP_ARGS(hm, shutdown_flags),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(uint32_t, shutdown_flags)
+ ),
+ TP_fast_assign(
+ __entry->dev = hm->dev;
+ __entry->shutdown_flags = shutdown_flags;
+ ),
+ TP_printk("dev %d:%d shutdown_flags %s",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __print_flags(__entry->shutdown_flags, "|", XFS_SHUTDOWN_STRINGS))
+);
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH