Commit 74c4795e authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: convey filesystem shutdown events to the health monitor



Connect the filesystem shutdown code to the health monitor so that xfs
can send events about that to the xfs_healer daemon.

Signed-off-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 5eb4cb18
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1028,6 +1028,9 @@ struct xfs_rtgroup_geometry {
#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;
@@ -1054,6 +1057,20 @@ struct xfs_health_monitor_inode {
	__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;
@@ -1074,6 +1091,7 @@ struct xfs_health_monitor_event {
		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 */
+2 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "xfs_rtrmap_btree.h"
#include "xfs_rtrefcount_btree.h"
#include "xfs_metafile.h"
#include "xfs_healthmon.h"

#include <linux/fserror.h>

@@ -544,6 +545,7 @@ xfs_do_force_shutdown(
		xfs_stack_trace();

	fserror_report_shutdown(mp->m_super, GFP_KERNEL);
	xfs_healthmon_report_shutdown(mp, flags);
}

/*
+70 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#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>
@@ -202,6 +203,11 @@ xfs_healthmon_merge_events(
			return false;
		}
		return false;

	case XFS_HEALTHMON_SHUTDOWN:
		/* yes, we can race to shutdown */
		existing->flags |= new->flags;
		return true;
	}

	return false;
@@ -494,6 +500,28 @@ xfs_healthmon_report_inode(
	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)
@@ -502,6 +530,44 @@ xfs_healthmon_reset_outbuf(
	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,
@@ -517,6 +583,7 @@ static const unsigned int type_map[] = {
	[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 */
@@ -545,6 +612,9 @@ xfs_healthmon_format_v0(
		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;
		}
+9 −0
Original line number Diff line number Diff line
@@ -72,6 +72,9 @@ enum xfs_healthmon_type {
	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 */
@@ -119,6 +122,10 @@ struct xfs_healthmon_event {
			uint32_t	gen;
			xfs_ino_t	ino;
		};
		/* shutdown */
		struct {
			unsigned int	flags;
		};
	};
};

@@ -132,6 +139,8 @@ void xfs_healthmon_report_inode(struct xfs_inode *ip,
		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);

+22 −1
Original line number Diff line number Diff line
@@ -6012,7 +6012,8 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount);
	{ 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" }, \
@@ -6022,6 +6023,7 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount);
	{ 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);
@@ -6063,6 +6065,9 @@ DECLARE_EVENT_CLASS(xfs_healthmon_event_class,
		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;
@@ -6207,6 +6212,22 @@ TRACE_EVENT(xfs_healthmon_report_inode,
		  __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