summaryrefslogtreecommitdiff
path: root/usr/src/cmd/zinject/zinject.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/zinject/zinject.c')
-rw-r--r--usr/src/cmd/zinject/zinject.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/usr/src/cmd/zinject/zinject.c b/usr/src/cmd/zinject/zinject.c
index 5528ac330a..c673cf9ea1 100644
--- a/usr/src/cmd/zinject/zinject.c
+++ b/usr/src/cmd/zinject/zinject.c
@@ -227,11 +227,15 @@ usage(void)
"\t\tfunctions which call spa_vdev_config_exit(), or \n"
"\t\tspa_vdev_exit() will trigger a panic.\n"
"\n"
- "\tzinject -d device [-e errno] [-L <nvlist|uber>] [-F] pool\n"
+ "\tzinject -d device [-e errno] [-L <nvlist|uber>] [-F]\n"
+ "\t [-T <read|write|free|claim|all> pool\n"
"\t\tInject a fault into a particular device or the device's\n"
"\t\tlabel. Label injection can either be 'nvlist' or 'uber'.\n"
"\t\t'errno' can either be 'nxio' (the default) or 'io'.\n"
"\n"
+ "\tzinject -d device -A <degrade|fault> pool\n"
+ "\t\tPerform a specific action on a particular device\n"
+ "\n"
"\tzinject -b objset:object:level:blkid pool\n"
"\n"
"\t\tInject an error into pool 'pool' with the numeric bookmark\n"
@@ -497,6 +501,22 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
}
int
+perform_action(const char *pool, zinject_record_t *record, int cmd)
+{
+ zfs_cmd_t zc;
+
+ ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
+ (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+ zc.zc_guid = record->zi_guid;
+ zc.zc_cookie = cmd;
+
+ if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ return (1);
+}
+
+int
main(int argc, char **argv)
{
int c;
@@ -509,6 +529,8 @@ main(int argc, char **argv)
int quiet = 0;
int error = 0;
int domount = 0;
+ int io_type = ZIO_TYPES;
+ int action = VDEV_STATE_UNKNOWN;
err_type_t type = TYPE_INVAL;
err_type_t label = TYPE_INVAL;
zinject_record_t record = { 0 };
@@ -546,11 +568,24 @@ main(int argc, char **argv)
return (0);
}
- while ((c = getopt(argc, argv, ":ab:d:f:Fqhc:t:l:mr:e:uL:p:")) != -1) {
+ while ((c = getopt(argc, argv,
+ ":aA:b:d:f:Fqhc:t:T:l:mr:e:uL:p:")) != -1) {
switch (c) {
case 'a':
flags |= ZINJECT_FLUSH_ARC;
break;
+ case 'A':
+ if (strcasecmp(optarg, "degrade") == 0) {
+ action = VDEV_STATE_DEGRADED;
+ } else if (strcasecmp(optarg, "fault") == 0) {
+ action = VDEV_STATE_FAULTED;
+ } else {
+ (void) fprintf(stderr, "invalid action '%s': "
+ "must be 'degrade' or 'fault'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
case 'b':
raw = optarg;
break;
@@ -611,6 +646,25 @@ main(int argc, char **argv)
case 'r':
range = optarg;
break;
+ case 'T':
+ if (strcasecmp(optarg, "read") == 0) {
+ io_type = ZIO_TYPE_READ;
+ } else if (strcasecmp(optarg, "write") == 0) {
+ io_type = ZIO_TYPE_WRITE;
+ } else if (strcasecmp(optarg, "free") == 0) {
+ io_type = ZIO_TYPE_FREE;
+ } else if (strcasecmp(optarg, "claim") == 0) {
+ io_type = ZIO_TYPE_CLAIM;
+ } else if (strcasecmp(optarg, "all") == 0) {
+ io_type = ZIO_TYPES;
+ } else {
+ (void) fprintf(stderr, "invalid I/O type "
+ "'%s': must be 'read', 'write', 'free', "
+ "'claim' or 'all'\n", optarg);
+ usage();
+ return (1);
+ }
+ break;
case 't':
if ((type = name_to_type(optarg)) == TYPE_INVAL &&
!MOS_TYPE(type)) {
@@ -708,10 +762,15 @@ main(int argc, char **argv)
return (1);
}
+ record.zi_iotype = io_type;
if (translate_device(pool, device, label, &record) != 0)
return (1);
if (!error)
error = ENXIO;
+
+ if (action != VDEV_STATE_UNKNOWN)
+ return (perform_action(pool, &record, action));
+
} else if (raw != NULL) {
if (range != NULL || type != TYPE_INVAL || level != 0 ||
record.zi_func[0] != '\0') {