From patchwork Tue Dec 31 23:50:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13924078 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 142B529415 for ; Tue, 31 Dec 2024 23:50:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689004; cv=none; b=axssYKhdWwypKkYRq3k5tpcLpEwhcAMwEcFN9eFrDlnHovBWMeqsWQOLVLB/IExsgvkndSg29By0Wo4DaX6oBdtAMBv6k8d7vQH0i+fIJESGATU0aFwNcAJXJm62mosbPJkNahZeiWNyEHJUNYx9jt8CWG3ZEPxLn0hwNCgBkaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1735689004; c=relaxed/simple; bh=E01BChRKDj93Lf3/ZyyFW34DF02y7KzDXags/INYgrM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=E9DMHiERNwf4Ha9cY6MheU1glkoGgd5B2QmVPIJkUi/apwgfmhsem0LGCIdEUdQWfYRNfsSNfqZI+4fpyWzYxkzgw62m68WjXK+PEUHbs6VP/1c9PeHULlxrDD0K+ioxsCaTBP7D3glGr0EySUVDqKnFcBwU6qD5xIjbiJvI6jQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D/OTJx1v; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D/OTJx1v" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E4BB5C4CED2; Tue, 31 Dec 2024 23:50:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1735689003; bh=E01BChRKDj93Lf3/ZyyFW34DF02y7KzDXags/INYgrM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=D/OTJx1vyFTId20zvKZg365WBsaLH5MWTkUF93MXoRjpwvV+nHXSp1BWScAPUc+qV LDADV23liwKm3XH/xQCXy11QtPXM0o4rvMwa3urgtq1S00paQ3HIRzs/DApSLTC2d6 C8X897A4mECp4QHqOPmcHuaTAgYdGGFqx1B17L6XHDM7tkLG4Hv3ROAY1PzbkoI/WK GuLdp1H+8NaqmG4yBQLuHWRGH2T1hK4+xOJXnocIkX6qsyqAv0fEYambZZVaKCDCcl Rrjy+pm6BjJyw60OVJWQRP/+VY7ZLRci1M/lEwIPCco21cRGLD2Nm1u4qt70h9Bs+T EAyTgd2szu5YA== Date: Tue, 31 Dec 2024 15:50:03 -0800 Subject: [PATCH 09/21] xfs_io: monitor filesystem health events From: "Darrick J. Wong" To: aalbersh@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173568778598.2710211.14676877759844485020.stgit@frogsfrogsfrogs> In-Reply-To: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> References: <173568778426.2710211.10173859713748230492.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a subcommand to monitor for health events generated by the kernel. Signed-off-by: "Darrick J. Wong" --- io/Makefile | 1 io/healthmon.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 io/io.h | 1 man/man8/xfs_io.8 | 25 +++++++ 5 files changed, 211 insertions(+) create mode 100644 io/healthmon.c diff --git a/io/Makefile b/io/Makefile index c57594b090f70c..451d2a15b25919 100644 --- a/io/Makefile +++ b/io/Makefile @@ -26,6 +26,7 @@ CFILES = \ fsuuid.c \ fsync.c \ getrusage.c \ + healthmon.c \ imap.c \ init.c \ inject.c \ diff --git a/io/healthmon.c b/io/healthmon.c new file mode 100644 index 00000000000000..7d372d7d8c532b --- /dev/null +++ b/io/healthmon.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024-2025 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "libxfs.h" +#include "libfrog/fsgeom.h" +#include "libfrog/paths.h" +#include "command.h" +#include "init.h" +#include "io.h" + +static void +healthmon_help(void) +{ + printf(_( +"Monitor filesystem health events" +"\n" +"-c Replace the open file with the monitor file.\n" +"-d delay_ms Sleep this many milliseconds between reads.\n" +"-p Only probe for the existence of the ioctl.\n" +"-v Request all events.\n" +"\n")); +} + +static inline int +monitor_sleep( + int delay_ms) +{ + struct timespec ts; + + if (!delay_ms) + return 0; + + ts.tv_sec = delay_ms / 1000; + ts.tv_nsec = (delay_ms % 1000) * 1000000; + + return nanosleep(&ts, NULL); +} + +static int +monitor( + size_t bufsize, + bool consume, + int delay_ms, + bool verbose, + bool only_probe) +{ + struct xfs_health_monitor hmo = { + .format = XFS_HEALTH_MONITOR_FMT_JSON, + }; + char *buf; + ssize_t bytes_read; + int mon_fd; + int ret = 1; + + if (verbose) + hmo.flags |= XFS_HEALTH_MONITOR_ALL; + + mon_fd = ioctl(file->fd, XFS_IOC_HEALTH_MONITOR, &hmo); + if (mon_fd < 0) { + perror("XFS_IOC_HEALTH_MONITOR"); + return 1; + } + + if (only_probe) { + ret = 0; + goto out_mon; + } + + buf = malloc(bufsize); + if (!buf) { + perror("malloc"); + goto out_mon; + } + + if (consume) { + close(file->fd); + file->fd = mon_fd; + } + + monitor_sleep(delay_ms); + while ((bytes_read = read(mon_fd, buf, bufsize)) > 0) { + char *write_ptr = buf; + ssize_t bytes_written; + size_t to_write = bytes_read; + + while ((bytes_written = write(STDOUT_FILENO, write_ptr, to_write)) > 0) { + write_ptr += bytes_written; + to_write -= bytes_written; + } + if (bytes_written < 0) { + perror("healthdump"); + goto out_buf; + } + + monitor_sleep(delay_ms); + } + if (bytes_read < 0) { + perror("healthmon"); + goto out_buf; + } + + ret = 0; + +out_buf: + free(buf); +out_mon: + close(mon_fd); + return ret; +} + +static int +healthmon_f( + int argc, + char **argv) +{ + size_t bufsize = 4096; + bool consume = false; + bool verbose = false; + bool only_probe = false; + int delay_ms = 0; + int c; + + while ((c = getopt(argc, argv, "b:cd:pv")) != EOF) { + switch (c) { + case 'b': + errno = 0; + c = atoi(optarg); + if (c < 0 || errno) { + printf("%s: bufsize must be positive\n", + optarg); + exitcode = 1; + return 0; + } + bufsize = c; + break; + case 'c': + consume = true; + break; + case 'd': + errno = 0; + delay_ms = atoi(optarg); + if (delay_ms < 0 || errno) { + printf("%s: delay must be positive msecs\n", + optarg); + exitcode = 1; + return 0; + } + break; + case 'p': + only_probe = true; + break; + case 'v': + verbose = true; + break; + default: + exitcode = 1; + healthmon_help(); + return 0; + } + } + + return monitor(bufsize, consume, delay_ms, verbose, only_probe); +} + +static struct cmdinfo healthmon_cmd = { + .name = "healthmon", + .cfunc = healthmon_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT | CMD_NOMAP_OK, + .args = "[-c] [-d delay_ms] [-v]", + .help = healthmon_help, +}; + +void +healthmon_init(void) +{ + healthmon_cmd.oneline = _("monitor filesystem health events"); + + add_command(&healthmon_cmd); +} diff --git a/io/init.c b/io/init.c index 17b772813bc113..22ebd2f7522a18 100644 --- a/io/init.c +++ b/io/init.c @@ -92,6 +92,7 @@ init_commands(void) crc32cselftest_init(); exchangerange_init(); fsprops_init(); + healthmon_init(); } /* diff --git a/io/io.h b/io/io.h index 7ae7cf90ace323..267f3ffac36924 100644 --- a/io/io.h +++ b/io/io.h @@ -157,3 +157,4 @@ void exchangerange_init(void); void fsprops_init(void); void aginfo_init(void); void fsrefcounts_init(void); +void healthmon_init(void); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index c4d09ce07f597b..632d07807f44f0 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1419,6 +1419,31 @@ .SH FILESYSTEM COMMANDS .RE .PD +.TP +.BI "healthmon [ \-c " bufsize " ] [ \-c ] [ \-d " delay_ms " ] [ \-p ] [ \-v ]" +Watch for filesystem health events and write them to the console. +.RE +.RS 1.0i +.PD 0 +.TP +.BI "\-b " bufsize +Use a buffer of this size to read events from the kernel. +.TP +.BI \-c +Close the open file and replace it with the monitor file. +.TP +.BI "\-d " delay_ms +Sleep for this long between read attempts. +.TP +.B \-p +Probe for the existence of the functionality by opening the monitoring fd and +closing it immediately. +.TP +.BI \-v +Request all health events, even if nothing changed. +.PD +.RE + .TP .BI "inject [ " tag " ]" Inject errors into a filesystem to observe filesystem behavior at