xref: /linux/tools/testing/selftests/ublk/fault_inject.c (revision 6d8854216ebb60959ddb6f4ea4123bd449ba6cf6)
181586652SUday Shankar // SPDX-License-Identifier: GPL-2.0
281586652SUday Shankar 
381586652SUday Shankar /*
481586652SUday Shankar  * Fault injection ublk target. Hack this up however you like for
581586652SUday Shankar  * testing specific behaviors of ublk_drv. Currently is a null target
681586652SUday Shankar  * with a configurable delay before completing each I/O. This delay can
781586652SUday Shankar  * be used to test ublk_drv's handling of I/O outstanding to the ublk
881586652SUday Shankar  * server when it dies.
981586652SUday Shankar  */
1081586652SUday Shankar 
1181586652SUday Shankar #include "kublk.h"
1281586652SUday Shankar 
ublk_fault_inject_tgt_init(const struct dev_ctx * ctx,struct ublk_dev * dev)1381586652SUday Shankar static int ublk_fault_inject_tgt_init(const struct dev_ctx *ctx,
1481586652SUday Shankar 				      struct ublk_dev *dev)
1581586652SUday Shankar {
1681586652SUday Shankar 	const struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
1781586652SUday Shankar 	unsigned long dev_size = 250UL << 30;
1881586652SUday Shankar 
196f1a182aSMing Lei 	if (ctx->auto_zc_fallback) {
206f1a182aSMing Lei 		ublk_err("%s: not support auto_zc_fallback\n", __func__);
216f1a182aSMing Lei 		return -EINVAL;
226f1a182aSMing Lei 	}
236f1a182aSMing Lei 
2481586652SUday Shankar 	dev->tgt.dev_size = dev_size;
2581586652SUday Shankar 	dev->tgt.params = (struct ublk_params) {
2681586652SUday Shankar 		.types = UBLK_PARAM_TYPE_BASIC,
2781586652SUday Shankar 		.basic = {
2881586652SUday Shankar 			.logical_bs_shift	= 9,
2981586652SUday Shankar 			.physical_bs_shift	= 12,
3081586652SUday Shankar 			.io_opt_shift		= 12,
3181586652SUday Shankar 			.io_min_shift		= 9,
3281586652SUday Shankar 			.max_sectors		= info->max_io_buf_bytes >> 9,
3381586652SUday Shankar 			.dev_sectors		= dev_size >> 9,
3481586652SUday Shankar 		},
3581586652SUday Shankar 	};
3681586652SUday Shankar 
3781586652SUday Shankar 	dev->private_data = (void *)(unsigned long)(ctx->fault_inject.delay_us * 1000);
3881586652SUday Shankar 	return 0;
3981586652SUday Shankar }
4081586652SUday Shankar 
ublk_fault_inject_queue_io(struct ublk_queue * q,int tag)4181586652SUday Shankar static int ublk_fault_inject_queue_io(struct ublk_queue *q, int tag)
4281586652SUday Shankar {
4381586652SUday Shankar 	const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
4481586652SUday Shankar 	struct io_uring_sqe *sqe;
4581586652SUday Shankar 	struct __kernel_timespec ts = {
4681586652SUday Shankar 		.tv_nsec = (long long)q->dev->private_data,
4781586652SUday Shankar 	};
4881586652SUday Shankar 
49*97737097SUday Shankar 	ublk_io_alloc_sqes(ublk_get_io(q, tag), &sqe, 1);
5081586652SUday Shankar 	io_uring_prep_timeout(sqe, &ts, 1, 0);
51bf098d72SUday Shankar 	sqe->user_data = build_user_data(tag, ublksrv_get_op(iod), 0, q->q_id, 1);
5281586652SUday Shankar 
5381586652SUday Shankar 	ublk_queued_tgt_io(q, tag, 1);
5481586652SUday Shankar 
5581586652SUday Shankar 	return 0;
5681586652SUday Shankar }
5781586652SUday Shankar 
ublk_fault_inject_tgt_io_done(struct ublk_queue * q,int tag,const struct io_uring_cqe * cqe)5881586652SUday Shankar static void ublk_fault_inject_tgt_io_done(struct ublk_queue *q, int tag,
5981586652SUday Shankar 					  const struct io_uring_cqe *cqe)
6081586652SUday Shankar {
6181586652SUday Shankar 	const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag);
6281586652SUday Shankar 
6381586652SUday Shankar 	if (cqe->res != -ETIME)
6481586652SUday Shankar 		ublk_err("%s: unexpected cqe res %d\n", __func__, cqe->res);
6581586652SUday Shankar 
6681586652SUday Shankar 	if (ublk_completed_tgt_io(q, tag))
6781586652SUday Shankar 		ublk_complete_io(q, tag, iod->nr_sectors << 9);
6881586652SUday Shankar 	else
6981586652SUday Shankar 		ublk_err("%s: io not complete after 1 cqe\n", __func__);
7081586652SUday Shankar }
7181586652SUday Shankar 
ublk_fault_inject_cmd_line(struct dev_ctx * ctx,int argc,char * argv[])7281586652SUday Shankar static void ublk_fault_inject_cmd_line(struct dev_ctx *ctx, int argc, char *argv[])
7381586652SUday Shankar {
7481586652SUday Shankar 	static const struct option longopts[] = {
7581586652SUday Shankar 		{ "delay_us", 	1,	NULL,  0  },
7681586652SUday Shankar 		{ 0, 0, 0, 0 }
7781586652SUday Shankar 	};
7881586652SUday Shankar 	int option_idx, opt;
7981586652SUday Shankar 
8081586652SUday Shankar 	ctx->fault_inject.delay_us = 0;
8181586652SUday Shankar 	while ((opt = getopt_long(argc, argv, "",
8281586652SUday Shankar 				  longopts, &option_idx)) != -1) {
8381586652SUday Shankar 		switch (opt) {
8481586652SUday Shankar 		case 0:
8581586652SUday Shankar 			if (!strcmp(longopts[option_idx].name, "delay_us"))
8681586652SUday Shankar 				ctx->fault_inject.delay_us = strtoll(optarg, NULL, 10);
8781586652SUday Shankar 		}
8881586652SUday Shankar 	}
8981586652SUday Shankar }
9081586652SUday Shankar 
ublk_fault_inject_usage(const struct ublk_tgt_ops * ops)9181586652SUday Shankar static void ublk_fault_inject_usage(const struct ublk_tgt_ops *ops)
9281586652SUday Shankar {
9381586652SUday Shankar 	printf("\tfault_inject: [--delay_us us (default 0)]\n");
9481586652SUday Shankar }
9581586652SUday Shankar 
9681586652SUday Shankar const struct ublk_tgt_ops fault_inject_tgt_ops = {
9781586652SUday Shankar 	.name = "fault_inject",
9881586652SUday Shankar 	.init_tgt = ublk_fault_inject_tgt_init,
9981586652SUday Shankar 	.queue_io = ublk_fault_inject_queue_io,
10081586652SUday Shankar 	.tgt_io_done = ublk_fault_inject_tgt_io_done,
10181586652SUday Shankar 	.parse_cmd_line = ublk_fault_inject_cmd_line,
10281586652SUday Shankar 	.usage = ublk_fault_inject_usage,
10381586652SUday Shankar };
104