From patchwork Sat Feb 24 01:35:13 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: 13570231 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 2C45B33D1 for ; Sat, 24 Feb 2024 01:35:13 +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=1708738514; cv=none; b=PusQAjzKbhrw2V7ATxRlrLevgtiaR4N+2ZtGVmTUf+A8aW6r1Coy2v+njpYEOhz16D0poFguLlcjKq6MyomR8k27cv4er/E93L5RDL5Pf/9NUBsbA76DHKRA9xgsPXfOEnwXUebLNw3wVhrprxEFRSQFGuHrQA+PgVP+AYEVM/I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708738514; c=relaxed/simple; bh=ADljHypUX3Xr3Jn3NFTblDNaMPC3GY5fCidc78tiSOw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XISFtIKFt10DzguTq4Qb8deQC2U8SjuXmKgQBJEG0HAW0uAHxZV5BV0igDa8wV45XcOqPzl5d2Qh/BlwBlaarjyd+vl60U3J3v6jVCpcqTAyadNeDiVoBB3NDl8VQk5n4YIIfV5rh2Wmt738cG7j79cQJWGKwA1mdbcySC7cqIo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jlHmQmTl; 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="jlHmQmTl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 91E33C433F1; Sat, 24 Feb 2024 01:35:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708738513; bh=ADljHypUX3Xr3Jn3NFTblDNaMPC3GY5fCidc78tiSOw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jlHmQmTl0b1lkG7DDKWogFkA/NopvcLmnCuPpIVwYbULokkM17WhlwUpexeZZLJ3g 7YwOhShcI1iMtlNzuYaQO0ACvcG9PnpzXcek8R+o1GVB/UGTX4Glljg7C7Eu/5pFhe X8XaErABAHrDwusVDEmY1PCI4a3n7kHHCBlPvuh2pYV6e8ms7SDIs6/KomVttQhBZK eUGdz1lvHDq3VE1P/SONVyUBgqmXMuYSPFs+MbBM0eiXLQZ3zu+l3fmgEnFDlIgSqQ S2NcO+g/etzbVMJD6HdOi+9xBi1rLoMeD9p7tY1YZkKcg103rGcMNsbjoM9hvBRYcd g0sygH8+1bsxw== Date: Fri, 23 Feb 2024 17:35:13 -0800 Subject: [PATCH 4/7] xfs_io: monitor filesystem health events From: "Darrick J. Wong" To: cem@kernel.org, kent.overstreet@linux.dev, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170873836612.1902540.13429166309518341696.stgit@frogsfrogsfrogs> In-Reply-To: <170873836546.1902540.13109376239205481967.stgit@frogsfrogsfrogs> References: <170873836546.1902540.13109376239205481967.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++ io/init.c | 1 io/io.h | 1 man/man8/xfs_io.8 | 22 +++++++ 5 files changed, 197 insertions(+) create mode 100644 io/healthmon.c diff --git a/io/Makefile b/io/Makefile index 787027fe10ed..b1f9cebd63b0 100644 --- a/io/Makefile +++ b/io/Makefile @@ -24,6 +24,7 @@ CFILES = \ fsuuid.c \ fsync.c \ getrusage.c \ + healthmon.c \ imap.c \ inject.c \ label.c \ diff --git a/io/healthmon.c b/io/healthmon.c new file mode 100644 index 000000000000..7db8c52c96c0 --- /dev/null +++ b/io/healthmon.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 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); +} + +#define BUFSIZE (4096) + +static int +monitor( + 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) +{ + bool consume = false; + bool verbose = false; + bool only_probe = false; + int delay_ms = 0; + int c; + + while ((c = getopt(argc, argv, "cd:pv")) != EOF) { + switch (c) { + 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(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 452f4cfc898c..ef32e74bc744 100644 --- a/io/init.c +++ b/io/init.c @@ -91,6 +91,7 @@ init_commands(void) utimes_init(); crc32cselftest_init(); exchrange_init(); + healthmon_init(); } /* diff --git a/io/io.h b/io/io.h index 06a8ae1db496..b8bed3b66171 100644 --- a/io/io.h +++ b/io/io.h @@ -192,3 +192,4 @@ extern void bulkstat_init(void); extern void exchrange_init(void); extern void aginfo_init(void); extern void fsrefcounts_init(void); +extern void healthmon_init(void); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 93a4f0790d8e..9f00d26a0b49 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1407,6 +1407,28 @@ flag. .RE .PD +.TP +.BI "healthmon [ \-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 \-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