107107 * zinject
108108 * zinject <-a | -u pool>
109109 * zinject -c <id|all>
110+ * zinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]
111+ * [-T iotype] [-t type object | -b bookmark pool]
110112 * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
111113 * [-r range] <object>
112114 * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
132134 * The '-f' flag controls the frequency of errors injected, expressed as a
133135 * real number percentage between 0.0001 and 100. The default is 100.
134136 *
135- * The this form is responsible for actually injecting the handler into the
137+ * The <object> form is responsible for actually injecting the handler into the
136138 * framework. It takes the arguments described above, translates them to the
137139 * internal tuple using libzpool, and then issues an ioctl() to register the
138140 * handler.
139141 *
140- * The final form can target a specific bookmark, regardless of whether a
142+ * The '-b' option can target a specific bookmark, regardless of whether a
141143 * human-readable interface has been designed. It allows developers to specify
142144 * a particular block by number.
145+ *
146+ * The '-E' option injects pipeline ready stage delays for the given object or
147+ * bookmark. The delay is specified in milliseconds, and it supports I/O type
148+ * and range filters.
143149 */
144150
145151#include <errno.h>
@@ -346,6 +352,13 @@ usage(void)
346352 "\t\tsuch that the operation takes a minimum of supplied seconds\n"
347353 "\t\tto complete.\n"
348354 "\n"
355+ "\tzinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]\n"
356+ "\t\t[-T iotype] [-t type object | -b bookmark pool]\n"
357+ "\n"
358+ "\t\tInject pipeline ready stage delays for the given object path\n"
359+ "\t\t(data or dnode) or raw bookmark. The delay is specified in\n"
360+ "\t\tmilliseconds.\n"
361+ "\n"
349362 "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
350363 "\t\tCause the pool to stop writing blocks yet not\n"
351364 "\t\treport errors for a duration. Simulates buggy hardware\n"
@@ -724,12 +737,15 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
724737 if (quiet ) {
725738 (void ) printf ("%llu\n" , (u_longlong_t )zc .zc_guid );
726739 } else {
740+ boolean_t show_object = B_FALSE ;
741+ boolean_t show_iotype = B_FALSE ;
727742 (void ) printf ("Added handler %llu with the following "
728743 "properties:\n" , (u_longlong_t )zc .zc_guid );
729744 (void ) printf (" pool: %s\n" , pool );
730745 if (record -> zi_guid ) {
731746 (void ) printf (" vdev: %llx\n" ,
732747 (u_longlong_t )record -> zi_guid );
748+ show_iotype = B_TRUE ;
733749 } else if (record -> zi_func [0 ] != '\0' ) {
734750 (void ) printf (" panic function: %s\n" ,
735751 record -> zi_func );
@@ -742,7 +758,18 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
742758 } else if (record -> zi_timer > 0 ) {
743759 (void ) printf (" timer: %lld ms\n" ,
744760 (u_longlong_t )NSEC2MSEC (record -> zi_timer ));
761+ if (record -> zi_cmd == ZINJECT_DELAY_READY ) {
762+ show_object = B_TRUE ;
763+ show_iotype = B_TRUE ;
764+ }
745765 } else {
766+ show_object = B_TRUE ;
767+ }
768+ if (show_iotype ) {
769+ (void ) printf ("iotype: %s\n" ,
770+ iotype_to_str (record -> zi_iotype ));
771+ }
772+ if (show_object ) {
746773 (void ) printf ("objset: %llu\n" ,
747774 (u_longlong_t )record -> zi_objset );
748775 (void ) printf ("object: %llu\n" ,
@@ -910,6 +937,7 @@ main(int argc, char **argv)
910937 int ret ;
911938 int flags = 0 ;
912939 uint32_t dvas = 0 ;
940+ hrtime_t ready_delay = -1 ;
913941
914942 if ((g_zfs = libzfs_init ()) == NULL ) {
915943 (void ) fprintf (stderr , "%s\n" , libzfs_error_init (errno ));
@@ -940,7 +968,7 @@ main(int argc, char **argv)
940968 }
941969
942970 while ((c = getopt (argc , argv ,
943- ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:" )) != -1 ) {
971+ ":aA:b:C:d:D:E: f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:" )) != -1 ) {
944972 switch (c ) {
945973 case 'a' :
946974 flags |= ZINJECT_FLUSH_ARC ;
@@ -1113,6 +1141,18 @@ main(int argc, char **argv)
11131141 case 'u' :
11141142 flags |= ZINJECT_UNLOAD_SPA ;
11151143 break ;
1144+ case 'E' :
1145+ ready_delay = MSEC2NSEC (strtol (optarg , & end , 10 ));
1146+ if (ready_delay <= 0 || * end != '\0' ) {
1147+ (void ) fprintf (stderr , "invalid delay '%s': "
1148+ "must be a positive duration\n" , optarg );
1149+ usage ();
1150+ libzfs_fini (g_zfs );
1151+ return (1 );
1152+ }
1153+ record .zi_cmd = ZINJECT_DELAY_READY ;
1154+ record .zi_timer = ready_delay ;
1155+ break ;
11161156 case 'L' :
11171157 if ((label = name_to_type (optarg )) == TYPE_INVAL &&
11181158 !LABEL_TYPE (type )) {
@@ -1150,7 +1190,7 @@ main(int argc, char **argv)
11501190 */
11511191 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
11521192 level != 0 || record .zi_cmd != ZINJECT_UNINITIALIZED ||
1153- record .zi_freq > 0 || dvas != 0 ) {
1193+ record .zi_freq > 0 || dvas != 0 || ready_delay >= 0 ) {
11541194 (void ) fprintf (stderr , "cancel (-c) incompatible with "
11551195 "any other options\n" );
11561196 usage ();
@@ -1186,7 +1226,7 @@ main(int argc, char **argv)
11861226 */
11871227 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
11881228 level != 0 || record .zi_cmd != ZINJECT_UNINITIALIZED ||
1189- dvas != 0 ) {
1229+ dvas != 0 || ready_delay >= 0 ) {
11901230 (void ) fprintf (stderr , "device (-d) incompatible with "
11911231 "data error injection\n" );
11921232 usage ();
@@ -1276,13 +1316,23 @@ main(int argc, char **argv)
12761316 return (1 );
12771317 }
12781318
1279- record .zi_cmd = ZINJECT_DATA_FAULT ;
1319+ if (record .zi_cmd == ZINJECT_UNINITIALIZED ) {
1320+ record .zi_cmd = ZINJECT_DATA_FAULT ;
1321+ if (!error )
1322+ error = EIO ;
1323+ } else if (error != 0 ) {
1324+ (void ) fprintf (stderr , "error type -e incompatible "
1325+ "with delay injection\n" );
1326+ libzfs_fini (g_zfs );
1327+ return (1 );
1328+ } else {
1329+ record .zi_iotype = io_type ;
1330+ }
1331+
12801332 if (translate_raw (raw , & record ) != 0 ) {
12811333 libzfs_fini (g_zfs );
12821334 return (1 );
12831335 }
1284- if (!error )
1285- error = EIO ;
12861336 } else if (record .zi_cmd == ZINJECT_PANIC ) {
12871337 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
12881338 level != 0 || device != NULL || record .zi_freq > 0 ||
@@ -1410,6 +1460,13 @@ main(int argc, char **argv)
14101460 record .zi_dvas = dvas ;
14111461 }
14121462
1463+ if (record .zi_cmd != ZINJECT_UNINITIALIZED && error != 0 ) {
1464+ (void ) fprintf (stderr , "error type -e incompatible "
1465+ "with delay injection\n" );
1466+ libzfs_fini (g_zfs );
1467+ return (1 );
1468+ }
1469+
14131470 if (error == EACCES ) {
14141471 if (type != TYPE_DATA ) {
14151472 (void ) fprintf (stderr , "decryption errors "
@@ -1425,17 +1482,19 @@ main(int argc, char **argv)
14251482 * not found.
14261483 */
14271484 error = ECKSUM ;
1428- } else {
1485+ } else if ( record . zi_cmd == ZINJECT_UNINITIALIZED ) {
14291486 record .zi_cmd = ZINJECT_DATA_FAULT ;
1487+ if (!error )
1488+ error = EIO ;
1489+ } else {
1490+ record .zi_iotype = io_type ;
14301491 }
14311492
14321493 if (translate_record (type , argv [0 ], range , level , & record , pool ,
14331494 dataset ) != 0 ) {
14341495 libzfs_fini (g_zfs );
14351496 return (1 );
14361497 }
1437- if (!error )
1438- error = EIO ;
14391498 }
14401499
14411500 /*
0 commit comments