1 /* SPDX-License-Identifier: MIT */ 2 /* 3 * Description: uring_cmd based ublk 4 */ 5 6 #include "kublk.h" 7 8 #define MAX_NR_TGT_ARG 64 9 10 unsigned int ublk_dbg_mask = UBLK_LOG; 11 static const struct ublk_tgt_ops *tgt_ops_list[] = { 12 &null_tgt_ops, 13 &loop_tgt_ops, 14 &stripe_tgt_ops, 15 &fault_inject_tgt_ops, 16 }; 17 18 static const struct ublk_tgt_ops *ublk_find_tgt(const char *name) 19 { 20 int i; 21 22 if (name == NULL) 23 return NULL; 24 25 for (i = 0; i < ARRAY_SIZE(tgt_ops_list); i++) 26 if (strcmp(tgt_ops_list[i]->name, name) == 0) 27 return tgt_ops_list[i]; 28 return NULL; 29 } 30 31 static inline int ublk_setup_ring(struct io_uring *r, int depth, 32 int cq_depth, unsigned flags) 33 { 34 struct io_uring_params p; 35 36 memset(&p, 0, sizeof(p)); 37 p.flags = flags | IORING_SETUP_CQSIZE; 38 p.cq_entries = cq_depth; 39 40 return io_uring_queue_init_params(depth, r, &p); 41 } 42 43 static void ublk_ctrl_init_cmd(struct ublk_dev *dev, 44 struct io_uring_sqe *sqe, 45 struct ublk_ctrl_cmd_data *data) 46 { 47 struct ublksrv_ctrl_dev_info *info = &dev->dev_info; 48 struct ublksrv_ctrl_cmd *cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe); 49 50 sqe->fd = dev->ctrl_fd; 51 sqe->opcode = IORING_OP_URING_CMD; 52 sqe->ioprio = 0; 53 54 if (data->flags & CTRL_CMD_HAS_BUF) { 55 cmd->addr = data->addr; 56 cmd->len = data->len; 57 } 58 59 if (data->flags & CTRL_CMD_HAS_DATA) 60 cmd->data[0] = data->data[0]; 61 62 cmd->dev_id = info->dev_id; 63 cmd->queue_id = -1; 64 65 ublk_set_sqe_cmd_op(sqe, data->cmd_op); 66 67 io_uring_sqe_set_data(sqe, cmd); 68 } 69 70 static int __ublk_ctrl_cmd(struct ublk_dev *dev, 71 struct ublk_ctrl_cmd_data *data) 72 { 73 struct io_uring_sqe *sqe; 74 struct io_uring_cqe *cqe; 75 int ret = -EINVAL; 76 77 sqe = io_uring_get_sqe(&dev->ring); 78 if (!sqe) { 79 ublk_err("%s: can't get sqe ret %d\n", __func__, ret); 80 return ret; 81 } 82 83 ublk_ctrl_init_cmd(dev, sqe, data); 84 85 ret = io_uring_submit(&dev->ring); 86 if (ret < 0) { 87 ublk_err("uring submit ret %d\n", ret); 88 return ret; 89 } 90 91 ret = io_uring_wait_cqe(&dev->ring, &cqe); 92 if (ret < 0) { 93 ublk_err("wait cqe: %s\n", strerror(-ret)); 94 return ret; 95 } 96 io_uring_cqe_seen(&dev->ring, cqe); 97 98 return cqe->res; 99 } 100 101 static int ublk_ctrl_stop_dev(struct ublk_dev *dev) 102 { 103 struct ublk_ctrl_cmd_data data = { 104 .cmd_op = UBLK_U_CMD_STOP_DEV, 105 }; 106 107 return __ublk_ctrl_cmd(dev, &data); 108 } 109 110 static int ublk_ctrl_start_dev(struct ublk_dev *dev, 111 int daemon_pid) 112 { 113 struct ublk_ctrl_cmd_data data = { 114 .cmd_op = UBLK_U_CMD_START_DEV, 115 .flags = CTRL_CMD_HAS_DATA, 116 }; 117 118 dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid; 119 120 return __ublk_ctrl_cmd(dev, &data); 121 } 122 123 static int ublk_ctrl_start_user_recovery(struct ublk_dev *dev) 124 { 125 struct ublk_ctrl_cmd_data data = { 126 .cmd_op = UBLK_U_CMD_START_USER_RECOVERY, 127 }; 128 129 return __ublk_ctrl_cmd(dev, &data); 130 } 131 132 static int ublk_ctrl_end_user_recovery(struct ublk_dev *dev, int daemon_pid) 133 { 134 struct ublk_ctrl_cmd_data data = { 135 .cmd_op = UBLK_U_CMD_END_USER_RECOVERY, 136 .flags = CTRL_CMD_HAS_DATA, 137 }; 138 139 dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid; 140 141 return __ublk_ctrl_cmd(dev, &data); 142 } 143 144 static int ublk_ctrl_add_dev(struct ublk_dev *dev) 145 { 146 struct ublk_ctrl_cmd_data data = { 147 .cmd_op = UBLK_U_CMD_ADD_DEV, 148 .flags = CTRL_CMD_HAS_BUF, 149 .addr = (__u64) (uintptr_t) &dev->dev_info, 150 .len = sizeof(struct ublksrv_ctrl_dev_info), 151 }; 152 153 return __ublk_ctrl_cmd(dev, &data); 154 } 155 156 static int ublk_ctrl_del_dev(struct ublk_dev *dev) 157 { 158 struct ublk_ctrl_cmd_data data = { 159 .cmd_op = UBLK_U_CMD_DEL_DEV, 160 .flags = 0, 161 }; 162 163 return __ublk_ctrl_cmd(dev, &data); 164 } 165 166 static int ublk_ctrl_get_info(struct ublk_dev *dev) 167 { 168 struct ublk_ctrl_cmd_data data = { 169 .cmd_op = UBLK_U_CMD_GET_DEV_INFO, 170 .flags = CTRL_CMD_HAS_BUF, 171 .addr = (__u64) (uintptr_t) &dev->dev_info, 172 .len = sizeof(struct ublksrv_ctrl_dev_info), 173 }; 174 175 return __ublk_ctrl_cmd(dev, &data); 176 } 177 178 static int ublk_ctrl_set_params(struct ublk_dev *dev, 179 struct ublk_params *params) 180 { 181 struct ublk_ctrl_cmd_data data = { 182 .cmd_op = UBLK_U_CMD_SET_PARAMS, 183 .flags = CTRL_CMD_HAS_BUF, 184 .addr = (__u64) (uintptr_t) params, 185 .len = sizeof(*params), 186 }; 187 params->len = sizeof(*params); 188 return __ublk_ctrl_cmd(dev, &data); 189 } 190 191 static int ublk_ctrl_get_params(struct ublk_dev *dev, 192 struct ublk_params *params) 193 { 194 struct ublk_ctrl_cmd_data data = { 195 .cmd_op = UBLK_U_CMD_GET_PARAMS, 196 .flags = CTRL_CMD_HAS_BUF, 197 .addr = (__u64)params, 198 .len = sizeof(*params), 199 }; 200 201 params->len = sizeof(*params); 202 203 return __ublk_ctrl_cmd(dev, &data); 204 } 205 206 static int ublk_ctrl_get_features(struct ublk_dev *dev, 207 __u64 *features) 208 { 209 struct ublk_ctrl_cmd_data data = { 210 .cmd_op = UBLK_U_CMD_GET_FEATURES, 211 .flags = CTRL_CMD_HAS_BUF, 212 .addr = (__u64) (uintptr_t) features, 213 .len = sizeof(*features), 214 }; 215 216 return __ublk_ctrl_cmd(dev, &data); 217 } 218 219 static const char *ublk_dev_state_desc(struct ublk_dev *dev) 220 { 221 switch (dev->dev_info.state) { 222 case UBLK_S_DEV_DEAD: 223 return "DEAD"; 224 case UBLK_S_DEV_LIVE: 225 return "LIVE"; 226 case UBLK_S_DEV_QUIESCED: 227 return "QUIESCED"; 228 default: 229 return "UNKNOWN"; 230 }; 231 } 232 233 static void ublk_print_cpu_set(const cpu_set_t *set, char *buf, unsigned len) 234 { 235 unsigned done = 0; 236 int i; 237 238 for (i = 0; i < CPU_SETSIZE; i++) { 239 if (CPU_ISSET(i, set)) 240 done += snprintf(&buf[done], len - done, "%d ", i); 241 } 242 } 243 244 static void ublk_adjust_affinity(cpu_set_t *set) 245 { 246 int j, updated = 0; 247 248 /* 249 * Just keep the 1st CPU now. 250 * 251 * In future, auto affinity selection can be tried. 252 */ 253 for (j = 0; j < CPU_SETSIZE; j++) { 254 if (CPU_ISSET(j, set)) { 255 if (!updated) { 256 updated = 1; 257 continue; 258 } 259 CPU_CLR(j, set); 260 } 261 } 262 } 263 264 /* Caller must free the allocated buffer */ 265 static int ublk_ctrl_get_affinity(struct ublk_dev *ctrl_dev, cpu_set_t **ptr_buf) 266 { 267 struct ublk_ctrl_cmd_data data = { 268 .cmd_op = UBLK_U_CMD_GET_QUEUE_AFFINITY, 269 .flags = CTRL_CMD_HAS_DATA | CTRL_CMD_HAS_BUF, 270 }; 271 cpu_set_t *buf; 272 int i, ret; 273 274 buf = malloc(sizeof(cpu_set_t) * ctrl_dev->dev_info.nr_hw_queues); 275 if (!buf) 276 return -ENOMEM; 277 278 for (i = 0; i < ctrl_dev->dev_info.nr_hw_queues; i++) { 279 data.data[0] = i; 280 data.len = sizeof(cpu_set_t); 281 data.addr = (__u64)&buf[i]; 282 283 ret = __ublk_ctrl_cmd(ctrl_dev, &data); 284 if (ret < 0) { 285 free(buf); 286 return ret; 287 } 288 ublk_adjust_affinity(&buf[i]); 289 } 290 291 *ptr_buf = buf; 292 return 0; 293 } 294 295 static void ublk_ctrl_dump(struct ublk_dev *dev) 296 { 297 struct ublksrv_ctrl_dev_info *info = &dev->dev_info; 298 struct ublk_params p; 299 cpu_set_t *affinity; 300 int ret; 301 302 ret = ublk_ctrl_get_params(dev, &p); 303 if (ret < 0) { 304 ublk_err("failed to get params %d %s\n", ret, strerror(-ret)); 305 return; 306 } 307 308 ret = ublk_ctrl_get_affinity(dev, &affinity); 309 if (ret < 0) { 310 ublk_err("failed to get affinity %m\n"); 311 return; 312 } 313 314 ublk_log("dev id %d: nr_hw_queues %d queue_depth %d block size %d dev_capacity %lld\n", 315 info->dev_id, info->nr_hw_queues, info->queue_depth, 316 1 << p.basic.logical_bs_shift, p.basic.dev_sectors); 317 ublk_log("\tmax rq size %d daemon pid %d flags 0x%llx state %s\n", 318 info->max_io_buf_bytes, info->ublksrv_pid, info->flags, 319 ublk_dev_state_desc(dev)); 320 321 if (affinity) { 322 char buf[512]; 323 int i; 324 325 for (i = 0; i < info->nr_hw_queues; i++) { 326 ublk_print_cpu_set(&affinity[i], buf, sizeof(buf)); 327 printf("\tqueue %u: tid %d affinity(%s)\n", 328 i, dev->q[i].tid, buf); 329 } 330 free(affinity); 331 } 332 333 fflush(stdout); 334 } 335 336 static void ublk_ctrl_deinit(struct ublk_dev *dev) 337 { 338 close(dev->ctrl_fd); 339 free(dev); 340 } 341 342 static struct ublk_dev *ublk_ctrl_init(void) 343 { 344 struct ublk_dev *dev = (struct ublk_dev *)calloc(1, sizeof(*dev)); 345 struct ublksrv_ctrl_dev_info *info = &dev->dev_info; 346 int ret; 347 348 dev->ctrl_fd = open(CTRL_DEV, O_RDWR); 349 if (dev->ctrl_fd < 0) { 350 free(dev); 351 return NULL; 352 } 353 354 info->max_io_buf_bytes = UBLK_IO_MAX_BYTES; 355 356 ret = ublk_setup_ring(&dev->ring, UBLK_CTRL_RING_DEPTH, 357 UBLK_CTRL_RING_DEPTH, IORING_SETUP_SQE128); 358 if (ret < 0) { 359 ublk_err("queue_init: %s\n", strerror(-ret)); 360 free(dev); 361 return NULL; 362 } 363 dev->nr_fds = 1; 364 365 return dev; 366 } 367 368 static int __ublk_queue_cmd_buf_sz(unsigned depth) 369 { 370 int size = depth * sizeof(struct ublksrv_io_desc); 371 unsigned int page_sz = getpagesize(); 372 373 return round_up(size, page_sz); 374 } 375 376 static int ublk_queue_max_cmd_buf_sz(void) 377 { 378 return __ublk_queue_cmd_buf_sz(UBLK_MAX_QUEUE_DEPTH); 379 } 380 381 static int ublk_queue_cmd_buf_sz(struct ublk_queue *q) 382 { 383 return __ublk_queue_cmd_buf_sz(q->q_depth); 384 } 385 386 static void ublk_queue_deinit(struct ublk_queue *q) 387 { 388 int i; 389 int nr_ios = q->q_depth; 390 391 io_uring_unregister_buffers(&q->ring); 392 393 io_uring_unregister_ring_fd(&q->ring); 394 395 if (q->ring.ring_fd > 0) { 396 io_uring_unregister_files(&q->ring); 397 close(q->ring.ring_fd); 398 q->ring.ring_fd = -1; 399 } 400 401 if (q->io_cmd_buf) 402 munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q)); 403 404 for (i = 0; i < nr_ios; i++) 405 free(q->ios[i].buf_addr); 406 } 407 408 static int ublk_queue_init(struct ublk_queue *q) 409 { 410 struct ublk_dev *dev = q->dev; 411 int depth = dev->dev_info.queue_depth; 412 int i, ret = -1; 413 int cmd_buf_size, io_buf_size; 414 unsigned long off; 415 int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth; 416 417 q->tgt_ops = dev->tgt.ops; 418 q->state = 0; 419 q->q_depth = depth; 420 q->cmd_inflight = 0; 421 q->tid = gettid(); 422 423 if (dev->dev_info.flags & UBLK_F_SUPPORT_ZERO_COPY) { 424 q->state |= UBLKSRV_NO_BUF; 425 q->state |= UBLKSRV_ZC; 426 } 427 428 cmd_buf_size = ublk_queue_cmd_buf_sz(q); 429 off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz(); 430 q->io_cmd_buf = mmap(0, cmd_buf_size, PROT_READ, 431 MAP_SHARED | MAP_POPULATE, dev->fds[0], off); 432 if (q->io_cmd_buf == MAP_FAILED) { 433 ublk_err("ublk dev %d queue %d map io_cmd_buf failed %m\n", 434 q->dev->dev_info.dev_id, q->q_id); 435 goto fail; 436 } 437 438 io_buf_size = dev->dev_info.max_io_buf_bytes; 439 for (i = 0; i < q->q_depth; i++) { 440 q->ios[i].buf_addr = NULL; 441 q->ios[i].flags = UBLKSRV_NEED_FETCH_RQ | UBLKSRV_IO_FREE; 442 443 if (q->state & UBLKSRV_NO_BUF) 444 continue; 445 446 if (posix_memalign((void **)&q->ios[i].buf_addr, 447 getpagesize(), io_buf_size)) { 448 ublk_err("ublk dev %d queue %d io %d posix_memalign failed %m\n", 449 dev->dev_info.dev_id, q->q_id, i); 450 goto fail; 451 } 452 } 453 454 ret = ublk_setup_ring(&q->ring, ring_depth, cq_depth, 455 IORING_SETUP_COOP_TASKRUN | 456 IORING_SETUP_SINGLE_ISSUER | 457 IORING_SETUP_DEFER_TASKRUN); 458 if (ret < 0) { 459 ublk_err("ublk dev %d queue %d setup io_uring failed %d\n", 460 q->dev->dev_info.dev_id, q->q_id, ret); 461 goto fail; 462 } 463 464 if (dev->dev_info.flags & UBLK_F_SUPPORT_ZERO_COPY) { 465 ret = io_uring_register_buffers_sparse(&q->ring, q->q_depth); 466 if (ret) { 467 ublk_err("ublk dev %d queue %d register spare buffers failed %d", 468 dev->dev_info.dev_id, q->q_id, ret); 469 goto fail; 470 } 471 } 472 473 io_uring_register_ring_fd(&q->ring); 474 475 ret = io_uring_register_files(&q->ring, dev->fds, dev->nr_fds); 476 if (ret) { 477 ublk_err("ublk dev %d queue %d register files failed %d\n", 478 q->dev->dev_info.dev_id, q->q_id, ret); 479 goto fail; 480 } 481 482 return 0; 483 fail: 484 ublk_queue_deinit(q); 485 ublk_err("ublk dev %d queue %d failed\n", 486 dev->dev_info.dev_id, q->q_id); 487 return -ENOMEM; 488 } 489 490 #define WAIT_USEC 100000 491 #define MAX_WAIT_USEC (3 * 1000000) 492 static int ublk_dev_prep(const struct dev_ctx *ctx, struct ublk_dev *dev) 493 { 494 int dev_id = dev->dev_info.dev_id; 495 unsigned int wait_usec = 0; 496 int ret = 0, fd = -1; 497 char buf[64]; 498 499 snprintf(buf, 64, "%s%d", UBLKC_DEV, dev_id); 500 501 while (wait_usec < MAX_WAIT_USEC) { 502 fd = open(buf, O_RDWR); 503 if (fd >= 0) 504 break; 505 usleep(WAIT_USEC); 506 wait_usec += WAIT_USEC; 507 } 508 if (fd < 0) { 509 ublk_err("can't open %s %s\n", buf, strerror(errno)); 510 return -1; 511 } 512 513 dev->fds[0] = fd; 514 if (dev->tgt.ops->init_tgt) 515 ret = dev->tgt.ops->init_tgt(ctx, dev); 516 if (ret) 517 close(dev->fds[0]); 518 return ret; 519 } 520 521 static void ublk_dev_unprep(struct ublk_dev *dev) 522 { 523 if (dev->tgt.ops->deinit_tgt) 524 dev->tgt.ops->deinit_tgt(dev); 525 close(dev->fds[0]); 526 } 527 528 int ublk_queue_io_cmd(struct ublk_queue *q, struct ublk_io *io, unsigned tag) 529 { 530 struct ublksrv_io_cmd *cmd; 531 struct io_uring_sqe *sqe[1]; 532 unsigned int cmd_op = 0; 533 __u64 user_data; 534 535 /* only freed io can be issued */ 536 if (!(io->flags & UBLKSRV_IO_FREE)) 537 return 0; 538 539 /* 540 * we issue because we need either fetching or committing or 541 * getting data 542 */ 543 if (!(io->flags & 544 (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_NEED_GET_DATA))) 545 return 0; 546 547 if (io->flags & UBLKSRV_NEED_GET_DATA) 548 cmd_op = UBLK_U_IO_NEED_GET_DATA; 549 else if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP) 550 cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ; 551 else if (io->flags & UBLKSRV_NEED_FETCH_RQ) 552 cmd_op = UBLK_U_IO_FETCH_REQ; 553 554 if (io_uring_sq_space_left(&q->ring) < 1) 555 io_uring_submit(&q->ring); 556 557 ublk_queue_alloc_sqes(q, sqe, 1); 558 if (!sqe[0]) { 559 ublk_err("%s: run out of sqe %d, tag %d\n", 560 __func__, q->q_id, tag); 561 return -1; 562 } 563 564 cmd = (struct ublksrv_io_cmd *)ublk_get_sqe_cmd(sqe[0]); 565 566 if (cmd_op == UBLK_U_IO_COMMIT_AND_FETCH_REQ) 567 cmd->result = io->result; 568 569 /* These fields should be written once, never change */ 570 ublk_set_sqe_cmd_op(sqe[0], cmd_op); 571 sqe[0]->fd = 0; /* dev->fds[0] */ 572 sqe[0]->opcode = IORING_OP_URING_CMD; 573 sqe[0]->flags = IOSQE_FIXED_FILE; 574 sqe[0]->rw_flags = 0; 575 cmd->tag = tag; 576 cmd->q_id = q->q_id; 577 if (!(q->state & UBLKSRV_NO_BUF)) 578 cmd->addr = (__u64) (uintptr_t) io->buf_addr; 579 else 580 cmd->addr = 0; 581 582 user_data = build_user_data(tag, _IOC_NR(cmd_op), 0, 0); 583 io_uring_sqe_set_data64(sqe[0], user_data); 584 585 io->flags = 0; 586 587 q->cmd_inflight += 1; 588 589 ublk_dbg(UBLK_DBG_IO_CMD, "%s: (qid %d tag %u cmd_op %u) iof %x stopping %d\n", 590 __func__, q->q_id, tag, cmd_op, 591 io->flags, !!(q->state & UBLKSRV_QUEUE_STOPPING)); 592 return 1; 593 } 594 595 static void ublk_submit_fetch_commands(struct ublk_queue *q) 596 { 597 int i = 0; 598 599 for (i = 0; i < q->q_depth; i++) 600 ublk_queue_io_cmd(q, &q->ios[i], i); 601 } 602 603 static int ublk_queue_is_idle(struct ublk_queue *q) 604 { 605 return !io_uring_sq_ready(&q->ring) && !q->io_inflight; 606 } 607 608 static int ublk_queue_is_done(struct ublk_queue *q) 609 { 610 return (q->state & UBLKSRV_QUEUE_STOPPING) && ublk_queue_is_idle(q); 611 } 612 613 static inline void ublksrv_handle_tgt_cqe(struct ublk_queue *q, 614 struct io_uring_cqe *cqe) 615 { 616 unsigned tag = user_data_to_tag(cqe->user_data); 617 618 if (cqe->res < 0 && cqe->res != -EAGAIN) 619 ublk_err("%s: failed tgt io: res %d qid %u tag %u, cmd_op %u\n", 620 __func__, cqe->res, q->q_id, 621 user_data_to_tag(cqe->user_data), 622 user_data_to_op(cqe->user_data)); 623 624 if (q->tgt_ops->tgt_io_done) 625 q->tgt_ops->tgt_io_done(q, tag, cqe); 626 } 627 628 static void ublk_handle_cqe(struct io_uring *r, 629 struct io_uring_cqe *cqe, void *data) 630 { 631 struct ublk_queue *q = container_of(r, struct ublk_queue, ring); 632 unsigned tag = user_data_to_tag(cqe->user_data); 633 unsigned cmd_op = user_data_to_op(cqe->user_data); 634 int fetch = (cqe->res != UBLK_IO_RES_ABORT) && 635 !(q->state & UBLKSRV_QUEUE_STOPPING); 636 struct ublk_io *io; 637 638 if (cqe->res < 0 && cqe->res != -ENODEV) 639 ublk_err("%s: res %d userdata %llx queue state %x\n", __func__, 640 cqe->res, cqe->user_data, q->state); 641 642 ublk_dbg(UBLK_DBG_IO_CMD, "%s: res %d (qid %d tag %u cmd_op %u target %d/%d) stopping %d\n", 643 __func__, cqe->res, q->q_id, tag, cmd_op, 644 is_target_io(cqe->user_data), 645 user_data_to_tgt_data(cqe->user_data), 646 (q->state & UBLKSRV_QUEUE_STOPPING)); 647 648 /* Don't retrieve io in case of target io */ 649 if (is_target_io(cqe->user_data)) { 650 ublksrv_handle_tgt_cqe(q, cqe); 651 return; 652 } 653 654 io = &q->ios[tag]; 655 q->cmd_inflight--; 656 657 if (!fetch) { 658 q->state |= UBLKSRV_QUEUE_STOPPING; 659 io->flags &= ~UBLKSRV_NEED_FETCH_RQ; 660 } 661 662 if (cqe->res == UBLK_IO_RES_OK) { 663 assert(tag < q->q_depth); 664 if (q->tgt_ops->queue_io) 665 q->tgt_ops->queue_io(q, tag); 666 } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) { 667 io->flags |= UBLKSRV_NEED_GET_DATA | UBLKSRV_IO_FREE; 668 ublk_queue_io_cmd(q, io, tag); 669 } else { 670 /* 671 * COMMIT_REQ will be completed immediately since no fetching 672 * piggyback is required. 673 * 674 * Marking IO_FREE only, then this io won't be issued since 675 * we only issue io with (UBLKSRV_IO_FREE | UBLKSRV_NEED_*) 676 * 677 * */ 678 io->flags = UBLKSRV_IO_FREE; 679 } 680 } 681 682 static int ublk_reap_events_uring(struct io_uring *r) 683 { 684 struct io_uring_cqe *cqe; 685 unsigned head; 686 int count = 0; 687 688 io_uring_for_each_cqe(r, head, cqe) { 689 ublk_handle_cqe(r, cqe, NULL); 690 count += 1; 691 } 692 io_uring_cq_advance(r, count); 693 694 return count; 695 } 696 697 static int ublk_process_io(struct ublk_queue *q) 698 { 699 int ret, reapped; 700 701 ublk_dbg(UBLK_DBG_QUEUE, "dev%d-q%d: to_submit %d inflight cmd %u stopping %d\n", 702 q->dev->dev_info.dev_id, 703 q->q_id, io_uring_sq_ready(&q->ring), 704 q->cmd_inflight, 705 (q->state & UBLKSRV_QUEUE_STOPPING)); 706 707 if (ublk_queue_is_done(q)) 708 return -ENODEV; 709 710 ret = io_uring_submit_and_wait(&q->ring, 1); 711 reapped = ublk_reap_events_uring(&q->ring); 712 713 ublk_dbg(UBLK_DBG_QUEUE, "submit result %d, reapped %d stop %d idle %d\n", 714 ret, reapped, (q->state & UBLKSRV_QUEUE_STOPPING), 715 (q->state & UBLKSRV_QUEUE_IDLE)); 716 717 return reapped; 718 } 719 720 static void ublk_queue_set_sched_affinity(const struct ublk_queue *q, 721 cpu_set_t *cpuset) 722 { 723 if (sched_setaffinity(0, sizeof(*cpuset), cpuset) < 0) 724 ublk_err("ublk dev %u queue %u set affinity failed", 725 q->dev->dev_info.dev_id, q->q_id); 726 } 727 728 struct ublk_queue_info { 729 struct ublk_queue *q; 730 sem_t *queue_sem; 731 cpu_set_t *affinity; 732 }; 733 734 static void *ublk_io_handler_fn(void *data) 735 { 736 struct ublk_queue_info *info = data; 737 struct ublk_queue *q = info->q; 738 int dev_id = q->dev->dev_info.dev_id; 739 int ret; 740 741 ret = ublk_queue_init(q); 742 if (ret) { 743 ublk_err("ublk dev %d queue %d init queue failed\n", 744 dev_id, q->q_id); 745 return NULL; 746 } 747 /* IO perf is sensitive with queue pthread affinity on NUMA machine*/ 748 ublk_queue_set_sched_affinity(q, info->affinity); 749 sem_post(info->queue_sem); 750 751 ublk_dbg(UBLK_DBG_QUEUE, "tid %d: ublk dev %d queue %d started\n", 752 q->tid, dev_id, q->q_id); 753 754 /* submit all io commands to ublk driver */ 755 ublk_submit_fetch_commands(q); 756 do { 757 if (ublk_process_io(q) < 0) 758 break; 759 } while (1); 760 761 ublk_dbg(UBLK_DBG_QUEUE, "ublk dev %d queue %d exited\n", dev_id, q->q_id); 762 ublk_queue_deinit(q); 763 return NULL; 764 } 765 766 static void ublk_set_parameters(struct ublk_dev *dev) 767 { 768 int ret; 769 770 ret = ublk_ctrl_set_params(dev, &dev->tgt.params); 771 if (ret) 772 ublk_err("dev %d set basic parameter failed %d\n", 773 dev->dev_info.dev_id, ret); 774 } 775 776 static int ublk_send_dev_event(const struct dev_ctx *ctx, struct ublk_dev *dev, int dev_id) 777 { 778 uint64_t id; 779 int evtfd = ctx->_evtfd; 780 781 if (evtfd < 0) 782 return -EBADF; 783 784 if (dev_id >= 0) 785 id = dev_id + 1; 786 else 787 id = ERROR_EVTFD_DEVID; 788 789 if (dev && ctx->shadow_dev) 790 memcpy(&ctx->shadow_dev->q, &dev->q, sizeof(dev->q)); 791 792 if (write(evtfd, &id, sizeof(id)) != sizeof(id)) 793 return -EINVAL; 794 795 close(evtfd); 796 shmdt(ctx->shadow_dev); 797 798 return 0; 799 } 800 801 802 static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev) 803 { 804 const struct ublksrv_ctrl_dev_info *dinfo = &dev->dev_info; 805 struct ublk_queue_info *qinfo; 806 cpu_set_t *affinity_buf; 807 void *thread_ret; 808 sem_t queue_sem; 809 int ret, i; 810 811 ublk_dbg(UBLK_DBG_DEV, "%s enter\n", __func__); 812 813 qinfo = (struct ublk_queue_info *)calloc(sizeof(struct ublk_queue_info), 814 dinfo->nr_hw_queues); 815 if (!qinfo) 816 return -ENOMEM; 817 818 sem_init(&queue_sem, 0, 0); 819 ret = ublk_dev_prep(ctx, dev); 820 if (ret) 821 return ret; 822 823 ret = ublk_ctrl_get_affinity(dev, &affinity_buf); 824 if (ret) 825 return ret; 826 827 for (i = 0; i < dinfo->nr_hw_queues; i++) { 828 dev->q[i].dev = dev; 829 dev->q[i].q_id = i; 830 831 qinfo[i].q = &dev->q[i]; 832 qinfo[i].queue_sem = &queue_sem; 833 qinfo[i].affinity = &affinity_buf[i]; 834 pthread_create(&dev->q[i].thread, NULL, 835 ublk_io_handler_fn, 836 &qinfo[i]); 837 } 838 839 for (i = 0; i < dinfo->nr_hw_queues; i++) 840 sem_wait(&queue_sem); 841 free(qinfo); 842 free(affinity_buf); 843 844 /* everything is fine now, start us */ 845 if (ctx->recovery) 846 ret = ublk_ctrl_end_user_recovery(dev, getpid()); 847 else { 848 ublk_set_parameters(dev); 849 ret = ublk_ctrl_start_dev(dev, getpid()); 850 } 851 if (ret < 0) { 852 ublk_err("%s: ublk_ctrl_start_dev failed: %d\n", __func__, ret); 853 goto fail; 854 } 855 856 ublk_ctrl_get_info(dev); 857 if (ctx->fg) 858 ublk_ctrl_dump(dev); 859 else 860 ublk_send_dev_event(ctx, dev, dev->dev_info.dev_id); 861 862 /* wait until we are terminated */ 863 for (i = 0; i < dinfo->nr_hw_queues; i++) 864 pthread_join(dev->q[i].thread, &thread_ret); 865 fail: 866 ublk_dev_unprep(dev); 867 ublk_dbg(UBLK_DBG_DEV, "%s exit\n", __func__); 868 869 return ret; 870 } 871 872 static int wait_ublk_dev(const char *path, int evt_mask, unsigned timeout) 873 { 874 #define EV_SIZE (sizeof(struct inotify_event)) 875 #define EV_BUF_LEN (128 * (EV_SIZE + 16)) 876 struct pollfd pfd; 877 int fd, wd; 878 int ret = -EINVAL; 879 const char *dev_name = basename(path); 880 881 fd = inotify_init(); 882 if (fd < 0) { 883 ublk_dbg(UBLK_DBG_DEV, "%s: inotify init failed\n", __func__); 884 return fd; 885 } 886 887 wd = inotify_add_watch(fd, "/dev", evt_mask); 888 if (wd == -1) { 889 ublk_dbg(UBLK_DBG_DEV, "%s: add watch for /dev failed\n", __func__); 890 goto fail; 891 } 892 893 pfd.fd = fd; 894 pfd.events = POLL_IN; 895 while (1) { 896 int i = 0; 897 char buffer[EV_BUF_LEN]; 898 ret = poll(&pfd, 1, 1000 * timeout); 899 900 if (ret == -1) { 901 ublk_err("%s: poll inotify failed: %d\n", __func__, ret); 902 goto rm_watch; 903 } else if (ret == 0) { 904 ublk_err("%s: poll inotify timeout\n", __func__); 905 ret = -ETIMEDOUT; 906 goto rm_watch; 907 } 908 909 ret = read(fd, buffer, EV_BUF_LEN); 910 if (ret < 0) { 911 ublk_err("%s: read inotify fd failed\n", __func__); 912 goto rm_watch; 913 } 914 915 while (i < ret) { 916 struct inotify_event *event = (struct inotify_event *)&buffer[i]; 917 918 ublk_dbg(UBLK_DBG_DEV, "%s: inotify event %x %s\n", 919 __func__, event->mask, event->name); 920 if (event->mask & evt_mask) { 921 if (!strcmp(event->name, dev_name)) { 922 ret = 0; 923 goto rm_watch; 924 } 925 } 926 i += EV_SIZE + event->len; 927 } 928 } 929 rm_watch: 930 inotify_rm_watch(fd, wd); 931 fail: 932 close(fd); 933 return ret; 934 } 935 936 static int ublk_stop_io_daemon(const struct ublk_dev *dev) 937 { 938 int daemon_pid = dev->dev_info.ublksrv_pid; 939 int dev_id = dev->dev_info.dev_id; 940 char ublkc[64]; 941 int ret = 0; 942 943 if (daemon_pid < 0) 944 return 0; 945 946 /* daemon may be dead already */ 947 if (kill(daemon_pid, 0) < 0) 948 goto wait; 949 950 snprintf(ublkc, sizeof(ublkc), "/dev/%s%d", "ublkc", dev_id); 951 952 /* ublk char device may be gone already */ 953 if (access(ublkc, F_OK) != 0) 954 goto wait; 955 956 /* Wait until ublk char device is closed, when the daemon is shutdown */ 957 ret = wait_ublk_dev(ublkc, IN_CLOSE, 10); 958 /* double check and since it may be closed before starting inotify */ 959 if (ret == -ETIMEDOUT) 960 ret = kill(daemon_pid, 0) < 0; 961 wait: 962 waitpid(daemon_pid, NULL, 0); 963 ublk_dbg(UBLK_DBG_DEV, "%s: pid %d dev_id %d ret %d\n", 964 __func__, daemon_pid, dev_id, ret); 965 966 return ret; 967 } 968 969 static int __cmd_dev_add(const struct dev_ctx *ctx) 970 { 971 unsigned nr_queues = ctx->nr_hw_queues; 972 const char *tgt_type = ctx->tgt_type; 973 unsigned depth = ctx->queue_depth; 974 __u64 features; 975 const struct ublk_tgt_ops *ops; 976 struct ublksrv_ctrl_dev_info *info; 977 struct ublk_dev *dev; 978 int dev_id = ctx->dev_id; 979 int ret, i; 980 981 ops = ublk_find_tgt(tgt_type); 982 if (!ops) { 983 ublk_err("%s: no such tgt type, type %s\n", 984 __func__, tgt_type); 985 return -ENODEV; 986 } 987 988 if (nr_queues > UBLK_MAX_QUEUES || depth > UBLK_QUEUE_DEPTH) { 989 ublk_err("%s: invalid nr_queues or depth queues %u depth %u\n", 990 __func__, nr_queues, depth); 991 return -EINVAL; 992 } 993 994 dev = ublk_ctrl_init(); 995 if (!dev) { 996 ublk_err("%s: can't alloc dev id %d, type %s\n", 997 __func__, dev_id, tgt_type); 998 return -ENOMEM; 999 } 1000 1001 /* kernel doesn't support get_features */ 1002 ret = ublk_ctrl_get_features(dev, &features); 1003 if (ret < 0) 1004 return -EINVAL; 1005 1006 if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) 1007 return -ENOTSUP; 1008 1009 info = &dev->dev_info; 1010 info->dev_id = ctx->dev_id; 1011 info->nr_hw_queues = nr_queues; 1012 info->queue_depth = depth; 1013 info->flags = ctx->flags; 1014 dev->tgt.ops = ops; 1015 dev->tgt.sq_depth = depth; 1016 dev->tgt.cq_depth = depth; 1017 1018 for (i = 0; i < MAX_BACK_FILES; i++) { 1019 if (ctx->files[i]) { 1020 strcpy(dev->tgt.backing_file[i], ctx->files[i]); 1021 dev->tgt.nr_backing_files++; 1022 } 1023 } 1024 1025 if (ctx->recovery) 1026 ret = ublk_ctrl_start_user_recovery(dev); 1027 else 1028 ret = ublk_ctrl_add_dev(dev); 1029 if (ret < 0) { 1030 ublk_err("%s: can't add dev id %d, type %s ret %d\n", 1031 __func__, dev_id, tgt_type, ret); 1032 goto fail; 1033 } 1034 1035 ret = ublk_start_daemon(ctx, dev); 1036 ublk_dbg(UBLK_DBG_DEV, "%s: daemon exit %d\b", ret); 1037 if (ret < 0) 1038 ublk_ctrl_del_dev(dev); 1039 1040 fail: 1041 if (ret < 0) 1042 ublk_send_dev_event(ctx, dev, -1); 1043 ublk_ctrl_deinit(dev); 1044 return ret; 1045 } 1046 1047 static int __cmd_dev_list(struct dev_ctx *ctx); 1048 1049 static int cmd_dev_add(struct dev_ctx *ctx) 1050 { 1051 int res; 1052 1053 if (ctx->fg) 1054 goto run; 1055 1056 ctx->_shmid = shmget(IPC_PRIVATE, sizeof(struct ublk_dev), IPC_CREAT | 0666); 1057 if (ctx->_shmid < 0) { 1058 ublk_err("%s: failed to shmget %s\n", __func__, strerror(errno)); 1059 exit(-1); 1060 } 1061 ctx->shadow_dev = (struct ublk_dev *)shmat(ctx->_shmid, NULL, 0); 1062 if (ctx->shadow_dev == (struct ublk_dev *)-1) { 1063 ublk_err("%s: failed to shmat %s\n", __func__, strerror(errno)); 1064 exit(-1); 1065 } 1066 ctx->_evtfd = eventfd(0, 0); 1067 if (ctx->_evtfd < 0) { 1068 ublk_err("%s: failed to create eventfd %s\n", __func__, strerror(errno)); 1069 exit(-1); 1070 } 1071 1072 res = fork(); 1073 if (res == 0) { 1074 int res2; 1075 1076 setsid(); 1077 res2 = fork(); 1078 if (res2 == 0) { 1079 /* prepare for detaching */ 1080 close(STDIN_FILENO); 1081 close(STDOUT_FILENO); 1082 close(STDERR_FILENO); 1083 run: 1084 res = __cmd_dev_add(ctx); 1085 return res; 1086 } else { 1087 /* detached from the foreground task */ 1088 exit(EXIT_SUCCESS); 1089 } 1090 } else if (res > 0) { 1091 uint64_t id; 1092 int exit_code = EXIT_FAILURE; 1093 1094 res = read(ctx->_evtfd, &id, sizeof(id)); 1095 close(ctx->_evtfd); 1096 if (res == sizeof(id) && id != ERROR_EVTFD_DEVID) { 1097 ctx->dev_id = id - 1; 1098 if (__cmd_dev_list(ctx) >= 0) 1099 exit_code = EXIT_SUCCESS; 1100 } 1101 shmdt(ctx->shadow_dev); 1102 shmctl(ctx->_shmid, IPC_RMID, NULL); 1103 /* wait for child and detach from it */ 1104 wait(NULL); 1105 exit(exit_code); 1106 } else { 1107 exit(EXIT_FAILURE); 1108 } 1109 } 1110 1111 static int __cmd_dev_del(struct dev_ctx *ctx) 1112 { 1113 int number = ctx->dev_id; 1114 struct ublk_dev *dev; 1115 int ret; 1116 1117 dev = ublk_ctrl_init(); 1118 dev->dev_info.dev_id = number; 1119 1120 ret = ublk_ctrl_get_info(dev); 1121 if (ret < 0) 1122 goto fail; 1123 1124 ret = ublk_ctrl_stop_dev(dev); 1125 if (ret < 0) 1126 ublk_err("%s: stop dev %d failed ret %d\n", __func__, number, ret); 1127 1128 ret = ublk_stop_io_daemon(dev); 1129 if (ret < 0) 1130 ublk_err("%s: stop daemon id %d dev %d, ret %d\n", 1131 __func__, dev->dev_info.ublksrv_pid, number, ret); 1132 ublk_ctrl_del_dev(dev); 1133 fail: 1134 ublk_ctrl_deinit(dev); 1135 1136 return (ret >= 0) ? 0 : ret; 1137 } 1138 1139 static int cmd_dev_del(struct dev_ctx *ctx) 1140 { 1141 int i; 1142 1143 if (ctx->dev_id >= 0 || !ctx->all) 1144 return __cmd_dev_del(ctx); 1145 1146 for (i = 0; i < 255; i++) { 1147 ctx->dev_id = i; 1148 __cmd_dev_del(ctx); 1149 } 1150 return 0; 1151 } 1152 1153 static int __cmd_dev_list(struct dev_ctx *ctx) 1154 { 1155 struct ublk_dev *dev = ublk_ctrl_init(); 1156 int ret; 1157 1158 if (!dev) 1159 return -ENODEV; 1160 1161 dev->dev_info.dev_id = ctx->dev_id; 1162 1163 ret = ublk_ctrl_get_info(dev); 1164 if (ret < 0) { 1165 if (ctx->logging) 1166 ublk_err("%s: can't get dev info from %d: %d\n", 1167 __func__, ctx->dev_id, ret); 1168 } else { 1169 if (ctx->shadow_dev) 1170 memcpy(&dev->q, ctx->shadow_dev->q, sizeof(dev->q)); 1171 1172 ublk_ctrl_dump(dev); 1173 } 1174 1175 ublk_ctrl_deinit(dev); 1176 1177 return ret; 1178 } 1179 1180 static int cmd_dev_list(struct dev_ctx *ctx) 1181 { 1182 int i; 1183 1184 if (ctx->dev_id >= 0 || !ctx->all) 1185 return __cmd_dev_list(ctx); 1186 1187 ctx->logging = false; 1188 for (i = 0; i < 255; i++) { 1189 ctx->dev_id = i; 1190 __cmd_dev_list(ctx); 1191 } 1192 return 0; 1193 } 1194 1195 static int cmd_dev_get_features(void) 1196 { 1197 #define const_ilog2(x) (63 - __builtin_clzll(x)) 1198 static const char *feat_map[] = { 1199 [const_ilog2(UBLK_F_SUPPORT_ZERO_COPY)] = "ZERO_COPY", 1200 [const_ilog2(UBLK_F_URING_CMD_COMP_IN_TASK)] = "COMP_IN_TASK", 1201 [const_ilog2(UBLK_F_NEED_GET_DATA)] = "GET_DATA", 1202 [const_ilog2(UBLK_F_USER_RECOVERY)] = "USER_RECOVERY", 1203 [const_ilog2(UBLK_F_USER_RECOVERY_REISSUE)] = "RECOVERY_REISSUE", 1204 [const_ilog2(UBLK_F_UNPRIVILEGED_DEV)] = "UNPRIVILEGED_DEV", 1205 [const_ilog2(UBLK_F_CMD_IOCTL_ENCODE)] = "CMD_IOCTL_ENCODE", 1206 [const_ilog2(UBLK_F_USER_COPY)] = "USER_COPY", 1207 [const_ilog2(UBLK_F_ZONED)] = "ZONED", 1208 [const_ilog2(UBLK_F_USER_RECOVERY_FAIL_IO)] = "RECOVERY_FAIL_IO", 1209 }; 1210 struct ublk_dev *dev; 1211 __u64 features = 0; 1212 int ret; 1213 1214 dev = ublk_ctrl_init(); 1215 if (!dev) { 1216 fprintf(stderr, "ublksrv_ctrl_init failed id\n"); 1217 return -EOPNOTSUPP; 1218 } 1219 1220 ret = ublk_ctrl_get_features(dev, &features); 1221 if (!ret) { 1222 int i; 1223 1224 printf("ublk_drv features: 0x%llx\n", features); 1225 1226 for (i = 0; i < sizeof(features) * 8; i++) { 1227 const char *feat; 1228 1229 if (!((1ULL << i) & features)) 1230 continue; 1231 if (i < sizeof(feat_map) / sizeof(feat_map[0])) 1232 feat = feat_map[i]; 1233 else 1234 feat = "unknown"; 1235 printf("\t%-20s: 0x%llx\n", feat, 1ULL << i); 1236 } 1237 } 1238 1239 return ret; 1240 } 1241 1242 static void __cmd_create_help(char *exe, bool recovery) 1243 { 1244 int i; 1245 1246 printf("%s %s -t [null|loop|stripe|fault_inject] [-q nr_queues] [-d depth] [-n dev_id]\n", 1247 exe, recovery ? "recover" : "add"); 1248 printf("\t[--foreground] [--quiet] [-z] [--debug_mask mask] [-r 0|1 ] [-g]\n"); 1249 printf("\t[-e 0|1 ] [-i 0|1]\n"); 1250 printf("\t[target options] [backfile1] [backfile2] ...\n"); 1251 printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n"); 1252 1253 for (i = 0; i < sizeof(tgt_ops_list) / sizeof(tgt_ops_list[0]); i++) { 1254 const struct ublk_tgt_ops *ops = tgt_ops_list[i]; 1255 1256 if (ops->usage) 1257 ops->usage(ops); 1258 } 1259 } 1260 1261 static void cmd_add_help(char *exe) 1262 { 1263 __cmd_create_help(exe, false); 1264 printf("\n"); 1265 } 1266 1267 static void cmd_recover_help(char *exe) 1268 { 1269 __cmd_create_help(exe, true); 1270 printf("\tPlease provide exact command line for creating this device with real dev_id\n"); 1271 printf("\n"); 1272 } 1273 1274 static int cmd_dev_help(char *exe) 1275 { 1276 cmd_add_help(exe); 1277 cmd_recover_help(exe); 1278 1279 printf("%s del [-n dev_id] -a \n", exe); 1280 printf("\t -a delete all devices -n delete specified device\n\n"); 1281 printf("%s list [-n dev_id] -a \n", exe); 1282 printf("\t -a list all devices, -n list specified device, default -a \n\n"); 1283 printf("%s features\n", exe); 1284 return 0; 1285 } 1286 1287 int main(int argc, char *argv[]) 1288 { 1289 static const struct option longopts[] = { 1290 { "all", 0, NULL, 'a' }, 1291 { "type", 1, NULL, 't' }, 1292 { "number", 1, NULL, 'n' }, 1293 { "queues", 1, NULL, 'q' }, 1294 { "depth", 1, NULL, 'd' }, 1295 { "debug_mask", 1, NULL, 0 }, 1296 { "quiet", 0, NULL, 0 }, 1297 { "zero_copy", 0, NULL, 'z' }, 1298 { "foreground", 0, NULL, 0 }, 1299 { "recovery", 1, NULL, 'r' }, 1300 { "recovery_fail_io", 1, NULL, 'e'}, 1301 { "recovery_reissue", 1, NULL, 'i'}, 1302 { "get_data", 1, NULL, 'g'}, 1303 { 0, 0, 0, 0 } 1304 }; 1305 const struct ublk_tgt_ops *ops = NULL; 1306 int option_idx, opt; 1307 const char *cmd = argv[1]; 1308 struct dev_ctx ctx = { 1309 .queue_depth = 128, 1310 .nr_hw_queues = 2, 1311 .dev_id = -1, 1312 .tgt_type = "unknown", 1313 }; 1314 int ret = -EINVAL, i; 1315 int tgt_argc = 1; 1316 char *tgt_argv[MAX_NR_TGT_ARG] = { NULL }; 1317 int value; 1318 1319 if (argc == 1) 1320 return ret; 1321 1322 opterr = 0; 1323 optind = 2; 1324 while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:gaz", 1325 longopts, &option_idx)) != -1) { 1326 switch (opt) { 1327 case 'a': 1328 ctx.all = 1; 1329 break; 1330 case 'n': 1331 ctx.dev_id = strtol(optarg, NULL, 10); 1332 break; 1333 case 't': 1334 if (strlen(optarg) < sizeof(ctx.tgt_type)) 1335 strcpy(ctx.tgt_type, optarg); 1336 break; 1337 case 'q': 1338 ctx.nr_hw_queues = strtol(optarg, NULL, 10); 1339 break; 1340 case 'd': 1341 ctx.queue_depth = strtol(optarg, NULL, 10); 1342 break; 1343 case 'z': 1344 ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY; 1345 break; 1346 case 'r': 1347 value = strtol(optarg, NULL, 10); 1348 if (value) 1349 ctx.flags |= UBLK_F_USER_RECOVERY; 1350 break; 1351 case 'e': 1352 value = strtol(optarg, NULL, 10); 1353 if (value) 1354 ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_FAIL_IO; 1355 break; 1356 case 'i': 1357 value = strtol(optarg, NULL, 10); 1358 if (value) 1359 ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE; 1360 break; 1361 case 'g': 1362 ctx.flags |= UBLK_F_NEED_GET_DATA; 1363 break; 1364 case 0: 1365 if (!strcmp(longopts[option_idx].name, "debug_mask")) 1366 ublk_dbg_mask = strtol(optarg, NULL, 16); 1367 if (!strcmp(longopts[option_idx].name, "quiet")) 1368 ublk_dbg_mask = 0; 1369 if (!strcmp(longopts[option_idx].name, "foreground")) 1370 ctx.fg = 1; 1371 break; 1372 case '?': 1373 /* 1374 * target requires every option must have argument 1375 */ 1376 if (argv[optind][0] == '-' || argv[optind - 1][0] != '-') { 1377 fprintf(stderr, "every target option requires argument: %s %s\n", 1378 argv[optind - 1], argv[optind]); 1379 exit(EXIT_FAILURE); 1380 } 1381 1382 if (tgt_argc < (MAX_NR_TGT_ARG - 1) / 2) { 1383 tgt_argv[tgt_argc++] = argv[optind - 1]; 1384 tgt_argv[tgt_argc++] = argv[optind]; 1385 } else { 1386 fprintf(stderr, "too many target options\n"); 1387 exit(EXIT_FAILURE); 1388 } 1389 optind += 1; 1390 break; 1391 } 1392 } 1393 1394 i = optind; 1395 while (i < argc && ctx.nr_files < MAX_BACK_FILES) { 1396 ctx.files[ctx.nr_files++] = argv[i++]; 1397 } 1398 1399 ops = ublk_find_tgt(ctx.tgt_type); 1400 if (ops && ops->parse_cmd_line) { 1401 optind = 0; 1402 1403 tgt_argv[0] = ctx.tgt_type; 1404 ops->parse_cmd_line(&ctx, tgt_argc, tgt_argv); 1405 } 1406 1407 if (!strcmp(cmd, "add")) 1408 ret = cmd_dev_add(&ctx); 1409 else if (!strcmp(cmd, "recover")) { 1410 if (ctx.dev_id < 0) { 1411 fprintf(stderr, "device id isn't provided for recovering\n"); 1412 ret = -EINVAL; 1413 } else { 1414 ctx.recovery = 1; 1415 ret = cmd_dev_add(&ctx); 1416 } 1417 } else if (!strcmp(cmd, "del")) 1418 ret = cmd_dev_del(&ctx); 1419 else if (!strcmp(cmd, "list")) { 1420 ctx.all = 1; 1421 ret = cmd_dev_list(&ctx); 1422 } else if (!strcmp(cmd, "help")) 1423 ret = cmd_dev_help(argv[0]); 1424 else if (!strcmp(cmd, "features")) 1425 ret = cmd_dev_get_features(); 1426 else 1427 cmd_dev_help(argv[0]); 1428 1429 return ret; 1430 } 1431