xref: /linux/tools/testing/selftests/ublk/fault_inject.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 /*
4  * Fault injection ublk target. Hack this up however you like for
5  * testing specific behaviors of ublk_drv. Currently is a null target
6  * with a configurable delay before completing each I/O. This delay can
7  * be used to test ublk_drv's handling of I/O outstanding to the ublk
8  * server when it dies.
9  */
10 
11 #include "kublk.h"
12 
13 struct fi_opts {
14 	long long delay_ns;
15 	bool die_during_fetch;
16 };
17 
18 static int ublk_fault_inject_tgt_init(const struct dev_ctx *ctx,
19 				      struct ublk_dev *dev)
20 {
21 	const struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
22 	unsigned long dev_size = 250UL << 30;
23 	struct fi_opts *opts = NULL;
24 
25 	if (ctx->auto_zc_fallback) {
26 		ublk_err("%s: not support auto_zc_fallback\n", __func__);
27 		return -EINVAL;
28 	}
29 
30 	dev->tgt.dev_size = dev_size;
31 	dev->tgt.params = (struct ublk_params) {
32 		.types = UBLK_PARAM_TYPE_BASIC,
33 		.basic = {
34 			.logical_bs_shift	= 9,
35 			.physical_bs_shift	= 12,
36 			.io_opt_shift		= 12,
37 			.io_min_shift		= 9,
38 			.max_sectors		= info->max_io_buf_bytes >> 9,
39 			.dev_sectors		= dev_size >> 9,
40 		},
41 	};
42 	ublk_set_integrity_params(ctx, &dev->tgt.params);
43 
44 	opts = calloc(1, sizeof(*opts));
45 	if (!opts) {
46 		ublk_err("%s: couldn't allocate memory for opts\n", __func__);
47 		return -ENOMEM;
48 	}
49 
50 	opts->delay_ns = ctx->fault_inject.delay_us * 1000;
51 	opts->die_during_fetch = ctx->fault_inject.die_during_fetch;
52 	dev->private_data = opts;
53 
54 	return 0;
55 }
56 
57 static void ublk_fault_inject_pre_fetch_io(struct ublk_thread *t,
58 					   struct ublk_queue *q, int tag,
59 					   bool batch)
60 {
61 	struct fi_opts *opts = q->dev->private_data;
62 
63 	if (!opts->die_during_fetch)
64 		return;
65 
66 	/*
67 	 * Each queue fetches its IOs in increasing order of tags, so
68 	 * dying just before we're about to fetch tag 1 (regardless of
69 	 * what queue we're on) guarantees that we've fetched a nonempty
70 	 * proper subset of the tags on that queue.
71 	 */
72 	if (tag == 1) {
73 		/*
74 		 * Ensure our commands are actually live in the kernel
75 		 * before we die.
76 		 */
77 		io_uring_submit(&t->ring);
78 		raise(SIGKILL);
79 	}
80 }
81 
82 static int ublk_fault_inject_queue_io(struct ublk_thread *t,
83 				      struct ublk_queue *q, int tag)
84 {
85 	const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
86 	struct io_uring_sqe *sqe;
87 	struct fi_opts *opts = q->dev->private_data;
88 	struct __kernel_timespec ts = {
89 		.tv_nsec = opts->delay_ns,
90 	};
91 
92 	ublk_io_alloc_sqes(t, &sqe, 1);
93 	io_uring_prep_timeout(sqe, &ts, 1, 0);
94 	sqe->user_data = build_user_data(tag, ublksrv_get_op(iod), 0, q->q_id, 1);
95 
96 	ublk_queued_tgt_io(t, q, tag, 1);
97 
98 	return 0;
99 }
100 
101 static void ublk_fault_inject_tgt_io_done(struct ublk_thread *t,
102 					  struct ublk_queue *q,
103 					  const struct io_uring_cqe *cqe)
104 {
105 	unsigned tag = user_data_to_tag(cqe->user_data);
106 	const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
107 
108 	if (cqe->res != -ETIME)
109 		ublk_err("%s: unexpected cqe res %d\n", __func__, cqe->res);
110 
111 	if (ublk_completed_tgt_io(t, q, tag))
112 		ublk_complete_io(t, q, tag, iod->nr_sectors << 9);
113 	else
114 		ublk_err("%s: io not complete after 1 cqe\n", __func__);
115 }
116 
117 static void ublk_fault_inject_cmd_line(struct dev_ctx *ctx, int argc, char *argv[])
118 {
119 	static const struct option longopts[] = {
120 		{ "delay_us", 	1,	NULL,  0  },
121 		{ "die_during_fetch", 1, NULL, 0  },
122 		{ 0, 0, 0, 0 }
123 	};
124 	int option_idx, opt;
125 
126 	ctx->fault_inject.delay_us = 0;
127 	ctx->fault_inject.die_during_fetch = false;
128 	while ((opt = getopt_long(argc, argv, "",
129 				  longopts, &option_idx)) != -1) {
130 		switch (opt) {
131 		case 0:
132 			if (!strcmp(longopts[option_idx].name, "delay_us"))
133 				ctx->fault_inject.delay_us = strtoll(optarg, NULL, 10);
134 			if (!strcmp(longopts[option_idx].name, "die_during_fetch"))
135 				ctx->fault_inject.die_during_fetch = strtoll(optarg, NULL, 10);
136 		}
137 	}
138 }
139 
140 static void ublk_fault_inject_usage(const struct ublk_tgt_ops *ops)
141 {
142 	printf("\tfault_inject: [--delay_us us (default 0)] [--die_during_fetch 1]\n");
143 }
144 
145 const struct ublk_tgt_ops fault_inject_tgt_ops = {
146 	.name = "fault_inject",
147 	.init_tgt = ublk_fault_inject_tgt_init,
148 	.pre_fetch_io = ublk_fault_inject_pre_fetch_io,
149 	.queue_io = ublk_fault_inject_queue_io,
150 	.tgt_io_done = ublk_fault_inject_tgt_io_done,
151 	.parse_cmd_line = ublk_fault_inject_cmd_line,
152 	.usage = ublk_fault_inject_usage,
153 };
154