Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <liburing.h>
7 : :
8 : : #include "spdk/stdinc.h"
9 : : #include "spdk/string.h"
10 : : #include "spdk/bdev.h"
11 : : #include "spdk/endian.h"
12 : : #include "spdk/env.h"
13 : : #include "spdk/likely.h"
14 : : #include "spdk/log.h"
15 : : #include "spdk/util.h"
16 : : #include "spdk/queue.h"
17 : : #include "spdk/json.h"
18 : : #include "spdk/ublk.h"
19 : : #include "spdk/thread.h"
20 : :
21 : : #include "ublk_internal.h"
22 : :
23 : : #define UBLK_CTRL_DEV "/dev/ublk-control"
24 : : #define UBLK_BLK_CDEV "/dev/ublkc"
25 : :
26 : : #define LINUX_SECTOR_SHIFT 9
27 : : #define UBLK_IO_MAX_BYTES SPDK_BDEV_LARGE_BUF_MAX_SIZE
28 : : #define UBLK_DEV_MAX_QUEUES 32
29 : : #define UBLK_DEV_MAX_QUEUE_DEPTH 1024
30 : : #define UBLK_QUEUE_REQUEST 16384
31 : : #define UBLK_STOP_BUSY_WAITING_MS 10000
32 : : #define UBLK_BUSY_POLLING_INTERVAL_US 20000
33 : : #define UBLK_DEFAULT_CTRL_URING_POLLING_INTERVAL_US 1000
34 : : /* By default, kernel ublk_drv driver can support up to 64 block devices */
35 : : #define UBLK_DEFAULT_MAX_SUPPORTED_DEVS 64
36 : : /* UBLK io_uing size is 4k entries */
37 : : #define UBLK_IO_URING_DEPTH 32768
38 : : #define UBLK_MAX_DEV_TBL_SIZE 256
39 : : #if 0
40 : : #define USE_FIXED_FILES 1
41 : : #endif
42 : :
43 : : #define UBLK_IOBUF_SMALL_CACHE_SIZE 128
44 : : #define UBLK_IOBUF_LARGE_CACHE_SIZE 32
45 : :
46 : : #define UBLK_DEBUGLOG(ublk, format, ...) \
47 : : SPDK_DEBUGLOG(ublk, "ublk%d: " format, ublk->ublk_id, ##__VA_ARGS__);
48 : :
49 : : static uint32_t g_num_ublk_poll_groups = 0;
50 : : static uint32_t g_next_ublk_poll_group = 0;
51 : : static uint32_t g_ublks_max = UBLK_DEFAULT_MAX_SUPPORTED_DEVS;
52 : : static struct spdk_cpuset g_core_mask;
53 : : static bool g_disable_user_copy = false;
54 : : static bool g_use_fixed_files = false;
55 : :
56 : : struct ublk_queue;
57 : : struct ublk_poll_group;
58 : : struct ublk_io;
59 : : static void _ublk_submit_bdev_io(struct ublk_queue *q, struct ublk_io *io);
60 : : static void ublk_dev_queue_fini(struct ublk_queue *q);
61 : : static int ublk_poll(void *arg);
62 : :
63 : : static int ublk_set_params(struct spdk_ublk_dev *ublk);
64 : : static int ublk_start_dev(struct spdk_ublk_dev *ublk, bool is_recovering);
65 : : static void ublk_free_dev(struct spdk_ublk_dev *ublk);
66 : : static void ublk_delete_dev(void *arg);
67 : : static int ublk_close_dev(struct spdk_ublk_dev *ublk);
68 : : static int ublk_ctrl_start_recovery(struct spdk_ublk_dev *ublk);
69 : : static void ublk_dev_init_io_cmds(struct io_uring *r, uint32_t ring_sz);
70 : :
71 : : static int ublk_ctrl_cmd_submit(struct spdk_ublk_dev *ublk, uint32_t cmd_op);
72 : :
73 : : static const char *ublk_op_name[64] = {
74 : : [UBLK_CMD_GET_DEV_INFO] = "UBLK_CMD_GET_DEV_INFO",
75 : : [UBLK_CMD_ADD_DEV] = "UBLK_CMD_ADD_DEV",
76 : : [UBLK_CMD_DEL_DEV] = "UBLK_CMD_DEL_DEV",
77 : : [UBLK_CMD_START_DEV] = "UBLK_CMD_START_DEV",
78 : : [UBLK_CMD_STOP_DEV] = "UBLK_CMD_STOP_DEV",
79 : : [UBLK_CMD_SET_PARAMS] = "UBLK_CMD_SET_PARAMS",
80 : : [UBLK_CMD_START_USER_RECOVERY] = "UBLK_CMD_START_USER_RECOVERY",
81 : : [UBLK_CMD_END_USER_RECOVERY] = "UBLK_CMD_END_USER_RECOVERY",
82 : : };
83 : :
84 : : typedef void (*ublk_get_buf_cb)(struct ublk_io *io);
85 : :
86 : : struct ublk_io {
87 : : void *payload;
88 : : void *mpool_entry;
89 : : bool need_data;
90 : : bool user_copy;
91 : : uint16_t tag;
92 : : uint64_t payload_size;
93 : : uint32_t cmd_op;
94 : : int32_t result;
95 : : struct spdk_bdev_desc *bdev_desc;
96 : : struct spdk_io_channel *bdev_ch;
97 : : const struct ublksrv_io_desc *iod;
98 : : ublk_get_buf_cb get_buf_cb;
99 : : struct ublk_queue *q;
100 : : /* for bdev io_wait */
101 : : struct spdk_bdev_io_wait_entry bdev_io_wait;
102 : : struct spdk_iobuf_entry iobuf;
103 : :
104 : : TAILQ_ENTRY(ublk_io) tailq;
105 : : };
106 : :
107 : : struct ublk_queue {
108 : : uint32_t q_id;
109 : : uint32_t q_depth;
110 : : struct ublk_io *ios;
111 : : TAILQ_HEAD(, ublk_io) completed_io_list;
112 : : TAILQ_HEAD(, ublk_io) inflight_io_list;
113 : : uint32_t cmd_inflight;
114 : : bool is_stopping;
115 : : struct ublksrv_io_desc *io_cmd_buf;
116 : : /* *ring is a pointer to shared ring created for poll group
117 : : */
118 : : struct io_uring *ring;
119 : : struct spdk_ublk_dev *dev;
120 : : struct ublk_poll_group *poll_group;
121 : : struct spdk_io_channel *bdev_ch;
122 : :
123 : : TAILQ_ENTRY(ublk_queue) tailq;
124 : : };
125 : :
126 : : struct spdk_ublk_dev {
127 : : struct spdk_bdev *bdev;
128 : : struct spdk_bdev_desc *bdev_desc;
129 : :
130 : : int cdev_fd;
131 : : struct ublk_params dev_params;
132 : : struct ublksrv_ctrl_dev_info dev_info;
133 : :
134 : : uint32_t ublk_id;
135 : : uint32_t num_queues;
136 : : uint32_t queue_depth;
137 : : uint32_t online_num_queues;
138 : : uint32_t sector_per_block_shift;
139 : : struct ublk_queue queues[UBLK_DEV_MAX_QUEUES];
140 : :
141 : : struct spdk_poller *retry_poller;
142 : : int retry_count;
143 : : uint32_t queues_closed;
144 : : ublk_ctrl_cb ctrl_cb;
145 : : void *cb_arg;
146 : : uint32_t current_cmd_op;
147 : : uint32_t ctrl_ops_in_progress;
148 : : bool is_closing;
149 : : bool is_recovering;
150 : : int ublk_idx;
151 : :
152 : : TAILQ_ENTRY(spdk_ublk_dev) tailq;
153 : : TAILQ_ENTRY(spdk_ublk_dev) wait_tailq;
154 : : };
155 : :
156 : : struct ublk_poll_group {
157 : : struct spdk_thread *ublk_thread;
158 : : struct spdk_poller *ublk_poller;
159 : : struct spdk_iobuf_channel iobuf_ch;
160 : : struct io_uring ring;
161 : : int pg_fd_table[UBLK_MAX_DEV_TBL_SIZE];
162 : : TAILQ_HEAD(, ublk_queue) queue_list;
163 : : };
164 : :
165 : : struct ublk_tgt {
166 : : int ctrl_fd;
167 : : bool active;
168 : : bool is_destroying;
169 : : spdk_ublk_fini_cb cb_fn;
170 : : void *cb_arg;
171 : : struct io_uring ctrl_ring;
172 : : struct spdk_poller *ctrl_poller;
173 : : uint32_t ctrl_ops_in_progress;
174 : : struct ublk_poll_group *poll_groups;
175 : : uint32_t num_ublk_devs;
176 : : uint64_t features;
177 : : /* `ublk_drv` supports UBLK_F_CMD_IOCTL_ENCODE */
178 : : bool ioctl_encode;
179 : : /* `ublk_drv` supports UBLK_F_USER_COPY */
180 : : bool user_copy;
181 : : /* `ublk_drv` supports UBLK_F_USER_RECOVERY */
182 : : bool user_recovery;
183 : : struct spdk_ublk_dev *dev_tbl[UBLK_MAX_DEV_TBL_SIZE];
184 : : };
185 : :
186 : : static TAILQ_HEAD(, spdk_ublk_dev) g_ublk_devs = TAILQ_HEAD_INITIALIZER(g_ublk_devs);
187 : : static struct ublk_tgt g_ublk_tgt;
188 : :
189 : : /* helpers for using io_uring */
190 : : static inline int
191 : 0 : ublk_setup_ring(uint32_t depth, struct io_uring *r, unsigned flags)
192 : : {
193 : 0 : struct io_uring_params p = {};
194 : :
195 : 0 : p.flags = flags | IORING_SETUP_CQSIZE;
196 : 0 : p.cq_entries = depth;
197 : :
198 : 0 : return io_uring_queue_init_params(depth, r, &p);
199 : : }
200 : :
201 : : static inline struct io_uring_sqe *
202 : 0 : ublk_uring_get_sqe(struct io_uring *r, uint32_t idx)
203 : : {
204 : : /* Need to update the idx since we set IORING_SETUP_SQE128 parameter in ublk_setup_ring */
205 : 0 : return &r->sq.sqes[idx << 1];
206 : : }
207 : :
208 : : static inline void *
209 : 0 : ublk_get_sqe_cmd(struct io_uring_sqe *sqe)
210 : : {
211 : 0 : return (void *)&sqe->addr3;
212 : : }
213 : :
214 : : static inline void
215 : 0 : ublk_set_sqe_cmd_op(struct io_uring_sqe *sqe, uint32_t cmd_op)
216 : : {
217 : 0 : uint32_t opc = cmd_op;
218 : :
219 [ # # # # ]: 0 : if (g_ublk_tgt.ioctl_encode) {
220 [ # # # # : 0 : switch (cmd_op) {
# # # # #
# # # ]
221 : : /* ctrl uring */
222 : 0 : case UBLK_CMD_GET_DEV_INFO:
223 : 0 : opc = _IOR('u', UBLK_CMD_GET_DEV_INFO, struct ublksrv_ctrl_cmd);
224 : 0 : break;
225 : 0 : case UBLK_CMD_ADD_DEV:
226 : 0 : opc = _IOWR('u', UBLK_CMD_ADD_DEV, struct ublksrv_ctrl_cmd);
227 : 0 : break;
228 : 0 : case UBLK_CMD_DEL_DEV:
229 : 0 : opc = _IOWR('u', UBLK_CMD_DEL_DEV, struct ublksrv_ctrl_cmd);
230 : 0 : break;
231 : 0 : case UBLK_CMD_START_DEV:
232 : 0 : opc = _IOWR('u', UBLK_CMD_START_DEV, struct ublksrv_ctrl_cmd);
233 : 0 : break;
234 : 0 : case UBLK_CMD_STOP_DEV:
235 : 0 : opc = _IOWR('u', UBLK_CMD_STOP_DEV, struct ublksrv_ctrl_cmd);
236 : 0 : break;
237 : 0 : case UBLK_CMD_SET_PARAMS:
238 : 0 : opc = _IOWR('u', UBLK_CMD_SET_PARAMS, struct ublksrv_ctrl_cmd);
239 : 0 : break;
240 : 0 : case UBLK_CMD_START_USER_RECOVERY:
241 : 0 : opc = _IOWR('u', UBLK_CMD_START_USER_RECOVERY, struct ublksrv_ctrl_cmd);
242 : 0 : break;
243 : 0 : case UBLK_CMD_END_USER_RECOVERY:
244 : 0 : opc = _IOWR('u', UBLK_CMD_END_USER_RECOVERY, struct ublksrv_ctrl_cmd);
245 : 0 : break;
246 : :
247 : : /* io uring */
248 : 0 : case UBLK_IO_FETCH_REQ:
249 : 0 : opc = _IOWR('u', UBLK_IO_FETCH_REQ, struct ublksrv_io_cmd);
250 : 0 : break;
251 : 0 : case UBLK_IO_COMMIT_AND_FETCH_REQ:
252 : 0 : opc = _IOWR('u', UBLK_IO_COMMIT_AND_FETCH_REQ, struct ublksrv_io_cmd);
253 : 0 : break;
254 : 0 : case UBLK_IO_NEED_GET_DATA:
255 : 0 : opc = _IOWR('u', UBLK_IO_NEED_GET_DATA, struct ublksrv_io_cmd);
256 : 0 : break;
257 : 0 : default:
258 : 0 : break;
259 : : }
260 : : }
261 : :
262 : 0 : sqe->off = opc;
263 : 0 : }
264 : :
265 : : static inline uint64_t
266 : 0 : build_user_data(uint16_t tag, uint8_t op, uint32_t q_id, uint32_t ublk_idx)
267 : : {
268 : : /*
269 : : * tag: 16 bits
270 : : * op: 8 bits
271 : : * q_id: 5 bits
272 : : * ublk_id: 32 bits
273 : : */
274 [ # # # # : 0 : assert(!(tag >> 16) && !(op >> 8) && !(q_id >> 5));
# # ]
275 [ # # ]: 0 : return tag | (op << 16) | (q_id << 24) | ((uint64_t)ublk_idx << 29);
276 : : }
277 : :
278 : : static inline uint16_t
279 : 0 : user_data_to_tag(uint64_t user_data)
280 : : {
281 : 0 : return user_data & 0xffff;
282 : : }
283 : :
284 : : static inline uint8_t
285 : 0 : user_data_to_op(uint64_t user_data)
286 : : {
287 : 0 : return (user_data >> 16) & 0xff;
288 : : }
289 : :
290 : : static inline uint8_t
291 : 0 : user_data_to_qid(uint64_t user_data)
292 : : {
293 : 0 : return (user_data >> 24) & 0x1f;
294 : : }
295 : :
296 : : static inline uint32_t
297 : 0 : user_data_to_ublk_idx(uint64_t user_data)
298 : : {
299 : 0 : return (user_data >> 29);
300 : : }
301 : :
302 : : static inline uint64_t
303 : 0 : ublk_user_copy_pos(uint16_t q_id, uint16_t tag)
304 : : {
305 : 0 : return (uint64_t)UBLKSRV_IO_BUF_OFFSET + ((((uint64_t)q_id) << UBLK_QID_OFF) | (((
306 : 0 : uint64_t)tag) << UBLK_TAG_OFF));
307 : : }
308 : :
309 : : void
310 : 418 : spdk_ublk_init(void)
311 : : {
312 [ - + ]: 418 : assert(spdk_thread_is_app_thread(NULL));
313 : :
314 : 418 : g_ublk_tgt.ctrl_fd = -1;
315 : 418 : g_ublk_tgt.ctrl_ring.ring_fd = -1;
316 : 418 : }
317 : :
318 : : static void
319 : 0 : ublk_ctrl_cmd_error(struct spdk_ublk_dev *ublk, int32_t res)
320 : : {
321 [ # # ]: 0 : assert(res != 0);
322 : :
323 : 0 : SPDK_ERRLOG("ctrlr cmd %s failed, %s\n", ublk_op_name[ublk->current_cmd_op], spdk_strerror(-res));
324 [ # # ]: 0 : if (ublk->ctrl_cb) {
325 : 0 : ublk->ctrl_cb(ublk->cb_arg, res);
326 : 0 : ublk->ctrl_cb = NULL;
327 : : }
328 : :
329 [ # # # # : 0 : switch (ublk->current_cmd_op) {
# ]
330 : 0 : case UBLK_CMD_ADD_DEV:
331 : : case UBLK_CMD_SET_PARAMS:
332 : : case UBLK_CMD_START_USER_RECOVERY:
333 : : case UBLK_CMD_END_USER_RECOVERY:
334 : 0 : ublk_delete_dev(ublk);
335 : 0 : break;
336 : 0 : case UBLK_CMD_START_DEV:
337 : 0 : ublk_close_dev(ublk);
338 : 0 : break;
339 : 0 : case UBLK_CMD_GET_DEV_INFO:
340 : 0 : ublk_free_dev(ublk);
341 : 0 : break;
342 : 0 : case UBLK_CMD_STOP_DEV:
343 : : case UBLK_CMD_DEL_DEV:
344 : 0 : break;
345 : 0 : default:
346 : 0 : SPDK_ERRLOG("No match cmd operation,cmd_op = %d\n", ublk->current_cmd_op);
347 : 0 : break;
348 : : }
349 : 0 : }
350 : :
351 : : static void
352 : 0 : ublk_ctrl_process_cqe(struct io_uring_cqe *cqe)
353 : : {
354 : : struct spdk_ublk_dev *ublk;
355 : 0 : int rc = 0;
356 : :
357 : 0 : ublk = (struct spdk_ublk_dev *)cqe->user_data;
358 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "ctrl cmd %s completed\n", ublk_op_name[ublk->current_cmd_op]);
359 : 0 : ublk->ctrl_ops_in_progress--;
360 : :
361 [ # # ]: 0 : if (spdk_unlikely(cqe->res != 0)) {
362 : 0 : ublk_ctrl_cmd_error(ublk, cqe->res);
363 : 0 : return;
364 : : }
365 : :
366 [ # # # # : 0 : switch (ublk->current_cmd_op) {
# # # #
# ]
367 : 0 : case UBLK_CMD_ADD_DEV:
368 : 0 : rc = ublk_set_params(ublk);
369 [ # # ]: 0 : if (rc < 0) {
370 : 0 : ublk_delete_dev(ublk);
371 : 0 : goto cb_done;
372 : : }
373 : 0 : break;
374 : 0 : case UBLK_CMD_SET_PARAMS:
375 : 0 : rc = ublk_start_dev(ublk, false);
376 [ # # ]: 0 : if (rc < 0) {
377 : 0 : ublk_delete_dev(ublk);
378 : 0 : goto cb_done;
379 : : }
380 : 0 : break;
381 : 0 : case UBLK_CMD_START_DEV:
382 : 0 : goto cb_done;
383 : : break;
384 : 0 : case UBLK_CMD_STOP_DEV:
385 : 0 : break;
386 : 0 : case UBLK_CMD_DEL_DEV:
387 [ # # ]: 0 : if (ublk->ctrl_cb) {
388 : 0 : ublk->ctrl_cb(ublk->cb_arg, 0);
389 : 0 : ublk->ctrl_cb = NULL;
390 : : }
391 : 0 : ublk_free_dev(ublk);
392 : 0 : break;
393 : 0 : case UBLK_CMD_GET_DEV_INFO:
394 : 0 : rc = ublk_ctrl_start_recovery(ublk);
395 [ # # ]: 0 : if (rc < 0) {
396 : 0 : ublk_delete_dev(ublk);
397 : 0 : goto cb_done;
398 : : }
399 : 0 : break;
400 : 0 : case UBLK_CMD_START_USER_RECOVERY:
401 : 0 : rc = ublk_start_dev(ublk, true);
402 [ # # ]: 0 : if (rc < 0) {
403 : 0 : ublk_delete_dev(ublk);
404 : 0 : goto cb_done;
405 : : }
406 : 0 : break;
407 : 0 : case UBLK_CMD_END_USER_RECOVERY:
408 : 0 : SPDK_NOTICELOG("Ublk %u recover done successfully\n", ublk->ublk_id);
409 : 0 : ublk->is_recovering = false;
410 : 0 : goto cb_done;
411 : : break;
412 : 0 : default:
413 : 0 : SPDK_ERRLOG("No match cmd operation,cmd_op = %d\n", ublk->current_cmd_op);
414 : 0 : break;
415 : : }
416 : :
417 : 0 : return;
418 : :
419 : 0 : cb_done:
420 [ # # ]: 0 : if (ublk->ctrl_cb) {
421 : 0 : ublk->ctrl_cb(ublk->cb_arg, rc);
422 : 0 : ublk->ctrl_cb = NULL;
423 : : }
424 : : }
425 : :
426 : : static int
427 : 0 : ublk_ctrl_poller(void *arg)
428 : : {
429 : 0 : struct io_uring *ring = &g_ublk_tgt.ctrl_ring;
430 : 0 : struct io_uring_cqe *cqe;
431 : 0 : const int max = 8;
432 : 0 : int i, count = 0, rc;
433 : :
434 [ # # ]: 0 : if (!g_ublk_tgt.ctrl_ops_in_progress) {
435 : 0 : return SPDK_POLLER_IDLE;
436 : : }
437 : :
438 [ # # ]: 0 : for (i = 0; i < max; i++) {
439 : 0 : rc = io_uring_peek_cqe(ring, &cqe);
440 [ # # ]: 0 : if (rc == -EAGAIN) {
441 : 0 : break;
442 : : }
443 : :
444 [ # # ]: 0 : assert(cqe != NULL);
445 : 0 : g_ublk_tgt.ctrl_ops_in_progress--;
446 : :
447 : 0 : ublk_ctrl_process_cqe(cqe);
448 : :
449 : 0 : io_uring_cqe_seen(ring, cqe);
450 : 0 : count++;
451 : : }
452 : :
453 : 0 : return count > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
454 : : }
455 : :
456 : : static int
457 : 0 : ublk_ctrl_cmd_submit(struct spdk_ublk_dev *ublk, uint32_t cmd_op)
458 : : {
459 : 0 : uint32_t dev_id = ublk->ublk_id;
460 : 0 : int rc = -EINVAL;
461 : : struct io_uring_sqe *sqe;
462 : : struct ublksrv_ctrl_cmd *cmd;
463 : :
464 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "ctrl cmd %s\n", ublk_op_name[cmd_op]);
465 : :
466 : 0 : sqe = io_uring_get_sqe(&g_ublk_tgt.ctrl_ring);
467 [ # # ]: 0 : if (!sqe) {
468 : 0 : SPDK_ERRLOG("No available sqe in ctrl ring\n");
469 : 0 : assert(false);
470 : : return -ENOENT;
471 : : }
472 : :
473 : 0 : cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe);
474 : 0 : sqe->fd = g_ublk_tgt.ctrl_fd;
475 : 0 : sqe->opcode = IORING_OP_URING_CMD;
476 : 0 : sqe->ioprio = 0;
477 : 0 : cmd->dev_id = dev_id;
478 : 0 : cmd->queue_id = -1;
479 : 0 : ublk->current_cmd_op = cmd_op;
480 : :
481 [ # # # # : 0 : switch (cmd_op) {
# # # # ]
482 : 0 : case UBLK_CMD_ADD_DEV:
483 : : case UBLK_CMD_GET_DEV_INFO:
484 : 0 : cmd->addr = (__u64)(uintptr_t)&ublk->dev_info;
485 : 0 : cmd->len = sizeof(ublk->dev_info);
486 : 0 : break;
487 : 0 : case UBLK_CMD_SET_PARAMS:
488 : 0 : cmd->addr = (__u64)(uintptr_t)&ublk->dev_params;
489 : 0 : cmd->len = sizeof(ublk->dev_params);
490 : 0 : break;
491 : 0 : case UBLK_CMD_START_DEV:
492 : 0 : cmd->data[0] = getpid();
493 : 0 : break;
494 : 0 : case UBLK_CMD_STOP_DEV:
495 : 0 : break;
496 : 0 : case UBLK_CMD_DEL_DEV:
497 : 0 : break;
498 : 0 : case UBLK_CMD_START_USER_RECOVERY:
499 : 0 : break;
500 : 0 : case UBLK_CMD_END_USER_RECOVERY:
501 : 0 : cmd->data[0] = getpid();
502 : 0 : break;
503 : 0 : default:
504 : 0 : SPDK_ERRLOG("No match cmd operation,cmd_op = %d\n", cmd_op);
505 : 0 : return -EINVAL;
506 : : }
507 : 0 : ublk_set_sqe_cmd_op(sqe, cmd_op);
508 : 0 : io_uring_sqe_set_data(sqe, ublk);
509 : :
510 : 0 : rc = io_uring_submit(&g_ublk_tgt.ctrl_ring);
511 [ # # ]: 0 : if (rc < 0) {
512 : 0 : SPDK_ERRLOG("uring submit rc %d\n", rc);
513 : 0 : assert(false);
514 : : return rc;
515 : : }
516 : 0 : g_ublk_tgt.ctrl_ops_in_progress++;
517 : 0 : ublk->ctrl_ops_in_progress++;
518 : :
519 : 0 : return 0;
520 : : }
521 : :
522 : : static int
523 : 0 : ublk_ctrl_cmd_get_features(void)
524 : : {
525 : : int rc;
526 : : struct io_uring_sqe *sqe;
527 : 0 : struct io_uring_cqe *cqe;
528 : : struct ublksrv_ctrl_cmd *cmd;
529 : : uint32_t cmd_op;
530 : :
531 : 0 : sqe = io_uring_get_sqe(&g_ublk_tgt.ctrl_ring);
532 [ # # ]: 0 : if (!sqe) {
533 : 0 : SPDK_ERRLOG("No available sqe in ctrl ring\n");
534 : 0 : assert(false);
535 : : return -ENOENT;
536 : : }
537 : :
538 : 0 : cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe);
539 : 0 : sqe->fd = g_ublk_tgt.ctrl_fd;
540 : 0 : sqe->opcode = IORING_OP_URING_CMD;
541 : 0 : sqe->ioprio = 0;
542 : 0 : cmd->dev_id = -1;
543 : 0 : cmd->queue_id = -1;
544 : 0 : cmd->addr = (__u64)(uintptr_t)&g_ublk_tgt.features;
545 : 0 : cmd->len = sizeof(g_ublk_tgt.features);
546 : :
547 : 0 : cmd_op = UBLK_U_CMD_GET_FEATURES;
548 : 0 : ublk_set_sqe_cmd_op(sqe, cmd_op);
549 : :
550 : 0 : rc = io_uring_submit(&g_ublk_tgt.ctrl_ring);
551 [ # # ]: 0 : if (rc < 0) {
552 : 0 : SPDK_ERRLOG("uring submit rc %d\n", rc);
553 : 0 : return rc;
554 : : }
555 : :
556 : 0 : rc = io_uring_wait_cqe(&g_ublk_tgt.ctrl_ring, &cqe);
557 [ # # ]: 0 : if (rc < 0) {
558 : 0 : SPDK_ERRLOG("wait cqe rc %d\n", rc);
559 : 0 : return rc;
560 : : }
561 : :
562 [ # # ]: 0 : if (cqe->res == 0) {
563 : 0 : g_ublk_tgt.ioctl_encode = !!(g_ublk_tgt.features & UBLK_F_CMD_IOCTL_ENCODE);
564 : 0 : g_ublk_tgt.user_copy = !!(g_ublk_tgt.features & UBLK_F_USER_COPY);
565 [ # # # # ]: 0 : g_ublk_tgt.user_copy &= !g_disable_user_copy;
566 : 0 : g_ublk_tgt.user_recovery = !!(g_ublk_tgt.features & UBLK_F_USER_RECOVERY);
567 [ # # # # ]: 0 : SPDK_NOTICELOG("User Copy %s\n", g_ublk_tgt.user_copy ? "enabled" : "disabled");
568 : : }
569 : 0 : io_uring_cqe_seen(&g_ublk_tgt.ctrl_ring, cqe);
570 : :
571 : 0 : return 0;
572 : : }
573 : :
574 : : static int
575 : 0 : ublk_queue_cmd_buf_sz(uint32_t q_depth)
576 : : {
577 : 0 : uint32_t size = q_depth * sizeof(struct ublksrv_io_desc);
578 : 0 : uint32_t page_sz = getpagesize();
579 : :
580 : : /* round up size */
581 : 0 : return (size + page_sz - 1) & ~(page_sz - 1);
582 : : }
583 : :
584 : : static int
585 : 0 : ublk_get_max_support_devs(void)
586 : : {
587 : : FILE *file;
588 : 0 : char str[128];
589 : :
590 : 0 : file = fopen("/sys/module/ublk_drv/parameters/ublks_max", "r");
591 [ # # ]: 0 : if (!file) {
592 : 0 : return -ENOENT;
593 : : }
594 : :
595 [ # # ]: 0 : if (!fgets(str, sizeof(str), file)) {
596 : 0 : fclose(file);
597 : 0 : return -EINVAL;
598 : : }
599 : 0 : fclose(file);
600 : :
601 : 0 : spdk_str_chomp(str);
602 : 0 : return spdk_strtol(str, 10);
603 : : }
604 : :
605 : : static void
606 : 0 : ublk_device_table_init(void)
607 : : {
608 : : uint32_t i;
609 : 0 : SPDK_NOTICELOG("Initializing device table\n");
610 [ # # ]: 0 : for (i = 0 ; i < UBLK_MAX_DEV_TBL_SIZE ; i++) {
611 : 0 : g_ublk_tgt.dev_tbl[i] = NULL;
612 : : }
613 : 0 : }
614 : :
615 : : #if 0
616 : : static void
617 : : ublk_device_table_clear_check(void)
618 : : {
619 : : uint32_t i;
620 : :
621 : : for (i = 0 ; i < UBLK_MAX_DEV_TBL_SIZE ; i++) {
622 : : if (g_ublk_tgt.dev_tbl[i]) {
623 : : printf(" Idx %i, entry not empty\n", i);
624 : : g_ublk_tgt.dev_tbl[i] = NULL;
625 : : }
626 : : }
627 : : }
628 : : #endif
629 : :
630 : : static void
631 : 0 : ublk_init_fd_table(struct ublk_poll_group *poll_group)
632 : : {
633 : : int i;
634 [ # # ]: 0 : for (i = 0; i < UBLK_MAX_DEV_TBL_SIZE; i++) {
635 : 0 : poll_group->pg_fd_table[i] = -1;
636 : : }
637 : 0 : }
638 : :
639 : : static void
640 : 0 : ublk_add_fd_to_ring(struct ublk_poll_group *poll_group, struct spdk_ublk_dev *ublk)
641 : : {
642 : 0 : int ublk_idx = ublk->ublk_idx;
643 : 0 : int fd = ublk->cdev_fd;
644 : :
645 [ # # ]: 0 : if (poll_group->pg_fd_table[ublk_idx] == -1) {
646 : 0 : poll_group->pg_fd_table[ublk_idx] = fd;
647 [ # # ]: 0 : } else if (poll_group->pg_fd_table[ublk_idx] != fd) {
648 : 0 : SPDK_ERRLOG(" ERROR! Other FD (%d) already exist at ublk_idx %d\n",
649 : : poll_group->pg_fd_table[ublk_idx], ublk_idx);
650 : 0 : assert(false);
651 : : }
652 : 0 : }
653 : :
654 : : static void
655 : 0 : ublk_remove_fd_from_ring(struct ublk_poll_group *poll_group, struct spdk_ublk_dev *ublk)
656 : : {
657 : 0 : int ublk_idx = ublk->ublk_idx;
658 [ # # ]: 0 : if (poll_group->pg_fd_table[ublk_idx] == ublk->cdev_fd) {
659 : 0 : poll_group->pg_fd_table[ublk_idx] = -1;
660 [ # # ]: 0 : } else if (poll_group->pg_fd_table[ublk->ublk_idx] != -1) {
661 : 0 : SPDK_ERRLOG(" ERROR! FD mismatch at ublk_idx %d. Attempt to remove %d while %d is present\n",
662 : : ublk_idx, ublk->cdev_fd, poll_group->pg_fd_table[ublk->ublk_idx]);
663 : 0 : assert(false);
664 : : }
665 : 0 : }
666 : :
667 : : static int
668 : 0 : ublk_open(void)
669 : : {
670 : : int rc, ublks_max;
671 : :
672 : 0 : g_ublk_tgt.ctrl_fd = open(UBLK_CTRL_DEV, O_RDWR);
673 [ # # ]: 0 : if (g_ublk_tgt.ctrl_fd < 0) {
674 : 0 : rc = errno;
675 : 0 : SPDK_ERRLOG("UBLK control dev %s can't be opened, error=%s\n", UBLK_CTRL_DEV, spdk_strerror(errno));
676 : 0 : return -rc;
677 : : }
678 : :
679 : 0 : ublks_max = ublk_get_max_support_devs();
680 [ # # ]: 0 : if (ublks_max > 0) {
681 : 0 : g_ublks_max = ublks_max;
682 : : }
683 : :
684 : : /* TBD - limit size?
685 : : * Device table size is set to UBLK_MAX_DEV_TBL_SIZE, so we need to limit max number
686 : : * of supported devices to that value */
687 : 0 : g_ublks_max = spdk_min(g_ublks_max, UBLK_MAX_DEV_TBL_SIZE);
688 : :
689 : : /* We need to set SQPOLL for kernels 6.1 and earlier, since they would not defer ublk ctrl
690 : : * ring processing to a workqueue. Ctrl ring processing is minimal, so SQPOLL is fine.
691 : : * All the commands sent via control uring for a ublk device is executed one by one, so use
692 : : * ublks_max * 2 as the number of uring entries is enough.
693 : : */
694 : 0 : rc = ublk_setup_ring(g_ublks_max * 8, &g_ublk_tgt.ctrl_ring,
695 : : IORING_SETUP_SQE128 | IORING_SETUP_SQPOLL);
696 [ # # ]: 0 : if (rc < 0) {
697 : 0 : SPDK_ERRLOG("UBLK ctrl queue_init: %s\n", spdk_strerror(-rc));
698 : 0 : goto err;
699 : : }
700 : :
701 : 0 : rc = ublk_ctrl_cmd_get_features();
702 [ # # ]: 0 : if (rc) {
703 : 0 : goto err;
704 : : }
705 : :
706 : 0 : return 0;
707 : :
708 : 0 : err:
709 : 0 : close(g_ublk_tgt.ctrl_fd);
710 : 0 : g_ublk_tgt.ctrl_fd = -1;
711 : 0 : return rc;
712 : : }
713 : :
714 : : static void
715 : 0 : ublk_destroy_rings(int num)
716 : : {
717 : : int i;
718 : : struct ublk_poll_group *poll_group;
719 [ # # ]: 0 : for (i = 0; i < num ; i++) {
720 : 0 : poll_group = &g_ublk_tgt.poll_groups[i];
721 : 0 : io_uring_queue_exit(&poll_group->ring);
722 : : }
723 : : /* Close control dev/ring as well */
724 : 0 : close(g_ublk_tgt.ctrl_fd);
725 : 0 : g_ublk_tgt.ctrl_fd = -1;
726 : 0 : }
727 : :
728 : : static int
729 : 0 : ublk_parse_core_mask(const char *mask)
730 : : {
731 : 0 : struct spdk_cpuset tmp_mask;
732 : : int rc;
733 : :
734 [ # # ]: 0 : if (mask == NULL) {
735 : 0 : spdk_env_get_cpuset(&g_core_mask);
736 : 0 : return 0;
737 : : }
738 : :
739 : 0 : rc = spdk_cpuset_parse(&g_core_mask, mask);
740 [ # # ]: 0 : if (rc < 0) {
741 : 0 : SPDK_ERRLOG("invalid cpumask %s\n", mask);
742 : 0 : return -EINVAL;
743 : : }
744 : :
745 [ # # ]: 0 : if (spdk_cpuset_count(&g_core_mask) == 0) {
746 : 0 : SPDK_ERRLOG("no cpus specified\n");
747 : 0 : return -EINVAL;
748 : : }
749 : :
750 : 0 : spdk_env_get_cpuset(&tmp_mask);
751 : 0 : spdk_cpuset_and(&tmp_mask, &g_core_mask);
752 : :
753 [ # # ]: 0 : if (!spdk_cpuset_equal(&tmp_mask, &g_core_mask)) {
754 : 0 : SPDK_ERRLOG("one of selected cpu is outside of core mask(=%s)\n",
755 : : spdk_cpuset_fmt(&g_core_mask));
756 : 0 : return -EINVAL;
757 : : }
758 : :
759 : 0 : return 0;
760 : : }
761 : :
762 : : static void
763 : 0 : ublk_poller_register(void *args)
764 : : {
765 : 0 : struct ublk_poll_group *poll_group = args;
766 : : int rc;
767 : :
768 [ # # ]: 0 : assert(spdk_get_thread() == poll_group->ublk_thread);
769 : : /* Bind ublk spdk_thread to current CPU core in order to avoid thread context switch
770 : : * during uring processing as required by ublk kernel.
771 : : */
772 : 0 : spdk_thread_bind(spdk_get_thread(), true);
773 : :
774 : 0 : TAILQ_INIT(&poll_group->queue_list);
775 : 0 : poll_group->ublk_poller = SPDK_POLLER_REGISTER(ublk_poll, poll_group, 0);
776 : 0 : rc = spdk_iobuf_channel_init(&poll_group->iobuf_ch, "ublk",
777 : : UBLK_IOBUF_SMALL_CACHE_SIZE, UBLK_IOBUF_LARGE_CACHE_SIZE);
778 [ # # ]: 0 : if (rc != 0) {
779 : 0 : assert(false);
780 : : }
781 : 0 : }
782 : :
783 : : struct rpc_create_target {
784 : : bool disable_user_copy;
785 : : };
786 : :
787 : : static const struct spdk_json_object_decoder rpc_ublk_create_target[] = {
788 : : {"disable_user_copy", offsetof(struct rpc_create_target, disable_user_copy), spdk_json_decode_bool, true},
789 : : };
790 : :
791 : : int
792 : 0 : ublk_use_fixed_files(char *state)
793 : : {
794 : : size_t i;
795 [ # # ]: 0 : size_t len = strlen(state);
796 : :
797 [ # # # # ]: 0 : if (g_ublk_tgt.active == true) {
798 : 0 : SPDK_ERRLOG("Changing of fixed files state is allowed only before UBLK target creation\n");
799 : 0 : return -EBUSY;
800 : : }
801 : :
802 [ # # ]: 0 : for (i = 0; i < len; i++) {
803 : 0 : state[i] = tolower(state[i]);
804 : : }
805 : :
806 [ # # # # : 0 : if ((len == strlen("enable")) && (strncmp(state, "enable", strlen("enable")) == 0)) {
# # ]
807 : 0 : g_use_fixed_files = true;
808 [ # # # # : 0 : } else if ((len == strlen("disable")) && (strncmp(state, "disable", strlen("disable")) == 0)) {
# # ]
809 : 0 : g_use_fixed_files = false;
810 : : } else {
811 : 0 : return -EINVAL;
812 : : }
813 [ # # # # ]: 0 : SPDK_NOTICELOG("IOSQE_FIXED_FILE using has been %s for UBLK target\n",
814 : : g_use_fixed_files == false ? "disabled" : "enabled");
815 : :
816 : 0 : return 0;
817 : : }
818 : :
819 : : int
820 : 0 : ublk_create_target(const char *cpumask_str, const struct spdk_json_val *params)
821 : : {
822 : : int rc;
823 : : uint32_t i;
824 : 0 : uint32_t num_rings = 0;
825 : 0 : char thread_name[32];
826 : 0 : struct rpc_create_target req = {};
827 : : struct ublk_poll_group *poll_group;
828 : :
829 [ # # # # ]: 0 : if (g_ublk_tgt.active == true) {
830 : 0 : SPDK_ERRLOG("UBLK target has been created\n");
831 : 0 : return -EBUSY;
832 : : }
833 : :
834 : 0 : rc = ublk_parse_core_mask(cpumask_str);
835 [ # # ]: 0 : if (rc != 0) {
836 : 0 : return rc;
837 : : }
838 : :
839 [ # # ]: 0 : if (params) {
840 [ # # ]: 0 : if (spdk_json_decode_object_relaxed(params, rpc_ublk_create_target,
841 : : SPDK_COUNTOF(rpc_ublk_create_target),
842 : : &req)) {
843 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
844 : 0 : return -EINVAL;
845 : : }
846 [ # # ]: 0 : g_disable_user_copy = req.disable_user_copy;
847 : : }
848 : :
849 [ # # ]: 0 : assert(g_ublk_tgt.poll_groups == NULL);
850 : 0 : g_ublk_tgt.poll_groups = calloc(spdk_env_get_core_count(), sizeof(*poll_group));
851 [ # # ]: 0 : if (!g_ublk_tgt.poll_groups) {
852 : 0 : return -ENOMEM;
853 : : }
854 : :
855 : 0 : ublk_device_table_init();
856 : 0 : rc = ublk_open();
857 [ # # ]: 0 : if (rc != 0) {
858 : 0 : SPDK_ERRLOG("Fail to open UBLK, error=%s\n", spdk_strerror(-rc));
859 : 0 : free(g_ublk_tgt.poll_groups);
860 : 0 : g_ublk_tgt.poll_groups = NULL;
861 : 0 : return rc;
862 : : }
863 : :
864 : 0 : spdk_iobuf_register_module("ublk");
865 [ # # ]: 0 : SPDK_ENV_FOREACH_CORE(i) {
866 [ # # ]: 0 : if (!spdk_cpuset_get_cpu(&g_core_mask, i)) {
867 : 0 : continue;
868 : : }
869 : 0 : poll_group = &g_ublk_tgt.poll_groups[num_rings];
870 : 0 : ublk_init_fd_table(poll_group);
871 : 0 : rc = ublk_setup_ring(UBLK_IO_URING_DEPTH, &poll_group->ring,
872 : : IORING_SETUP_SQE128);
873 [ # # ]: 0 : if (rc < 0) {
874 : 0 : SPDK_ERRLOG("Fail to create io_urings for UBLK target poll group, error=%s\n",
875 : : spdk_strerror(-rc));
876 : 0 : ublk_destroy_rings(num_rings);
877 : 0 : free(g_ublk_tgt.poll_groups);
878 : 0 : return rc;
879 : : }
880 [ # # ]: 0 : printf("ublk_dev_init_io_cmds for ring_fd %d\n", poll_group->ring.ring_fd);
881 : 0 : ublk_dev_init_io_cmds(&poll_group->ring, UBLK_IO_URING_DEPTH);
882 : :
883 [ # # # # ]: 0 : if (g_use_fixed_files) {
884 : : /* This applies to File Descriptor Mode only */
885 : 0 : rc = io_uring_register_files_sparse(&poll_group->ring, UBLK_MAX_DEV_TBL_SIZE);
886 : :
887 [ # # ]: 0 : if (rc < 0) {
888 : 0 : SPDK_ERRLOG("Fail to register FD table for UBLK, error=%s\n", spdk_strerror(-rc));
889 : : /* TBD Add removal of all PG on failure */
890 : 0 : ublk_destroy_rings(num_rings);
891 : 0 : free(g_ublk_tgt.poll_groups);
892 : 0 : return rc;
893 : : }
894 : : }
895 : 0 : num_rings++;
896 : : }
897 : :
898 [ # # ]: 0 : SPDK_ENV_FOREACH_CORE(i) {
899 [ # # ]: 0 : if (!spdk_cpuset_get_cpu(&g_core_mask, i)) {
900 : 0 : continue;
901 : : }
902 [ # # ]: 0 : snprintf(thread_name, sizeof(thread_name), "ublk_thread%u", i);
903 : 0 : poll_group = &g_ublk_tgt.poll_groups[g_num_ublk_poll_groups];
904 : 0 : poll_group->ublk_thread = spdk_thread_create(thread_name, &g_core_mask);
905 : 0 : spdk_thread_send_msg(poll_group->ublk_thread, ublk_poller_register, poll_group);
906 : 0 : g_num_ublk_poll_groups++;
907 : : }
908 : :
909 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
910 : 0 : g_ublk_tgt.active = true;
911 : 0 : g_ublk_tgt.ctrl_ops_in_progress = 0;
912 : 0 : g_ublk_tgt.ctrl_poller = SPDK_POLLER_REGISTER(ublk_ctrl_poller, NULL,
913 : : UBLK_DEFAULT_CTRL_URING_POLLING_INTERVAL_US);
914 : :
915 [ # # # # ]: 0 : if (g_use_fixed_files == true) {
916 : 0 : SPDK_NOTICELOG("IOSQE_FIXED_FILE flag is enabled for UBLK target\n");
917 : : } else {
918 : 0 : SPDK_NOTICELOG("IOSQE_FIXED_FILE flag is disabled for UBLK target\n");
919 : : }
920 : 0 : SPDK_NOTICELOG("UBLK target created successfully\n");
921 : :
922 : 0 : return 0;
923 : : }
924 : :
925 : : static void
926 : 418 : _ublk_fini_done(void *args)
927 : : {
928 : : uint32_t i;
929 : :
930 [ - + - + ]: 418 : SPDK_DEBUGLOG(ublk, "\n");
931 : :
932 [ - + ]: 418 : for (i = 0; i < g_num_ublk_poll_groups; i++) {
933 [ # # # # ]: 0 : if (g_use_fixed_files) {
934 : 0 : io_uring_unregister_files(&g_ublk_tgt.poll_groups[i].ring);
935 : : }
936 : 0 : io_uring_queue_exit(&g_ublk_tgt.poll_groups[i].ring);
937 : 0 : g_ublk_tgt.poll_groups[i].ring.ring_fd = -1;
938 : : }
939 : :
940 : 418 : g_num_ublk_poll_groups = 0;
941 : 418 : g_next_ublk_poll_group = 0;
942 : 418 : g_ublk_tgt.is_destroying = false;
943 : 418 : g_ublk_tgt.active = false;
944 : 418 : g_ublk_tgt.features = 0;
945 : 418 : g_ublk_tgt.ioctl_encode = false;
946 : 418 : g_ublk_tgt.user_copy = false;
947 : 418 : g_ublk_tgt.user_recovery = false;
948 : :
949 [ + - ]: 418 : if (g_ublk_tgt.cb_fn) {
950 : 418 : g_ublk_tgt.cb_fn(g_ublk_tgt.cb_arg);
951 : 418 : g_ublk_tgt.cb_fn = NULL;
952 : 418 : g_ublk_tgt.cb_arg = NULL;
953 : : }
954 : :
955 [ - + ]: 418 : if (g_ublk_tgt.poll_groups) {
956 : 0 : free(g_ublk_tgt.poll_groups);
957 : 0 : g_ublk_tgt.poll_groups = NULL;
958 : : }
959 : : #if 0
960 : : ublk_device_table_clear_check();
961 : : #endif
962 : 418 : }
963 : :
964 : : static void
965 : 424 : ublk_thread_exit(void *args)
966 : : {
967 : 424 : struct spdk_thread *ublk_thread = spdk_get_thread();
968 : : uint32_t i;
969 : :
970 [ - + ]: 424 : for (i = 0; i < g_num_ublk_poll_groups; i++) {
971 [ # # ]: 0 : if (g_ublk_tgt.poll_groups[i].ublk_thread == ublk_thread) {
972 : 0 : spdk_poller_unregister(&g_ublk_tgt.poll_groups[i].ublk_poller);
973 : 0 : spdk_iobuf_channel_fini(&g_ublk_tgt.poll_groups[i].iobuf_ch);
974 : 0 : spdk_thread_bind(ublk_thread, false);
975 : 0 : spdk_thread_exit(ublk_thread);
976 : : }
977 : : }
978 : 424 : }
979 : :
980 : : static int
981 : 0 : ublk_close_dev(struct spdk_ublk_dev *ublk)
982 : : {
983 : : int rc;
984 : :
985 : : /* set is_closing */
986 [ # # # # ]: 0 : if (ublk->is_closing) {
987 : 0 : return -EBUSY;
988 : : }
989 : 0 : ublk->is_closing = true;
990 : :
991 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_STOP_DEV);
992 [ # # ]: 0 : if (rc < 0) {
993 : 0 : SPDK_ERRLOG("stop dev %d failed\n", ublk->ublk_id);
994 : : }
995 : 0 : return rc;
996 : : }
997 : :
998 : : static void
999 : 418 : _ublk_fini(void *args)
1000 : : {
1001 : : struct spdk_ublk_dev *ublk, *ublk_tmp;
1002 : : static int stop_block = 0;
1003 [ - + ]: 418 : TAILQ_FOREACH_SAFE(ublk, &g_ublk_devs, tailq, ublk_tmp) {
1004 : 0 : ublk_close_dev(ublk);
1005 : 0 : stop_block++;
1006 [ # # ]: 0 : if (stop_block % 4 == 0) {
1007 : 0 : spdk_thread_send_msg(spdk_get_thread(), _ublk_fini, NULL);
1008 : 0 : return;
1009 : : }
1010 : : }
1011 : 418 : stop_block = 0;
1012 : : /* Check if all ublks closed */
1013 [ + - ]: 418 : if (TAILQ_EMPTY(&g_ublk_devs)) {
1014 [ - + - + ]: 418 : SPDK_DEBUGLOG(ublk, "finish shutdown\n");
1015 : 418 : spdk_poller_unregister(&g_ublk_tgt.ctrl_poller);
1016 [ - + ]: 418 : if (g_ublk_tgt.ctrl_ring.ring_fd >= 0) {
1017 : 0 : io_uring_queue_exit(&g_ublk_tgt.ctrl_ring);
1018 : 0 : g_ublk_tgt.ctrl_ring.ring_fd = -1;
1019 : : }
1020 [ - + ]: 418 : if (g_ublk_tgt.ctrl_fd >= 0) {
1021 : 0 : close(g_ublk_tgt.ctrl_fd);
1022 : 0 : g_ublk_tgt.ctrl_fd = -1;
1023 : : }
1024 : 418 : spdk_for_each_thread(ublk_thread_exit, NULL, _ublk_fini_done);
1025 : : } else {
1026 : 0 : spdk_thread_send_msg(spdk_get_thread(), _ublk_fini, NULL);
1027 : : }
1028 : : }
1029 : :
1030 : : int
1031 : 418 : spdk_ublk_fini(spdk_ublk_fini_cb cb_fn, void *cb_arg)
1032 : : {
1033 [ - + ]: 418 : assert(spdk_thread_is_app_thread(NULL));
1034 : :
1035 [ - + - + ]: 418 : if (g_ublk_tgt.is_destroying == true) {
1036 : : /* UBLK target is being destroying */
1037 : 0 : return -EBUSY;
1038 : : }
1039 : 418 : g_ublk_tgt.cb_fn = cb_fn;
1040 : 418 : g_ublk_tgt.cb_arg = cb_arg;
1041 : 418 : g_ublk_tgt.is_destroying = true;
1042 : 418 : _ublk_fini(NULL);
1043 : :
1044 : 418 : return 0;
1045 : : }
1046 : :
1047 : : int
1048 : 0 : ublk_destroy_target(spdk_ublk_fini_cb cb_fn, void *cb_arg)
1049 : : {
1050 : : int rc;
1051 : :
1052 [ # # # # ]: 0 : if (g_ublk_tgt.active == false) {
1053 : : /* UBLK target has not been created */
1054 : 0 : return -ENOENT;
1055 : : }
1056 : :
1057 : 0 : rc = spdk_ublk_fini(cb_fn, cb_arg);
1058 : :
1059 : 0 : return rc;
1060 : : }
1061 : :
1062 : : struct spdk_ublk_dev *
1063 : 0 : ublk_dev_find_by_id(uint32_t ublk_id)
1064 : : {
1065 : : struct spdk_ublk_dev *ublk;
1066 : :
1067 : : /* check whether ublk has already been registered by ublk path. */
1068 [ # # ]: 0 : TAILQ_FOREACH(ublk, &g_ublk_devs, tailq) {
1069 [ # # ]: 0 : if (ublk->ublk_id == ublk_id) {
1070 : 0 : return ublk;
1071 : : }
1072 : : }
1073 : :
1074 : 0 : return NULL;
1075 : : }
1076 : :
1077 : : uint32_t
1078 : 0 : ublk_dev_get_id(struct spdk_ublk_dev *ublk)
1079 : : {
1080 : 0 : return ublk->ublk_id;
1081 : : }
1082 : :
1083 : 0 : struct spdk_ublk_dev *ublk_dev_first(void)
1084 : : {
1085 : 0 : return TAILQ_FIRST(&g_ublk_devs);
1086 : : }
1087 : :
1088 : 0 : struct spdk_ublk_dev *ublk_dev_next(struct spdk_ublk_dev *prev)
1089 : : {
1090 : 0 : return TAILQ_NEXT(prev, tailq);
1091 : : }
1092 : :
1093 : : uint32_t
1094 : 0 : ublk_dev_get_queue_depth(struct spdk_ublk_dev *ublk)
1095 : : {
1096 : 0 : return ublk->queue_depth;
1097 : : }
1098 : :
1099 : : uint32_t
1100 : 0 : ublk_dev_get_num_queues(struct spdk_ublk_dev *ublk)
1101 : : {
1102 : 0 : return ublk->num_queues;
1103 : : }
1104 : :
1105 : : const char *
1106 : 0 : ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk)
1107 : : {
1108 : 0 : return spdk_bdev_get_name(ublk->bdev);
1109 : : }
1110 : :
1111 : : void
1112 : 72 : spdk_ublk_write_config_json(struct spdk_json_write_ctx *w)
1113 : : {
1114 : : struct spdk_ublk_dev *ublk;
1115 : :
1116 : 72 : spdk_json_write_array_begin(w);
1117 : :
1118 [ - + - + ]: 72 : if (g_ublk_tgt.active) {
1119 : 0 : spdk_json_write_object_begin(w);
1120 : :
1121 : 0 : spdk_json_write_named_string(w, "method", "ublk_create_target");
1122 : 0 : spdk_json_write_named_object_begin(w, "params");
1123 : 0 : spdk_json_write_named_string(w, "cpumask", spdk_cpuset_fmt(&g_core_mask));
1124 : 0 : spdk_json_write_object_end(w);
1125 : :
1126 : 0 : spdk_json_write_object_end(w);
1127 : : }
1128 : :
1129 [ - + ]: 72 : TAILQ_FOREACH(ublk, &g_ublk_devs, tailq) {
1130 : 0 : spdk_json_write_object_begin(w);
1131 : :
1132 : 0 : spdk_json_write_named_string(w, "method", "ublk_start_disk");
1133 : :
1134 : 0 : spdk_json_write_named_object_begin(w, "params");
1135 : 0 : spdk_json_write_named_string(w, "bdev_name", ublk_dev_get_bdev_name(ublk));
1136 : 0 : spdk_json_write_named_uint32(w, "ublk_id", ublk->ublk_id);
1137 : 0 : spdk_json_write_named_uint32(w, "num_queues", ublk->num_queues);
1138 : 0 : spdk_json_write_named_uint32(w, "queue_depth", ublk->queue_depth);
1139 : 0 : spdk_json_write_object_end(w);
1140 : :
1141 : 0 : spdk_json_write_object_end(w);
1142 : : }
1143 : :
1144 : 72 : spdk_json_write_array_end(w);
1145 : 72 : }
1146 : :
1147 : : static void
1148 : 0 : ublk_device_tbl_insert(struct spdk_ublk_dev *ublk)
1149 : : {
1150 : : uint32_t i;
1151 : :
1152 [ # # ]: 0 : for (i = 0 ; i < g_ublks_max; i++) {
1153 [ # # ]: 0 : if (g_ublk_tgt.dev_tbl[i] == NULL) {
1154 : 0 : g_ublk_tgt.dev_tbl[i] = ublk;
1155 : 0 : ublk->ublk_idx = i;
1156 : 0 : return;
1157 : : }
1158 : : }
1159 : 0 : SPDK_ERRLOG("Error adding to device table. Table full, ublk_id %d\n", ublk->ublk_id);
1160 : : }
1161 : :
1162 : : static void
1163 : 0 : ublk_device_tbl_remove(struct spdk_ublk_dev *ublk)
1164 : : {
1165 : 0 : int idx = ublk->ublk_idx ;
1166 [ # # ]: 0 : if (g_ublk_tgt.dev_tbl[idx]->ublk_id == ublk->ublk_id) {
1167 : 0 : ublk->ublk_idx = -1;
1168 : 0 : g_ublk_tgt.dev_tbl[idx] = NULL;
1169 : 0 : return;
1170 : : } else {
1171 : 0 : SPDK_ERRLOG("Error removing from tbl. idx %d, ublk_id is %d should be %d\n",
1172 : : idx, g_ublk_tgt.dev_tbl[idx]->ublk_id, ublk->ublk_id);
1173 : : }
1174 : : }
1175 : :
1176 : : static void
1177 : 0 : ublk_dev_list_register(struct spdk_ublk_dev *ublk)
1178 : : {
1179 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "add to tailq\n");
1180 : 0 : TAILQ_INSERT_TAIL(&g_ublk_devs, ublk, tailq);
1181 : 0 : g_ublk_tgt.num_ublk_devs++;
1182 : 0 : }
1183 : :
1184 : : static void
1185 : 0 : ublk_dev_list_unregister(struct spdk_ublk_dev *ublk)
1186 : : {
1187 : : /*
1188 : : * ublk device may be stopped before registered.
1189 : : * check whether it was registered.
1190 : : */
1191 : :
1192 [ # # ]: 0 : if (ublk_dev_find_by_id(ublk->ublk_id)) {
1193 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "remove from tailq\n");
1194 [ # # ]: 0 : TAILQ_REMOVE(&g_ublk_devs, ublk, tailq);
1195 [ # # ]: 0 : assert(g_ublk_tgt.num_ublk_devs);
1196 : 0 : g_ublk_tgt.num_ublk_devs--;
1197 : 0 : return;
1198 : : }
1199 : :
1200 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "not found in tailq\n");
1201 : 0 : assert(false);
1202 : : }
1203 : :
1204 : : static void
1205 : 0 : ublk_delete_dev(void *arg)
1206 : : {
1207 : 0 : struct spdk_ublk_dev *ublk = arg;
1208 : 0 : int rc = 0;
1209 : : uint32_t q_idx;
1210 : :
1211 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
1212 [ # # ]: 0 : for (q_idx = 0; q_idx < ublk->num_queues; q_idx++) {
1213 : 0 : ublk_remove_fd_from_ring(ublk->queues[q_idx].poll_group, ublk);
1214 : : }
1215 : :
1216 [ # # ]: 0 : for (q_idx = 0; q_idx < ublk->num_queues; q_idx++) {
1217 : 0 : ublk_dev_queue_fini(&ublk->queues[q_idx]);
1218 : : }
1219 : :
1220 [ # # ]: 0 : if (ublk->cdev_fd >= 0) {
1221 : 0 : close(ublk->cdev_fd);
1222 : 0 : ublk->cdev_fd = -1;
1223 : : }
1224 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_DEL_DEV);
1225 [ # # ]: 0 : if (rc < 0) {
1226 : 0 : SPDK_ERRLOG("delete dev %d failed\n", ublk->ublk_id);
1227 : : }
1228 : 0 : }
1229 : :
1230 : : static int
1231 : 0 : _ublk_close_dev_retry(void *arg)
1232 : : {
1233 : 0 : struct spdk_ublk_dev *ublk = arg;
1234 : :
1235 [ # # ]: 0 : if (ublk->ctrl_ops_in_progress > 0) {
1236 [ # # ]: 0 : if (ublk->retry_count-- > 0) {
1237 : 0 : return SPDK_POLLER_BUSY;
1238 : : }
1239 : 0 : SPDK_ERRLOG("Timeout on ctrl op completion.\n");
1240 : : }
1241 : 0 : spdk_poller_unregister(&ublk->retry_poller);
1242 : 0 : ublk_delete_dev(ublk);
1243 : 0 : return SPDK_POLLER_BUSY;
1244 : : }
1245 : :
1246 : : static void
1247 : 0 : ublk_try_close_dev(void *arg)
1248 : : {
1249 : 0 : struct spdk_ublk_dev *ublk = arg;
1250 : :
1251 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
1252 : :
1253 : 0 : ublk->queues_closed += 1;
1254 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk_io, "ublkb%u closed queues %u\n", ublk->ublk_id, ublk->queues_closed);
1255 : :
1256 [ # # ]: 0 : if (ublk->queues_closed < ublk->num_queues) {
1257 : 0 : return;
1258 : : }
1259 : :
1260 [ # # ]: 0 : if (ublk->ctrl_ops_in_progress > 0) {
1261 [ # # ]: 0 : assert(ublk->retry_poller == NULL);
1262 : 0 : ublk->retry_count = UBLK_STOP_BUSY_WAITING_MS * 1000ULL / UBLK_BUSY_POLLING_INTERVAL_US;
1263 : 0 : ublk->retry_poller = SPDK_POLLER_REGISTER(_ublk_close_dev_retry, ublk,
1264 : : UBLK_BUSY_POLLING_INTERVAL_US);
1265 : : } else {
1266 : 0 : ublk_delete_dev(ublk);
1267 : : }
1268 : : }
1269 : :
1270 : : static void
1271 : 0 : ublk_try_close_queue(struct ublk_queue *q)
1272 : : {
1273 : 0 : struct spdk_ublk_dev *ublk = q->dev;
1274 : :
1275 : : /* Close queue until no I/O is submitted to bdev in flight,
1276 : : * no I/O is waiting to commit result, and all I/Os are aborted back.
1277 : : */
1278 [ # # ]: 0 : if (!TAILQ_EMPTY(&q->inflight_io_list)) {
1279 : : /* wait for next retry */
1280 : 0 : return;
1281 : : }
1282 [ # # ]: 0 : if (!TAILQ_EMPTY(&q->completed_io_list)) {
1283 : : /* wait for next retry */
1284 : 0 : return;
1285 : : }
1286 [ # # ]: 0 : if (q->cmd_inflight) {
1287 : : /* wait for next retry */
1288 : 0 : return;
1289 : : }
1290 : :
1291 [ # # ]: 0 : TAILQ_REMOVE(&q->poll_group->queue_list, q, tailq);
1292 : 0 : spdk_put_io_channel(q->bdev_ch);
1293 : 0 : q->bdev_ch = NULL;
1294 : :
1295 : 0 : spdk_thread_send_msg(spdk_thread_get_app_thread(), ublk_try_close_dev, ublk);
1296 : : }
1297 : :
1298 : : static inline struct spdk_ublk_dev *
1299 : 0 : ublk_device_lookup(uint32_t idx)
1300 : : {
1301 : 0 : return g_ublk_tgt.dev_tbl[idx];
1302 : : }
1303 : :
1304 : : int
1305 : 0 : ublk_stop_disk(uint32_t ublk_id, ublk_ctrl_cb ctrl_cb, void *cb_arg)
1306 : : {
1307 : : struct spdk_ublk_dev *ublk;
1308 : :
1309 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
1310 : :
1311 : 0 : ublk = ublk_dev_find_by_id(ublk_id);
1312 [ # # ]: 0 : if (ublk == NULL) {
1313 : 0 : SPDK_ERRLOG("no ublk dev with ublk_id=%u\n", ublk_id);
1314 : 0 : return -ENODEV;
1315 : : }
1316 [ # # # # ]: 0 : if (ublk->is_closing) {
1317 : 0 : SPDK_WARNLOG("ublk %d is closing\n", ublk->ublk_id);
1318 : 0 : return -EBUSY;
1319 : : }
1320 [ # # ]: 0 : if (ublk->ctrl_cb) {
1321 : 0 : SPDK_WARNLOG("ublk %d is busy with RPC call\n", ublk->ublk_id);
1322 : 0 : return -EBUSY;
1323 : : }
1324 : :
1325 : 0 : ublk->ctrl_cb = ctrl_cb;
1326 : 0 : ublk->cb_arg = cb_arg;
1327 : 0 : return ublk_close_dev(ublk);
1328 : : }
1329 : :
1330 : : static inline void
1331 : 0 : ublk_mark_io_done(struct ublk_io *io, int res)
1332 : : {
1333 : : /*
1334 : : * mark io done by target, so that SPDK can commit its
1335 : : * result and fetch new request via io_uring command.
1336 : : */
1337 : 0 : io->cmd_op = UBLK_IO_COMMIT_AND_FETCH_REQ;
1338 : 0 : io->result = res;
1339 : 0 : io->need_data = false;
1340 : 0 : }
1341 : :
1342 : : static void
1343 : 0 : ublk_io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1344 : : {
1345 : 0 : struct ublk_io *io = cb_arg;
1346 : 0 : struct ublk_queue *q = io->q;
1347 : : int res;
1348 : :
1349 [ # # ]: 0 : if (success) {
1350 : 0 : res = io->result;
1351 : : } else {
1352 : 0 : res = -EIO;
1353 : : }
1354 : :
1355 : 0 : ublk_mark_io_done(io, res);
1356 : :
1357 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk_io, "(qid %d tag %d res %d)\n",
1358 : : q->q_id, io->tag, res);
1359 [ # # ]: 0 : TAILQ_REMOVE(&q->inflight_io_list, io, tailq);
1360 : 0 : TAILQ_INSERT_TAIL(&q->completed_io_list, io, tailq);
1361 : :
1362 [ # # ]: 0 : if (bdev_io != NULL) {
1363 : 0 : spdk_bdev_free_io(bdev_io);
1364 : : }
1365 : 0 : }
1366 : :
1367 : : static void
1368 : 0 : ublk_queue_user_copy(struct ublk_io *io, bool is_write)
1369 : : {
1370 : 0 : struct ublk_queue *q = io->q;
1371 : 0 : const struct ublksrv_io_desc *iod = io->iod;
1372 : : struct io_uring_sqe *sqe;
1373 : : uint64_t pos;
1374 : : uint32_t nbytes;
1375 : 0 : struct spdk_ublk_dev *ublk = q->dev;
1376 : 0 : uint32_t ublk_idx = ublk->ublk_idx;
1377 : :
1378 : 0 : nbytes = iod->nr_sectors * (1ULL << LINUX_SECTOR_SHIFT);
1379 : 0 : pos = ublk_user_copy_pos(q->q_id, io->tag);
1380 : 0 : sqe = io_uring_get_sqe(q->ring);
1381 [ # # ]: 0 : assert(sqe);
1382 : :
1383 [ # # ]: 0 : if (is_write) {
1384 : 0 : io_uring_prep_read(sqe, 0, io->payload, nbytes, pos);
1385 : : } else {
1386 : 0 : io_uring_prep_write(sqe, 0, io->payload, nbytes, pos);
1387 : : }
1388 [ # # # # ]: 0 : if (g_use_fixed_files) {
1389 : 0 : io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
1390 : : } else {
1391 : 0 : io_uring_sqe_set_flags(sqe, 0);
1392 : : }
1393 : 0 : io_uring_sqe_set_data64(sqe, build_user_data(io->tag, 0, q->q_id, ublk_idx));
1394 : :
1395 : 0 : io->user_copy = true;
1396 [ # # ]: 0 : TAILQ_REMOVE(&q->inflight_io_list, io, tailq);
1397 : 0 : TAILQ_INSERT_TAIL(&q->completed_io_list, io, tailq);
1398 : 0 : }
1399 : :
1400 : : static void
1401 : 0 : ublk_user_copy_read_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
1402 : : {
1403 : 0 : struct ublk_io *io = cb_arg;
1404 : :
1405 : 0 : spdk_bdev_free_io(bdev_io);
1406 : :
1407 [ # # ]: 0 : if (success) {
1408 : 0 : ublk_queue_user_copy(io, false);
1409 : 0 : return;
1410 : : }
1411 : : /* READ IO Error */
1412 : 0 : ublk_io_done(NULL, false, cb_arg);
1413 : : }
1414 : :
1415 : : static void
1416 : 0 : ublk_resubmit_io(void *arg)
1417 : : {
1418 : 0 : struct ublk_io *io = (struct ublk_io *)arg;
1419 : :
1420 : 0 : _ublk_submit_bdev_io(io->q, io);
1421 : 0 : }
1422 : :
1423 : : static void
1424 : 0 : ublk_queue_io(struct ublk_io *io)
1425 : : {
1426 : : int rc;
1427 : 0 : struct spdk_bdev *bdev = io->q->dev->bdev;
1428 : 0 : struct ublk_queue *q = io->q;
1429 : :
1430 : 0 : io->bdev_io_wait.bdev = bdev;
1431 : 0 : io->bdev_io_wait.cb_fn = ublk_resubmit_io;
1432 : 0 : io->bdev_io_wait.cb_arg = io;
1433 : :
1434 : 0 : rc = spdk_bdev_queue_io_wait(bdev, q->bdev_ch, &io->bdev_io_wait);
1435 [ # # ]: 0 : if (rc != 0) {
1436 : 0 : SPDK_ERRLOG("Queue io failed in ublk_queue_io, rc=%d.\n", rc);
1437 : 0 : ublk_io_done(NULL, false, io);
1438 : : }
1439 : 0 : }
1440 : :
1441 : : static void
1442 : 0 : ublk_io_get_buffer_cb(struct spdk_iobuf_entry *iobuf, void *buf)
1443 : : {
1444 : 0 : struct ublk_io *io = SPDK_CONTAINEROF(iobuf, struct ublk_io, iobuf);
1445 : :
1446 : 0 : io->mpool_entry = buf;
1447 [ # # ]: 0 : assert(io->payload == NULL);
1448 : 0 : io->payload = (void *)(uintptr_t)SPDK_ALIGN_CEIL((uintptr_t)buf, 4096ULL);
1449 : 0 : io->get_buf_cb(io);
1450 : 0 : }
1451 : :
1452 : : static void
1453 : 0 : ublk_io_get_buffer(struct ublk_io *io, struct spdk_iobuf_channel *iobuf_ch,
1454 : : ublk_get_buf_cb get_buf_cb)
1455 : : {
1456 : : void *buf;
1457 : :
1458 : 0 : io->payload_size = io->iod->nr_sectors * (1ULL << LINUX_SECTOR_SHIFT);
1459 : 0 : io->get_buf_cb = get_buf_cb;
1460 : 0 : buf = spdk_iobuf_get(iobuf_ch, io->payload_size, &io->iobuf, ublk_io_get_buffer_cb);
1461 : :
1462 [ # # ]: 0 : if (buf != NULL) {
1463 : 0 : ublk_io_get_buffer_cb(&io->iobuf, buf);
1464 : : }
1465 : 0 : }
1466 : :
1467 : : static void
1468 : 0 : ublk_io_put_buffer(struct ublk_io *io, struct spdk_iobuf_channel *iobuf_ch)
1469 : : {
1470 [ # # ]: 0 : if (io->payload) {
1471 : 0 : spdk_iobuf_put(iobuf_ch, io->mpool_entry, io->payload_size);
1472 : 0 : io->mpool_entry = NULL;
1473 : 0 : io->payload = NULL;
1474 : : }
1475 : 0 : }
1476 : :
1477 : : static void
1478 : 0 : _ublk_submit_bdev_io(struct ublk_queue *q, struct ublk_io *io)
1479 : : {
1480 : 0 : struct spdk_ublk_dev *ublk = q->dev;
1481 : 0 : struct spdk_bdev_desc *desc = io->bdev_desc;
1482 : 0 : struct spdk_io_channel *ch = io->bdev_ch;
1483 : : uint64_t offset_blocks, num_blocks;
1484 : : spdk_bdev_io_completion_cb read_cb;
1485 : : uint8_t ublk_op;
1486 : 0 : int rc = 0;
1487 : 0 : const struct ublksrv_io_desc *iod = io->iod;
1488 : :
1489 : 0 : ublk_op = ublksrv_get_op(iod);
1490 [ # # ]: 0 : offset_blocks = iod->start_sector >> ublk->sector_per_block_shift;
1491 [ # # ]: 0 : num_blocks = iod->nr_sectors >> ublk->sector_per_block_shift;
1492 : :
1493 [ # # # # : 0 : switch (ublk_op) {
# # ]
1494 : 0 : case UBLK_IO_OP_READ:
1495 [ # # # # ]: 0 : if (g_ublk_tgt.user_copy) {
1496 : 0 : read_cb = ublk_user_copy_read_done;
1497 : : } else {
1498 : 0 : read_cb = ublk_io_done;
1499 : : }
1500 : 0 : rc = spdk_bdev_read_blocks(desc, ch, io->payload, offset_blocks, num_blocks, read_cb, io);
1501 : 0 : break;
1502 : 0 : case UBLK_IO_OP_WRITE:
1503 : 0 : rc = spdk_bdev_write_blocks(desc, ch, io->payload, offset_blocks, num_blocks, ublk_io_done, io);
1504 : 0 : break;
1505 : 0 : case UBLK_IO_OP_FLUSH:
1506 : 0 : rc = spdk_bdev_flush_blocks(desc, ch, 0, spdk_bdev_get_num_blocks(ublk->bdev), ublk_io_done, io);
1507 : 0 : break;
1508 : 0 : case UBLK_IO_OP_DISCARD:
1509 : 0 : rc = spdk_bdev_unmap_blocks(desc, ch, offset_blocks, num_blocks, ublk_io_done, io);
1510 : 0 : break;
1511 : 0 : case UBLK_IO_OP_WRITE_ZEROES:
1512 : 0 : rc = spdk_bdev_write_zeroes_blocks(desc, ch, offset_blocks, num_blocks, ublk_io_done, io);
1513 : 0 : break;
1514 : 0 : default:
1515 : 0 : rc = -1;
1516 : : }
1517 : :
1518 [ # # ]: 0 : if (rc < 0) {
1519 [ # # ]: 0 : if (rc == -ENOMEM) {
1520 [ # # # # ]: 0 : SPDK_INFOLOG(ublk, "No memory, start to queue io.\n");
1521 : 0 : ublk_queue_io(io);
1522 : : } else {
1523 : 0 : SPDK_ERRLOG("ublk io failed in ublk_queue_io, rc=%d, ublk_op=%u\n", rc, ublk_op);
1524 : 0 : ublk_io_done(NULL, false, io);
1525 : : }
1526 : : }
1527 : 0 : }
1528 : :
1529 : : static void
1530 : 0 : read_get_buffer_done(struct ublk_io *io)
1531 : : {
1532 : 0 : _ublk_submit_bdev_io(io->q, io);
1533 : 0 : }
1534 : :
1535 : : static void
1536 : 0 : user_copy_write_get_buffer_done(struct ublk_io *io)
1537 : : {
1538 : 0 : ublk_queue_user_copy(io, true);
1539 : 0 : }
1540 : :
1541 : : static void
1542 : 0 : ublk_submit_bdev_io(struct ublk_queue *q, struct ublk_io *io)
1543 : : {
1544 : 0 : struct spdk_iobuf_channel *iobuf_ch = &q->poll_group->iobuf_ch;
1545 : 0 : const struct ublksrv_io_desc *iod = io->iod;
1546 : : uint8_t ublk_op;
1547 : :
1548 : 0 : io->result = iod->nr_sectors * (1ULL << LINUX_SECTOR_SHIFT);
1549 : 0 : ublk_op = ublksrv_get_op(iod);
1550 [ # # # ]: 0 : switch (ublk_op) {
1551 : 0 : case UBLK_IO_OP_READ:
1552 : 0 : ublk_io_get_buffer(io, iobuf_ch, read_get_buffer_done);
1553 : 0 : break;
1554 : 0 : case UBLK_IO_OP_WRITE:
1555 [ # # # # ]: 0 : if (g_ublk_tgt.user_copy) {
1556 : 0 : ublk_io_get_buffer(io, iobuf_ch, user_copy_write_get_buffer_done);
1557 : : } else {
1558 : 0 : _ublk_submit_bdev_io(q, io);
1559 : : }
1560 : 0 : break;
1561 : 0 : default:
1562 : 0 : _ublk_submit_bdev_io(q, io);
1563 : 0 : break;
1564 : : }
1565 : 0 : }
1566 : :
1567 : : static inline void
1568 : 0 : ublksrv_queue_io_cmd(struct ublk_queue *q,
1569 : : struct ublk_io *io, unsigned tag)
1570 : : {
1571 : : struct ublksrv_io_cmd *cmd;
1572 : : struct io_uring_sqe *sqe;
1573 : 0 : unsigned int cmd_op = 0;;
1574 : : uint64_t user_data;
1575 : 0 : struct spdk_ublk_dev *ublk = q->dev;
1576 : 0 : uint32_t ublk_idx = ublk->ublk_idx;
1577 : :
1578 : : /* each io should have operation of fetching or committing */
1579 [ # # # # : 0 : assert((io->cmd_op == UBLK_IO_FETCH_REQ) || (io->cmd_op == UBLK_IO_NEED_GET_DATA) ||
# # ]
1580 : : (io->cmd_op == UBLK_IO_COMMIT_AND_FETCH_REQ));
1581 : 0 : cmd_op = io->cmd_op;
1582 : :
1583 : 0 : sqe = io_uring_get_sqe(q->ring);
1584 [ # # ]: 0 : assert(sqe);
1585 : :
1586 : 0 : cmd = (struct ublksrv_io_cmd *)ublk_get_sqe_cmd(sqe);
1587 [ # # ]: 0 : if (cmd_op == UBLK_IO_COMMIT_AND_FETCH_REQ) {
1588 : 0 : cmd->result = io->result;
1589 : : }
1590 : :
1591 : : /* These fields should be written once, never change */
1592 : 0 : ublk_set_sqe_cmd_op(sqe, cmd_op);
1593 : 0 : sqe->opcode = IORING_OP_URING_CMD;
1594 : :
1595 [ # # # # ]: 0 : if (g_use_fixed_files) {
1596 : 0 : sqe->flags = IOSQE_FIXED_FILE;
1597 : 0 : sqe->fd = 0;
1598 : : } else {
1599 : 0 : sqe->flags = 0;
1600 : 0 : sqe->fd = ublk->cdev_fd;
1601 : : }
1602 : 0 : sqe->rw_flags = 0;
1603 : 0 : cmd->tag = tag;
1604 [ # # # # ]: 0 : cmd->addr = g_ublk_tgt.user_copy ? 0 : (__u64)(uintptr_t)(io->payload);
1605 : 0 : cmd->q_id = q->q_id;
1606 : :
1607 : 0 : user_data = build_user_data(tag, cmd_op, q->q_id, ublk_idx);
1608 : 0 : io_uring_sqe_set_data64(sqe, user_data);
1609 : :
1610 : 0 : io->cmd_op = 0;
1611 : :
1612 [ # # # # : 0 : SPDK_DEBUGLOG(ublk_io, "(qid %d tag %u cmd_op %u) iof %x stopping %d\n",
# # ]
1613 : : q->q_id, tag, cmd_op,
1614 : : io->cmd_op, q->is_stopping);
1615 : 0 : }
1616 : :
1617 : : static int
1618 : 0 : ublk_io_xmit(struct ublk_queue *q)
1619 : : {
1620 : 0 : TAILQ_HEAD(, ublk_io) buffer_free_list;
1621 : : struct spdk_iobuf_channel *iobuf_ch;
1622 : 0 : int rc = 0, count = 0;
1623 : : struct ublk_io *io;
1624 : :
1625 [ # # ]: 0 : if (TAILQ_EMPTY(&q->completed_io_list)) {
1626 : 0 : return 0;
1627 : : }
1628 : :
1629 : 0 : TAILQ_INIT(&buffer_free_list);
1630 [ # # ]: 0 : while (!TAILQ_EMPTY(&q->completed_io_list)) {
1631 : 0 : io = TAILQ_FIRST(&q->completed_io_list);
1632 [ # # ]: 0 : assert(io != NULL);
1633 : : /*
1634 : : * Remove IO from list now assuming it will be completed. It will be inserted
1635 : : * back to the head if it cannot be completed. This approach is specifically
1636 : : * taken to work around a scan-build use-after-free mischaracterization.
1637 : : */
1638 [ # # ]: 0 : TAILQ_REMOVE(&q->completed_io_list, io, tailq);
1639 [ # # # # ]: 0 : if (!io->user_copy) {
1640 [ # # # # ]: 0 : if (!io->need_data) {
1641 : 0 : TAILQ_INSERT_TAIL(&buffer_free_list, io, tailq);
1642 : : }
1643 : 0 : ublksrv_queue_io_cmd(q, io, io->tag);
1644 : : }
1645 : 0 : count++;
1646 : : }
1647 : :
1648 : 0 : q->cmd_inflight += count;
1649 : 0 : rc = io_uring_submit(q->ring);
1650 [ # # ]: 0 : if (rc != count) {
1651 : 0 : SPDK_ERRLOG("could not submit all commands\n");
1652 : 0 : assert(false);
1653 : : }
1654 : :
1655 : : /* Note: for READ io, ublk will always copy the data out of
1656 : : * the buffers in the io_uring_submit context. Since we
1657 : : * are not using SQPOLL for IO rings, we can safely free
1658 : : * those IO buffers here. This design doesn't seem ideal,
1659 : : * but it's what's possible since there is no discrete
1660 : : * COMMIT_REQ operation. That will need to change in the
1661 : : * future should we ever want to support async copy
1662 : : * operations.
1663 : : */
1664 : 0 : iobuf_ch = &q->poll_group->iobuf_ch;
1665 [ # # ]: 0 : while (!TAILQ_EMPTY(&buffer_free_list)) {
1666 : 0 : io = TAILQ_FIRST(&buffer_free_list);
1667 [ # # ]: 0 : TAILQ_REMOVE(&buffer_free_list, io, tailq);
1668 : 0 : ublk_io_put_buffer(io, iobuf_ch);
1669 : : }
1670 : 0 : return rc;
1671 : : }
1672 : :
1673 : : static void
1674 : 0 : write_get_buffer_done(struct ublk_io *io)
1675 : : {
1676 : 0 : io->need_data = true;
1677 : 0 : io->cmd_op = UBLK_IO_NEED_GET_DATA;
1678 : 0 : io->result = 0;
1679 : :
1680 [ # # ]: 0 : TAILQ_REMOVE(&io->q->inflight_io_list, io, tailq);
1681 : 0 : TAILQ_INSERT_TAIL(&io->q->completed_io_list, io, tailq);
1682 : 0 : }
1683 : :
1684 : : static int
1685 : 0 : ublk_io_uring_recv(struct ublk_poll_group *poll_group)
1686 : : {
1687 : : struct io_uring_cqe *cqe;
1688 : : unsigned head, tag;
1689 : 0 : int fetch, count = 0;
1690 : : struct ublk_io *io;
1691 : : struct spdk_iobuf_channel *iobuf_ch;
1692 : : unsigned __attribute__((unused)) cmd_op;
1693 : : struct spdk_ublk_dev __attribute__((unused)) *ublk;
1694 : : uint32_t __attribute__((unused)) dev_idx;
1695 : : uint32_t __attribute__((unused)) q_id;
1696 : 0 : struct io_uring *ring = &poll_group->ring;
1697 : : struct ublk_queue *q;
1698 : :
1699 : :
1700 [ # # # # : 0 : io_uring_for_each_cqe(ring, head, cqe) {
# # ]
1701 : 0 : tag = user_data_to_tag(cqe->user_data);
1702 : 0 : cmd_op = user_data_to_op(cqe->user_data);
1703 : 0 : dev_idx = user_data_to_ublk_idx(cqe->user_data);
1704 : 0 : ublk = ublk_device_lookup(dev_idx);
1705 : 0 : q_id = user_data_to_qid(cqe->user_data);
1706 : 0 : q = &ublk->queues[q_id];
1707 : :
1708 [ # # ]: 0 : if (q->cmd_inflight == 0) {
1709 : 0 : continue;
1710 : : }
1711 : :
1712 : 0 : iobuf_ch = &poll_group->iobuf_ch;
1713 : 0 : io = &q->ios[tag];
1714 : :
1715 [ # # # # : 0 : SPDK_DEBUGLOG(ublk_io, "res %d qid %d tag %u, user copy %u, cmd_op %u\n",
# # ]
1716 : : cqe->res, q->q_id, tag, io->user_copy, user_data_to_op(cqe->user_data));
1717 : :
1718 : 0 : q->cmd_inflight--;
1719 : 0 : TAILQ_INSERT_TAIL(&q->inflight_io_list, io, tailq);
1720 : :
1721 [ # # # # ]: 0 : if (!io->user_copy) {
1722 [ # # # # : 0 : fetch = (cqe->res != UBLK_IO_RES_ABORT) && !q->is_stopping;
# # ]
1723 [ # # ]: 0 : if (!fetch) {
1724 : 0 : q->is_stopping = true;
1725 [ # # ]: 0 : if (io->cmd_op == UBLK_IO_FETCH_REQ) {
1726 : 0 : io->cmd_op = 0;
1727 : : }
1728 : : }
1729 : :
1730 [ # # ]: 0 : if (cqe->res == UBLK_IO_RES_OK) {
1731 : 0 : ublk_submit_bdev_io(q, io);
1732 [ # # ]: 0 : } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) {
1733 : 0 : ublk_io_get_buffer(io, iobuf_ch, write_get_buffer_done);
1734 : : } else {
1735 [ # # ]: 0 : if (cqe->res != UBLK_IO_RES_ABORT) {
1736 : 0 : SPDK_ERRLOG("ublk received error io: res %d qid %d tag %u cmd_op %u\n",
1737 : : cqe->res, q->q_id, tag, user_data_to_op(cqe->user_data));
1738 : : }
1739 [ # # ]: 0 : TAILQ_REMOVE(&q->inflight_io_list, io, tailq);
1740 : : }
1741 : : } else {
1742 : :
1743 : : /* clear `user_copy` for next use of this IO structure */
1744 : 0 : io->user_copy = false;
1745 : :
1746 [ # # # # ]: 0 : assert((ublksrv_get_op(io->iod) == UBLK_IO_OP_READ) ||
1747 : : (ublksrv_get_op(io->iod) == UBLK_IO_OP_WRITE));
1748 [ # # ]: 0 : if (cqe->res != io->result) {
1749 : : /* EIO */
1750 : 0 : ublk_io_done(NULL, false, io);
1751 : : } else {
1752 [ # # ]: 0 : if (ublksrv_get_op(io->iod) == UBLK_IO_OP_READ) {
1753 : : /* bdev_io is already freed in first READ cycle */
1754 : 0 : ublk_io_done(NULL, true, io);
1755 : : } else {
1756 : 0 : _ublk_submit_bdev_io(q, io);
1757 : : }
1758 : : }
1759 : : }
1760 : 0 : count += 1;
1761 [ # # ]: 0 : if (count == UBLK_QUEUE_REQUEST) {
1762 : 0 : break;
1763 : : }
1764 : : }
1765 : :
1766 : 0 : io_uring_cq_advance(ring, count);
1767 : :
1768 : 0 : return count;
1769 : : }
1770 : :
1771 : :
1772 : : static int
1773 : 0 : ublk_poll(void *arg)
1774 : : {
1775 : 0 : struct ublk_poll_group *poll_group = arg;
1776 : : struct ublk_queue *q, *q_tmp;
1777 : 0 : int sent, received, count = 0;
1778 : :
1779 [ # # ]: 0 : TAILQ_FOREACH_SAFE(q, &poll_group->queue_list, tailq, q_tmp) {
1780 : 0 : sent = ublk_io_xmit(q);
1781 : 0 : received = ublk_io_uring_recv(poll_group);
1782 [ # # # # ]: 0 : if (spdk_unlikely(q->is_stopping)) {
1783 : 0 : ublk_try_close_queue(q);
1784 : : }
1785 : 0 : count += sent + received;
1786 : : }
1787 [ # # ]: 0 : if (count > 0) {
1788 : 0 : return SPDK_POLLER_BUSY;
1789 : : } else {
1790 : 0 : return SPDK_POLLER_IDLE;
1791 : : }
1792 : : }
1793 : :
1794 : : static void
1795 : 0 : ublk_bdev_hot_remove(struct spdk_ublk_dev *ublk)
1796 : : {
1797 : 0 : ublk_close_dev(ublk);
1798 : 0 : }
1799 : :
1800 : : static void
1801 : 0 : ublk_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
1802 : : void *event_ctx)
1803 : : {
1804 [ # # ]: 0 : switch (type) {
1805 : 0 : case SPDK_BDEV_EVENT_REMOVE:
1806 : 0 : ublk_bdev_hot_remove(event_ctx);
1807 : 0 : break;
1808 : 0 : default:
1809 : 0 : SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
1810 : 0 : break;
1811 : : }
1812 : 0 : }
1813 : :
1814 : : static void
1815 : 0 : ublk_dev_init_io_cmds(struct io_uring *r, uint32_t ring_sz)
1816 : : {
1817 : : struct io_uring_sqe *sqe;
1818 : : uint32_t i;
1819 : :
1820 [ # # ]: 0 : for (i = 0; i < ring_sz; i++) {
1821 : 0 : sqe = ublk_uring_get_sqe(r, i);
1822 : :
1823 : : /* These fields should be written once, never change */
1824 [ # # # # ]: 0 : if (g_use_fixed_files) {
1825 : 0 : sqe->flags = IOSQE_FIXED_FILE;
1826 : : } else {
1827 : 0 : sqe->flags = 0;
1828 : : }
1829 : 0 : sqe->rw_flags = 0;
1830 : 0 : sqe->ioprio = 0;
1831 : 0 : sqe->off = 0;
1832 : : }
1833 : 0 : }
1834 : :
1835 : : static inline void
1836 : : ublk_dev_queue_ring_deinit(struct ublk_queue *q)
1837 : : {
1838 : : q->ring = NULL;
1839 : : }
1840 : :
1841 : : static int
1842 : 0 : ublk_dev_queue_init(struct ublk_queue *q)
1843 : : {
1844 : 0 : int rc = 0, cmd_buf_size;
1845 : : uint32_t j;
1846 : 0 : struct spdk_ublk_dev *ublk = q->dev;
1847 : : unsigned long off;
1848 : :
1849 : 0 : cmd_buf_size = ublk_queue_cmd_buf_sz(q->q_depth);
1850 : 0 : off = UBLKSRV_CMD_BUF_OFFSET +
1851 : 0 : q->q_id * (UBLK_MAX_QUEUE_DEPTH * sizeof(struct ublksrv_io_desc));
1852 : 0 : q->io_cmd_buf = (struct ublksrv_io_desc *)mmap(0, cmd_buf_size, PROT_READ,
1853 : : MAP_SHARED | MAP_POPULATE, ublk->cdev_fd, off);
1854 [ # # ]: 0 : if (q->io_cmd_buf == MAP_FAILED) {
1855 : 0 : q->io_cmd_buf = NULL;
1856 : 0 : rc = -errno;
1857 : 0 : SPDK_ERRLOG("Failed at mmap: %s\n", spdk_strerror(-rc));
1858 : 0 : return rc;
1859 : : }
1860 : :
1861 [ # # ]: 0 : for (j = 0; j < q->q_depth; j++) {
1862 : 0 : q->ios[j].cmd_op = UBLK_IO_FETCH_REQ;
1863 : 0 : q->ios[j].iod = &q->io_cmd_buf[j];
1864 : : }
1865 : :
1866 : 0 : return 0;
1867 : : }
1868 : :
1869 : : static void
1870 : 0 : ublk_dev_queue_fini(struct ublk_queue *q)
1871 : : {
1872 [ # # ]: 0 : if (q->io_cmd_buf) {
1873 : 0 : munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q->q_depth));
1874 : : }
1875 : 0 : q->ring = NULL;
1876 : 0 : }
1877 : :
1878 : : static void
1879 : 0 : ublk_dev_queue_io_init(struct ublk_queue *q)
1880 : : {
1881 : : struct ublk_io *io;
1882 : : uint32_t i;
1883 : : int rc __attribute__((unused));
1884 : : void *buf;
1885 : :
1886 : : /* Some older kernels require a buffer to get posted, even
1887 : : * when NEED_GET_DATA has been specified. So allocate a
1888 : : * temporary buffer, only for purposes of this workaround.
1889 : : * It never actually gets used, so we will free it immediately
1890 : : * after all of the commands are posted.
1891 : : */
1892 : 0 : buf = malloc(64);
1893 : :
1894 [ # # ]: 0 : assert(q->bdev_ch != NULL);
1895 : :
1896 : : /* Initialize and submit all io commands to ublk driver */
1897 [ # # ]: 0 : for (i = 0; i < q->q_depth; i++) {
1898 : 0 : io = &q->ios[i];
1899 : 0 : io->tag = (uint16_t)i;
1900 : 0 : io->payload = buf;
1901 : 0 : io->bdev_ch = q->bdev_ch;
1902 : 0 : io->bdev_desc = q->dev->bdev_desc;
1903 : 0 : ublksrv_queue_io_cmd(q, io, i);
1904 : : }
1905 : :
1906 : 0 : q->cmd_inflight += q->q_depth;
1907 : 0 : rc = io_uring_submit(q->ring);
1908 [ # # ]: 0 : assert(rc == (int)q->q_depth);
1909 [ # # ]: 0 : for (i = 0; i < q->q_depth; i++) {
1910 : 0 : io = &q->ios[i];
1911 : 0 : io->payload = NULL;
1912 : : }
1913 : 0 : free(buf);
1914 : 0 : }
1915 : :
1916 : : static int
1917 : 0 : ublk_set_params(struct spdk_ublk_dev *ublk)
1918 : : {
1919 : : int rc;
1920 : :
1921 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_SET_PARAMS);
1922 [ # # ]: 0 : if (rc < 0) {
1923 : 0 : SPDK_ERRLOG("UBLK can't set params for dev %d, rc %s\n", ublk->ublk_id, spdk_strerror(-rc));
1924 : : }
1925 : :
1926 : 0 : return rc;
1927 : : }
1928 : :
1929 : : static void
1930 : 0 : ublk_dev_info_init(struct spdk_ublk_dev *ublk)
1931 : : {
1932 : 0 : struct ublksrv_ctrl_dev_info uinfo = {
1933 : 0 : .queue_depth = ublk->queue_depth,
1934 : 0 : .nr_hw_queues = ublk->num_queues,
1935 : 0 : .dev_id = ublk->ublk_id,
1936 : : .max_io_buf_bytes = UBLK_IO_MAX_BYTES,
1937 : 0 : .ublksrv_pid = getpid(),
1938 : : .flags = UBLK_F_URING_CMD_COMP_IN_TASK,
1939 : : };
1940 : :
1941 [ # # # # ]: 0 : if (g_ublk_tgt.user_copy) {
1942 : 0 : uinfo.flags |= UBLK_F_USER_COPY;
1943 : : } else {
1944 : 0 : uinfo.flags |= UBLK_F_NEED_GET_DATA;
1945 : : }
1946 : :
1947 [ # # # # ]: 0 : if (g_ublk_tgt.user_recovery) {
1948 : 0 : uinfo.flags |= UBLK_F_USER_RECOVERY;
1949 : 0 : uinfo.flags |= UBLK_F_USER_RECOVERY_REISSUE;
1950 : : }
1951 : :
1952 : 0 : ublk->dev_info = uinfo;
1953 : 0 : }
1954 : :
1955 : : /* Set ublk device parameters based on bdev */
1956 : : static void
1957 : 0 : ublk_info_param_init(struct spdk_ublk_dev *ublk)
1958 : : {
1959 : 0 : struct spdk_bdev *bdev = ublk->bdev;
1960 : 0 : uint32_t blk_size = spdk_bdev_get_data_block_size(bdev);
1961 : 0 : uint32_t pblk_size = spdk_bdev_get_physical_block_size(bdev);
1962 : 0 : uint32_t io_opt_blocks = spdk_bdev_get_optimal_io_boundary(bdev);
1963 : 0 : uint64_t num_blocks = spdk_bdev_get_num_blocks(bdev);
1964 : 0 : uint8_t sectors_per_block = blk_size >> LINUX_SECTOR_SHIFT;
1965 : 0 : uint32_t io_min_size = blk_size;
1966 : 0 : uint32_t io_opt_size = spdk_max(io_opt_blocks * blk_size, io_min_size);
1967 : :
1968 : 0 : struct ublk_params uparams = {
1969 : : .types = UBLK_PARAM_TYPE_BASIC,
1970 : : .len = sizeof(struct ublk_params),
1971 : : .basic = {
1972 : 0 : .logical_bs_shift = spdk_u32log2(blk_size),
1973 : 0 : .physical_bs_shift = spdk_u32log2(pblk_size),
1974 : 0 : .io_min_shift = spdk_u32log2(io_min_size),
1975 : 0 : .io_opt_shift = spdk_u32log2(io_opt_size),
1976 : 0 : .dev_sectors = num_blocks * sectors_per_block,
1977 : : .max_sectors = UBLK_IO_MAX_BYTES >> LINUX_SECTOR_SHIFT,
1978 : : }
1979 : : };
1980 : :
1981 [ # # ]: 0 : if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH)) {
1982 : 0 : uparams.basic.attrs = UBLK_ATTR_VOLATILE_CACHE;
1983 : : }
1984 : :
1985 [ # # ]: 0 : if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
1986 : 0 : uparams.types |= UBLK_PARAM_TYPE_DISCARD;
1987 : 0 : uparams.discard.discard_alignment = sectors_per_block;
1988 : 0 : uparams.discard.max_discard_sectors = num_blocks * sectors_per_block;
1989 : 0 : uparams.discard.max_discard_segments = 1;
1990 : 0 : uparams.discard.discard_granularity = blk_size;
1991 [ # # ]: 0 : if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
1992 : 0 : uparams.discard.max_write_zeroes_sectors = num_blocks * sectors_per_block;
1993 : : }
1994 : : }
1995 : :
1996 : 0 : ublk->dev_params = uparams;
1997 : 0 : }
1998 : :
1999 : : static void
2000 : 0 : _ublk_free_dev(void *arg)
2001 : : {
2002 : 0 : struct spdk_ublk_dev *ublk = arg;
2003 : :
2004 : 0 : ublk_free_dev(ublk);
2005 : 0 : }
2006 : :
2007 : : static void
2008 : 0 : free_buffers(void *arg)
2009 : : {
2010 : 0 : struct ublk_queue *q = arg;
2011 : : uint32_t i;
2012 : :
2013 [ # # ]: 0 : for (i = 0; i < q->q_depth; i++) {
2014 : 0 : ublk_io_put_buffer(&q->ios[i], &q->poll_group->iobuf_ch);
2015 : : }
2016 : 0 : free(q->ios);
2017 : 0 : q->ios = NULL;
2018 : 0 : spdk_thread_send_msg(spdk_thread_get_app_thread(), _ublk_free_dev, q->dev);
2019 : 0 : }
2020 : :
2021 : : static void
2022 : 0 : ublk_free_dev(struct spdk_ublk_dev *ublk)
2023 : : {
2024 : : struct ublk_queue *q;
2025 : : uint32_t q_idx;
2026 : :
2027 [ # # ]: 0 : for (q_idx = 0; q_idx < ublk->num_queues; q_idx++) {
2028 : 0 : q = &ublk->queues[q_idx];
2029 : :
2030 : : /* The ublk_io of this queue are not initialized. */
2031 [ # # ]: 0 : if (q->ios == NULL) {
2032 : 0 : continue;
2033 : : }
2034 : :
2035 : : /* We found a queue that has an ios array that may have buffers
2036 : : * that need to be freed. Send a message to the queue's thread
2037 : : * so it can free the buffers back to that thread's iobuf channel.
2038 : : * When it's done, it will set q->ios to NULL and send a message
2039 : : * back to this function to continue.
2040 : : */
2041 [ # # ]: 0 : if (q->poll_group) {
2042 : 0 : spdk_thread_send_msg(q->poll_group->ublk_thread, free_buffers, q);
2043 : 0 : return;
2044 : : } else {
2045 : 0 : free(q->ios);
2046 : 0 : q->ios = NULL;
2047 : : }
2048 : : }
2049 : :
2050 : : /* All of the buffers associated with the queues have been freed, so now
2051 : : * continue with releasing resources for the rest of the ublk device.
2052 : : */
2053 [ # # ]: 0 : if (ublk->bdev_desc) {
2054 : 0 : spdk_bdev_close(ublk->bdev_desc);
2055 : 0 : ublk->bdev_desc = NULL;
2056 : : }
2057 : :
2058 : 0 : ublk_dev_list_unregister(ublk);
2059 : 0 : SPDK_NOTICELOG("ublk dev %d stopped\n", ublk->ublk_id);
2060 : 0 : ublk_device_tbl_remove(ublk);
2061 : :
2062 : 0 : free(ublk);
2063 : : }
2064 : :
2065 : : static int
2066 : 0 : ublk_ios_init(struct spdk_ublk_dev *ublk)
2067 : : {
2068 : : int rc;
2069 : : uint32_t i, j;
2070 : : struct ublk_queue *q;
2071 : :
2072 [ # # ]: 0 : for (i = 0; i < ublk->num_queues; i++) {
2073 : 0 : q = &ublk->queues[i];
2074 : :
2075 : 0 : TAILQ_INIT(&q->completed_io_list);
2076 : 0 : TAILQ_INIT(&q->inflight_io_list);
2077 : 0 : q->dev = ublk;
2078 : 0 : q->q_id = i;
2079 : 0 : q->q_depth = ublk->queue_depth;
2080 : 0 : q->ios = calloc(q->q_depth, sizeof(struct ublk_io));
2081 [ # # ]: 0 : if (!q->ios) {
2082 : 0 : rc = -ENOMEM;
2083 : 0 : SPDK_ERRLOG("could not allocate queue ios\n");
2084 : 0 : goto err;
2085 : : }
2086 [ # # ]: 0 : for (j = 0; j < q->q_depth; j++) {
2087 : 0 : q->ios[j].q = q;
2088 : : }
2089 : : }
2090 : :
2091 : 0 : return 0;
2092 : :
2093 : 0 : err:
2094 [ # # ]: 0 : for (i = 0; i < ublk->num_queues; i++) {
2095 : 0 : free(q->ios);
2096 : 0 : q->ios = NULL;
2097 : : }
2098 : 0 : return rc;
2099 : : }
2100 : :
2101 : : static void
2102 : 0 : ublk_queue_recovery_done(void *arg)
2103 : : {
2104 : 0 : struct spdk_ublk_dev *ublk = arg;
2105 : :
2106 : 0 : ublk->online_num_queues++;
2107 [ # # # # : 0 : if (ublk->is_recovering && (ublk->online_num_queues == ublk->num_queues)) {
# # ]
2108 : 0 : ublk_ctrl_cmd_submit(ublk, UBLK_CMD_END_USER_RECOVERY);
2109 : : }
2110 : 0 : }
2111 : :
2112 : : static void
2113 : 0 : ublk_queue_run(void *arg1)
2114 : : {
2115 : 0 : struct ublk_queue *q = arg1;
2116 : 0 : struct spdk_ublk_dev *ublk = q->dev;
2117 : 0 : struct ublk_poll_group *poll_group = q->poll_group;
2118 : :
2119 [ # # ]: 0 : assert(spdk_get_thread() == poll_group->ublk_thread);
2120 : 0 : q->bdev_ch = spdk_bdev_get_io_channel(ublk->bdev_desc);
2121 : 0 : q->ring = &poll_group->ring;
2122 : :
2123 : : /* Queues must be filled with IO in the io pthread */
2124 : 0 : ublk_dev_queue_io_init(q);
2125 : :
2126 : 0 : TAILQ_INSERT_TAIL(&poll_group->queue_list, q, tailq);
2127 : 0 : spdk_thread_send_msg(spdk_thread_get_app_thread(), ublk_queue_recovery_done, ublk);
2128 : 0 : }
2129 : :
2130 : : int
2131 : 0 : ublk_start_disk(const char *bdev_name, uint32_t ublk_id,
2132 : : uint32_t num_queues, uint32_t queue_depth,
2133 : : ublk_ctrl_cb ctrl_cb, void *cb_arg)
2134 : : {
2135 : : int rc;
2136 : : struct spdk_bdev *bdev;
2137 : 0 : struct spdk_ublk_dev *ublk = NULL;
2138 : : uint32_t sector_per_block;
2139 : :
2140 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
2141 : :
2142 [ # # # # ]: 0 : if (g_ublk_tgt.active == false) {
2143 : 0 : SPDK_ERRLOG("NO ublk target exist\n");
2144 : 0 : return -ENODEV;
2145 : : }
2146 : :
2147 : 0 : ublk = ublk_dev_find_by_id(ublk_id);
2148 [ # # ]: 0 : if (ublk != NULL) {
2149 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk, "ublk id %d is in use.\n", ublk_id);
2150 : 0 : return -EBUSY;
2151 : : }
2152 : :
2153 [ # # ]: 0 : if (g_ublk_tgt.num_ublk_devs >= g_ublks_max) {
2154 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk, "Reached maximum number of supported devices: %u\n", g_ublks_max);
2155 : 0 : return -ENOTSUP;
2156 : : }
2157 : :
2158 : 0 : ublk = calloc(1, sizeof(*ublk));
2159 [ # # ]: 0 : if (ublk == NULL) {
2160 : 0 : return -ENOMEM;
2161 : : }
2162 : 0 : ublk->ctrl_cb = ctrl_cb;
2163 : 0 : ublk->cb_arg = cb_arg;
2164 : 0 : ublk->cdev_fd = -1;
2165 : 0 : ublk->ublk_id = ublk_id;
2166 [ # # # # ]: 0 : UBLK_DEBUGLOG(ublk, "bdev %s num_queues %d queue_depth %d\n",
2167 : : bdev_name, num_queues, queue_depth);
2168 : :
2169 : 0 : rc = spdk_bdev_open_ext(bdev_name, true, ublk_bdev_event_cb, ublk, &ublk->bdev_desc);
2170 [ # # ]: 0 : if (rc != 0) {
2171 : 0 : SPDK_ERRLOG("could not open bdev %s, error=%d\n", bdev_name, rc);
2172 : 0 : free(ublk);
2173 : 0 : return rc;
2174 : : }
2175 : :
2176 : 0 : bdev = spdk_bdev_desc_get_bdev(ublk->bdev_desc);
2177 : 0 : ublk->bdev = bdev;
2178 : 0 : sector_per_block = spdk_bdev_get_data_block_size(ublk->bdev) >> LINUX_SECTOR_SHIFT;
2179 : 0 : ublk->sector_per_block_shift = spdk_u32log2(sector_per_block);
2180 : :
2181 : 0 : ublk->queues_closed = 0;
2182 : 0 : ublk->num_queues = num_queues;
2183 : 0 : ublk->queue_depth = queue_depth;
2184 [ # # ]: 0 : if (ublk->queue_depth > UBLK_DEV_MAX_QUEUE_DEPTH) {
2185 : 0 : SPDK_WARNLOG("Set Queue depth %d of UBLK %d to maximum %d\n",
2186 : : ublk->queue_depth, ublk->ublk_id, UBLK_DEV_MAX_QUEUE_DEPTH);
2187 : 0 : ublk->queue_depth = UBLK_DEV_MAX_QUEUE_DEPTH;
2188 : : }
2189 [ # # ]: 0 : if (ublk->num_queues > UBLK_DEV_MAX_QUEUES) {
2190 : 0 : SPDK_WARNLOG("Set Queue num %d of UBLK %d to maximum %d\n",
2191 : : ublk->num_queues, ublk->ublk_id, UBLK_DEV_MAX_QUEUES);
2192 : 0 : ublk->num_queues = UBLK_DEV_MAX_QUEUES;
2193 : : }
2194 : : #if 0
2195 : : for (i = 0; i < ublk->num_queues; i++) {
2196 : : ublk->queues[i].ring.ring_fd = -1;
2197 : : }
2198 : : #endif
2199 : 0 : ublk_dev_info_init(ublk);
2200 : 0 : ublk_info_param_init(ublk);
2201 : 0 : rc = ublk_ios_init(ublk);
2202 [ # # ]: 0 : if (rc != 0) {
2203 : 0 : spdk_bdev_close(ublk->bdev_desc);
2204 : 0 : free(ublk);
2205 : 0 : return rc;
2206 : : }
2207 : :
2208 [ # # # # ]: 0 : SPDK_INFOLOG(ublk, "Enabling kernel access to bdev %s via ublk %d\n",
2209 : : bdev_name, ublk_id);
2210 : :
2211 : : /* Add ublk_dev to the end of disk list */
2212 : 0 : ublk_dev_list_register(ublk);
2213 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_ADD_DEV);
2214 [ # # ]: 0 : if (rc < 0) {
2215 : 0 : SPDK_ERRLOG("UBLK can't add dev %d, rc %s\n", ublk->ublk_id, spdk_strerror(-rc));
2216 : 0 : ublk_free_dev(ublk);
2217 : : }
2218 : :
2219 : 0 : return rc;
2220 : : }
2221 : :
2222 : : static int
2223 : 0 : ublk_start_dev(struct spdk_ublk_dev *ublk, bool is_recovering)
2224 : : {
2225 : : int rc;
2226 : : uint32_t q_id;
2227 : 0 : char buf[64];
2228 : : struct ublk_poll_group *poll_group;
2229 : :
2230 [ # # ]: 0 : snprintf(buf, 64, "%s%d", UBLK_BLK_CDEV, ublk->ublk_id);
2231 [ # # ]: 0 : ublk->cdev_fd = open(buf, O_RDWR);
2232 [ # # ]: 0 : if (ublk->cdev_fd < 0) {
2233 : 0 : rc = ublk->cdev_fd;
2234 : 0 : SPDK_ERRLOG("can't open %s, rc %d\n", buf, rc);
2235 : 0 : return rc;
2236 : : }
2237 : : /* Add ublk_dev to lookup table */
2238 : 0 : ublk_device_tbl_insert(ublk);
2239 : :
2240 [ # # ]: 0 : for (q_id = 0; q_id < ublk->num_queues; q_id++) {
2241 : 0 : rc = ublk_dev_queue_init(&ublk->queues[q_id]);
2242 [ # # ]: 0 : if (rc) {
2243 : 0 : return rc;
2244 : : }
2245 : : }
2246 : :
2247 [ # # ]: 0 : if (!is_recovering) {
2248 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_START_DEV);
2249 [ # # ]: 0 : if (rc < 0) {
2250 : 0 : SPDK_ERRLOG("start dev %d failed, rc %s\n", ublk->ublk_id,
2251 : : spdk_strerror(-rc));
2252 : 0 : return rc;
2253 : : }
2254 : : }
2255 : :
2256 [ # # ]: 0 : for (q_id = 0; q_id < ublk->num_queues; q_id++) {
2257 : 0 : poll_group = &g_ublk_tgt.poll_groups[g_next_ublk_poll_group];
2258 : 0 : ublk->queues[q_id].poll_group = poll_group;
2259 : :
2260 : : /* Setup the file descriptor */
2261 : 0 : ublk_add_fd_to_ring(poll_group, ublk);
2262 : 0 : g_next_ublk_poll_group++;
2263 [ # # ]: 0 : if (g_next_ublk_poll_group == g_num_ublk_poll_groups) {
2264 : 0 : g_next_ublk_poll_group = 0;
2265 : : }
2266 : : }
2267 [ # # ]: 0 : for (q_id = 0; q_id < ublk->num_queues; q_id++) {
2268 : 0 : poll_group = ublk->queues[q_id].poll_group;
2269 : 0 : spdk_thread_send_msg(poll_group->ublk_thread, ublk_queue_run, &ublk->queues[q_id]);
2270 : : }
2271 : :
2272 : 0 : return 0;
2273 : : }
2274 : :
2275 : : static int
2276 : 0 : ublk_ctrl_start_recovery(struct spdk_ublk_dev *ublk)
2277 : : {
2278 : : int rc;
2279 : : #if 0
2280 : : uint32_t i;
2281 : : #endif
2282 : :
2283 [ # # ]: 0 : if (ublk->ublk_id != ublk->dev_info.dev_id) {
2284 : 0 : SPDK_ERRLOG("Invalid ublk ID\n");
2285 : 0 : return -EINVAL;
2286 : : }
2287 : :
2288 : 0 : ublk->num_queues = ublk->dev_info.nr_hw_queues;
2289 : 0 : ublk->queue_depth = ublk->dev_info.queue_depth;
2290 : 0 : ublk->dev_info.ublksrv_pid = getpid();
2291 : :
2292 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk, "Recovering ublk %d, num queues %u, queue depth %u, flags 0x%llx\n",
2293 : : ublk->ublk_id,
2294 : : ublk->num_queues, ublk->queue_depth, ublk->dev_info.flags);
2295 : :
2296 : : #if 0
2297 : : for (i = 0; i < ublk->num_queues; i++) {
2298 : : ublk->queues[i].ring.ring_fd = -1;
2299 : : }
2300 : : #endif
2301 : :
2302 : 0 : ublk_info_param_init(ublk);
2303 : 0 : rc = ublk_ios_init(ublk);
2304 [ # # ]: 0 : if (rc != 0) {
2305 : 0 : return rc;
2306 : : }
2307 : :
2308 : 0 : ublk->is_recovering = true;
2309 : 0 : return ublk_ctrl_cmd_submit(ublk, UBLK_CMD_START_USER_RECOVERY);
2310 : : }
2311 : :
2312 : : int
2313 : 0 : ublk_start_disk_recovery(const char *bdev_name, uint32_t ublk_id, ublk_ctrl_cb ctrl_cb,
2314 : : void *cb_arg)
2315 : : {
2316 : : int rc;
2317 : : struct spdk_bdev *bdev;
2318 : 0 : struct spdk_ublk_dev *ublk = NULL;
2319 : : uint32_t sector_per_block;
2320 : :
2321 [ # # ]: 0 : assert(spdk_thread_is_app_thread(NULL));
2322 : :
2323 [ # # # # ]: 0 : if (g_ublk_tgt.active == false) {
2324 : 0 : SPDK_ERRLOG("NO ublk target exist\n");
2325 : 0 : return -ENODEV;
2326 : : }
2327 : :
2328 [ # # # # ]: 0 : if (!g_ublk_tgt.user_recovery) {
2329 : 0 : SPDK_ERRLOG("User recovery is enabled with kernel version >= 6.4\n");
2330 : 0 : return -ENOTSUP;
2331 : : }
2332 : :
2333 : 0 : ublk = ublk_dev_find_by_id(ublk_id);
2334 [ # # ]: 0 : if (ublk != NULL) {
2335 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk, "ublk id %d is in use.\n", ublk_id);
2336 : 0 : return -EBUSY;
2337 : : }
2338 : :
2339 [ # # ]: 0 : if (g_ublk_tgt.num_ublk_devs >= g_ublks_max) {
2340 [ # # # # ]: 0 : SPDK_DEBUGLOG(ublk, "Reached maximum number of supported devices: %u\n", g_ublks_max);
2341 : 0 : return -ENOTSUP;
2342 : : }
2343 : :
2344 : 0 : ublk = calloc(1, sizeof(*ublk));
2345 [ # # ]: 0 : if (ublk == NULL) {
2346 : 0 : return -ENOMEM;
2347 : : }
2348 : 0 : ublk->ctrl_cb = ctrl_cb;
2349 : 0 : ublk->cb_arg = cb_arg;
2350 : 0 : ublk->cdev_fd = -1;
2351 : 0 : ublk->ublk_id = ublk_id;
2352 : :
2353 : 0 : rc = spdk_bdev_open_ext(bdev_name, true, ublk_bdev_event_cb, ublk, &ublk->bdev_desc);
2354 [ # # ]: 0 : if (rc != 0) {
2355 : 0 : SPDK_ERRLOG("could not open bdev %s, error=%d\n", bdev_name, rc);
2356 : 0 : free(ublk);
2357 : 0 : return rc;
2358 : : }
2359 : :
2360 : 0 : bdev = spdk_bdev_desc_get_bdev(ublk->bdev_desc);
2361 : 0 : ublk->bdev = bdev;
2362 : 0 : sector_per_block = spdk_bdev_get_data_block_size(ublk->bdev) >> LINUX_SECTOR_SHIFT;
2363 : 0 : ublk->sector_per_block_shift = spdk_u32log2(sector_per_block);
2364 : :
2365 : 0 : SPDK_NOTICELOG("Recovering ublk %d with bdev %s\n", ublk->ublk_id, bdev_name);
2366 : :
2367 : 0 : ublk_dev_list_register(ublk);
2368 : 0 : rc = ublk_ctrl_cmd_submit(ublk, UBLK_CMD_GET_DEV_INFO);
2369 [ # # ]: 0 : if (rc < 0) {
2370 : 0 : ublk_free_dev(ublk);
2371 : : }
2372 : :
2373 : 0 : return rc;
2374 : : }
2375 : :
2376 : 476 : SPDK_LOG_REGISTER_COMPONENT(ublk)
2377 : 476 : SPDK_LOG_REGISTER_COMPONENT(ublk_io)
|