1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: uring_cmd based ublk
4 */
5
6 #include <linux/fs.h>
7 #include <sys/un.h>
8 #include "kublk.h"
9
10 #define MAX_NR_TGT_ARG 64
11 #define KUBLK_PARAM_LOGICAL_BS_SHIFT 9
12 #define KUBLK_PARAM_PHYSICAL_BS_SHIFT 12
13 #define KUBLK_PARAM_ZONE_SECTORS 128
14 #define KUBLK_PARAM_NR_ZONES 16
15 #define KUBLK_PARAM_DEV_SECTORS \
16 (KUBLK_PARAM_ZONE_SECTORS * KUBLK_PARAM_NR_ZONES)
17 #define KUBLK_PARAM_ZONE_APPEND_SECTORS 8
18
19 unsigned int ublk_dbg_mask = UBLK_LOG;
20 static const struct ublk_tgt_ops *tgt_ops_list[] = {
21 &null_tgt_ops,
22 &loop_tgt_ops,
23 &stripe_tgt_ops,
24 &fault_inject_tgt_ops,
25 };
26
ublk_find_tgt(const char * name)27 static const struct ublk_tgt_ops *ublk_find_tgt(const char *name)
28 {
29 int i;
30
31 if (name == NULL)
32 return NULL;
33
34 for (i = 0; i < ARRAY_SIZE(tgt_ops_list); i++)
35 if (strcmp(tgt_ops_list[i]->name, name) == 0)
36 return tgt_ops_list[i];
37 return NULL;
38 }
39
ublk_setup_ring(struct io_uring * r,int depth,int cq_depth,unsigned flags)40 static inline int ublk_setup_ring(struct io_uring *r, int depth,
41 int cq_depth, unsigned flags)
42 {
43 struct io_uring_params p;
44
45 memset(&p, 0, sizeof(p));
46 p.flags = flags | IORING_SETUP_CQSIZE;
47 p.cq_entries = cq_depth;
48
49 return io_uring_queue_init_params(depth, r, &p);
50 }
51
ublk_ctrl_init_cmd(struct ublk_dev * dev,struct io_uring_sqe * sqe,struct ublk_ctrl_cmd_data * data)52 static void ublk_ctrl_init_cmd(struct ublk_dev *dev,
53 struct io_uring_sqe *sqe,
54 struct ublk_ctrl_cmd_data *data)
55 {
56 struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
57 struct ublksrv_ctrl_cmd *cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe);
58
59 sqe->fd = dev->ctrl_fd;
60 sqe->opcode = IORING_OP_URING_CMD;
61 sqe->ioprio = 0;
62
63 if (data->flags & CTRL_CMD_HAS_BUF) {
64 cmd->addr = data->addr;
65 cmd->len = data->len;
66 }
67
68 if (data->flags & CTRL_CMD_HAS_DATA)
69 cmd->data[0] = data->data[0];
70
71 cmd->dev_id = info->dev_id;
72 cmd->queue_id = -1;
73
74 ublk_set_sqe_cmd_op(sqe, data->cmd_op);
75
76 io_uring_sqe_set_data(sqe, cmd);
77 }
78
__ublk_ctrl_cmd(struct ublk_dev * dev,struct ublk_ctrl_cmd_data * data)79 static int __ublk_ctrl_cmd(struct ublk_dev *dev,
80 struct ublk_ctrl_cmd_data *data)
81 {
82 struct io_uring_sqe *sqe;
83 struct io_uring_cqe *cqe;
84 int ret = -EINVAL;
85
86 sqe = io_uring_get_sqe(&dev->ring);
87 if (!sqe) {
88 ublk_err("%s: can't get sqe ret %d\n", __func__, ret);
89 return ret;
90 }
91
92 ublk_ctrl_init_cmd(dev, sqe, data);
93
94 ret = io_uring_submit(&dev->ring);
95 if (ret < 0) {
96 ublk_err("uring submit ret %d\n", ret);
97 return ret;
98 }
99
100 ret = io_uring_wait_cqe(&dev->ring, &cqe);
101 if (ret < 0) {
102 ublk_err("wait cqe: %s\n", strerror(-ret));
103 return ret;
104 }
105 io_uring_cqe_seen(&dev->ring, cqe);
106
107 return cqe->res;
108 }
109
ublk_ctrl_stop_dev(struct ublk_dev * dev)110 static int ublk_ctrl_stop_dev(struct ublk_dev *dev)
111 {
112 struct ublk_ctrl_cmd_data data = {
113 .cmd_op = UBLK_U_CMD_STOP_DEV,
114 };
115
116 return __ublk_ctrl_cmd(dev, &data);
117 }
118
ublk_ctrl_try_stop_dev(struct ublk_dev * dev)119 static int ublk_ctrl_try_stop_dev(struct ublk_dev *dev)
120 {
121 struct ublk_ctrl_cmd_data data = {
122 .cmd_op = UBLK_U_CMD_TRY_STOP_DEV,
123 };
124
125 return __ublk_ctrl_cmd(dev, &data);
126 }
127
ublk_ctrl_start_dev(struct ublk_dev * dev,int daemon_pid)128 static int ublk_ctrl_start_dev(struct ublk_dev *dev,
129 int daemon_pid)
130 {
131 struct ublk_ctrl_cmd_data data = {
132 .cmd_op = UBLK_U_CMD_START_DEV,
133 .flags = CTRL_CMD_HAS_DATA,
134 };
135
136 dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid;
137
138 return __ublk_ctrl_cmd(dev, &data);
139 }
140
ublk_ctrl_start_user_recovery(struct ublk_dev * dev)141 static int ublk_ctrl_start_user_recovery(struct ublk_dev *dev)
142 {
143 struct ublk_ctrl_cmd_data data = {
144 .cmd_op = UBLK_U_CMD_START_USER_RECOVERY,
145 };
146
147 return __ublk_ctrl_cmd(dev, &data);
148 }
149
ublk_ctrl_end_user_recovery(struct ublk_dev * dev,int daemon_pid)150 static int ublk_ctrl_end_user_recovery(struct ublk_dev *dev, int daemon_pid)
151 {
152 struct ublk_ctrl_cmd_data data = {
153 .cmd_op = UBLK_U_CMD_END_USER_RECOVERY,
154 .flags = CTRL_CMD_HAS_DATA,
155 };
156
157 dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid;
158
159 return __ublk_ctrl_cmd(dev, &data);
160 }
161
ublk_ctrl_add_dev(struct ublk_dev * dev)162 static int ublk_ctrl_add_dev(struct ublk_dev *dev)
163 {
164 struct ublk_ctrl_cmd_data data = {
165 .cmd_op = UBLK_U_CMD_ADD_DEV,
166 .flags = CTRL_CMD_HAS_BUF,
167 .addr = (__u64) (uintptr_t) &dev->dev_info,
168 .len = sizeof(struct ublksrv_ctrl_dev_info),
169 };
170
171 return __ublk_ctrl_cmd(dev, &data);
172 }
173
ublk_ctrl_del_dev(struct ublk_dev * dev)174 static int ublk_ctrl_del_dev(struct ublk_dev *dev)
175 {
176 struct ublk_ctrl_cmd_data data = {
177 .cmd_op = UBLK_U_CMD_DEL_DEV,
178 .flags = 0,
179 };
180
181 return __ublk_ctrl_cmd(dev, &data);
182 }
183
ublk_ctrl_get_info(struct ublk_dev * dev)184 static int ublk_ctrl_get_info(struct ublk_dev *dev)
185 {
186 struct ublk_ctrl_cmd_data data = {
187 .cmd_op = UBLK_U_CMD_GET_DEV_INFO,
188 .flags = CTRL_CMD_HAS_BUF,
189 .addr = (__u64) (uintptr_t) &dev->dev_info,
190 .len = sizeof(struct ublksrv_ctrl_dev_info),
191 };
192
193 return __ublk_ctrl_cmd(dev, &data);
194 }
195
ublk_ctrl_set_params(struct ublk_dev * dev,struct ublk_params * params)196 static int ublk_ctrl_set_params(struct ublk_dev *dev,
197 struct ublk_params *params)
198 {
199 struct ublk_ctrl_cmd_data data = {
200 .cmd_op = UBLK_U_CMD_SET_PARAMS,
201 .flags = CTRL_CMD_HAS_BUF,
202 .addr = (__u64) (uintptr_t) params,
203 .len = sizeof(*params),
204 };
205 params->len = sizeof(*params);
206 return __ublk_ctrl_cmd(dev, &data);
207 }
208
ublk_ctrl_get_params(struct ublk_dev * dev,struct ublk_params * params)209 static int ublk_ctrl_get_params(struct ublk_dev *dev,
210 struct ublk_params *params)
211 {
212 struct ublk_ctrl_cmd_data data = {
213 .cmd_op = UBLK_U_CMD_GET_PARAMS,
214 .flags = CTRL_CMD_HAS_BUF,
215 .addr = (__u64)params,
216 .len = sizeof(*params),
217 };
218
219 params->len = sizeof(*params);
220
221 return __ublk_ctrl_cmd(dev, &data);
222 }
223
ublk_ctrl_get_features(struct ublk_dev * dev,__u64 * features)224 static int ublk_ctrl_get_features(struct ublk_dev *dev,
225 __u64 *features)
226 {
227 struct ublk_ctrl_cmd_data data = {
228 .cmd_op = UBLK_U_CMD_GET_FEATURES,
229 .flags = CTRL_CMD_HAS_BUF,
230 .addr = (__u64) (uintptr_t) features,
231 .len = sizeof(*features),
232 };
233
234 return __ublk_ctrl_cmd(dev, &data);
235 }
236
parse_param_types(const char * arg,__u32 * types)237 static int parse_param_types(const char *arg, __u32 *types)
238 {
239 char buf[128], *save = NULL, *tok;
240
241 if (strlen(arg) >= sizeof(buf))
242 return -EINVAL;
243
244 strcpy(buf, arg);
245 *types = 0;
246 tok = strtok_r(buf, ",", &save);
247 while (tok) {
248 if (!strcmp(tok, "none"))
249 ;
250 else if (!strcmp(tok, "basic"))
251 *types |= UBLK_PARAM_TYPE_BASIC;
252 else if (!strcmp(tok, "zoned"))
253 *types |= UBLK_PARAM_TYPE_ZONED;
254 else
255 return -EINVAL;
256 tok = strtok_r(NULL, ",", &save);
257 }
258
259 return 0;
260 }
261
ublk_init_params_from_ctx(const struct dev_ctx * ctx,struct ublk_params * params)262 static void ublk_init_params_from_ctx(const struct dev_ctx *ctx,
263 struct ublk_params *params)
264 {
265 const struct params_ctx *p = &ctx->params;
266
267 *params = (struct ublk_params) {
268 .types = p->types,
269 .basic = {
270 .logical_bs_shift = p->logical_bs_shift,
271 .physical_bs_shift = p->physical_bs_shift,
272 .io_min_shift = p->io_min_shift,
273 .io_opt_shift = p->io_opt_shift,
274 .max_sectors = p->max_sectors,
275 .chunk_sectors = p->chunk_sectors,
276 .dev_sectors = p->dev_sectors,
277 },
278 .zoned = {
279 .max_open_zones = p->max_open_zones,
280 .max_active_zones = p->max_active_zones,
281 .max_zone_append_sectors = p->max_zone_append_sectors,
282 },
283 };
284 }
285
ublk_ctrl_update_size(struct ublk_dev * dev,__u64 nr_sects)286 static int ublk_ctrl_update_size(struct ublk_dev *dev,
287 __u64 nr_sects)
288 {
289 struct ublk_ctrl_cmd_data data = {
290 .cmd_op = UBLK_U_CMD_UPDATE_SIZE,
291 .flags = CTRL_CMD_HAS_DATA,
292 };
293
294 data.data[0] = nr_sects;
295 return __ublk_ctrl_cmd(dev, &data);
296 }
297
ublk_ctrl_quiesce_dev(struct ublk_dev * dev,unsigned int timeout_ms)298 static int ublk_ctrl_quiesce_dev(struct ublk_dev *dev,
299 unsigned int timeout_ms)
300 {
301 struct ublk_ctrl_cmd_data data = {
302 .cmd_op = UBLK_U_CMD_QUIESCE_DEV,
303 .flags = CTRL_CMD_HAS_DATA,
304 };
305
306 data.data[0] = timeout_ms;
307 return __ublk_ctrl_cmd(dev, &data);
308 }
309
ublk_dev_state_desc(struct ublk_dev * dev)310 static const char *ublk_dev_state_desc(struct ublk_dev *dev)
311 {
312 switch (dev->dev_info.state) {
313 case UBLK_S_DEV_DEAD:
314 return "DEAD";
315 case UBLK_S_DEV_LIVE:
316 return "LIVE";
317 case UBLK_S_DEV_QUIESCED:
318 return "QUIESCED";
319 default:
320 return "UNKNOWN";
321 };
322 }
323
ublk_print_cpu_set(const cpu_set_t * set,char * buf,unsigned len)324 static void ublk_print_cpu_set(const cpu_set_t *set, char *buf, unsigned len)
325 {
326 unsigned done = 0;
327 int i;
328
329 for (i = 0; i < CPU_SETSIZE; i++) {
330 if (CPU_ISSET(i, set))
331 done += snprintf(&buf[done], len - done, "%d ", i);
332 }
333 }
334
ublk_adjust_affinity(cpu_set_t * set)335 static void ublk_adjust_affinity(cpu_set_t *set)
336 {
337 int j, updated = 0;
338
339 /*
340 * Just keep the 1st CPU now.
341 *
342 * In future, auto affinity selection can be tried.
343 */
344 for (j = 0; j < CPU_SETSIZE; j++) {
345 if (CPU_ISSET(j, set)) {
346 if (!updated) {
347 updated = 1;
348 continue;
349 }
350 CPU_CLR(j, set);
351 }
352 }
353 }
354
355 /* Caller must free the allocated buffer */
ublk_ctrl_get_affinity(struct ublk_dev * ctrl_dev,cpu_set_t ** ptr_buf)356 static int ublk_ctrl_get_affinity(struct ublk_dev *ctrl_dev, cpu_set_t **ptr_buf)
357 {
358 struct ublk_ctrl_cmd_data data = {
359 .cmd_op = UBLK_U_CMD_GET_QUEUE_AFFINITY,
360 .flags = CTRL_CMD_HAS_DATA | CTRL_CMD_HAS_BUF,
361 };
362 cpu_set_t *buf;
363 int i, ret;
364
365 buf = malloc(sizeof(cpu_set_t) * ctrl_dev->dev_info.nr_hw_queues);
366 if (!buf)
367 return -ENOMEM;
368
369 for (i = 0; i < ctrl_dev->dev_info.nr_hw_queues; i++) {
370 data.data[0] = i;
371 data.len = sizeof(cpu_set_t);
372 data.addr = (__u64)&buf[i];
373
374 ret = __ublk_ctrl_cmd(ctrl_dev, &data);
375 if (ret < 0) {
376 free(buf);
377 return ret;
378 }
379 ublk_adjust_affinity(&buf[i]);
380 }
381
382 *ptr_buf = buf;
383 return 0;
384 }
385
ublk_ctrl_dump(struct ublk_dev * dev)386 static void ublk_ctrl_dump(struct ublk_dev *dev)
387 {
388 struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
389 struct ublk_params p;
390 cpu_set_t *affinity;
391 int ret;
392
393 ret = ublk_ctrl_get_params(dev, &p);
394 if (ret < 0) {
395 ublk_err("failed to get params %d %s\n", ret, strerror(-ret));
396 return;
397 }
398
399 ret = ublk_ctrl_get_affinity(dev, &affinity);
400 if (ret < 0) {
401 ublk_err("failed to get affinity %m\n");
402 return;
403 }
404
405 ublk_log("dev id %d: nr_hw_queues %d queue_depth %d block size %d dev_capacity %lld\n",
406 info->dev_id, info->nr_hw_queues, info->queue_depth,
407 1 << p.basic.logical_bs_shift, p.basic.dev_sectors);
408 ublk_log("\tmax rq size %d daemon pid %d flags 0x%llx state %s\n",
409 info->max_io_buf_bytes, info->ublksrv_pid, info->flags,
410 ublk_dev_state_desc(dev));
411 if (info->flags & UBLK_F_IO_DESC_SIZE)
412 ublk_log("\tio_desc_size %u\n", info->io_desc_size);
413
414 if (affinity) {
415 char buf[512];
416 int i;
417
418 for (i = 0; i < info->nr_hw_queues; i++) {
419 ublk_print_cpu_set(&affinity[i], buf, sizeof(buf));
420 printf("\tqueue %u: affinity(%s)\n",
421 i, buf);
422 }
423 free(affinity);
424 }
425
426 fflush(stdout);
427 }
428
ublk_ctrl_deinit(struct ublk_dev * dev)429 static void ublk_ctrl_deinit(struct ublk_dev *dev)
430 {
431 close(dev->ctrl_fd);
432 free(dev);
433 }
434
ublk_ctrl_init(void)435 static struct ublk_dev *ublk_ctrl_init(void)
436 {
437 struct ublk_dev *dev = (struct ublk_dev *)calloc(1, sizeof(*dev));
438 struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
439 int ret;
440
441 dev->ctrl_fd = open(CTRL_DEV, O_RDWR);
442 if (dev->ctrl_fd < 0) {
443 free(dev);
444 return NULL;
445 }
446
447 info->max_io_buf_bytes = UBLK_IO_MAX_BYTES;
448
449 ret = ublk_setup_ring(&dev->ring, UBLK_CTRL_RING_DEPTH,
450 UBLK_CTRL_RING_DEPTH, IORING_SETUP_SQE128);
451 if (ret < 0) {
452 ublk_err("queue_init: %s\n", strerror(-ret));
453 free(dev);
454 return NULL;
455 }
456 dev->nr_fds = 1;
457
458 return dev;
459 }
460
__ublk_queue_cmd_buf_sz(const struct ublk_queue * q,__u16 depth)461 static size_t __ublk_queue_cmd_buf_sz(const struct ublk_queue *q, __u16 depth)
462 {
463 size_t size = depth * (size_t)q->io_desc_size;
464 size_t page_sz = getpagesize();
465
466 return round_up(size, page_sz);
467 }
468
ublk_queue_max_cmd_buf_sz(const struct ublk_queue * q)469 static size_t ublk_queue_max_cmd_buf_sz(const struct ublk_queue *q)
470 {
471 return __ublk_queue_cmd_buf_sz(q, UBLK_MAX_QUEUE_DEPTH);
472 }
473
ublk_queue_cmd_buf_sz(const struct ublk_queue * q)474 static size_t ublk_queue_cmd_buf_sz(const struct ublk_queue *q)
475 {
476 return __ublk_queue_cmd_buf_sz(q, q->q_depth);
477 }
478
ublk_queue_deinit(struct ublk_queue * q)479 static void ublk_queue_deinit(struct ublk_queue *q)
480 {
481 int i;
482 int nr_ios = q->q_depth;
483
484 if (q->io_cmd_buf)
485 munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q));
486
487 for (i = 0; i < nr_ios; i++) {
488 free(q->ios[i].buf_addr);
489 free(q->ios[i].integrity_buf);
490 }
491 }
492
ublk_thread_deinit(struct ublk_thread * t)493 static void ublk_thread_deinit(struct ublk_thread *t)
494 {
495 io_uring_unregister_buffers(&t->ring);
496
497 ublk_batch_free_buf(t);
498
499 io_uring_unregister_ring_fd(&t->ring);
500
501 if (t->ring.ring_fd > 0) {
502 io_uring_unregister_files(&t->ring);
503 close(t->ring.ring_fd);
504 t->ring.ring_fd = -1;
505 }
506 }
507
ublk_queue_init(struct ublk_queue * q,unsigned long long extra_flags,__u8 metadata_size)508 static int ublk_queue_init(struct ublk_queue *q, unsigned long long extra_flags,
509 __u8 metadata_size)
510 {
511 struct ublk_dev *dev = q->dev;
512 int depth = dev->dev_info.queue_depth;
513 int i;
514 size_t cmd_buf_size, io_buf_size, integrity_size;
515 unsigned long off;
516
517 pthread_spin_init(&q->lock, PTHREAD_PROCESS_PRIVATE);
518 q->tgt_ops = dev->tgt.ops;
519 q->flags = 0;
520 q->q_depth = depth;
521 q->flags = dev->dev_info.flags;
522 q->flags |= extra_flags;
523 q->metadata_size = metadata_size;
524 q->io_desc_size = dev->dev_info.io_desc_size;
525
526 /* Cache fd in queue for fast path access */
527 q->ublk_fd = dev->fds[0];
528
529 cmd_buf_size = ublk_queue_cmd_buf_sz(q);
530 off = UBLKSRV_CMD_BUF_OFFSET + q->q_id * ublk_queue_max_cmd_buf_sz(q);
531 q->io_cmd_buf = mmap(0, cmd_buf_size, PROT_READ,
532 MAP_SHARED | MAP_POPULATE, dev->fds[0], off);
533 if (q->io_cmd_buf == MAP_FAILED) {
534 ublk_err("ublk dev %d queue %d map io_cmd_buf failed %m\n",
535 q->dev->dev_info.dev_id, q->q_id);
536 goto fail;
537 }
538
539 io_buf_size = dev->dev_info.max_io_buf_bytes;
540 integrity_size = ublk_integrity_len(q, io_buf_size);
541 for (i = 0; i < q->q_depth; i++) {
542 q->ios[i].buf_addr = NULL;
543 q->ios[i].flags = UBLKS_IO_NEED_FETCH_RQ | UBLKS_IO_FREE;
544 q->ios[i].tag = i;
545
546 if (integrity_size) {
547 q->ios[i].integrity_buf = malloc(integrity_size);
548 if (!q->ios[i].integrity_buf) {
549 ublk_err("ublk dev %d queue %d io %d malloc(%d) failed: %m\n",
550 dev->dev_info.dev_id, q->q_id, i,
551 integrity_size);
552 goto fail;
553 }
554 }
555
556
557 if (ublk_queue_no_buf(q))
558 continue;
559
560 if (posix_memalign((void **)&q->ios[i].buf_addr,
561 getpagesize(), io_buf_size)) {
562 ublk_err("ublk dev %d queue %d io %d posix_memalign failed %m\n",
563 dev->dev_info.dev_id, q->q_id, i);
564 goto fail;
565 }
566 }
567
568 return 0;
569 fail:
570 ublk_queue_deinit(q);
571 ublk_err("ublk dev %d queue %d failed\n",
572 dev->dev_info.dev_id, q->q_id);
573 return -ENOMEM;
574 }
575
ublk_thread_init(struct ublk_thread * t,unsigned long long extra_flags)576 static int ublk_thread_init(struct ublk_thread *t, unsigned long long extra_flags)
577 {
578 struct ublk_dev *dev = t->dev;
579 unsigned long long flags = dev->dev_info.flags | extra_flags;
580 int ring_depth = dev->tgt.sq_depth, cq_depth = dev->tgt.cq_depth;
581 int ret;
582
583 /* FETCH_IO_CMDS is multishot, so increase cq depth for BATCH_IO */
584 if (ublk_dev_batch_io(dev))
585 cq_depth += dev->dev_info.queue_depth * 2;
586
587 ret = ublk_setup_ring(&t->ring, ring_depth, cq_depth,
588 IORING_SETUP_COOP_TASKRUN |
589 IORING_SETUP_SINGLE_ISSUER |
590 IORING_SETUP_DEFER_TASKRUN);
591 if (ret < 0) {
592 ublk_err("ublk dev %d thread %d setup io_uring failed %d\n",
593 dev->dev_info.dev_id, t->idx, ret);
594 goto fail;
595 }
596
597 if (dev->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_AUTO_BUF_REG)) {
598 unsigned nr_ios = dev->dev_info.queue_depth * dev->dev_info.nr_hw_queues;
599 unsigned max_nr_ios_per_thread = nr_ios / dev->nthreads;
600 max_nr_ios_per_thread += !!(nr_ios % dev->nthreads);
601
602 t->auto_buf_stride = max_nr_ios_per_thread;
603 t->nr_bufs = max_nr_ios_per_thread;
604 if ((extra_flags & UBLKS_Q_ROTATE_AUTO_BUF) &&
605 (dev->dev_info.flags & UBLK_F_AUTO_BUF_REG))
606 t->nr_bufs *= 2;
607 } else {
608 t->nr_bufs = 0;
609 t->auto_buf_stride = 0;
610 }
611
612 if (ublk_dev_batch_io(dev))
613 ublk_batch_prepare(t);
614
615 if (t->nr_bufs) {
616 ret = io_uring_register_buffers_sparse(&t->ring, t->nr_bufs);
617 if (ret) {
618 ublk_err("ublk dev %d thread %d register spare buffers failed %d\n",
619 dev->dev_info.dev_id, t->idx, ret);
620 goto fail;
621 }
622 }
623
624 if (ublk_dev_batch_io(dev)) {
625 ret = ublk_batch_alloc_buf(t);
626 if (ret) {
627 ublk_err("ublk dev %d thread %d alloc batch buf failed %d\n",
628 dev->dev_info.dev_id, t->idx, ret);
629 goto fail;
630 }
631 }
632
633 io_uring_register_ring_fd(&t->ring);
634
635 if (flags & UBLKS_Q_NO_UBLK_FIXED_FD) {
636 /* Register only backing files starting from index 1, exclude ublk control device */
637 if (dev->nr_fds > 1) {
638 ret = io_uring_register_files(&t->ring, &dev->fds[1], dev->nr_fds - 1);
639 } else {
640 /* No backing files to register, skip file registration */
641 ret = 0;
642 }
643 } else {
644 ret = io_uring_register_files(&t->ring, dev->fds, dev->nr_fds);
645 }
646 if (ret) {
647 ublk_err("ublk dev %d thread %d register files failed %d\n",
648 t->dev->dev_info.dev_id, t->idx, ret);
649 goto fail;
650 }
651
652 return 0;
653 fail:
654 ublk_thread_deinit(t);
655 ublk_err("ublk dev %d thread %d init failed\n",
656 dev->dev_info.dev_id, t->idx);
657 return -ENOMEM;
658 }
659
660 #define WAIT_USEC 100000
661 #define MAX_WAIT_USEC (3 * 1000000)
ublk_dev_prep(const struct dev_ctx * ctx,struct ublk_dev * dev)662 static int ublk_dev_prep(const struct dev_ctx *ctx, struct ublk_dev *dev)
663 {
664 int dev_id = dev->dev_info.dev_id;
665 unsigned int wait_usec = 0;
666 int ret = 0, fd = -1;
667 char buf[64];
668
669 snprintf(buf, 64, "%s%d", UBLKC_DEV, dev_id);
670
671 while (wait_usec < MAX_WAIT_USEC) {
672 fd = open(buf, O_RDWR);
673 if (fd >= 0)
674 break;
675 usleep(WAIT_USEC);
676 wait_usec += WAIT_USEC;
677 }
678 if (fd < 0) {
679 ublk_err("can't open %s %s\n", buf, strerror(errno));
680 return -1;
681 }
682
683 dev->fds[0] = fd;
684 if (dev->tgt.ops->init_tgt)
685 ret = dev->tgt.ops->init_tgt(ctx, dev);
686 if (ret)
687 close(dev->fds[0]);
688 return ret;
689 }
690
ublk_dev_unprep(struct ublk_dev * dev)691 static void ublk_dev_unprep(struct ublk_dev *dev)
692 {
693 if (dev->tgt.ops->deinit_tgt)
694 dev->tgt.ops->deinit_tgt(dev);
695 close(dev->fds[0]);
696 }
697
ublk_set_auto_buf_reg(const struct ublk_thread * t,const struct ublk_queue * q,struct io_uring_sqe * sqe,unsigned short tag)698 static void ublk_set_auto_buf_reg(const struct ublk_thread *t,
699 const struct ublk_queue *q,
700 struct io_uring_sqe *sqe,
701 unsigned short tag)
702 {
703 struct ublk_auto_buf_reg buf = {};
704
705 if (q->tgt_ops->buf_index)
706 buf.index = q->tgt_ops->buf_index(t, q, tag);
707 else
708 buf.index = ublk_io_buf_idx(t, q, tag);
709
710 if (ublk_queue_auto_zc_fallback(q))
711 buf.flags = UBLK_AUTO_BUF_REG_FALLBACK;
712
713 sqe->addr = ublk_auto_buf_reg_to_sqe_addr(&buf);
714 }
715
716 /* Copy in pieces to test the buffer offset logic */
717 #define UBLK_USER_COPY_LEN 2048
718
ublk_user_copy(const struct ublk_io * io,__u8 match_ublk_op)719 static void ublk_user_copy(const struct ublk_io *io, __u8 match_ublk_op)
720 {
721 const struct ublk_queue *q = ublk_io_to_queue(io);
722 const struct ublksrv_io_desc *iod = ublk_get_iod(q, io->tag);
723 __u64 off = ublk_user_copy_offset(q->q_id, io->tag);
724 __u8 ublk_op = ublksrv_get_op(iod);
725 __u32 len = iod->nr_sectors << 9;
726 void *addr = io->buf_addr;
727 ssize_t copied;
728
729 if (ublk_op != match_ublk_op)
730 return;
731
732 while (len) {
733 __u32 copy_len = min(len, UBLK_USER_COPY_LEN);
734
735 if (ublk_op == UBLK_IO_OP_WRITE)
736 copied = pread(q->ublk_fd, addr, copy_len, off);
737 else if (ublk_op == UBLK_IO_OP_READ)
738 copied = pwrite(q->ublk_fd, addr, copy_len, off);
739 else
740 assert(0);
741 assert(copied == (ssize_t)copy_len);
742 addr += copy_len;
743 off += copy_len;
744 len -= copy_len;
745 }
746
747 if (!(iod->op_flags & UBLK_IO_F_INTEGRITY))
748 return;
749
750 len = ublk_integrity_len(q, iod->nr_sectors << 9);
751 off = ublk_user_copy_offset(q->q_id, io->tag);
752 off |= UBLKSRV_IO_INTEGRITY_FLAG;
753 if (ublk_op == UBLK_IO_OP_WRITE)
754 copied = pread(q->ublk_fd, io->integrity_buf, len, off);
755 else if (ublk_op == UBLK_IO_OP_READ)
756 copied = pwrite(q->ublk_fd, io->integrity_buf, len, off);
757 else
758 assert(0);
759 assert(copied == (ssize_t)len);
760 }
761
ublk_queue_io_cmd(struct ublk_thread * t,struct ublk_io * io)762 int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io)
763 {
764 struct ublk_queue *q = ublk_io_to_queue(io);
765 struct ublksrv_io_cmd *cmd;
766 struct io_uring_sqe *sqe[1];
767 unsigned int cmd_op = 0;
768 __u64 user_data;
769
770 /* only freed io can be issued */
771 if (!(io->flags & UBLKS_IO_FREE))
772 return 0;
773
774 /*
775 * we issue because we need either fetching or committing or
776 * getting data
777 */
778 if (!(io->flags &
779 (UBLKS_IO_NEED_FETCH_RQ | UBLKS_IO_NEED_COMMIT_RQ_COMP | UBLKS_IO_NEED_GET_DATA)))
780 return 0;
781
782 if (io->flags & UBLKS_IO_NEED_GET_DATA)
783 cmd_op = UBLK_U_IO_NEED_GET_DATA;
784 else if (io->flags & UBLKS_IO_NEED_COMMIT_RQ_COMP) {
785 if (ublk_queue_use_user_copy(q))
786 ublk_user_copy(io, UBLK_IO_OP_READ);
787
788 cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ;
789 } else if (io->flags & UBLKS_IO_NEED_FETCH_RQ)
790 cmd_op = UBLK_U_IO_FETCH_REQ;
791
792 if (io_uring_sq_space_left(&t->ring) < 1)
793 io_uring_submit(&t->ring);
794
795 ublk_io_alloc_sqes(t, sqe, 1);
796 if (!sqe[0]) {
797 ublk_err("%s: run out of sqe. thread %u, tag %d\n",
798 __func__, t->idx, io->tag);
799 return -1;
800 }
801
802 cmd = (struct ublksrv_io_cmd *)ublk_get_sqe_cmd(sqe[0]);
803
804 if (cmd_op == UBLK_U_IO_COMMIT_AND_FETCH_REQ)
805 cmd->result = io->result;
806
807 /* These fields should be written once, never change */
808 ublk_set_sqe_cmd_op(sqe[0], cmd_op);
809 sqe[0]->fd = ublk_get_registered_fd(q, 0); /* dev->fds[0] */
810 sqe[0]->opcode = IORING_OP_URING_CMD;
811 if (q->flags & UBLKS_Q_NO_UBLK_FIXED_FD)
812 sqe[0]->flags = 0; /* Use raw FD, not fixed file */
813 else
814 sqe[0]->flags = IOSQE_FIXED_FILE;
815 sqe[0]->rw_flags = 0;
816 cmd->tag = io->tag;
817 cmd->q_id = q->q_id;
818 if (!ublk_queue_no_buf(q) && !ublk_queue_use_user_copy(q))
819 cmd->addr = (__u64) (uintptr_t) io->buf_addr;
820 else
821 cmd->addr = 0;
822
823 if (ublk_queue_use_auto_zc(q))
824 ublk_set_auto_buf_reg(t, q, sqe[0], io->tag);
825
826 user_data = build_user_data(io->tag, _IOC_NR(cmd_op), 0, q->q_id, 0);
827 io_uring_sqe_set_data64(sqe[0], user_data);
828
829 io->flags = 0;
830
831 t->cmd_inflight += 1;
832
833 ublk_dbg(UBLK_DBG_IO_CMD, "%s: (thread %u qid %d tag %u cmd_op %u) iof %x stopping %d\n",
834 __func__, t->idx, q->q_id, io->tag, cmd_op,
835 io->flags, !!(t->state & UBLKS_T_STOPPING));
836 return 1;
837 }
838
ublk_submit_fetch_commands(struct ublk_thread * t)839 static void ublk_submit_fetch_commands(struct ublk_thread *t)
840 {
841 struct ublk_queue *q;
842 struct ublk_io *io;
843 int i = 0, j = 0;
844
845 if (t->dev->per_io_tasks) {
846 /*
847 * Lexicographically order all the (qid,tag) pairs, with
848 * qid taking priority (so (1,0) > (0,1)). Then make
849 * this thread the daemon for every Nth entry in this
850 * list (N is the number of threads), starting at this
851 * thread's index. This ensures that each queue is
852 * handled by as many ublk server threads as possible,
853 * so that load that is concentrated on one or a few
854 * queues can make use of all ublk server threads.
855 */
856 const struct ublksrv_ctrl_dev_info *dinfo = &t->dev->dev_info;
857 int nr_ios = dinfo->nr_hw_queues * dinfo->queue_depth;
858 for (i = t->idx; i < nr_ios; i += t->dev->nthreads) {
859 int q_id = i / dinfo->queue_depth;
860 int tag = i % dinfo->queue_depth;
861 q = &t->dev->q[q_id];
862 io = &q->ios[tag];
863 io->buf_index = j++;
864 if (q->tgt_ops->pre_fetch_io)
865 q->tgt_ops->pre_fetch_io(t, q, tag, false);
866 ublk_queue_io_cmd(t, io);
867 }
868 } else {
869 /*
870 * Service exclusively the queue whose q_id matches our
871 * thread index.
872 */
873 struct ublk_queue *q = &t->dev->q[t->idx];
874 for (i = 0; i < q->q_depth; i++) {
875 io = &q->ios[i];
876 io->buf_index = i;
877 if (q->tgt_ops->pre_fetch_io)
878 q->tgt_ops->pre_fetch_io(t, q, i, false);
879 ublk_queue_io_cmd(t, io);
880 }
881 }
882 }
883
ublk_thread_is_idle(struct ublk_thread * t)884 static int ublk_thread_is_idle(struct ublk_thread *t)
885 {
886 return !io_uring_sq_ready(&t->ring) && !t->io_inflight;
887 }
888
ublk_thread_is_done(struct ublk_thread * t)889 static int ublk_thread_is_done(struct ublk_thread *t)
890 {
891 return (t->state & UBLKS_T_STOPPING) && ublk_thread_is_idle(t) && !t->cmd_inflight;
892 }
893
ublksrv_handle_tgt_cqe(struct ublk_thread * t,struct ublk_queue * q,struct io_uring_cqe * cqe)894 static inline void ublksrv_handle_tgt_cqe(struct ublk_thread *t,
895 struct ublk_queue *q,
896 struct io_uring_cqe *cqe)
897 {
898 if (cqe->res < 0 && cqe->res != -EAGAIN)
899 ublk_err("%s: failed tgt io: res %d qid %u tag %u, cmd_op %u\n",
900 __func__, cqe->res, q->q_id,
901 user_data_to_tag(cqe->user_data),
902 user_data_to_op(cqe->user_data));
903
904 if (q->tgt_ops->tgt_io_done)
905 q->tgt_ops->tgt_io_done(t, q, cqe);
906 }
907
ublk_handle_uring_cmd(struct ublk_thread * t,struct ublk_queue * q,const struct io_uring_cqe * cqe)908 static void ublk_handle_uring_cmd(struct ublk_thread *t,
909 struct ublk_queue *q,
910 const struct io_uring_cqe *cqe)
911 {
912 int fetch = (cqe->res != UBLK_IO_RES_ABORT) &&
913 !(t->state & UBLKS_T_STOPPING);
914 unsigned tag = user_data_to_tag(cqe->user_data);
915 struct ublk_io *io = &q->ios[tag];
916
917 t->cmd_inflight--;
918
919 if (!fetch) {
920 t->state |= UBLKS_T_STOPPING;
921 io->flags &= ~UBLKS_IO_NEED_FETCH_RQ;
922 }
923
924 if (cqe->res == UBLK_IO_RES_OK) {
925 ublk_assert(tag < q->q_depth);
926
927 if (ublk_queue_use_user_copy(q))
928 ublk_user_copy(io, UBLK_IO_OP_WRITE);
929
930 if (q->tgt_ops->queue_io)
931 q->tgt_ops->queue_io(t, q, tag);
932 } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) {
933 io->flags |= UBLKS_IO_NEED_GET_DATA | UBLKS_IO_FREE;
934 ublk_queue_io_cmd(t, io);
935 } else {
936 /*
937 * COMMIT_REQ will be completed immediately since no fetching
938 * piggyback is required.
939 *
940 * Marking IO_FREE only, then this io won't be issued since
941 * we only issue io with (UBLKS_IO_FREE | UBLKSRV_NEED_*)
942 *
943 * */
944 io->flags = UBLKS_IO_FREE;
945 }
946 }
947
ublk_handle_cqe(struct ublk_thread * t,struct io_uring_cqe * cqe,void * data)948 static void ublk_handle_cqe(struct ublk_thread *t,
949 struct io_uring_cqe *cqe, void *data)
950 {
951 struct ublk_dev *dev = t->dev;
952 unsigned q_id = user_data_to_q_id(cqe->user_data);
953 unsigned cmd_op = user_data_to_op(cqe->user_data);
954
955 if (cqe->res < 0 && cqe->res != -ENODEV && cqe->res != -ENOBUFS)
956 ublk_err("%s: res %d userdata %llx thread state %x\n", __func__,
957 cqe->res, cqe->user_data, t->state);
958
959 ublk_dbg(UBLK_DBG_IO_CMD, "%s: res %d (thread %d qid %d tag %u cmd_op %x "
960 "data %lx target %d/%d) stopping %d\n",
961 __func__, cqe->res, t->idx, q_id,
962 user_data_to_tag(cqe->user_data),
963 cmd_op, cqe->user_data, is_target_io(cqe->user_data),
964 user_data_to_tgt_data(cqe->user_data),
965 (t->state & UBLKS_T_STOPPING));
966
967 /* Don't retrieve io in case of target io */
968 if (is_target_io(cqe->user_data)) {
969 ublksrv_handle_tgt_cqe(t, &dev->q[q_id], cqe);
970 return;
971 }
972
973 if (ublk_thread_batch_io(t))
974 ublk_batch_compl_cmd(t, cqe);
975 else
976 ublk_handle_uring_cmd(t, &dev->q[q_id], cqe);
977 }
978
ublk_reap_events_uring(struct ublk_thread * t)979 static int ublk_reap_events_uring(struct ublk_thread *t)
980 {
981 struct io_uring_cqe *cqe;
982 unsigned head;
983 int count = 0;
984
985 io_uring_for_each_cqe(&t->ring, head, cqe) {
986 ublk_handle_cqe(t, cqe, NULL);
987 count += 1;
988 }
989 io_uring_cq_advance(&t->ring, count);
990
991 return count;
992 }
993
ublk_process_io(struct ublk_thread * t)994 static int ublk_process_io(struct ublk_thread *t)
995 {
996 int ret, reapped;
997
998 ublk_dbg(UBLK_DBG_THREAD, "dev%d-t%u: to_submit %d inflight cmd %u stopping %d\n",
999 t->dev->dev_info.dev_id,
1000 t->idx, io_uring_sq_ready(&t->ring),
1001 t->cmd_inflight,
1002 (t->state & UBLKS_T_STOPPING));
1003
1004 if (ublk_thread_is_done(t))
1005 return -ENODEV;
1006
1007 ret = io_uring_submit_and_wait(&t->ring, 1);
1008 if (ublk_thread_batch_io(t)) {
1009 ublk_batch_prep_commit(t);
1010 reapped = ublk_reap_events_uring(t);
1011 ublk_batch_commit_io_cmds(t);
1012 } else {
1013 reapped = ublk_reap_events_uring(t);
1014 }
1015
1016 ublk_dbg(UBLK_DBG_THREAD, "submit result %d, reapped %d stop %d idle %d\n",
1017 ret, reapped, (t->state & UBLKS_T_STOPPING),
1018 (t->state & UBLKS_T_IDLE));
1019
1020 return reapped;
1021 }
1022
1023 struct ublk_thread_info {
1024 struct ublk_dev *dev;
1025 pthread_t thread;
1026 unsigned idx;
1027 sem_t *ready;
1028 cpu_set_t *affinity;
1029 unsigned long long extra_flags;
1030 unsigned char (*q_thread_map)[UBLK_MAX_QUEUES];
1031 };
1032
ublk_thread_set_sched_affinity(const struct ublk_thread_info * info)1033 static void ublk_thread_set_sched_affinity(const struct ublk_thread_info *info)
1034 {
1035 if (pthread_setaffinity_np(pthread_self(), sizeof(*info->affinity), info->affinity) < 0)
1036 ublk_err("ublk dev %u thread %u set affinity failed",
1037 info->dev->dev_info.dev_id, info->idx);
1038 }
1039
ublk_batch_setup_queues(struct ublk_thread * t)1040 static void ublk_batch_setup_queues(struct ublk_thread *t)
1041 {
1042 int i;
1043
1044 for (i = 0; i < t->dev->dev_info.nr_hw_queues; i++) {
1045 struct ublk_queue *q = &t->dev->q[i];
1046 int ret;
1047
1048 /*
1049 * Only prepare io commands in the mapped thread context,
1050 * otherwise io command buffer index may not work as expected
1051 */
1052 if (t->q_map[i] == 0)
1053 continue;
1054
1055 if (q->tgt_ops->pre_fetch_io)
1056 q->tgt_ops->pre_fetch_io(t, q, 0, true);
1057
1058 ret = ublk_batch_queue_prep_io_cmds(t, q);
1059 ublk_assert(ret >= 0);
1060 }
1061 }
1062
__ublk_io_handler_fn(struct ublk_thread_info * info)1063 static __attribute__((noinline)) int __ublk_io_handler_fn(struct ublk_thread_info *info)
1064 {
1065 struct ublk_thread t = {
1066 .dev = info->dev,
1067 .idx = info->idx,
1068 };
1069 int dev_id = info->dev->dev_info.dev_id;
1070 int ret;
1071
1072 /* Copy per-thread queue mapping into thread-local variable */
1073 if (info->q_thread_map)
1074 memcpy(t.q_map, info->q_thread_map[info->idx], sizeof(t.q_map));
1075
1076 ret = ublk_thread_init(&t, info->extra_flags);
1077 if (ret) {
1078 ublk_err("ublk dev %d thread %u init failed\n",
1079 dev_id, t.idx);
1080 return ret;
1081 }
1082 sem_post(info->ready);
1083
1084 ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %u started\n",
1085 gettid(), dev_id, t.idx);
1086
1087 if (!ublk_thread_batch_io(&t)) {
1088 /* submit all io commands to ublk driver */
1089 ublk_submit_fetch_commands(&t);
1090 } else {
1091 ublk_batch_setup_queues(&t);
1092 ublk_batch_start_fetch(&t);
1093 }
1094
1095 do {
1096 if (ublk_process_io(&t) < 0)
1097 break;
1098 } while (1);
1099
1100 ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %d exiting\n",
1101 gettid(), dev_id, t.idx);
1102 ublk_thread_deinit(&t);
1103 return 0;
1104 }
1105
ublk_io_handler_fn(void * data)1106 static void *ublk_io_handler_fn(void *data)
1107 {
1108 struct ublk_thread_info *info = data;
1109
1110 /*
1111 * IO perf is sensitive with queue pthread affinity on NUMA machine
1112 *
1113 * Set sched_affinity at beginning, so following allocated memory/pages
1114 * could be CPU/NUMA aware.
1115 */
1116 if (info->affinity)
1117 ublk_thread_set_sched_affinity(info);
1118
1119 __ublk_io_handler_fn(info);
1120
1121 return NULL;
1122 }
1123
ublk_set_parameters(struct ublk_dev * dev)1124 static void ublk_set_parameters(struct ublk_dev *dev)
1125 {
1126 int ret;
1127
1128 ret = ublk_ctrl_set_params(dev, &dev->tgt.params);
1129 if (ret)
1130 ublk_err("dev %d set basic parameter failed %d\n",
1131 dev->dev_info.dev_id, ret);
1132 }
1133
ublk_send_dev_event(const struct dev_ctx * ctx,struct ublk_dev * dev,int dev_id)1134 static int ublk_send_dev_event(const struct dev_ctx *ctx, struct ublk_dev *dev, int dev_id)
1135 {
1136 uint64_t id;
1137 int evtfd = ctx->_evtfd;
1138
1139 if (evtfd < 0)
1140 return -EBADF;
1141
1142 if (dev_id >= 0)
1143 id = dev_id + 1;
1144 else
1145 id = ERROR_EVTFD_DEVID;
1146
1147 if (dev && ctx->shadow_dev)
1148 memcpy(&ctx->shadow_dev->q, &dev->q, sizeof(dev->q));
1149
1150 if (write(evtfd, &id, sizeof(id)) != sizeof(id))
1151 return -EINVAL;
1152
1153 close(evtfd);
1154 shmdt(ctx->shadow_dev);
1155
1156 return 0;
1157 }
1158
1159
1160 /*
1161 * Shared memory registration socket listener.
1162 *
1163 * The parent daemon context listens on a per-device unix socket at
1164 * /run/ublk/ublkb<dev_id>.sock for shared memory registration requests
1165 * from clients. Clients send a memfd via SCM_RIGHTS; the server
1166 * registers it with the kernel, mmaps it, and returns the assigned index.
1167 */
1168 #define UBLK_SHMEM_SOCK_DIR "/run/ublk"
1169
1170 /* defined in kublk.h, shared with file_backed.c (loop target) */
1171 struct ublk_shmem_entry shmem_table[UBLK_BUF_MAX];
1172 int shmem_count;
1173
ublk_shmem_sock_path(int dev_id,char * buf,size_t len)1174 static void ublk_shmem_sock_path(int dev_id, char *buf, size_t len)
1175 {
1176 snprintf(buf, len, "%s/ublkb%d.sock", UBLK_SHMEM_SOCK_DIR, dev_id);
1177 }
1178
ublk_shmem_sock_create(int dev_id)1179 static int ublk_shmem_sock_create(int dev_id)
1180 {
1181 struct sockaddr_un addr = { .sun_family = AF_UNIX };
1182 char path[108];
1183 int fd;
1184
1185 mkdir(UBLK_SHMEM_SOCK_DIR, 0755);
1186 ublk_shmem_sock_path(dev_id, path, sizeof(path));
1187 unlink(path);
1188
1189 fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
1190 if (fd < 0)
1191 return -1;
1192
1193 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
1194 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1195 close(fd);
1196 return -1;
1197 }
1198
1199 listen(fd, 4);
1200 ublk_dbg(UBLK_DBG_DEV, "shmem socket created: %s\n", path);
1201 return fd;
1202 }
1203
ublk_shmem_sock_destroy(int dev_id,int sock_fd)1204 static void ublk_shmem_sock_destroy(int dev_id, int sock_fd)
1205 {
1206 char path[108];
1207
1208 if (sock_fd >= 0)
1209 close(sock_fd);
1210 ublk_shmem_sock_path(dev_id, path, sizeof(path));
1211 unlink(path);
1212 }
1213
1214 /* Receive a memfd from a client via SCM_RIGHTS */
ublk_shmem_recv_fd(int client_fd)1215 static int ublk_shmem_recv_fd(int client_fd)
1216 {
1217 char buf[1];
1218 struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
1219 union {
1220 char cmsg_buf[CMSG_SPACE(sizeof(int))];
1221 struct cmsghdr align;
1222 } u;
1223 struct msghdr msg = {
1224 .msg_iov = &iov,
1225 .msg_iovlen = 1,
1226 .msg_control = u.cmsg_buf,
1227 .msg_controllen = sizeof(u.cmsg_buf),
1228 };
1229 struct cmsghdr *cmsg;
1230
1231 if (recvmsg(client_fd, &msg, 0) <= 0)
1232 return -1;
1233
1234 cmsg = CMSG_FIRSTHDR(&msg);
1235 if (!cmsg || cmsg->cmsg_level != SOL_SOCKET ||
1236 cmsg->cmsg_type != SCM_RIGHTS)
1237 return -1;
1238
1239 return *(int *)CMSG_DATA(cmsg);
1240 }
1241
1242 /* Register a shared memory buffer: store fd, mmap it, return index */
ublk_shmem_register(int shmem_fd)1243 static int ublk_shmem_register(int shmem_fd)
1244 {
1245 off_t size;
1246 void *base;
1247 int idx;
1248
1249 if (shmem_count >= UBLK_BUF_MAX)
1250 return -1;
1251
1252 size = lseek(shmem_fd, 0, SEEK_END);
1253 if (size <= 0)
1254 return -1;
1255
1256 base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
1257 shmem_fd, 0);
1258 if (base == MAP_FAILED)
1259 return -1;
1260
1261 idx = shmem_count++;
1262 shmem_table[idx].fd = shmem_fd;
1263 shmem_table[idx].mmap_base = base;
1264 shmem_table[idx].size = size;
1265
1266 ublk_dbg(UBLK_DBG_DEV, "shmem registered: index=%d fd=%d size=%zu\n",
1267 idx, shmem_fd, (size_t)size);
1268 return idx;
1269 }
1270
ublk_shmem_unregister_all(void)1271 static void ublk_shmem_unregister_all(void)
1272 {
1273 int i;
1274
1275 for (i = 0; i < shmem_count; i++) {
1276 if (shmem_table[i].mmap_base) {
1277 munmap(shmem_table[i].mmap_base,
1278 shmem_table[i].size);
1279 close(shmem_table[i].fd);
1280 shmem_table[i].mmap_base = NULL;
1281 }
1282 }
1283 shmem_count = 0;
1284 }
1285
ublk_ctrl_reg_buf(struct ublk_dev * dev,void * addr,size_t size,__u32 flags)1286 static int ublk_ctrl_reg_buf(struct ublk_dev *dev, void *addr, size_t size,
1287 __u32 flags)
1288 {
1289 struct ublk_shmem_buf_reg buf_reg = {
1290 .addr = (unsigned long)addr,
1291 .len = size,
1292 .flags = flags,
1293 };
1294 struct ublk_ctrl_cmd_data data = {
1295 .cmd_op = UBLK_U_CMD_REG_BUF,
1296 .flags = CTRL_CMD_HAS_BUF,
1297 .addr = (unsigned long)&buf_reg,
1298 .len = sizeof(buf_reg),
1299 };
1300
1301 return __ublk_ctrl_cmd(dev, &data);
1302 }
1303
1304 /*
1305 * Handle one client connection: receive memfd, mmap it, register
1306 * the VA range with kernel, send back the assigned index.
1307 */
ublk_shmem_handle_client(int sock_fd,struct ublk_dev * dev)1308 static void ublk_shmem_handle_client(int sock_fd, struct ublk_dev *dev)
1309 {
1310 int client_fd, memfd, idx, ret;
1311 int32_t reply;
1312 off_t size;
1313 void *base;
1314
1315 client_fd = accept(sock_fd, NULL, NULL);
1316 if (client_fd < 0)
1317 return;
1318
1319 memfd = ublk_shmem_recv_fd(client_fd);
1320 if (memfd < 0) {
1321 reply = -1;
1322 goto out;
1323 }
1324
1325 /* mmap the memfd in server address space */
1326 size = lseek(memfd, 0, SEEK_END);
1327 if (size <= 0) {
1328 reply = -1;
1329 close(memfd);
1330 goto out;
1331 }
1332 base = mmap(NULL, size, PROT_READ | PROT_WRITE,
1333 MAP_SHARED | MAP_POPULATE, memfd, 0);
1334 if (base == MAP_FAILED) {
1335 reply = -1;
1336 close(memfd);
1337 goto out;
1338 }
1339
1340 /* Register server's VA range with kernel for PFN matching */
1341 ret = ublk_ctrl_reg_buf(dev, base, size, 0);
1342 if (ret < 0) {
1343 ublk_dbg(UBLK_DBG_DEV,
1344 "shmem_zc: kernel reg failed %d\n", ret);
1345 munmap(base, size);
1346 close(memfd);
1347 reply = ret;
1348 goto out;
1349 }
1350
1351 /* Store in table for I/O handling */
1352 idx = ublk_shmem_register(memfd);
1353 if (idx >= 0) {
1354 shmem_table[idx].mmap_base = base;
1355 shmem_table[idx].size = size;
1356 }
1357 reply = idx;
1358 out:
1359 send(client_fd, &reply, sizeof(reply), 0);
1360 close(client_fd);
1361 }
1362
1363 struct shmem_listener_info {
1364 int dev_id;
1365 int stop_efd; /* eventfd to signal listener to stop */
1366 int sock_fd; /* listener socket fd (output) */
1367 struct ublk_dev *dev;
1368 };
1369
1370 /*
1371 * Socket listener thread: runs in the parent daemon context alongside
1372 * the I/O threads. Accepts shared memory registration requests from
1373 * clients via SCM_RIGHTS. Exits when stop_efd is signaled.
1374 */
ublk_shmem_listener_fn(void * data)1375 static void *ublk_shmem_listener_fn(void *data)
1376 {
1377 struct shmem_listener_info *info = data;
1378 struct pollfd pfds[2];
1379
1380 info->sock_fd = ublk_shmem_sock_create(info->dev_id);
1381 if (info->sock_fd < 0)
1382 return NULL;
1383
1384 pfds[0].fd = info->sock_fd;
1385 pfds[0].events = POLLIN;
1386 pfds[1].fd = info->stop_efd;
1387 pfds[1].events = POLLIN;
1388
1389 while (1) {
1390 int ret = poll(pfds, 2, -1);
1391
1392 if (ret < 0)
1393 break;
1394
1395 /* Stop signal from parent */
1396 if (pfds[1].revents & POLLIN)
1397 break;
1398
1399 /* Client connection */
1400 if (pfds[0].revents & POLLIN)
1401 ublk_shmem_handle_client(info->sock_fd, info->dev);
1402 }
1403
1404 return NULL;
1405 }
1406
ublk_shmem_htlb_setup(const struct dev_ctx * ctx,struct ublk_dev * dev)1407 static int ublk_shmem_htlb_setup(const struct dev_ctx *ctx,
1408 struct ublk_dev *dev)
1409 {
1410 int fd, idx, ret;
1411 struct stat st;
1412 void *base;
1413
1414 fd = open(ctx->htlb_path, O_RDWR);
1415 if (fd < 0) {
1416 ublk_err("htlb: can't open %s\n", ctx->htlb_path);
1417 return -errno;
1418 }
1419
1420 if (fstat(fd, &st) < 0 || st.st_size <= 0) {
1421 ublk_err("htlb: invalid file size\n");
1422 close(fd);
1423 return -EINVAL;
1424 }
1425
1426 base = mmap(NULL, st.st_size,
1427 ctx->rdonly_shmem_buf ? PROT_READ : PROT_READ | PROT_WRITE,
1428 MAP_SHARED | MAP_POPULATE, fd, 0);
1429 if (base == MAP_FAILED) {
1430 ublk_err("htlb: mmap failed\n");
1431 close(fd);
1432 return -ENOMEM;
1433 }
1434
1435 ret = ublk_ctrl_reg_buf(dev, base, st.st_size,
1436 ctx->rdonly_shmem_buf ? UBLK_SHMEM_BUF_READ_ONLY : 0);
1437 if (ret < 0) {
1438 ublk_err("htlb: reg_buf failed: %d\n", ret);
1439 munmap(base, st.st_size);
1440 close(fd);
1441 return ret;
1442 }
1443
1444 if (shmem_count >= UBLK_BUF_MAX) {
1445 munmap(base, st.st_size);
1446 close(fd);
1447 return -ENOMEM;
1448 }
1449
1450 idx = shmem_count++;
1451 shmem_table[idx].fd = fd;
1452 shmem_table[idx].mmap_base = base;
1453 shmem_table[idx].size = st.st_size;
1454
1455 ublk_dbg(UBLK_DBG_DEV, "htlb registered: index=%d size=%zu\n",
1456 idx, (size_t)st.st_size);
1457 return 0;
1458 }
1459
ublk_start_daemon(const struct dev_ctx * ctx,struct ublk_dev * dev)1460 static int ublk_start_daemon(const struct dev_ctx *ctx, struct ublk_dev *dev)
1461 {
1462 const struct ublksrv_ctrl_dev_info *dinfo = &dev->dev_info;
1463 struct shmem_listener_info linfo = {};
1464 struct ublk_thread_info *tinfo;
1465 unsigned long long extra_flags = 0;
1466 cpu_set_t *affinity_buf;
1467 unsigned char (*q_thread_map)[UBLK_MAX_QUEUES] = NULL;
1468 uint64_t stop_val = 1;
1469 pthread_t listener;
1470 void *thread_ret;
1471 sem_t ready;
1472 int ret, i;
1473
1474 ublk_dbg(UBLK_DBG_DEV, "%s enter\n", __func__);
1475
1476 tinfo = calloc(sizeof(struct ublk_thread_info), dev->nthreads);
1477 if (!tinfo)
1478 return -ENOMEM;
1479
1480 sem_init(&ready, 0, 0);
1481 ret = ublk_dev_prep(ctx, dev);
1482 if (ret)
1483 return ret;
1484
1485 ret = ublk_ctrl_get_affinity(dev, &affinity_buf);
1486 if (ret)
1487 return ret;
1488
1489 if (ublk_dev_batch_io(dev)) {
1490 q_thread_map = calloc(dev->nthreads, sizeof(*q_thread_map));
1491 if (!q_thread_map) {
1492 ret = -ENOMEM;
1493 goto fail;
1494 }
1495 ublk_batch_setup_map(q_thread_map, dev->nthreads,
1496 dinfo->nr_hw_queues);
1497 }
1498
1499 if (ctx->auto_zc_fallback)
1500 extra_flags = UBLKS_Q_AUTO_BUF_REG_FALLBACK;
1501 if (ctx->no_ublk_fixed_fd)
1502 extra_flags |= UBLKS_Q_NO_UBLK_FIXED_FD;
1503 if (ctx->rotate_auto_buf)
1504 extra_flags |= UBLKS_Q_ROTATE_AUTO_BUF;
1505
1506 for (i = 0; i < dinfo->nr_hw_queues; i++) {
1507 dev->q[i].dev = dev;
1508 dev->q[i].q_id = i;
1509
1510 ret = ublk_queue_init(&dev->q[i], extra_flags,
1511 ctx->metadata_size);
1512 if (ret) {
1513 ublk_err("ublk dev %d queue %d init queue failed\n",
1514 dinfo->dev_id, i);
1515 goto fail;
1516 }
1517 }
1518
1519 for (i = 0; i < dev->nthreads; i++) {
1520 tinfo[i].dev = dev;
1521 tinfo[i].idx = i;
1522 tinfo[i].ready = &ready;
1523 tinfo[i].extra_flags = extra_flags;
1524 tinfo[i].q_thread_map = q_thread_map;
1525
1526 /*
1527 * If threads are not tied 1:1 to queues, setting thread
1528 * affinity based on queue affinity makes little sense.
1529 * However, thread CPU affinity has significant impact
1530 * on performance, so to compare fairly, we'll still set
1531 * thread CPU affinity based on queue affinity where
1532 * possible.
1533 */
1534 if (dev->nthreads == dinfo->nr_hw_queues)
1535 tinfo[i].affinity = &affinity_buf[i];
1536 pthread_create(&tinfo[i].thread, NULL,
1537 ublk_io_handler_fn,
1538 &tinfo[i]);
1539 }
1540
1541 for (i = 0; i < dev->nthreads; i++)
1542 sem_wait(&ready);
1543 free(affinity_buf);
1544 free(q_thread_map);
1545
1546 /* everything is fine now, start us */
1547 if (ctx->recovery)
1548 ret = ublk_ctrl_end_user_recovery(dev, getpid());
1549 else {
1550 ublk_set_parameters(dev);
1551 ret = ublk_ctrl_start_dev(dev, getpid());
1552 }
1553 if (ret < 0) {
1554 ublk_err("%s: ublk_ctrl_start_dev failed: %d\n", __func__, ret);
1555 /* stop device so that inflight uring_cmd can be cancelled */
1556 ublk_ctrl_stop_dev(dev);
1557 goto fail_start;
1558 }
1559
1560 if (ctx->htlb_path) {
1561 ret = ublk_shmem_htlb_setup(ctx, dev);
1562 if (ret < 0) {
1563 ublk_err("htlb setup failed: %d\n", ret);
1564 ublk_ctrl_stop_dev(dev);
1565 goto fail_start;
1566 }
1567 }
1568
1569 ublk_ctrl_get_info(dev);
1570 if (ctx->fg)
1571 ublk_ctrl_dump(dev);
1572 else
1573 ublk_send_dev_event(ctx, dev, dev->dev_info.dev_id);
1574 fail_start:
1575 /*
1576 * Wait for I/O threads to exit. While waiting, a listener
1577 * thread accepts shared memory registration requests from
1578 * clients via a per-device unix socket (SCM_RIGHTS fd passing).
1579 */
1580 linfo.dev_id = dinfo->dev_id;
1581 linfo.dev = dev;
1582 linfo.stop_efd = eventfd(0, 0);
1583 if (linfo.stop_efd >= 0)
1584 pthread_create(&listener, NULL,
1585 ublk_shmem_listener_fn, &linfo);
1586
1587 for (i = 0; i < (int)dev->nthreads; i++)
1588 pthread_join(tinfo[i].thread, &thread_ret);
1589
1590 /* Signal listener thread to stop and wait for it */
1591 if (linfo.stop_efd >= 0) {
1592 write(linfo.stop_efd, &stop_val, sizeof(stop_val));
1593 pthread_join(listener, NULL);
1594 close(linfo.stop_efd);
1595 ublk_shmem_sock_destroy(dinfo->dev_id, linfo.sock_fd);
1596 }
1597 ublk_shmem_unregister_all();
1598 free(tinfo);
1599 fail:
1600 for (i = 0; i < dinfo->nr_hw_queues; i++)
1601 ublk_queue_deinit(&dev->q[i]);
1602 ublk_dev_unprep(dev);
1603 ublk_dbg(UBLK_DBG_DEV, "%s exit\n", __func__);
1604
1605 return ret;
1606 }
1607
wait_ublk_dev(const char * path,int evt_mask,unsigned timeout)1608 static int wait_ublk_dev(const char *path, int evt_mask, unsigned timeout)
1609 {
1610 #define EV_SIZE (sizeof(struct inotify_event))
1611 #define EV_BUF_LEN (128 * (EV_SIZE + 16))
1612 struct pollfd pfd;
1613 int fd, wd;
1614 int ret = -EINVAL;
1615 const char *dev_name = basename(path);
1616
1617 fd = inotify_init();
1618 if (fd < 0) {
1619 ublk_dbg(UBLK_DBG_DEV, "%s: inotify init failed\n", __func__);
1620 return fd;
1621 }
1622
1623 wd = inotify_add_watch(fd, "/dev", evt_mask);
1624 if (wd == -1) {
1625 ublk_dbg(UBLK_DBG_DEV, "%s: add watch for /dev failed\n", __func__);
1626 goto fail;
1627 }
1628
1629 pfd.fd = fd;
1630 pfd.events = POLL_IN;
1631 while (1) {
1632 int i = 0;
1633 char buffer[EV_BUF_LEN];
1634 ret = poll(&pfd, 1, 1000 * timeout);
1635
1636 if (ret == -1) {
1637 ublk_err("%s: poll inotify failed: %d\n", __func__, ret);
1638 goto rm_watch;
1639 } else if (ret == 0) {
1640 ublk_err("%s: poll inotify timeout\n", __func__);
1641 ret = -ETIMEDOUT;
1642 goto rm_watch;
1643 }
1644
1645 ret = read(fd, buffer, EV_BUF_LEN);
1646 if (ret < 0) {
1647 ublk_err("%s: read inotify fd failed\n", __func__);
1648 goto rm_watch;
1649 }
1650
1651 while (i < ret) {
1652 struct inotify_event *event = (struct inotify_event *)&buffer[i];
1653
1654 ublk_dbg(UBLK_DBG_DEV, "%s: inotify event %x %s\n",
1655 __func__, event->mask, event->name);
1656 if (event->mask & evt_mask) {
1657 if (!strcmp(event->name, dev_name)) {
1658 ret = 0;
1659 goto rm_watch;
1660 }
1661 }
1662 i += EV_SIZE + event->len;
1663 }
1664 }
1665 rm_watch:
1666 inotify_rm_watch(fd, wd);
1667 fail:
1668 close(fd);
1669 return ret;
1670 }
1671
ublk_stop_io_daemon(const struct ublk_dev * dev)1672 static int ublk_stop_io_daemon(const struct ublk_dev *dev)
1673 {
1674 int daemon_pid = dev->dev_info.ublksrv_pid;
1675 int dev_id = dev->dev_info.dev_id;
1676 char ublkc[64];
1677 int ret = 0;
1678
1679 if (daemon_pid < 0)
1680 return 0;
1681
1682 /* daemon may be dead already */
1683 if (kill(daemon_pid, 0) < 0)
1684 goto wait;
1685
1686 snprintf(ublkc, sizeof(ublkc), "/dev/%s%d", "ublkc", dev_id);
1687
1688 /* ublk char device may be gone already */
1689 if (access(ublkc, F_OK) != 0)
1690 goto wait;
1691
1692 /* Wait until ublk char device is closed, when the daemon is shutdown */
1693 ret = wait_ublk_dev(ublkc, IN_CLOSE, 10);
1694 /* double check and since it may be closed before starting inotify */
1695 if (ret == -ETIMEDOUT)
1696 ret = kill(daemon_pid, 0) < 0;
1697 wait:
1698 waitpid(daemon_pid, NULL, 0);
1699 ublk_dbg(UBLK_DBG_DEV, "%s: pid %d dev_id %d ret %d\n",
1700 __func__, daemon_pid, dev_id, ret);
1701
1702 return ret;
1703 }
1704
__cmd_dev_add(const struct dev_ctx * ctx)1705 static int __cmd_dev_add(const struct dev_ctx *ctx)
1706 {
1707 unsigned nthreads = ctx->nthreads;
1708 unsigned nr_queues = ctx->nr_hw_queues;
1709 const char *tgt_type = ctx->tgt_type;
1710 unsigned depth = ctx->queue_depth;
1711 __u64 features;
1712 const struct ublk_tgt_ops *ops;
1713 struct ublksrv_ctrl_dev_info *info;
1714 struct ublk_dev *dev = NULL;
1715 int dev_id = ctx->dev_id;
1716 int ret, i;
1717
1718 ops = ublk_find_tgt(tgt_type);
1719 if (!ops) {
1720 ublk_err("%s: no such tgt type, type %s\n",
1721 __func__, tgt_type);
1722 ret = -ENODEV;
1723 goto fail;
1724 }
1725
1726 if (nr_queues > UBLK_MAX_QUEUES || depth > UBLK_QUEUE_DEPTH) {
1727 ublk_err("%s: invalid nr_queues or depth queues %u depth %u\n",
1728 __func__, nr_queues, depth);
1729 ret = -EINVAL;
1730 goto fail;
1731 }
1732
1733 /* default to 1:1 threads:queues if nthreads is unspecified */
1734 if (!nthreads)
1735 nthreads = nr_queues;
1736
1737 if (nthreads > UBLK_MAX_THREADS) {
1738 ublk_err("%s: %u is too many threads (max %u)\n",
1739 __func__, nthreads, UBLK_MAX_THREADS);
1740 ret = -EINVAL;
1741 goto fail;
1742 }
1743
1744 if (nthreads != nr_queues && (!ctx->per_io_tasks &&
1745 !(ctx->flags & UBLK_F_BATCH_IO))) {
1746 ublk_err("%s: threads %u must be same as queues %u if "
1747 "not using per_io_tasks\n",
1748 __func__, nthreads, nr_queues);
1749 ret = -EINVAL;
1750 goto fail;
1751 }
1752
1753 dev = ublk_ctrl_init();
1754 if (!dev) {
1755 ublk_err("%s: can't alloc dev id %d, type %s\n",
1756 __func__, dev_id, tgt_type);
1757 ret = -ENOMEM;
1758 goto fail;
1759 }
1760
1761 /* kernel doesn't support get_features */
1762 ret = ublk_ctrl_get_features(dev, &features);
1763 if (ret < 0) {
1764 ret = -EINVAL;
1765 goto fail;
1766 }
1767
1768 if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) {
1769 ret = -ENOTSUP;
1770 goto fail;
1771 }
1772
1773 info = &dev->dev_info;
1774 info->dev_id = ctx->dev_id;
1775 info->nr_hw_queues = nr_queues;
1776 info->queue_depth = depth;
1777 info->io_desc_size = ctx->io_desc_size;
1778 info->flags = ctx->flags;
1779 if ((features & UBLK_F_QUIESCE) &&
1780 (info->flags & UBLK_F_USER_RECOVERY))
1781 info->flags |= UBLK_F_QUIESCE;
1782 dev->nthreads = nthreads;
1783 dev->per_io_tasks = ctx->per_io_tasks;
1784 dev->tgt.ops = ops;
1785 dev->tgt.sq_depth = depth;
1786 dev->tgt.cq_depth = depth;
1787
1788 for (i = 0; i < MAX_BACK_FILES; i++) {
1789 if (ctx->files[i]) {
1790 strcpy(dev->tgt.backing_file[i], ctx->files[i]);
1791 dev->tgt.nr_backing_files++;
1792 }
1793 }
1794
1795 if (ctx->recovery)
1796 ret = ublk_ctrl_start_user_recovery(dev);
1797 else
1798 ret = ublk_ctrl_add_dev(dev);
1799 if (ret < 0) {
1800 ublk_err("%s: can't add dev id %d, type %s ret %d\n",
1801 __func__, dev_id, tgt_type, ret);
1802 goto fail;
1803 }
1804
1805 /*
1806 * The kernel may reduce nr_hw_queues (e.g. capped to nr_cpu_ids).
1807 * Cap nthreads to the actual queue count to avoid creating extra
1808 * handler threads that will hang during device removal.
1809 *
1810 * per_io_tasks mode is excluded: threads interleave across all
1811 * queues so nthreads > nr_hw_queues is valid and intentional.
1812 */
1813 if (!ctx->per_io_tasks && dev->nthreads > info->nr_hw_queues)
1814 dev->nthreads = info->nr_hw_queues;
1815
1816 ret = ublk_start_daemon(ctx, dev);
1817 ublk_dbg(UBLK_DBG_DEV, "%s: daemon exit %d\n", __func__, ret);
1818 if (ret < 0)
1819 ublk_ctrl_del_dev(dev);
1820
1821 fail:
1822 if (ret < 0)
1823 ublk_send_dev_event(ctx, dev, -1);
1824 if (dev)
1825 ublk_ctrl_deinit(dev);
1826 return ret;
1827 }
1828
1829 static int __cmd_dev_list(struct dev_ctx *ctx);
1830
cmd_dev_set_params(struct dev_ctx * ctx)1831 static int cmd_dev_set_params(struct dev_ctx *ctx)
1832 {
1833 struct ublksrv_ctrl_dev_info *info;
1834 struct ublk_params params;
1835 struct ublk_dev *dev;
1836 __u64 features;
1837 int ret, del_ret;
1838
1839 dev = ublk_ctrl_init();
1840 if (!dev)
1841 return -ENODEV;
1842
1843 ret = ublk_ctrl_get_features(dev, &features);
1844 if (ret < 0)
1845 goto out;
1846
1847 if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) {
1848 ret = -ENOTSUP;
1849 goto out;
1850 }
1851
1852 info = &dev->dev_info;
1853 info->dev_id = ctx->dev_id;
1854 info->nr_hw_queues = ctx->nr_hw_queues;
1855 info->queue_depth = ctx->queue_depth;
1856 info->io_desc_size = ctx->io_desc_size;
1857 info->flags = ctx->flags;
1858
1859 ret = ublk_ctrl_add_dev(dev);
1860 if (ret < 0)
1861 goto out;
1862
1863 ublk_init_params_from_ctx(ctx, ¶ms);
1864
1865 ret = ublk_ctrl_set_params(dev, ¶ms);
1866 printf("SET_PARAMS returned %d\n", ret);
1867
1868 del_ret = ublk_ctrl_del_dev(dev);
1869 if (del_ret < 0 && ret == 0)
1870 ret = del_ret;
1871 out:
1872 ublk_ctrl_deinit(dev);
1873 return ret < 0 ? ret : 0;
1874 }
1875
cmd_dev_add(struct dev_ctx * ctx)1876 static int cmd_dev_add(struct dev_ctx *ctx)
1877 {
1878 int res;
1879
1880 if (ctx->fg)
1881 goto run;
1882
1883 ctx->_shmid = shmget(IPC_PRIVATE, sizeof(struct ublk_dev), IPC_CREAT | 0666);
1884 if (ctx->_shmid < 0) {
1885 ublk_err("%s: failed to shmget %s\n", __func__, strerror(errno));
1886 exit(-1);
1887 }
1888 ctx->shadow_dev = (struct ublk_dev *)shmat(ctx->_shmid, NULL, 0);
1889 if (ctx->shadow_dev == (struct ublk_dev *)-1) {
1890 ublk_err("%s: failed to shmat %s\n", __func__, strerror(errno));
1891 exit(-1);
1892 }
1893 ctx->_evtfd = eventfd(0, 0);
1894 if (ctx->_evtfd < 0) {
1895 ublk_err("%s: failed to create eventfd %s\n", __func__, strerror(errno));
1896 exit(-1);
1897 }
1898
1899 res = fork();
1900 if (res == 0) {
1901 int res2;
1902
1903 setsid();
1904 res2 = fork();
1905 if (res2 == 0) {
1906 /* prepare for detaching */
1907 close(STDIN_FILENO);
1908 close(STDOUT_FILENO);
1909 close(STDERR_FILENO);
1910 run:
1911 res = __cmd_dev_add(ctx);
1912 return res;
1913 } else {
1914 /* detached from the foreground task */
1915 exit(EXIT_SUCCESS);
1916 }
1917 } else if (res > 0) {
1918 uint64_t id;
1919 int exit_code = EXIT_FAILURE;
1920
1921 res = read(ctx->_evtfd, &id, sizeof(id));
1922 close(ctx->_evtfd);
1923 if (res == sizeof(id) && id != ERROR_EVTFD_DEVID) {
1924 ctx->dev_id = id - 1;
1925 if (__cmd_dev_list(ctx) >= 0)
1926 exit_code = EXIT_SUCCESS;
1927 }
1928 shmdt(ctx->shadow_dev);
1929 shmctl(ctx->_shmid, IPC_RMID, NULL);
1930 /* wait for child and detach from it */
1931 wait(NULL);
1932 if (exit_code == EXIT_FAILURE)
1933 ublk_err("%s: command failed\n", __func__);
1934 exit(exit_code);
1935 } else {
1936 exit(EXIT_FAILURE);
1937 }
1938 }
1939
__cmd_dev_del(struct dev_ctx * ctx)1940 static int __cmd_dev_del(struct dev_ctx *ctx)
1941 {
1942 int number = ctx->dev_id;
1943 struct ublk_dev *dev;
1944 int ret;
1945
1946 dev = ublk_ctrl_init();
1947 dev->dev_info.dev_id = number;
1948
1949 ret = ublk_ctrl_get_info(dev);
1950 if (ret < 0)
1951 goto fail;
1952
1953 ret = ublk_ctrl_stop_dev(dev);
1954 if (ret < 0)
1955 ublk_err("%s: stop dev %d failed ret %d\n", __func__, number, ret);
1956
1957 ret = ublk_stop_io_daemon(dev);
1958 if (ret < 0)
1959 ublk_err("%s: stop daemon id %d dev %d, ret %d\n",
1960 __func__, dev->dev_info.ublksrv_pid, number, ret);
1961 ublk_ctrl_del_dev(dev);
1962 fail:
1963 ublk_ctrl_deinit(dev);
1964
1965 return (ret >= 0) ? 0 : ret;
1966 }
1967
cmd_dev_del(struct dev_ctx * ctx)1968 static int cmd_dev_del(struct dev_ctx *ctx)
1969 {
1970 int i;
1971
1972 if (ctx->dev_id >= 0 || !ctx->all)
1973 return __cmd_dev_del(ctx);
1974
1975 for (i = 0; i < 255; i++) {
1976 ctx->dev_id = i;
1977 __cmd_dev_del(ctx);
1978 }
1979 return 0;
1980 }
1981
cmd_dev_stop(struct dev_ctx * ctx)1982 static int cmd_dev_stop(struct dev_ctx *ctx)
1983 {
1984 int number = ctx->dev_id;
1985 struct ublk_dev *dev;
1986 int ret;
1987
1988 if (number < 0) {
1989 ublk_err("%s: device id is required\n", __func__);
1990 return -EINVAL;
1991 }
1992
1993 dev = ublk_ctrl_init();
1994 dev->dev_info.dev_id = number;
1995
1996 ret = ublk_ctrl_get_info(dev);
1997 if (ret < 0)
1998 goto fail;
1999
2000 if (ctx->safe_stop) {
2001 ret = ublk_ctrl_try_stop_dev(dev);
2002 if (ret < 0)
2003 ublk_err("%s: try_stop dev %d failed ret %d\n",
2004 __func__, number, ret);
2005 } else {
2006 ret = ublk_ctrl_stop_dev(dev);
2007 if (ret < 0)
2008 ublk_err("%s: stop dev %d failed ret %d\n",
2009 __func__, number, ret);
2010 }
2011
2012 fail:
2013 ublk_ctrl_deinit(dev);
2014
2015 return ret;
2016 }
2017
__cmd_dev_list(struct dev_ctx * ctx)2018 static int __cmd_dev_list(struct dev_ctx *ctx)
2019 {
2020 struct ublk_dev *dev = ublk_ctrl_init();
2021 int ret;
2022
2023 if (!dev)
2024 return -ENODEV;
2025
2026 dev->dev_info.dev_id = ctx->dev_id;
2027
2028 ret = ublk_ctrl_get_info(dev);
2029 if (ret < 0) {
2030 if (ctx->logging)
2031 ublk_err("%s: can't get dev info from %d: %d\n",
2032 __func__, ctx->dev_id, ret);
2033 } else {
2034 if (ctx->shadow_dev)
2035 memcpy(&dev->q, ctx->shadow_dev->q, sizeof(dev->q));
2036
2037 ublk_ctrl_dump(dev);
2038 }
2039
2040 ublk_ctrl_deinit(dev);
2041
2042 return ret;
2043 }
2044
cmd_dev_list(struct dev_ctx * ctx)2045 static int cmd_dev_list(struct dev_ctx *ctx)
2046 {
2047 int i;
2048
2049 if (ctx->dev_id >= 0 || !ctx->all)
2050 return __cmd_dev_list(ctx);
2051
2052 ctx->logging = false;
2053 for (i = 0; i < 255; i++) {
2054 ctx->dev_id = i;
2055 __cmd_dev_list(ctx);
2056 }
2057 return 0;
2058 }
2059
cmd_dev_get_features(void)2060 static int cmd_dev_get_features(void)
2061 {
2062 #define const_ilog2(x) (63 - __builtin_clzll(x))
2063 #define FEAT_NAME(f) [const_ilog2(f)] = #f
2064 static const char *feat_map[] = {
2065 FEAT_NAME(UBLK_F_SUPPORT_ZERO_COPY),
2066 FEAT_NAME(UBLK_F_URING_CMD_COMP_IN_TASK),
2067 FEAT_NAME(UBLK_F_NEED_GET_DATA),
2068 FEAT_NAME(UBLK_F_USER_RECOVERY),
2069 FEAT_NAME(UBLK_F_USER_RECOVERY_REISSUE),
2070 FEAT_NAME(UBLK_F_UNPRIVILEGED_DEV),
2071 FEAT_NAME(UBLK_F_CMD_IOCTL_ENCODE),
2072 FEAT_NAME(UBLK_F_USER_COPY),
2073 FEAT_NAME(UBLK_F_ZONED),
2074 FEAT_NAME(UBLK_F_USER_RECOVERY_FAIL_IO),
2075 FEAT_NAME(UBLK_F_UPDATE_SIZE),
2076 FEAT_NAME(UBLK_F_AUTO_BUF_REG),
2077 FEAT_NAME(UBLK_F_QUIESCE),
2078 FEAT_NAME(UBLK_F_PER_IO_DAEMON),
2079 FEAT_NAME(UBLK_F_BUF_REG_OFF_DAEMON),
2080 FEAT_NAME(UBLK_F_INTEGRITY),
2081 FEAT_NAME(UBLK_F_SAFE_STOP_DEV),
2082 FEAT_NAME(UBLK_F_BATCH_IO),
2083 FEAT_NAME(UBLK_F_NO_AUTO_PART_SCAN),
2084 FEAT_NAME(UBLK_F_SHMEM_ZC),
2085 FEAT_NAME(UBLK_F_IO_DESC_SIZE),
2086 };
2087 struct ublk_dev *dev;
2088 __u64 features = 0;
2089 int ret;
2090
2091 dev = ublk_ctrl_init();
2092 if (!dev) {
2093 fprintf(stderr, "ublksrv_ctrl_init failed id\n");
2094 return -EOPNOTSUPP;
2095 }
2096
2097 ret = ublk_ctrl_get_features(dev, &features);
2098 if (!ret) {
2099 int i;
2100
2101 printf("ublk_drv features: 0x%llx\n", features);
2102
2103 for (i = 0; i < sizeof(features) * 8; i++) {
2104 const char *feat;
2105
2106 if (!((1ULL << i) & features))
2107 continue;
2108 if (i < ARRAY_SIZE(feat_map))
2109 feat = feat_map[i];
2110 else
2111 feat = "unknown";
2112 printf("0x%-16llx: %s\n", 1ULL << i, feat);
2113 }
2114 }
2115
2116 return ret;
2117 }
2118
cmd_dev_update_size(struct dev_ctx * ctx)2119 static int cmd_dev_update_size(struct dev_ctx *ctx)
2120 {
2121 struct ublk_dev *dev = ublk_ctrl_init();
2122 struct ublk_params p;
2123 int ret = -EINVAL;
2124
2125 if (!dev)
2126 return -ENODEV;
2127
2128 if (ctx->dev_id < 0) {
2129 fprintf(stderr, "device id isn't provided\n");
2130 goto out;
2131 }
2132
2133 dev->dev_info.dev_id = ctx->dev_id;
2134 ret = ublk_ctrl_get_params(dev, &p);
2135 if (ret < 0) {
2136 ublk_err("failed to get params %d %s\n", ret, strerror(-ret));
2137 goto out;
2138 }
2139
2140 if (ctx->size & ((1 << p.basic.logical_bs_shift) - 1)) {
2141 ublk_err("size isn't aligned with logical block size\n");
2142 ret = -EINVAL;
2143 goto out;
2144 }
2145
2146 ret = ublk_ctrl_update_size(dev, ctx->size >> 9);
2147 out:
2148 ublk_ctrl_deinit(dev);
2149 return ret;
2150 }
2151
cmd_dev_quiesce(struct dev_ctx * ctx)2152 static int cmd_dev_quiesce(struct dev_ctx *ctx)
2153 {
2154 struct ublk_dev *dev = ublk_ctrl_init();
2155 int ret = -EINVAL;
2156
2157 if (!dev)
2158 return -ENODEV;
2159
2160 if (ctx->dev_id < 0) {
2161 fprintf(stderr, "device id isn't provided for quiesce\n");
2162 goto out;
2163 }
2164 dev->dev_info.dev_id = ctx->dev_id;
2165 ret = ublk_ctrl_quiesce_dev(dev, 10000);
2166
2167 out:
2168 ublk_ctrl_deinit(dev);
2169 return ret;
2170 }
2171
__cmd_create_help(char * exe,bool recovery)2172 static void __cmd_create_help(char *exe, bool recovery)
2173 {
2174 int i;
2175
2176 printf("%s %s -t [null|loop|stripe|fault_inject] [-q nr_queues] [-d depth] [-n dev_id]\n",
2177 exe, recovery ? "recover" : "add");
2178 printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1] [-g] [-u]\n");
2179 printf("\t[-e 0|1 ] [-i 0|1] [--no_ublk_fixed_fd]\n");
2180 printf("\t[--nthreads threads] [--per_io_tasks]\n");
2181 printf("\t[--integrity_capable] [--integrity_reftag] [--metadata_size SIZE] "
2182 "[--pi_offset OFFSET] [--csum_type ip|t10dif|nvme] [--tag_size SIZE]\n");
2183 printf("\t[--batch|-b] [--rotate_auto_buf] [--no_auto_part_scan]\n");
2184 printf("\t[--io_desc_size SIZE]\n");
2185 printf("\t[target options] [backfile1] [backfile2] ...\n");
2186 printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n");
2187 printf("\tdefault: nthreads=nr_queues");
2188
2189 for (i = 0; i < ARRAY_SIZE(tgt_ops_list); i++) {
2190 const struct ublk_tgt_ops *ops = tgt_ops_list[i];
2191
2192 if (ops->usage)
2193 ops->usage(ops);
2194 }
2195 }
2196
cmd_add_help(char * exe)2197 static void cmd_add_help(char *exe)
2198 {
2199 __cmd_create_help(exe, false);
2200 printf("\n");
2201 }
2202
cmd_recover_help(char * exe)2203 static void cmd_recover_help(char *exe)
2204 {
2205 __cmd_create_help(exe, true);
2206 printf("\tPlease provide exact command line for creating this device with real dev_id\n");
2207 printf("\n");
2208 }
2209
cmd_dev_help(char * exe)2210 static int cmd_dev_help(char *exe)
2211 {
2212 cmd_add_help(exe);
2213 cmd_recover_help(exe);
2214
2215 printf("%s del [-n dev_id] -a \n", exe);
2216 printf("\t -a delete all devices -n delete specified device\n\n");
2217 printf("%s stop -n dev_id [--safe]\n", exe);
2218 printf("\t --safe only stop if device has no active openers\n\n");
2219 printf("%s list [-n dev_id] -a \n", exe);
2220 printf("\t -a list all devices, -n list specified device, default -a \n\n");
2221 printf("%s set_params [-n dev_id] [-q nr_queues] [-d depth] [-u] [--zoned]\n", exe);
2222 printf("\t[--param_types basic[,zoned]|none]\n");
2223 printf("\t issue ADD_DEV, SET_PARAMS and DEL_DEV without START_DEV\n\n");
2224 printf("%s features\n", exe);
2225 printf("%s update_size -n dev_id -s|--size size_in_bytes \n", exe);
2226 printf("%s quiesce -n dev_id\n", exe);
2227 return 0;
2228 }
2229
main(int argc,char * argv[])2230 int main(int argc, char *argv[])
2231 {
2232 static const struct option longopts[] = {
2233 { "all", 0, NULL, 'a' },
2234 { "type", 1, NULL, 't' },
2235 { "number", 1, NULL, 'n' },
2236 { "queues", 1, NULL, 'q' },
2237 { "depth", 1, NULL, 'd' },
2238 { "debug_mask", 1, NULL, 0 },
2239 { "quiet", 0, NULL, 0 },
2240 { "zero_copy", 0, NULL, 'z' },
2241 { "foreground", 0, NULL, 0 },
2242 { "recovery", 1, NULL, 'r' },
2243 { "recovery_fail_io", 1, NULL, 'e'},
2244 { "recovery_reissue", 1, NULL, 'i'},
2245 { "get_data", 1, NULL, 'g'},
2246 { "auto_zc", 0, NULL, 0 },
2247 { "auto_zc_fallback", 0, NULL, 0 },
2248 { "user_copy", 0, NULL, 'u'},
2249 { "size", 1, NULL, 's'},
2250 { "nthreads", 1, NULL, 0 },
2251 { "per_io_tasks", 0, NULL, 0 },
2252 { "no_ublk_fixed_fd", 0, NULL, 0 },
2253 { "integrity_capable", 0, NULL, 0 },
2254 { "integrity_reftag", 0, NULL, 0 },
2255 { "metadata_size", 1, NULL, 0 },
2256 { "pi_offset", 1, NULL, 0 },
2257 { "csum_type", 1, NULL, 0 },
2258 { "tag_size", 1, NULL, 0 },
2259 { "safe", 0, NULL, 0 },
2260 { "batch", 0, NULL, 'b'},
2261 { "rotate_auto_buf", 0, NULL, 0 },
2262 { "no_auto_part_scan", 0, NULL, 0 },
2263 { "shmem_zc", 0, NULL, 0 },
2264 { "htlb", 1, NULL, 0 },
2265 { "rdonly_shmem_buf", 0, NULL, 0 },
2266 { "io_desc_size", 1, NULL, 0 },
2267 { "zoned", 0, NULL, 0 },
2268 { "param_types", 1, NULL, 0 },
2269 { "logical_bs_shift", 1, NULL, 0 },
2270 { "physical_bs_shift", 1, NULL, 0 },
2271 { "io_min_shift", 1, NULL, 0 },
2272 { "io_opt_shift", 1, NULL, 0 },
2273 { "max_sectors", 1, NULL, 0 },
2274 { "chunk_sectors", 1, NULL, 0 },
2275 { "dev_sectors", 1, NULL, 0 },
2276 { "max_zone_append_sectors", 1, NULL, 0 },
2277 { "max_open_zones", 1, NULL, 0 },
2278 { "max_active_zones", 1, NULL, 0 },
2279 { 0, 0, 0, 0 }
2280 };
2281 const struct ublk_tgt_ops *ops = NULL;
2282 int option_idx, opt;
2283 const char *cmd = argv[1];
2284 struct dev_ctx ctx = {
2285 ._evtfd = -1,
2286 .queue_depth = 128,
2287 .nr_hw_queues = 2,
2288 .dev_id = -1,
2289 .tgt_type = "unknown",
2290 .csum_type = LBMD_PI_CSUM_NONE,
2291 .io_desc_size = sizeof(struct ublksrv_io_desc),
2292 .params = {
2293 .types = UBLK_PARAM_TYPE_BASIC,
2294 .logical_bs_shift = KUBLK_PARAM_LOGICAL_BS_SHIFT,
2295 .physical_bs_shift = KUBLK_PARAM_PHYSICAL_BS_SHIFT,
2296 .io_min_shift = KUBLK_PARAM_LOGICAL_BS_SHIFT,
2297 .io_opt_shift = KUBLK_PARAM_PHYSICAL_BS_SHIFT,
2298 .max_sectors =
2299 UBLK_IO_MAX_BYTES >> KUBLK_PARAM_LOGICAL_BS_SHIFT,
2300 .chunk_sectors = KUBLK_PARAM_ZONE_SECTORS,
2301 .dev_sectors = KUBLK_PARAM_DEV_SECTORS,
2302 .max_zone_append_sectors =
2303 KUBLK_PARAM_ZONE_APPEND_SECTORS,
2304 },
2305 };
2306 int ret = -EINVAL, i;
2307 int tgt_argc = 1;
2308 char *tgt_argv[MAX_NR_TGT_ARG] = { NULL };
2309 int value;
2310
2311 if (argc == 1)
2312 return ret;
2313
2314 opterr = 0;
2315 optind = 2;
2316 while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:s:gazub",
2317 longopts, &option_idx)) != -1) {
2318 switch (opt) {
2319 case 'a':
2320 ctx.all = 1;
2321 break;
2322 case 'b':
2323 ctx.flags |= UBLK_F_BATCH_IO;
2324 break;
2325 case 'n':
2326 ctx.dev_id = strtol(optarg, NULL, 10);
2327 break;
2328 case 't':
2329 if (strlen(optarg) < sizeof(ctx.tgt_type))
2330 strcpy(ctx.tgt_type, optarg);
2331 break;
2332 case 'q':
2333 ctx.nr_hw_queues = strtol(optarg, NULL, 10);
2334 break;
2335 case 'd':
2336 ctx.queue_depth = strtol(optarg, NULL, 10);
2337 break;
2338 case 'z':
2339 ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY;
2340 break;
2341 case 'r':
2342 value = strtol(optarg, NULL, 10);
2343 if (value)
2344 ctx.flags |= UBLK_F_USER_RECOVERY;
2345 break;
2346 case 'e':
2347 value = strtol(optarg, NULL, 10);
2348 if (value)
2349 ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_FAIL_IO;
2350 break;
2351 case 'i':
2352 value = strtol(optarg, NULL, 10);
2353 if (value)
2354 ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE;
2355 break;
2356 case 'g':
2357 ctx.flags |= UBLK_F_NEED_GET_DATA;
2358 break;
2359 case 'u':
2360 ctx.flags |= UBLK_F_USER_COPY;
2361 break;
2362 case 's':
2363 ctx.size = strtoull(optarg, NULL, 10);
2364 break;
2365 case 0:
2366 if (!strcmp(longopts[option_idx].name, "debug_mask"))
2367 ublk_dbg_mask = strtol(optarg, NULL, 16);
2368 if (!strcmp(longopts[option_idx].name, "quiet"))
2369 ublk_dbg_mask = 0;
2370 if (!strcmp(longopts[option_idx].name, "foreground"))
2371 ctx.fg = 1;
2372 if (!strcmp(longopts[option_idx].name, "auto_zc"))
2373 ctx.flags |= UBLK_F_AUTO_BUF_REG;
2374 if (!strcmp(longopts[option_idx].name, "auto_zc_fallback"))
2375 ctx.auto_zc_fallback = 1;
2376 if (!strcmp(longopts[option_idx].name, "rotate_auto_buf"))
2377 ctx.rotate_auto_buf = 1;
2378 if (!strcmp(longopts[option_idx].name, "nthreads"))
2379 ctx.nthreads = strtol(optarg, NULL, 10);
2380 if (!strcmp(longopts[option_idx].name, "per_io_tasks"))
2381 ctx.per_io_tasks = 1;
2382 if (!strcmp(longopts[option_idx].name, "no_ublk_fixed_fd"))
2383 ctx.no_ublk_fixed_fd = 1;
2384 if (!strcmp(longopts[option_idx].name, "integrity_capable"))
2385 ctx.integrity_flags |= LBMD_PI_CAP_INTEGRITY;
2386 if (!strcmp(longopts[option_idx].name, "integrity_reftag"))
2387 ctx.integrity_flags |= LBMD_PI_CAP_REFTAG;
2388 if (!strcmp(longopts[option_idx].name, "metadata_size"))
2389 ctx.metadata_size = strtoul(optarg, NULL, 0);
2390 if (!strcmp(longopts[option_idx].name, "pi_offset"))
2391 ctx.pi_offset = strtoul(optarg, NULL, 0);
2392 if (!strcmp(longopts[option_idx].name, "csum_type")) {
2393 if (!strcmp(optarg, "ip")) {
2394 ctx.csum_type = LBMD_PI_CSUM_IP;
2395 } else if (!strcmp(optarg, "t10dif")) {
2396 ctx.csum_type = LBMD_PI_CSUM_CRC16_T10DIF;
2397 } else if (!strcmp(optarg, "nvme")) {
2398 ctx.csum_type = LBMD_PI_CSUM_CRC64_NVME;
2399 } else {
2400 ublk_err("invalid csum_type: %s\n", optarg);
2401 return -EINVAL;
2402 }
2403 }
2404 if (!strcmp(longopts[option_idx].name, "tag_size"))
2405 ctx.tag_size = strtoul(optarg, NULL, 0);
2406 if (!strcmp(longopts[option_idx].name, "safe"))
2407 ctx.safe_stop = 1;
2408 if (!strcmp(longopts[option_idx].name, "no_auto_part_scan"))
2409 ctx.flags |= UBLK_F_NO_AUTO_PART_SCAN;
2410 if (!strcmp(longopts[option_idx].name, "shmem_zc"))
2411 ctx.flags |= UBLK_F_SHMEM_ZC;
2412 if (!strcmp(longopts[option_idx].name, "htlb"))
2413 ctx.htlb_path = strdup(optarg);
2414 if (!strcmp(longopts[option_idx].name, "rdonly_shmem_buf"))
2415 ctx.rdonly_shmem_buf = 1;
2416 if (!strcmp(longopts[option_idx].name, "io_desc_size")) {
2417 ctx.flags |= UBLK_F_IO_DESC_SIZE;
2418 ctx.io_desc_size = strtoul(optarg, NULL, 0);
2419 }
2420 if (!strcmp(longopts[option_idx].name, "zoned"))
2421 ctx.flags |= UBLK_F_ZONED;
2422 if (!strcmp(longopts[option_idx].name, "param_types")) {
2423 ret = parse_param_types(optarg, &ctx.params.types);
2424 if (ret)
2425 return ret;
2426 }
2427 if (!strcmp(longopts[option_idx].name, "logical_bs_shift"))
2428 ctx.params.logical_bs_shift = strtoul(optarg, NULL, 0);
2429 if (!strcmp(longopts[option_idx].name, "physical_bs_shift"))
2430 ctx.params.physical_bs_shift = strtoul(optarg, NULL, 0);
2431 if (!strcmp(longopts[option_idx].name, "io_min_shift"))
2432 ctx.params.io_min_shift = strtoul(optarg, NULL, 0);
2433 if (!strcmp(longopts[option_idx].name, "io_opt_shift"))
2434 ctx.params.io_opt_shift = strtoul(optarg, NULL, 0);
2435 if (!strcmp(longopts[option_idx].name, "max_sectors"))
2436 ctx.params.max_sectors = strtoul(optarg, NULL, 0);
2437 if (!strcmp(longopts[option_idx].name, "chunk_sectors"))
2438 ctx.params.chunk_sectors = strtoul(optarg, NULL, 0);
2439 if (!strcmp(longopts[option_idx].name, "dev_sectors"))
2440 ctx.params.dev_sectors = strtoull(optarg, NULL, 0);
2441 if (!strcmp(longopts[option_idx].name, "max_zone_append_sectors"))
2442 ctx.params.max_zone_append_sectors =
2443 strtoul(optarg, NULL, 0);
2444 if (!strcmp(longopts[option_idx].name, "max_open_zones"))
2445 ctx.params.max_open_zones = strtoul(optarg, NULL, 0);
2446 if (!strcmp(longopts[option_idx].name, "max_active_zones"))
2447 ctx.params.max_active_zones = strtoul(optarg, NULL, 0);
2448 break;
2449 case '?':
2450 /*
2451 * target requires every option must have argument
2452 */
2453 if (argv[optind][0] == '-' || argv[optind - 1][0] != '-') {
2454 fprintf(stderr, "every target option requires argument: %s %s\n",
2455 argv[optind - 1], argv[optind]);
2456 exit(EXIT_FAILURE);
2457 }
2458
2459 if (tgt_argc < (MAX_NR_TGT_ARG - 1) / 2) {
2460 tgt_argv[tgt_argc++] = argv[optind - 1];
2461 tgt_argv[tgt_argc++] = argv[optind];
2462 } else {
2463 fprintf(stderr, "too many target options\n");
2464 exit(EXIT_FAILURE);
2465 }
2466 optind += 1;
2467 break;
2468 }
2469 }
2470
2471 if (ctx.per_io_tasks && (ctx.flags & UBLK_F_BATCH_IO)) {
2472 ublk_err("per_io_task and F_BATCH_IO conflict\n");
2473 return -EINVAL;
2474 }
2475
2476 /* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */
2477 if (ctx.auto_zc_fallback &&
2478 !((ctx.flags & UBLK_F_AUTO_BUF_REG) &&
2479 (ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {
2480 ublk_err("%s: auto_zc_fallback is set but neither "
2481 "F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",
2482 __func__);
2483 return -EINVAL;
2484 }
2485
2486 if (!!(ctx.flags & UBLK_F_NEED_GET_DATA) +
2487 !!(ctx.flags & UBLK_F_USER_COPY) +
2488 (ctx.flags & UBLK_F_SUPPORT_ZERO_COPY && !ctx.auto_zc_fallback) +
2489 (ctx.flags & UBLK_F_AUTO_BUF_REG && !ctx.auto_zc_fallback) +
2490 ctx.auto_zc_fallback > 1) {
2491 fprintf(stderr, "too many data copy modes specified\n");
2492 return -EINVAL;
2493 }
2494
2495 if (ctx.metadata_size) {
2496 if (!(ctx.flags & UBLK_F_USER_COPY)) {
2497 ublk_err("integrity requires user_copy\n");
2498 return -EINVAL;
2499 }
2500
2501 ctx.flags |= UBLK_F_INTEGRITY;
2502 } else if (ctx.integrity_flags ||
2503 ctx.pi_offset ||
2504 ctx.csum_type != LBMD_PI_CSUM_NONE ||
2505 ctx.tag_size) {
2506 ublk_err("integrity parameters require metadata_size\n");
2507 return -EINVAL;
2508 }
2509
2510 if ((ctx.flags & UBLK_F_AUTO_BUF_REG) &&
2511 (ctx.flags & UBLK_F_BATCH_IO) &&
2512 (ctx.nthreads > ctx.nr_hw_queues)) {
2513 ublk_err("too many threads for F_AUTO_BUF_REG & F_BATCH_IO\n");
2514 return -EINVAL;
2515 }
2516
2517 if (ctx.rotate_auto_buf &&
2518 !((ctx.flags & UBLK_F_AUTO_BUF_REG) &&
2519 (ctx.flags & UBLK_F_BATCH_IO))) {
2520 ublk_err("rotate_auto_buf requires --auto_zc and --batch\n");
2521 return -EINVAL;
2522 }
2523
2524 i = optind;
2525 while (i < argc && ctx.nr_files < MAX_BACK_FILES) {
2526 ctx.files[ctx.nr_files++] = argv[i++];
2527 }
2528
2529 ops = ublk_find_tgt(ctx.tgt_type);
2530 if (ops && ops->parse_cmd_line) {
2531 optind = 0;
2532
2533 tgt_argv[0] = ctx.tgt_type;
2534 ops->parse_cmd_line(&ctx, tgt_argc, tgt_argv);
2535 }
2536
2537 if (!strcmp(cmd, "set_params"))
2538 ret = cmd_dev_set_params(&ctx);
2539 else if (!strcmp(cmd, "add"))
2540 ret = cmd_dev_add(&ctx);
2541 else if (!strcmp(cmd, "recover")) {
2542 if (ctx.dev_id < 0) {
2543 fprintf(stderr, "device id isn't provided for recovering\n");
2544 ret = -EINVAL;
2545 } else {
2546 ctx.recovery = 1;
2547 ret = cmd_dev_add(&ctx);
2548 }
2549 } else if (!strcmp(cmd, "del"))
2550 ret = cmd_dev_del(&ctx);
2551 else if (!strcmp(cmd, "stop"))
2552 ret = cmd_dev_stop(&ctx);
2553 else if (!strcmp(cmd, "list")) {
2554 ctx.all = 1;
2555 ret = cmd_dev_list(&ctx);
2556 } else if (!strcmp(cmd, "help"))
2557 ret = cmd_dev_help(argv[0]);
2558 else if (!strcmp(cmd, "features"))
2559 ret = cmd_dev_get_features();
2560 else if (!strcmp(cmd, "update_size"))
2561 ret = cmd_dev_update_size(&ctx);
2562 else if (!strcmp(cmd, "quiesce"))
2563 ret = cmd_dev_quiesce(&ctx);
2564 else
2565 cmd_dev_help(argv[0]);
2566
2567 return ret;
2568 }
2569