From: Darrick J. Wong Date: Sun, 22 Feb 2026 22:41:13 +0000 (-0800) Subject: xfs_io: add a media verify command X-Git-Tag: v7.0.0~48 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=bbed6dcf85f36603d68cbb763e1d47f7943c13bb;p=xfsprogs-dev.git xfs_io: add a media verify command Add a subcommand to invoke the media verification ioctl to make sure that we can actually check the storage underneath an xfs filesystem. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- diff --git a/io/Makefile b/io/Makefile index 8e378335..79d5e172 100644 --- a/io/Makefile +++ b/io/Makefile @@ -51,7 +51,8 @@ CFILES = \ sync.c \ sync_file_range.c \ truncate.c \ - utimes.c + utimes.c \ + verify_media.c LLDLIBS = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) $(LIBPTHREAD) $(LIBUUID) LTDEPENDENCIES = $(LIBXCMD) $(LIBHANDLE) $(LIBFROG) diff --git a/io/init.c b/io/init.c index cb5573f4..f2a551ef 100644 --- a/io/init.c +++ b/io/init.c @@ -93,6 +93,7 @@ init_commands(void) exchangerange_init(); fsprops_init(); healthmon_init(); + verifymedia_init(); } /* diff --git a/io/io.h b/io/io.h index 2f5262bc..0f12b3cf 100644 --- a/io/io.h +++ b/io/io.h @@ -163,3 +163,4 @@ void exchangerange_init(void); void fsprops_init(void); void aginfo_init(void); void healthmon_init(void); +void verifymedia_init(void); diff --git a/io/verify_media.c b/io/verify_media.c new file mode 100644 index 00000000..73eb40e3 --- /dev/null +++ b/io/verify_media.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2026 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "command.h" +#include "input.h" +#include "init.h" +#include "io.h" + +static void +verifymedia_help(void) +{ + printf(_( +"\n" +" Verify the media of the devices backing the filesystem.\n" +"\n" +" -d -- Verify the data device (default).\n" +" -l -- Verify the log device.\n" +" -r -- Verify the realtime device.\n" +" -R -- Report media errors to fsnotify.\n" +" -s -- Sleep this many usecs between IOs.\n" +"\n" +" start is the byte offset of the start of the range to verify. If the start\n" +" is specified, the end may (optionally) be specified as well." +"\n" +" end is the byte offset of the end of the range to verify.\n" +"\n" +" If neither start nor end are specified, the media verification will\n" +" check the entire device." +"\n")); +} + +static int +verifymedia_f( + int argc, + char **argv) +{ + xfs_daddr_t orig_start_daddr = 0; + struct xfs_verify_media me = { + .me_start_daddr = orig_start_daddr, + .me_end_daddr = ~0ULL, + .me_dev = XFS_DEV_DATA, + }; + struct timeval t1, t2; + long long l; + size_t fsblocksize, fssectsize; + const char *verifydev = _("datadev"); + int c, ret; + + init_cvtnum(&fsblocksize, &fssectsize); + + while ((c = getopt(argc, argv, "b:dlrRs:")) != EOF) { + switch (c) { + case 'd': + me.me_dev = XFS_DEV_DATA; + verifydev = _("datadev"); + break; + case 'l': + me.me_dev = XFS_DEV_LOG; + verifydev = _("logdev"); + break; + case 'r': + me.me_dev = XFS_DEV_RT; + verifydev = _("rtdev"); + break; + case 'b': + l = cvtnum(fsblocksize, fssectsize, optarg); + if (l < 0 || l > UINT_MAX) { + printf("non-numeric maxio argument -- %s\n", + optarg); + exitcode = 1; + return 0; + } + me.me_max_io_size = l; + break; + case 'R': + me.me_flags |= XFS_VERIFY_MEDIA_REPORT; + break; + case 's': + l = atoi(optarg); + if (l < 0) { + printf("non-numeric rest_us argument -- %s\n", + optarg); + exitcode = 1; + return 0; + } + me.me_rest_us = l; + break; + default: + verifymedia_help(); + exitcode = 1; + return 0; + } + } + + /* Range start (optional) */ + if (optind < argc) { + l = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (l < 0) { + printf("non-numeric start argument -- %s\n", + argv[optind]); + exitcode = 1; + return 0; + } + + orig_start_daddr = l / 512; + me.me_start_daddr = orig_start_daddr; + optind++; + } + + /* Range end (optional if range start was specified) */ + if (optind < argc) { + l = cvtnum(fsblocksize, fssectsize, argv[optind]); + if (l < 0) { + printf("non-numeric end argument -- %s\n", + argv[optind]); + exitcode = 1; + return 0; + } + + me.me_end_daddr = ((l + 511) / 512); + optind++; + } + + if (optind < argc) { + printf("too many arguments -- %s\n", argv[optind]); + exitcode = 1; + return 0; + } + + gettimeofday(&t1, NULL); + ret = ioctl(file->fd, XFS_IOC_VERIFY_MEDIA, &me); + gettimeofday(&t2, NULL); + t2 = tsub(t2, t1); + if (ret < 0) { + fprintf(stderr, + "%s: ioctl(XFS_IOC_VERIFY_MEDIA) [\"%s\"]: %s\n", + progname, file->name, strerror(errno)); + exitcode = 1; + return 0; + } + + if (me.me_ioerror) { + fprintf(stderr, + "%s: verify error at offset %llu length %llu: %s\n", + verifydev, + BBTOB(me.me_start_daddr), + BBTOB(me.me_end_daddr - me.me_start_daddr), + strerror(me.me_ioerror)); + exitcode = 1; + } else { + unsigned long long total; + + if (me.me_end_daddr > orig_start_daddr) + total = BBTOB(me.me_end_daddr - orig_start_daddr); + else + total = 0; + report_io_times("verified", &t2, BBTOB(orig_start_daddr), + BBTOB(me.me_start_daddr - orig_start_daddr), + total, 1, false); + } + + return 0; +} + +static struct cmdinfo verifymedia_cmd = { + .name = "verifymedia", + .cfunc = verifymedia_f, + .argmin = 0, + .argmax = -1, + .flags = CMD_FLAG_ONESHOT | CMD_NOMAP_OK, + .args = "[-lr] [start [end]]", + .help = verifymedia_help, +}; + +void +verifymedia_init(void) +{ + add_command(&verifymedia_cmd); +} diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index f7f2956a..2090cd4c 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1389,6 +1389,48 @@ specific points under adverse conditions. Without the argument, displays the list of error tags available. Only available in expert mode and requires privileges. +.TP +.BI "verifymedia [ \-bdlrsR ] [ " start " [ " end " ]]" +Check for media errors on the storage devices backing XFS. +The +.I start +and +.I end +parameters are the range of physical storage to verify, in bytes. +The +.I start +parameter is inclusive. +The +.I end +parameter is exclusive. +If neither +.IR start " nor " end +are specified, the entire device will be verified. +.RE +.RS 1.0i +.PD 0 +.TP +.B \-b +Don't issue any IOs larger than this size. +.TP +.B \-d +Verify the data device. +This is the default. +.TP +.B \-l +Verify the log device instead of the data device. +.TP +.B \-r +Verify the realtime device instead of the data device. +.TP +.B \-R +Report media errors to fsnotify. +.TP +.B \-s +Sleep this many microseconds between IO requests. +.PD +.RE + .TP .BI "rginfo [ \-r " rgno " ]" Show information about or update the state of realtime allocation groups.