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