@@ -346,6 +346,13 @@ usage(void)
346346 "\t\tsuch that the operation takes a minimum of supplied seconds\n"
347347 "\t\tto complete.\n"
348348 "\n"
349+ "\tzinject -E <seconds> [-a] [-m] [-f freq] [-l level] [-r range]\n"
350+ "\t\t[-T iotype] [-t type object | -b bookmark pool]\n"
351+ "\n"
352+ "\t\tInject pipeline ready stage delays for the given object path\n"
353+ "\t\t(data or dnode) or raw bookmark. Arguments other than -E are\n"
354+ "\t\tthe same as for injecting errors documented below."
355+ "\n"
349356 "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
350357 "\t\tCause the pool to stop writing blocks yet not\n"
351358 "\t\treport errors for a duration. Simulates buggy hardware\n"
@@ -724,12 +731,15 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
724731 if (quiet ) {
725732 (void ) printf ("%llu\n" , (u_longlong_t )zc .zc_guid );
726733 } else {
734+ boolean_t show_object = B_FALSE ;
735+ boolean_t show_iotype = B_FALSE ;
727736 (void ) printf ("Added handler %llu with the following "
728737 "properties:\n" , (u_longlong_t )zc .zc_guid );
729738 (void ) printf (" pool: %s\n" , pool );
730739 if (record -> zi_guid ) {
731740 (void ) printf (" vdev: %llx\n" ,
732741 (u_longlong_t )record -> zi_guid );
742+ show_iotype = B_TRUE ;
733743 } else if (record -> zi_func [0 ] != '\0' ) {
734744 (void ) printf (" panic function: %s\n" ,
735745 record -> zi_func );
@@ -742,7 +752,18 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
742752 } else if (record -> zi_timer > 0 ) {
743753 (void ) printf (" timer: %lld ms\n" ,
744754 (u_longlong_t )NSEC2MSEC (record -> zi_timer ));
755+ if (record -> zi_cmd == ZINJECT_DELAY_READY ) {
756+ show_object = B_TRUE ;
757+ show_iotype = B_TRUE ;
758+ }
745759 } else {
760+ show_object = B_TRUE ;
761+ }
762+ if (show_iotype ) {
763+ (void ) printf ("iotype: %s\n" ,
764+ iotype_to_str (record -> zi_iotype ));
765+ }
766+ if (show_object ) {
746767 (void ) printf ("objset: %llu\n" ,
747768 (u_longlong_t )record -> zi_objset );
748769 (void ) printf ("object: %llu\n" ,
@@ -830,6 +851,25 @@ parse_frequency(const char *str, uint32_t *percent)
830851 return (0 );
831852}
832853
854+ static int
855+ parse_duration (const char * str , hrtime_t * time )
856+ {
857+ double val ;
858+ char * end ;
859+
860+ val = strtod (str , & end );
861+ if (end == NULL || * end != '\0' )
862+ return (EINVAL );
863+
864+ /* valid range is [0, LLONG_MAX] */
865+ val *= NANOSEC ;
866+ if (val < 0 || val > LLONG_MAX )
867+ return (ERANGE );
868+
869+ * time = (hrtime_t )val ;
870+ return (0 );
871+ }
872+
833873/*
834874 * This function converts a string specifier for DVAs into a bit mask.
835875 * The dva's provided by the user should be 0 indexed and separated by
@@ -910,6 +950,7 @@ main(int argc, char **argv)
910950 int ret ;
911951 int flags = 0 ;
912952 uint32_t dvas = 0 ;
953+ hrtime_t ready_delay = -1 ;
913954
914955 if ((g_zfs = libzfs_init ()) == NULL ) {
915956 (void ) fprintf (stderr , "%s\n" , libzfs_error_init (errno ));
@@ -940,7 +981,7 @@ main(int argc, char **argv)
940981 }
941982
942983 while ((c = getopt (argc , argv ,
943- ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:" )) != -1 ) {
984+ ":aA:b:C:d:D:E: f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:" )) != -1 ) {
944985 switch (c ) {
945986 case 'a' :
946987 flags |= ZINJECT_FLUSH_ARC ;
@@ -1113,6 +1154,18 @@ main(int argc, char **argv)
11131154 case 'u' :
11141155 flags |= ZINJECT_UNLOAD_SPA ;
11151156 break ;
1157+ case 'E' :
1158+ ret = parse_duration (optarg , & ready_delay );
1159+ if (ret != 0 ) {
1160+ (void ) fprintf (stderr , "invalid delay '%s': "
1161+ "must be a positive duration\n" , optarg );
1162+ usage ();
1163+ libzfs_fini (g_zfs );
1164+ return (1 );
1165+ }
1166+ record .zi_cmd = ZINJECT_DELAY_READY ;
1167+ record .zi_timer = ready_delay ;
1168+ break ;
11161169 case 'L' :
11171170 if ((label = name_to_type (optarg )) == TYPE_INVAL &&
11181171 !LABEL_TYPE (type )) {
@@ -1150,7 +1203,7 @@ main(int argc, char **argv)
11501203 */
11511204 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
11521205 level != 0 || record .zi_cmd != ZINJECT_UNINITIALIZED ||
1153- record .zi_freq > 0 || dvas != 0 ) {
1206+ record .zi_freq > 0 || dvas != 0 || ready_delay >= 0 ) {
11541207 (void ) fprintf (stderr , "cancel (-c) incompatible with "
11551208 "any other options\n" );
11561209 usage ();
@@ -1186,7 +1239,7 @@ main(int argc, char **argv)
11861239 */
11871240 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
11881241 level != 0 || record .zi_cmd != ZINJECT_UNINITIALIZED ||
1189- dvas != 0 ) {
1242+ dvas != 0 || ready_delay >= 0 ) {
11901243 (void ) fprintf (stderr , "device (-d) incompatible with "
11911244 "data error injection\n" );
11921245 usage ();
@@ -1276,13 +1329,23 @@ main(int argc, char **argv)
12761329 return (1 );
12771330 }
12781331
1279- record .zi_cmd = ZINJECT_DATA_FAULT ;
1332+ if (record .zi_cmd == ZINJECT_UNINITIALIZED ) {
1333+ record .zi_cmd = ZINJECT_DATA_FAULT ;
1334+ if (!error )
1335+ error = EIO ;
1336+ } else if (error != 0 ) {
1337+ (void ) fprintf (stderr , "error type -e incompatible "
1338+ "with delay injection\n" );
1339+ libzfs_fini (g_zfs );
1340+ return (1 );
1341+ } else {
1342+ record .zi_iotype = io_type ;
1343+ }
1344+
12801345 if (translate_raw (raw , & record ) != 0 ) {
12811346 libzfs_fini (g_zfs );
12821347 return (1 );
12831348 }
1284- if (!error )
1285- error = EIO ;
12861349 } else if (record .zi_cmd == ZINJECT_PANIC ) {
12871350 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
12881351 level != 0 || device != NULL || record .zi_freq > 0 ||
@@ -1410,6 +1473,13 @@ main(int argc, char **argv)
14101473 record .zi_dvas = dvas ;
14111474 }
14121475
1476+ if (record .zi_cmd != ZINJECT_UNINITIALIZED && error != 0 ) {
1477+ (void ) fprintf (stderr , "error type -e incompatible "
1478+ "with delay injection\n" );
1479+ libzfs_fini (g_zfs );
1480+ return (1 );
1481+ }
1482+
14131483 if (error == EACCES ) {
14141484 if (type != TYPE_DATA ) {
14151485 (void ) fprintf (stderr , "decryption errors "
@@ -1425,17 +1495,19 @@ main(int argc, char **argv)
14251495 * not found.
14261496 */
14271497 error = ECKSUM ;
1428- } else {
1498+ } else if ( record . zi_cmd == ZINJECT_UNINITIALIZED ) {
14291499 record .zi_cmd = ZINJECT_DATA_FAULT ;
1500+ if (!error )
1501+ error = EIO ;
1502+ } else {
1503+ record .zi_iotype = io_type ;
14301504 }
14311505
14321506 if (translate_record (type , argv [0 ], range , level , & record , pool ,
14331507 dataset ) != 0 ) {
14341508 libzfs_fini (g_zfs );
14351509 return (1 );
14361510 }
1437- if (!error )
1438- error = EIO ;
14391511 }
14401512
14411513 /*
0 commit comments