107107 * zinject
108108 * zinject <-a | -u pool>
109109 * zinject -c <id|all>
110+ * zinject -w <state|0> [-W <delay>]
110111 * zinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]
111112 * [-T iotype] [-t type object | -b bookmark pool]
112113 * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
119120 * The '-c' option will clear the given handler, or all handlers if 'all' is
120121 * specified.
121122 *
123+ * The '-w' flag waits until an injection event occurs. Wait calls accept a
124+ * state value to ensure no events are lost. Use '-w 0 -W 0' initially and
125+ * then pass the state value printed on stdout to subsequent wait calls.
126+ * The optional '-W' flag sets an optional timeout in seconds.
127+ *
122128 * The '-e' option takes a string describing the errno to simulate. This must
123129 * be one of 'io', 'checksum', 'decompress', or 'decrypt'. In most cases this
124130 * will result in the same behavior, but RAID-Z will produce a different set of
@@ -297,6 +303,14 @@ usage(void)
297303 "\t\tClear the particular record (if given a numeric ID), or\n"
298304 "\t\tall records if 'all' is specified.\n"
299305 "\n"
306+ "\tzinject -w <state|0> [-W delay]\n"
307+ "\n"
308+ "\t\tWait for an injection event to occur. The 'state' parameter\n"
309+ "\t\tshould be set to zero initially then the value printed to\n"
310+ "\t\tstdout after each call to synchronize with kernel state.\n"
311+ "\t\tThe optional timeout is specified in milliseconds.\n"
312+ "\t\tWaits forever if timeout is omitted.\n"
313+ "\n"
300314 "\tzinject -p <function name> pool\n"
301315 "\t\tInject a panic fault at the specified function. Only \n"
302316 "\t\tfunctions which call spa_vdev_config_exit(), or \n"
@@ -938,6 +952,8 @@ main(int argc, char **argv)
938952 int flags = 0 ;
939953 uint32_t dvas = 0 ;
940954 hrtime_t ready_delay = -1 ;
955+ char * wait = NULL ;
956+ hrtime_t wait_timeout = -1 ;
941957
942958 if ((g_zfs = libzfs_init ()) == NULL ) {
943959 (void ) fprintf (stderr , "%s\n" , libzfs_error_init (errno ));
@@ -968,7 +984,7 @@ main(int argc, char **argv)
968984 }
969985
970986 while ((c = getopt (argc , argv ,
971- ":aA:b:C:d:D:E:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:" )) != -1 ) {
987+ ":aA:b:C:d:D:E:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:w:W: " )) != -1 ) {
972988 switch (c ) {
973989 case 'a' :
974990 flags |= ZINJECT_FLUSH_ARC ;
@@ -1141,6 +1157,9 @@ main(int argc, char **argv)
11411157 case 'u' :
11421158 flags |= ZINJECT_UNLOAD_SPA ;
11431159 break ;
1160+ case 'w' :
1161+ wait = optarg ;
1162+ break ;
11441163 case 'E' :
11451164 ready_delay = MSEC2NSEC (strtol (optarg , & end , 10 ));
11461165 if (ready_delay <= 0 || * end != '\0' ) {
@@ -1163,6 +1182,16 @@ main(int argc, char **argv)
11631182 return (1 );
11641183 }
11651184 break ;
1185+ case 'W' :
1186+ wait_timeout = MSEC2NSEC (strtol (optarg , & end , 10 ));
1187+ if (wait_timeout < 0 || * end != '\0' ) {
1188+ (void ) fprintf (stderr , "invalid timeout '%s': "
1189+ "must be a non-negative integer\n" , optarg );
1190+ usage ();
1191+ libzfs_fini (g_zfs );
1192+ return (1 );
1193+ }
1194+ break ;
11661195 case ':' :
11671196 (void ) fprintf (stderr , "option -%c requires an "
11681197 "operand\n" , optopt );
@@ -1184,19 +1213,36 @@ main(int argc, char **argv)
11841213 if (record .zi_duration != 0 && record .zi_cmd == 0 )
11851214 record .zi_cmd = ZINJECT_IGNORED_WRITES ;
11861215
1187- if ( cancel != NULL ) {
1188- /*
1189- * '-c' is invalid with any other options.
1190- */
1191- if ( raw != NULL || range != NULL || type != TYPE_INVAL ||
1192- level != 0 || record . zi_cmd != ZINJECT_UNINITIALIZED ||
1193- record . zi_freq > 0 || dvas != 0 || ready_delay >= 0 ) {
1216+ /*
1217+ * '-c' and '-w' are invalid with any other options.
1218+ */
1219+ if ( raw != NULL || range != NULL || type != TYPE_INVAL ||
1220+ level != 0 || record . zi_cmd != ZINJECT_UNINITIALIZED ||
1221+ record . zi_freq > 0 || dvas != 0 || ready_delay >= 0 ) {
1222+ if ( cancel != NULL ) {
11941223 (void ) fprintf (stderr , "cancel (-c) incompatible with "
11951224 "any other options\n" );
11961225 usage ();
11971226 libzfs_fini (g_zfs );
11981227 return (2 );
11991228 }
1229+ if (wait != NULL ) {
1230+ (void ) fprintf (stderr , "wait (-w) incompatible with "
1231+ "any other options\n" );
1232+ usage ();
1233+ libzfs_fini (g_zfs );
1234+ return (2 );
1235+ }
1236+ }
1237+
1238+ if (cancel != NULL ) {
1239+ if (wait != NULL ) {
1240+ (void ) fprintf (stderr , "cancel (-c) incompatible with "
1241+ "wait (-w) option\n" );
1242+ usage ();
1243+ libzfs_fini (g_zfs );
1244+ return (2 );
1245+ }
12001246 if (argc != 0 ) {
12011247 (void ) fprintf (stderr , "extraneous argument to '-c'\n" );
12021248 usage ();
@@ -1219,6 +1265,32 @@ main(int argc, char **argv)
12191265 }
12201266 }
12211267
1268+ if (wait != NULL ) {
1269+ uint64_t state ;
1270+ if (argc != 0 ) {
1271+ (void ) fprintf (stderr , "extraneous argument to '-w'\n" );
1272+ usage ();
1273+ libzfs_fini (g_zfs );
1274+ return (2 );
1275+ }
1276+ state = (uint64_t )strtoull (wait , & end , 10 );
1277+ if (* end != 0 ) {
1278+ (void ) fprintf (stderr , "invalid state '%s': "
1279+ "must be an unsigned integer\n" , wait );
1280+ usage ();
1281+ libzfs_fini (g_zfs );
1282+ return (1 );
1283+ }
1284+ error = lzc_wait_inject (& state , wait_timeout );
1285+ if (error == ETIMEDOUT )
1286+ (void ) printf ("wait timeout\n" );
1287+ else if (error != 0 )
1288+ (void ) printf ("wait failed: %s\n" , strerror (error ));
1289+ else
1290+ (void ) printf ("%" PRIu64 "\n" , state );
1291+ return (error == 0 ? 0 : 1 );
1292+ }
1293+
12221294 if (device != NULL ) {
12231295 /*
12241296 * Device (-d) injection uses a completely different mechanism
0 commit comments