Skip to content

Commit 8d9f6e7

Browse files
committed
zinject: make iotype extendable
I'm about to add a new "type", and I need somewhere to put it! Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Signed-off-by: Rob Norris <[email protected]>
1 parent fe44c5a commit 8d9f6e7

File tree

3 files changed

+79
-29
lines changed

3 files changed

+79
-29
lines changed

cmd/zinject/zinject.c

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,35 @@ err_to_str(int err)
242242
return ("[unknown]");
243243
}
244244

245+
static const char *const iotypestrtable[ZINJECT_IOTYPES] = {
246+
[ZINJECT_IOTYPE_NULL] = "null",
247+
[ZINJECT_IOTYPE_READ] = "read",
248+
[ZINJECT_IOTYPE_WRITE] = "write",
249+
[ZINJECT_IOTYPE_FREE] = "free",
250+
[ZINJECT_IOTYPE_CLAIM] = "claim",
251+
[ZINJECT_IOTYPE_FLUSH] = "flush",
252+
[ZINJECT_IOTYPE_TRIM] = "trim",
253+
[ZINJECT_IOTYPE_ALL] = "all",
254+
};
255+
256+
static zinject_iotype_t
257+
str_to_iotype(const char *arg)
258+
{
259+
for (uint_t iotype = 0; iotype < ZINJECT_IOTYPES; iotype++)
260+
if (iotypestrtable[iotype] != NULL &&
261+
strcasecmp(iotypestrtable[iotype], arg) == 0)
262+
return (iotype);
263+
return (ZINJECT_IOTYPES);
264+
}
265+
266+
static const char *
267+
iotype_to_str(zinject_iotype_t iotype)
268+
{
269+
if (iotype >= ZINJECT_IOTYPES || iotypestrtable[iotype] == NULL)
270+
return ("[unknown]");
271+
return (iotypestrtable[iotype]);
272+
}
273+
245274
/*
246275
* Print usage message.
247276
*/
@@ -435,10 +464,6 @@ static int
435464
print_device_handler(int id, const char *pool, zinject_record_t *record,
436465
void *data)
437466
{
438-
static const char *iotypestr[] = {
439-
"null", "read", "write", "free", "claim", "flush", "trim", "all",
440-
};
441-
442467
int *count = data;
443468

444469
if (record->zi_guid == 0 || record->zi_func[0] != '\0')
@@ -465,7 +490,7 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
465490

466491
(void) printf("%3d %-15s %llx %-5s %-10s %8.4f%% "
467492
"%6lu %6lu\n", id, pool, (u_longlong_t)record->zi_guid,
468-
iotypestr[record->zi_iotype], err_to_str(record->zi_error),
493+
iotype_to_str(record->zi_iotype), err_to_str(record->zi_error),
469494
freq, record->zi_match_count, record->zi_inject_count);
470495

471496
return (0);
@@ -866,7 +891,7 @@ main(int argc, char **argv)
866891
int quiet = 0;
867892
int error = 0;
868893
int domount = 0;
869-
int io_type = ZIO_TYPES;
894+
int io_type = ZINJECT_IOTYPE_ALL;
870895
int action = VDEV_STATE_UNKNOWN;
871896
err_type_t type = TYPE_INVAL;
872897
err_type_t label = TYPE_INVAL;
@@ -1060,19 +1085,8 @@ main(int argc, char **argv)
10601085
}
10611086
break;
10621087
case 'T':
1063-
if (strcasecmp(optarg, "read") == 0) {
1064-
io_type = ZIO_TYPE_READ;
1065-
} else if (strcasecmp(optarg, "write") == 0) {
1066-
io_type = ZIO_TYPE_WRITE;
1067-
} else if (strcasecmp(optarg, "free") == 0) {
1068-
io_type = ZIO_TYPE_FREE;
1069-
} else if (strcasecmp(optarg, "claim") == 0) {
1070-
io_type = ZIO_TYPE_CLAIM;
1071-
} else if (strcasecmp(optarg, "flush") == 0) {
1072-
io_type = ZIO_TYPE_FLUSH;
1073-
} else if (strcasecmp(optarg, "all") == 0) {
1074-
io_type = ZIO_TYPES;
1075-
} else {
1088+
io_type = str_to_iotype(optarg);
1089+
if (io_type == ZINJECT_IOTYPES) {
10761090
(void) fprintf(stderr, "invalid I/O type "
10771091
"'%s': must be 'read', 'write', 'free', "
10781092
"'claim', 'flush' or 'all'\n", optarg);
@@ -1194,7 +1208,7 @@ main(int argc, char **argv)
11941208
}
11951209

11961210
if (error == EILSEQ &&
1197-
(record.zi_freq == 0 || io_type != ZIO_TYPE_READ)) {
1211+
(record.zi_freq == 0 || io_type != ZINJECT_IOTYPE_READ)) {
11981212
(void) fprintf(stderr, "device corrupt errors require "
11991213
"io type read and a frequency value\n");
12001214
libzfs_fini(g_zfs);
@@ -1209,9 +1223,9 @@ main(int argc, char **argv)
12091223

12101224
if (record.zi_nlanes) {
12111225
switch (io_type) {
1212-
case ZIO_TYPE_READ:
1213-
case ZIO_TYPE_WRITE:
1214-
case ZIO_TYPES:
1226+
case ZINJECT_IOTYPE_READ:
1227+
case ZINJECT_IOTYPE_WRITE:
1228+
case ZINJECT_IOTYPE_ALL:
12151229
break;
12161230
default:
12171231
(void) fprintf(stderr, "I/O type for a delay "

include/sys/zfs_ioctl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,24 @@ typedef enum zinject_type {
456456
ZINJECT_DELAY_EXPORT,
457457
} zinject_type_t;
458458

459+
typedef enum zinject_iotype {
460+
/*
461+
* Compatibility: zi_iotype used to be set to ZIO_TYPE_, so make sure
462+
* the corresponding ZINJECT_IOTYPE_ matches. Note that existing here
463+
* does not mean that injections are possible for all these types.
464+
*/
465+
ZINJECT_IOTYPE_NULL = ZIO_TYPE_NULL,
466+
ZINJECT_IOTYPE_READ = ZIO_TYPE_READ,
467+
ZINJECT_IOTYPE_WRITE = ZIO_TYPE_WRITE,
468+
ZINJECT_IOTYPE_FREE = ZIO_TYPE_FREE,
469+
ZINJECT_IOTYPE_CLAIM = ZIO_TYPE_CLAIM,
470+
ZINJECT_IOTYPE_FLUSH = ZIO_TYPE_FLUSH,
471+
ZINJECT_IOTYPE_TRIM = ZIO_TYPE_TRIM,
472+
ZINJECT_IOTYPE_ALL = ZIO_TYPES,
473+
/* Room for future expansion for ZIO_TYPE_* */
474+
ZINJECT_IOTYPES = 16,
475+
} zinject_iotype_t;
476+
459477
typedef struct zfs_share {
460478
uint64_t z_exportdata;
461479
uint64_t z_sharedata;

module/zfs/zio_inject.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,27 @@ zio_inject_bitflip_cb(void *data, size_t len, void *private)
376376
return (1); /* stop after first flip */
377377
}
378378

379+
/* Test if this zio matches the iotype from the injection record. */
380+
static boolean_t
381+
zio_match_iotype(zio_t *zio, uint32_t iotype)
382+
{
383+
ASSERT3P(zio, !=, NULL);
384+
385+
/* Unknown iotype, maybe from a newer version of zinject. Reject it. */
386+
if (iotype >= ZINJECT_IOTYPES)
387+
return (B_FALSE);
388+
389+
/* Standard IO types, match against ZIO type. */
390+
if (iotype < ZINJECT_IOTYPE_ALL)
391+
return (iotype == zio->io_type);
392+
393+
/* Match any standard IO type. */
394+
if (iotype == ZINJECT_IOTYPE_ALL)
395+
return (B_TRUE);
396+
397+
return (B_FALSE);
398+
}
399+
379400
static int
380401
zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
381402
{
@@ -410,9 +431,8 @@ zio_handle_device_injection_impl(vdev_t *vd, zio_t *zio, int err1, int err2)
410431
}
411432

412433
/* Handle type specific I/O failures */
413-
if (zio != NULL &&
414-
handler->zi_record.zi_iotype != ZIO_TYPES &&
415-
handler->zi_record.zi_iotype != zio->io_type)
434+
if (zio != NULL && !zio_match_iotype(zio,
435+
handler->zi_record.zi_iotype))
416436
continue;
417437

418438
if (handler->zi_record.zi_error == err1 ||
@@ -635,10 +655,8 @@ zio_handle_io_delay(zio_t *zio)
635655
continue;
636656

637657
/* also match on I/O type (e.g., -T read) */
638-
if (handler->zi_record.zi_iotype != ZIO_TYPES &&
639-
handler->zi_record.zi_iotype != zio->io_type) {
658+
if (!zio_match_iotype(zio, handler->zi_record.zi_iotype))
640659
continue;
641-
}
642660

643661
/*
644662
* Defensive; should never happen as the array allocation

0 commit comments

Comments
 (0)