Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) croit GmbH.
3 : : * All rights reserved.
4 : : * Copyright (c) 2023 Enakta Labs
5 : : * All rights reserved.
6 : : */
7 : :
8 : : #include <sys/queue.h>
9 : :
10 : : #include "spdk/bdev.h"
11 : : #include "spdk/bdev_module.h"
12 : : #include "spdk/endian.h"
13 : : #include "spdk/env.h"
14 : : #include "spdk/json.h"
15 : : #include "spdk/thread.h"
16 : : #include "spdk/queue.h"
17 : : #include "spdk/string.h"
18 : : #include "spdk/stdinc.h"
19 : : #include "spdk/log.h"
20 : :
21 : : #include <daos.h>
22 : : #include <daos_event.h>
23 : : #include <daos_fs.h>
24 : : #include <daos_types.h>
25 : : #include <daos_pool.h>
26 : : #include <daos_cont.h>
27 : : #include <daos_errno.h>
28 : :
29 : : #include "bdev_daos.h"
30 : :
31 : : struct bdev_daos_task {
32 : : daos_event_t ev;
33 : : struct spdk_thread *submit_td;
34 : : struct spdk_bdev_io *bdev_io;
35 : :
36 : : int io_status;
37 : : uint64_t offset;
38 : :
39 : : /* DAOS version of iovec and scatter/gather */
40 : : daos_size_t read_size;
41 : : d_iov_t diovs[SPDK_BDEV_IO_NUM_CHILD_IOV];
42 : : d_sg_list_t sgl;
43 : : };
44 : :
45 : : struct bdev_daos {
46 : : struct spdk_bdev disk;
47 : : daos_oclass_id_t oclass;
48 : :
49 : : char pool_name[DAOS_PROP_MAX_LABEL_BUF_LEN];
50 : : char cont_name[DAOS_PROP_MAX_LABEL_BUF_LEN];
51 : :
52 : : struct bdev_daos_task *reset_task;
53 : : struct spdk_poller *reset_retry_timer;
54 : : };
55 : :
56 : : struct bdev_daos_io_channel {
57 : : struct bdev_daos *disk;
58 : : struct spdk_poller *poller;
59 : :
60 : : daos_handle_t pool;
61 : : daos_handle_t cont;
62 : :
63 : : dfs_t *dfs;
64 : : dfs_obj_t *obj;
65 : : daos_handle_t queue;
66 : : };
67 : :
68 : : static uint32_t g_bdev_daos_init_count = 0;
69 : : static pthread_mutex_t g_bdev_daos_init_mutex = PTHREAD_MUTEX_INITIALIZER;
70 : :
71 : : static int bdev_daos_initialize(void);
72 : :
73 : : static int bdev_daos_get_engine(void);
74 : : static int bdev_daos_put_engine(void);
75 : :
76 : : static int
77 : 274 : bdev_daos_get_ctx_size(void)
78 : : {
79 : 274 : return sizeof(struct bdev_daos_task);
80 : : }
81 : :
82 : : static struct spdk_bdev_module daos_if = {
83 : : .name = "daos",
84 : : .module_init = bdev_daos_initialize,
85 : : .get_ctx_size = bdev_daos_get_ctx_size,
86 : : };
87 : :
88 : 151 : SPDK_BDEV_MODULE_REGISTER(daos, &daos_if)
89 : :
90 : :
91 : : /* Convert DAOS errors to closest POSIX errno
92 : : * This is pretty much copy of daos_der2errno()
93 : : * from https://github.com/daos-stack/daos/blob/master/src/include/daos/common.h
94 : : * but unfortunately it's not exported in DAOS packages
95 : : */
96 : : static inline int
97 : 0 : daos2posix_errno(int err)
98 : : {
99 [ # # ]: 0 : if (err > 0) {
100 : 0 : return EINVAL;
101 : : }
102 : :
103 [ # # # # : 0 : switch (err) {
# # # # #
# # # # #
# # # # #
# # ]
104 : 0 : case -DER_SUCCESS:
105 : 0 : return 0;
106 : 0 : case -DER_NO_PERM:
107 : : case -DER_EP_RO:
108 : : case -DER_EP_OLD:
109 : 0 : return EPERM;
110 : 0 : case -DER_ENOENT:
111 : : case -DER_NONEXIST:
112 : 0 : return ENOENT;
113 : 0 : case -DER_INVAL:
114 : : case -DER_NOTYPE:
115 : : case -DER_NOSCHEMA:
116 : : case -DER_NOLOCAL:
117 : : case -DER_NO_HDL:
118 : : case -DER_IO_INVAL:
119 : 0 : return EINVAL;
120 : 0 : case -DER_KEY2BIG:
121 : : case -DER_REC2BIG:
122 : 0 : return E2BIG;
123 : 0 : case -DER_EXIST:
124 : 0 : return EEXIST;
125 : 0 : case -DER_UNREACH:
126 : 0 : return EHOSTUNREACH;
127 : 0 : case -DER_NOSPACE:
128 : 0 : return ENOSPC;
129 : 0 : case -DER_ALREADY:
130 : 0 : return EALREADY;
131 : 0 : case -DER_NOMEM:
132 : 0 : return ENOMEM;
133 : 0 : case -DER_TIMEDOUT:
134 : 0 : return ETIMEDOUT;
135 : 0 : case -DER_BUSY:
136 : : case -DER_EQ_BUSY:
137 : 0 : return EBUSY;
138 : 0 : case -DER_AGAIN:
139 : 0 : return EAGAIN;
140 : 0 : case -DER_PROTO:
141 : 0 : return EPROTO;
142 : 0 : case -DER_IO:
143 : 0 : return EIO;
144 : 0 : case -DER_CANCELED:
145 : : case DER_OP_CANCELED:
146 : 0 : return ECANCELED;
147 : 0 : case -DER_OVERFLOW:
148 : 0 : return EOVERFLOW;
149 : 0 : case -DER_BADPATH:
150 : : case -DER_NOTDIR:
151 : 0 : return ENOTDIR;
152 : 0 : case -DER_STALE:
153 : 0 : return ESTALE;
154 : 0 : case -DER_TX_RESTART:
155 : 0 : return ERESTART;
156 : 0 : default:
157 : 0 : return EIO;
158 : : }
159 : : };
160 : :
161 : : static void
162 : 0 : bdev_daos_free(struct bdev_daos *bdev_daos)
163 : : {
164 [ # # ]: 0 : if (!bdev_daos) {
165 : 0 : return;
166 : : }
167 : :
168 : 0 : free(bdev_daos->disk.name);
169 : 0 : free(bdev_daos);
170 : : }
171 : :
172 : : static void
173 : 0 : bdev_daos_destruct_cb(void *io_device)
174 : : {
175 : : int rc;
176 : 0 : struct bdev_daos *daos = io_device;
177 : :
178 [ # # ]: 0 : assert(daos != NULL);
179 : :
180 : 0 : bdev_daos_free(daos);
181 : :
182 : 0 : rc = bdev_daos_put_engine();
183 [ # # ]: 0 : if (rc) {
184 : 0 : SPDK_ERRLOG("could not de-initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
185 : : }
186 : 0 : }
187 : :
188 : : static int
189 : 0 : bdev_daos_destruct(void *ctx)
190 : : {
191 : 0 : struct bdev_daos *daos = ctx;
192 : :
193 : 0 : SPDK_NOTICELOG("%s: destroying bdev_daos device\n", daos->disk.name);
194 : :
195 : 0 : spdk_io_device_unregister(daos, bdev_daos_destruct_cb);
196 : :
197 : 0 : return 0;
198 : : }
199 : :
200 : : static void
201 : 0 : _bdev_daos_io_complete(void *bdev_daos_task)
202 : : {
203 : 0 : struct bdev_daos_task *task = bdev_daos_task;
204 : :
205 [ # # # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "completed IO at %#lx with status %s (errno=%d)\n",
206 : : task->offset, task->io_status ? "FAILURE" : "SUCCESS", task->io_status);
207 : :
208 [ # # ]: 0 : if (task->io_status == 0) {
209 : 0 : spdk_bdev_io_complete(spdk_bdev_io_from_ctx(task), SPDK_BDEV_IO_STATUS_SUCCESS);
210 : : } else {
211 : 0 : spdk_bdev_io_complete_aio_status(spdk_bdev_io_from_ctx(task), task->io_status);
212 : : }
213 : 0 : }
214 : :
215 : : static void
216 : 0 : bdev_daos_io_complete(struct spdk_bdev_io *bdev_io, int io_status)
217 : : {
218 : 0 : struct bdev_daos_task *task = (struct bdev_daos_task *)bdev_io->driver_ctx;
219 : 0 : struct spdk_thread *current_thread = spdk_get_thread();
220 : :
221 [ # # ]: 0 : assert(task->submit_td != NULL);
222 : :
223 : 0 : task->io_status = io_status;
224 [ # # ]: 0 : if (task->submit_td != current_thread) {
225 : 0 : spdk_thread_send_msg(task->submit_td, _bdev_daos_io_complete, task);
226 : : } else {
227 : 0 : _bdev_daos_io_complete(task);
228 : : }
229 : 0 : }
230 : :
231 : : static int64_t
232 : 0 : bdev_daos_writev(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
233 : : struct bdev_daos_task *task,
234 : : struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset)
235 : : {
236 : : int rc;
237 : :
238 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "write %d iovs size %lu to off: %#lx\n",
239 : : iovcnt, nbytes, offset);
240 : :
241 [ # # ]: 0 : assert(ch != NULL);
242 [ # # ]: 0 : assert(daos != NULL);
243 [ # # ]: 0 : assert(task != NULL);
244 [ # # ]: 0 : assert(iov != NULL);
245 : :
246 [ # # ]: 0 : if (iovcnt > SPDK_BDEV_IO_NUM_CHILD_IOV) {
247 : 0 : SPDK_ERRLOG("iovs number [%d] exceeds max allowed limit [%d]\n", iovcnt,
248 : : SPDK_BDEV_IO_NUM_CHILD_IOV);
249 : 0 : return -E2BIG;
250 : : }
251 : :
252 [ # # ]: 0 : if ((rc = daos_event_init(&task->ev, ch->queue, NULL))) {
253 : 0 : SPDK_ERRLOG("%s: could not initialize async event: " DF_RC "\n",
254 : : daos->disk.name, DP_RC(rc));
255 : 0 : return -daos2posix_errno(rc);
256 : : }
257 : :
258 [ # # ]: 0 : for (int i = 0; i < iovcnt; i++, iov++) {
259 : 0 : d_iov_set(&(task->diovs[i]), iov->iov_base, iov->iov_len);
260 : : }
261 : :
262 : 0 : task->sgl.sg_nr = iovcnt;
263 : 0 : task->sgl.sg_nr_out = 0;
264 : 0 : task->sgl.sg_iovs = task->diovs;
265 : 0 : task->offset = offset;
266 : :
267 [ # # ]: 0 : if ((rc = dfs_write(ch->dfs, ch->obj, &task->sgl, offset, &task->ev))) {
268 : 0 : SPDK_ERRLOG("%s: could not start async write: %s\n",
269 : : daos->disk.name, strerror(rc));
270 : 0 : daos_event_fini(&task->ev);
271 : 0 : return -rc;
272 : : }
273 : :
274 : 0 : return nbytes;
275 : : }
276 : :
277 : : static int64_t
278 : 0 : bdev_daos_readv(struct bdev_daos *daos, struct bdev_daos_io_channel *ch,
279 : : struct bdev_daos_task *task,
280 : : struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset)
281 : : {
282 : : int rc;
283 : :
284 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "read %d iovs size %lu to off: %#lx\n",
285 : : iovcnt, nbytes, offset);
286 : :
287 [ # # ]: 0 : assert(ch != NULL);
288 [ # # ]: 0 : assert(daos != NULL);
289 [ # # ]: 0 : assert(task != NULL);
290 [ # # ]: 0 : assert(iov != NULL);
291 : :
292 [ # # ]: 0 : if (iovcnt > SPDK_BDEV_IO_NUM_CHILD_IOV) {
293 : 0 : SPDK_ERRLOG("iovs number [%d] exceeds max allowed limit [%d]\n", iovcnt,
294 : : SPDK_BDEV_IO_NUM_CHILD_IOV);
295 : 0 : return -E2BIG;
296 : : }
297 : :
298 [ # # ]: 0 : if ((rc = daos_event_init(&task->ev, ch->queue, NULL))) {
299 : 0 : SPDK_ERRLOG("%s: could not initialize async event: " DF_RC "\n",
300 : : daos->disk.name, DP_RC(rc));
301 : 0 : return -daos2posix_errno(rc);
302 : : }
303 : :
304 [ # # ]: 0 : for (int i = 0; i < iovcnt; i++, iov++) {
305 : 0 : d_iov_set(&(task->diovs[i]), iov->iov_base, iov->iov_len);
306 : : }
307 : :
308 : 0 : task->sgl.sg_nr = iovcnt;
309 : 0 : task->sgl.sg_nr_out = 0;
310 : 0 : task->sgl.sg_iovs = task->diovs;
311 : 0 : task->offset = offset;
312 : :
313 [ # # ]: 0 : if ((rc = dfs_read(ch->dfs, ch->obj, &task->sgl, offset, &task->read_size, &task->ev))) {
314 : 0 : SPDK_ERRLOG("%s: could not start async read: %s\n",
315 : : daos->disk.name, strerror(rc));
316 : 0 : daos_event_fini(&task->ev);
317 : 0 : return -rc;
318 : : }
319 : :
320 : 0 : return nbytes;
321 : : }
322 : :
323 : : static void
324 : 0 : bdev_daos_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
325 : : bool success)
326 : : {
327 : : int64_t rc;
328 : 0 : struct bdev_daos_io_channel *dch = spdk_io_channel_get_ctx(ch);
329 : :
330 [ # # ]: 0 : if (!success) {
331 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
332 : 0 : return;
333 : : }
334 : :
335 : 0 : rc = bdev_daos_readv((struct bdev_daos *)bdev_io->bdev->ctxt,
336 : : dch,
337 : 0 : (struct bdev_daos_task *)bdev_io->driver_ctx,
338 : : bdev_io->u.bdev.iovs,
339 : : bdev_io->u.bdev.iovcnt,
340 : 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
341 : 0 : bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
342 : :
343 [ # # ]: 0 : if (rc < 0) {
344 : 0 : spdk_bdev_io_complete_aio_status(bdev_io, rc);
345 : 0 : return;
346 : : }
347 : : }
348 : :
349 : : static void
350 : 0 : _bdev_daos_get_io_inflight(struct spdk_io_channel_iter *i)
351 : : {
352 : 0 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
353 : 0 : struct bdev_daos_io_channel *dch = spdk_io_channel_get_ctx(ch);
354 : 0 : int io_inflight = daos_eq_query(dch->queue, DAOS_EQR_WAITING, 0, NULL);
355 : :
356 [ # # ]: 0 : if (io_inflight > 0) {
357 : 0 : spdk_for_each_channel_continue(i, -1);
358 : 0 : return;
359 : : }
360 : :
361 : 0 : spdk_for_each_channel_continue(i, 0);
362 : : }
363 : :
364 : : static int bdev_daos_reset_retry_timer(void *arg);
365 : :
366 : : static void
367 : 0 : _bdev_daos_get_io_inflight_done(struct spdk_io_channel_iter *i, int status)
368 : : {
369 : 0 : struct bdev_daos *daos = spdk_io_channel_iter_get_ctx(i);
370 : :
371 [ # # ]: 0 : if (status == -1) {
372 : 0 : daos->reset_retry_timer = SPDK_POLLER_REGISTER(bdev_daos_reset_retry_timer, daos, 1000);
373 : 0 : return;
374 : : }
375 : :
376 : 0 : spdk_bdev_io_complete(spdk_bdev_io_from_ctx(daos->reset_task), SPDK_BDEV_IO_STATUS_SUCCESS);
377 : : }
378 : :
379 : : static int
380 : 0 : bdev_daos_reset_retry_timer(void *arg)
381 : : {
382 : 0 : struct bdev_daos *daos = arg;
383 : :
384 [ # # ]: 0 : if (daos->reset_retry_timer) {
385 : 0 : spdk_poller_unregister(&daos->reset_retry_timer);
386 : : }
387 : :
388 : 0 : spdk_for_each_channel(daos,
389 : : _bdev_daos_get_io_inflight,
390 : : daos,
391 : : _bdev_daos_get_io_inflight_done);
392 : :
393 : 0 : return SPDK_POLLER_BUSY;
394 : : }
395 : :
396 : : static void
397 : 0 : bdev_daos_reset(struct bdev_daos *daos, struct bdev_daos_task *task)
398 : : {
399 [ # # ]: 0 : assert(daos != NULL);
400 [ # # ]: 0 : assert(task != NULL);
401 : :
402 : 0 : daos->reset_task = task;
403 : 0 : bdev_daos_reset_retry_timer(daos);
404 : 0 : }
405 : :
406 : :
407 : : static int64_t
408 : 0 : bdev_daos_unmap(struct bdev_daos_io_channel *ch, uint64_t nbytes,
409 : : uint64_t offset)
410 : : {
411 : 0 : int rc = 0;
412 : :
413 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "unmap at %#lx with size %#lx\n", offset, nbytes);
414 [ # # ]: 0 : if ((rc = dfs_punch(ch->dfs, ch->obj, offset, nbytes))) {
415 : 0 : return -rc;
416 : : }
417 : 0 : return 0;
418 : : }
419 : :
420 : : static void
421 : 0 : _bdev_daos_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
422 : : {
423 : 0 : struct bdev_daos_io_channel *dch = spdk_io_channel_get_ctx(ch);
424 : :
425 : : int64_t rc;
426 [ # # # # : 0 : switch (bdev_io->type) {
# # ]
427 : 0 : case SPDK_BDEV_IO_TYPE_READ:
428 : 0 : spdk_bdev_io_get_buf(bdev_io, bdev_daos_get_buf_cb,
429 : 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
430 : 0 : break;
431 : :
432 : 0 : case SPDK_BDEV_IO_TYPE_WRITE:
433 : 0 : rc = bdev_daos_writev((struct bdev_daos *)bdev_io->bdev->ctxt,
434 : : dch,
435 : 0 : (struct bdev_daos_task *)bdev_io->driver_ctx,
436 : : bdev_io->u.bdev.iovs,
437 : : bdev_io->u.bdev.iovcnt,
438 : 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
439 : 0 : bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
440 [ # # ]: 0 : if (rc < 0) {
441 : 0 : spdk_bdev_io_complete_aio_status(bdev_io, rc);
442 : 0 : return;
443 : : }
444 : 0 : break;
445 : :
446 : 0 : case SPDK_BDEV_IO_TYPE_RESET:
447 : : /* Can't cancel in-flight requests, but can wait for their completions */
448 : 0 : bdev_daos_reset((struct bdev_daos *)bdev_io->bdev->ctxt,
449 : 0 : (struct bdev_daos_task *)bdev_io->driver_ctx);
450 : 0 : break;
451 : :
452 : 0 : case SPDK_BDEV_IO_TYPE_FLUSH:
453 : : /* NOOP because DAOS requests land on PMEM and writes are persistent upon completion */
454 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
455 : 0 : break;
456 : :
457 : 0 : case SPDK_BDEV_IO_TYPE_UNMAP:
458 : 0 : rc = bdev_daos_unmap(dch,
459 : 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
460 : 0 : bdev_io->u.bdev.offset_blocks * bdev_io->bdev->blocklen);
461 [ # # ]: 0 : if (!rc) {
462 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
463 : : } else {
464 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "%s: could not unmap: %s",
465 : : dch->disk->disk.name, strerror(-rc));
466 : 0 : spdk_bdev_io_complete_aio_status(bdev_io, rc);
467 : : }
468 : :
469 : 0 : break;
470 : :
471 : 0 : default:
472 : 0 : SPDK_ERRLOG("Wrong io type\n");
473 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
474 : 0 : break;
475 : : }
476 : : }
477 : :
478 : : static void
479 : 0 : bdev_daos_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
480 : : {
481 : 0 : struct bdev_daos_task *task = (struct bdev_daos_task *)bdev_io->driver_ctx;
482 : 0 : struct spdk_thread *submit_td = spdk_io_channel_get_thread(ch);
483 : :
484 [ # # ]: 0 : assert(task != NULL);
485 : :
486 : 0 : task->submit_td = submit_td;
487 : 0 : task->bdev_io = bdev_io;
488 : :
489 : 0 : _bdev_daos_submit_request(ch, bdev_io);
490 : 0 : }
491 : :
492 : : #define POLLING_EVENTS_NUM 64
493 : :
494 : : static int
495 : 0 : bdev_daos_channel_poll(void *arg)
496 : : {
497 : 0 : daos_event_t *evp[POLLING_EVENTS_NUM];
498 : 0 : struct bdev_daos_io_channel *ch = arg;
499 : :
500 [ # # ]: 0 : assert(ch != NULL);
501 [ # # ]: 0 : assert(ch->disk != NULL);
502 : :
503 : 0 : int rc = daos_eq_poll(ch->queue, 0, DAOS_EQ_NOWAIT,
504 : : POLLING_EVENTS_NUM, evp);
505 : :
506 [ # # ]: 0 : if (rc < 0) {
507 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "%s: could not poll daos event queue: " DF_RC "\n",
508 : : ch->disk->disk.name, DP_RC(rc));
509 : : /*
510 : : * TODO: There are cases when this is self healing, e.g.
511 : : * brief network issues, DAOS agent restarting etc.
512 : : * However, if the issue persists over some time better would be
513 : : * to remove a bdev or the whole controller
514 : : */
515 : 0 : return SPDK_POLLER_BUSY;
516 : : }
517 : :
518 [ # # ]: 0 : for (int i = 0; i < rc; ++i) {
519 : 0 : int status = 0;
520 : 0 : struct bdev_daos_task *task = SPDK_CONTAINEROF(evp[i], struct bdev_daos_task, ev);
521 : :
522 [ # # ]: 0 : assert(task != NULL);
523 : :
524 [ # # ]: 0 : if (task->ev.ev_error != DER_SUCCESS) {
525 : 0 : status = -task->ev.ev_error;
526 : : }
527 : :
528 : 0 : daos_event_fini(&task->ev);
529 : 0 : bdev_daos_io_complete(task->bdev_io, status);
530 : : }
531 : :
532 : 0 : return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
533 : : }
534 : :
535 : : static bool
536 : 0 : bdev_daos_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
537 : : {
538 [ # # ]: 0 : switch (io_type) {
539 : 0 : case SPDK_BDEV_IO_TYPE_READ:
540 : : case SPDK_BDEV_IO_TYPE_WRITE:
541 : : case SPDK_BDEV_IO_TYPE_RESET:
542 : : case SPDK_BDEV_IO_TYPE_FLUSH:
543 : : case SPDK_BDEV_IO_TYPE_UNMAP:
544 : 0 : return true;
545 : :
546 : 0 : default:
547 : 0 : return false;
548 : : }
549 : : }
550 : :
551 : : static struct spdk_io_channel *
552 : 0 : bdev_daos_get_io_channel(void *ctx)
553 : : {
554 : 0 : return spdk_get_io_channel(ctx);
555 : : }
556 : :
557 : : static void
558 : 0 : bdev_daos_write_json_config(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
559 : : {
560 : 0 : struct bdev_daos *daos = bdev->ctxt;
561 : :
562 : 0 : spdk_json_write_object_begin(w);
563 : :
564 : 0 : spdk_json_write_named_string(w, "method", "bdev_daos_create");
565 : :
566 : 0 : spdk_json_write_named_object_begin(w, "params");
567 : 0 : spdk_json_write_named_string(w, "name", bdev->name);
568 : 0 : spdk_json_write_named_string(w, "pool", daos->pool_name);
569 : 0 : spdk_json_write_named_string(w, "cont", daos->cont_name);
570 : 0 : spdk_json_write_named_uint64(w, "num_blocks", bdev->blockcnt);
571 : 0 : spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
572 : 0 : spdk_json_write_named_uuid(w, "uuid", &bdev->uuid);
573 : :
574 : 0 : spdk_json_write_object_end(w);
575 : :
576 : 0 : spdk_json_write_object_end(w);
577 : 0 : }
578 : :
579 : : static const struct spdk_bdev_fn_table daos_fn_table = {
580 : : .destruct = bdev_daos_destruct,
581 : : .submit_request = bdev_daos_submit_request,
582 : : .io_type_supported = bdev_daos_io_type_supported,
583 : : .get_io_channel = bdev_daos_get_io_channel,
584 : : .write_config_json = bdev_daos_write_json_config,
585 : : };
586 : :
587 : : static int
588 : 0 : bdev_daos_io_channel_setup_daos(struct bdev_daos_io_channel *ch)
589 : : {
590 : 0 : int rc = 0;
591 : 0 : struct bdev_daos *daos = ch->disk;
592 : 0 : daos_pool_info_t pinfo;
593 : 0 : daos_cont_info_t cinfo;
594 : :
595 : 0 : int fd_oflag = O_CREAT | O_RDWR;
596 : 0 : mode_t mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
597 : :
598 : 0 : rc = bdev_daos_get_engine();
599 [ # # ]: 0 : if (rc) {
600 : 0 : SPDK_ERRLOG("could not initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
601 : 0 : return -daos2posix_errno(rc);
602 : : }
603 : :
604 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "connecting to daos pool '%s'\n", daos->pool_name);
605 [ # # ]: 0 : if ((rc = daos_pool_connect(daos->pool_name, NULL, DAOS_PC_RW, &ch->pool, &pinfo, NULL))) {
606 : 0 : SPDK_ERRLOG("%s: could not connect to daos pool: " DF_RC "\n",
607 : : daos->disk.name, DP_RC(rc));
608 : 0 : return -daos2posix_errno(rc);
609 : : }
610 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "connecting to daos container '%s'\n", daos->cont_name);
611 [ # # ]: 0 : if ((rc = daos_cont_open(ch->pool, daos->cont_name, DAOS_COO_RW, &ch->cont, &cinfo, NULL))) {
612 : 0 : SPDK_ERRLOG("%s: could not open daos container: " DF_RC "\n",
613 : : daos->disk.name, DP_RC(rc));
614 : 0 : rc = daos2posix_errno(rc);
615 : 0 : goto cleanup_pool;
616 : : }
617 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "mounting daos dfs\n");
618 [ # # ]: 0 : if ((rc = dfs_mount(ch->pool, ch->cont, O_RDWR, &ch->dfs))) {
619 : 0 : SPDK_ERRLOG("%s: could not mount daos dfs: %s\n", daos->disk.name, strerror(rc));
620 : 0 : goto cleanup_cont;
621 : : }
622 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "opening dfs object\n");
623 [ # # ]: 0 : if ((rc = dfs_open(ch->dfs, NULL, daos->disk.name, mode, fd_oflag, daos->oclass,
624 : : 0, NULL, &ch->obj))) {
625 : 0 : SPDK_ERRLOG("%s: could not open dfs object: %s\n", daos->disk.name, strerror(rc));
626 : 0 : goto cleanup_mount;
627 : : }
628 [ # # ]: 0 : if ((rc = daos_eq_create(&ch->queue))) {
629 : 0 : SPDK_ERRLOG("%s: could not create daos event queue: " DF_RC "\n",
630 : : daos->disk.name, DP_RC(rc));
631 : 0 : rc = daos2posix_errno(rc);
632 : 0 : goto cleanup_obj;
633 : : }
634 : :
635 : 0 : return 0;
636 : :
637 : 0 : cleanup_obj:
638 : 0 : dfs_release(ch->obj);
639 : 0 : cleanup_mount:
640 : 0 : dfs_umount(ch->dfs);
641 : 0 : cleanup_cont:
642 : 0 : daos_cont_close(ch->cont, NULL);
643 : 0 : cleanup_pool:
644 : 0 : daos_pool_disconnect(ch->pool, NULL);
645 : :
646 : 0 : return -rc;
647 : : }
648 : :
649 : : static int
650 : 0 : bdev_daos_io_channel_create_cb(void *io_device, void *ctx_buf)
651 : : {
652 : : int rc;
653 : 0 : struct bdev_daos_io_channel *ch = ctx_buf;
654 : :
655 : 0 : ch->disk = io_device;
656 : :
657 [ # # ]: 0 : if ((rc = bdev_daos_io_channel_setup_daos(ch))) {
658 : 0 : return rc;
659 : : }
660 : :
661 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "%s: starting daos event queue poller\n",
662 : : ch->disk->disk.name);
663 : :
664 : 0 : ch->poller = SPDK_POLLER_REGISTER(bdev_daos_channel_poll, ch, 0);
665 : :
666 : 0 : return 0;
667 : : }
668 : :
669 : : static void
670 : 0 : bdev_daos_io_channel_destroy_cb(void *io_device, void *ctx_buf)
671 : : {
672 : : int rc;
673 : 0 : struct bdev_daos_io_channel *ch = ctx_buf;
674 : :
675 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "stopping daos event queue poller\n");
676 : :
677 : 0 : spdk_poller_unregister(&ch->poller);
678 : :
679 [ # # ]: 0 : if ((rc = daos_eq_destroy(ch->queue, DAOS_EQ_DESTROY_FORCE))) {
680 : 0 : SPDK_ERRLOG("could not destroy daos event queue: " DF_RC "\n", DP_RC(rc));
681 : : }
682 [ # # ]: 0 : if ((rc = dfs_release(ch->obj))) {
683 : 0 : SPDK_ERRLOG("could not release dfs object: %s\n", strerror(rc));
684 : : }
685 [ # # ]: 0 : if ((rc = dfs_umount(ch->dfs))) {
686 : 0 : SPDK_ERRLOG("could not unmount dfs: %s\n", strerror(rc));
687 : : }
688 [ # # ]: 0 : if ((rc = daos_cont_close(ch->cont, NULL))) {
689 : 0 : SPDK_ERRLOG("could not close container: " DF_RC "\n", DP_RC(rc));
690 : : }
691 [ # # ]: 0 : if ((rc = daos_pool_disconnect(ch->pool, NULL))) {
692 : 0 : SPDK_ERRLOG("could not disconnect from pool: " DF_RC "\n", DP_RC(rc));
693 : : }
694 : 0 : rc = bdev_daos_put_engine();
695 [ # # ]: 0 : if (rc) {
696 : 0 : SPDK_ERRLOG("could not de-initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
697 : : }
698 : 0 : }
699 : :
700 : : int
701 : 0 : create_bdev_daos(struct spdk_bdev **bdev,
702 : : const char *name, const struct spdk_uuid *uuid,
703 : : const char *pool, const char *cont, const char *oclass,
704 : : uint64_t num_blocks, uint32_t block_size)
705 : : {
706 : : int rc;
707 : : size_t len;
708 : : struct bdev_daos *daos;
709 : 0 : struct bdev_daos_io_channel ch = {};
710 : :
711 : 0 : SPDK_NOTICELOG("%s: creating bdev_daos disk on '%s:%s'\n", name, pool, cont);
712 : :
713 [ # # ]: 0 : if (num_blocks == 0) {
714 : 0 : SPDK_ERRLOG("Disk num_blocks must be greater than 0");
715 : 0 : return -EINVAL;
716 : : }
717 : :
718 [ # # ]: 0 : if (block_size % 512) {
719 : 0 : SPDK_ERRLOG("block size must be 512 bytes aligned\n");
720 : 0 : return -EINVAL;
721 : : }
722 : :
723 [ # # ]: 0 : if (!name) {
724 : 0 : SPDK_ERRLOG("device name cannot be empty\n");
725 : 0 : return -EINVAL;
726 : : }
727 : :
728 [ # # ]: 0 : if (!pool) {
729 : 0 : SPDK_ERRLOG("daos pool cannot be empty\n");
730 : 0 : return -EINVAL;
731 : : }
732 [ # # ]: 0 : if (!cont) {
733 : 0 : SPDK_ERRLOG("daos cont cannot be empty\n");
734 : 0 : return -EINVAL;
735 : : }
736 : :
737 : 0 : daos = calloc(1, sizeof(*daos));
738 [ # # ]: 0 : if (!daos) {
739 : 0 : SPDK_ERRLOG("calloc() failed\n");
740 : 0 : return -ENOMEM;
741 : : }
742 : :
743 [ # # ]: 0 : if (!oclass) {
744 : 0 : oclass = "SX"; /* Max throughput by default */
745 : : }
746 : 0 : daos->oclass = daos_oclass_name2id(oclass);
747 [ # # ]: 0 : if (daos->oclass == OC_UNKNOWN) {
748 : 0 : SPDK_ERRLOG("could not parse daos oclass: '%s'\n", oclass);
749 : 0 : free(daos);
750 : 0 : return -EINVAL;
751 : : }
752 : :
753 : 0 : len = strlen(pool);
754 [ # # ]: 0 : if (len > DAOS_PROP_LABEL_MAX_LEN) {
755 : 0 : SPDK_ERRLOG("daos pool name is too long\n");
756 : 0 : free(daos);
757 : 0 : return -EINVAL;
758 : : }
759 : 0 : memcpy(daos->pool_name, pool, len);
760 : :
761 : 0 : len = strlen(cont);
762 [ # # ]: 0 : if (len > DAOS_PROP_LABEL_MAX_LEN) {
763 : 0 : SPDK_ERRLOG("daos cont name is too long\n");
764 : 0 : free(daos);
765 : 0 : return -EINVAL;
766 : : }
767 : 0 : memcpy(daos->cont_name, cont, len);
768 : :
769 : 0 : daos->disk.name = strdup(name);
770 : 0 : daos->disk.product_name = "DAOS bdev";
771 : :
772 : 0 : daos->disk.write_cache = 0;
773 : 0 : daos->disk.blocklen = block_size;
774 : 0 : daos->disk.blockcnt = num_blocks;
775 : 0 : daos->disk.uuid = *uuid;
776 : 0 : daos->disk.max_num_segments = SPDK_BDEV_IO_NUM_CHILD_IOV;
777 : :
778 : 0 : daos->disk.ctxt = daos;
779 : 0 : daos->disk.fn_table = &daos_fn_table;
780 : 0 : daos->disk.module = &daos_if;
781 : :
782 : 0 : rc = bdev_daos_get_engine();
783 [ # # ]: 0 : if (rc) {
784 : 0 : SPDK_ERRLOG("could not initialize DAOS engine: " DF_RC "\n", DP_RC(rc));
785 : 0 : bdev_daos_free(daos);
786 : 0 : return -daos2posix_errno(rc);
787 : : }
788 : :
789 : : /* We try to connect to the DAOS container during channel creation, so simulate
790 : : * creating a channel here, so that we can return a failure when the DAOS bdev
791 : : * is created, instead of finding it out later when the first channel is created
792 : : * and leaving unusable bdev registered.
793 : : */
794 : 0 : rc = bdev_daos_io_channel_create_cb(daos, &ch);
795 [ # # ]: 0 : if (rc) {
796 : 0 : SPDK_ERRLOG("'%s' could not initialize io-channel: %s\n", name, strerror(-rc));
797 : 0 : bdev_daos_free(daos);
798 : 0 : return rc;
799 : : }
800 : 0 : bdev_daos_io_channel_destroy_cb(daos, &ch);
801 : :
802 : 0 : spdk_io_device_register(daos, bdev_daos_io_channel_create_cb,
803 : : bdev_daos_io_channel_destroy_cb,
804 : : sizeof(struct bdev_daos_io_channel),
805 : 0 : daos->disk.name);
806 : :
807 : :
808 : 0 : rc = spdk_bdev_register(&daos->disk);
809 [ # # ]: 0 : if (rc) {
810 : 0 : spdk_io_device_unregister(daos, NULL);
811 : 0 : bdev_daos_free(daos);
812 : 0 : return rc;
813 : : }
814 : :
815 : 0 : *bdev = &(daos->disk);
816 : :
817 : 0 : return rc;
818 : : }
819 : :
820 : : static void
821 : 0 : dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
822 : : {
823 : 0 : }
824 : :
825 : : int
826 : 0 : bdev_daos_resize(const char *name, const uint64_t new_size_in_mb)
827 : : {
828 : 0 : int rc = 0;
829 : 0 : struct spdk_bdev_desc *desc;
830 : : struct spdk_bdev *bdev;
831 : : struct spdk_io_channel *ch;
832 : : struct bdev_daos_io_channel *dch;
833 : : uint64_t new_size_in_byte;
834 : : uint64_t current_size_in_mb;
835 : :
836 : 0 : rc = spdk_bdev_open_ext(name, false, dummy_bdev_event_cb, NULL, &desc);
837 [ # # ]: 0 : if (rc != 0) {
838 : 0 : return rc;
839 : : }
840 : :
841 : 0 : bdev = spdk_bdev_desc_get_bdev(desc);
842 [ # # ]: 0 : if (bdev->module != &daos_if) {
843 : 0 : rc = -EINVAL;
844 : 0 : goto exit;
845 : : }
846 : :
847 : 0 : current_size_in_mb = bdev->blocklen * bdev->blockcnt / (1024 * 1024);
848 [ # # ]: 0 : if (current_size_in_mb > new_size_in_mb) {
849 : 0 : SPDK_ERRLOG("The new bdev size must be larger than current bdev size.\n");
850 : 0 : rc = -EINVAL;
851 : 0 : goto exit;
852 : : }
853 : :
854 : 0 : ch = bdev_daos_get_io_channel(bdev);
855 : 0 : dch = spdk_io_channel_get_ctx(ch);
856 : 0 : new_size_in_byte = new_size_in_mb * 1024 * 1024;
857 : :
858 : 0 : rc = dfs_punch(dch->dfs, dch->obj, new_size_in_byte, DFS_MAX_FSIZE);
859 : 0 : spdk_put_io_channel(ch);
860 [ # # ]: 0 : if (rc != 0) {
861 : 0 : SPDK_ERRLOG("failed to resize daos bdev: %s", strerror(rc));
862 : 0 : rc = -rc;
863 : 0 : goto exit;
864 : : }
865 : :
866 : 0 : SPDK_NOTICELOG("DAOS bdev device is resized: bdev name %s, old block count %" PRIu64
867 : : ", new block count %"
868 : : PRIu64 "\n",
869 : : bdev->name,
870 : : bdev->blockcnt,
871 : : new_size_in_byte / bdev->blocklen);
872 : 0 : rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_byte / bdev->blocklen);
873 [ # # ]: 0 : if (rc != 0) {
874 : 0 : SPDK_ERRLOG("failed to notify block cnt change.\n");
875 : : }
876 : :
877 : 0 : exit:
878 : 0 : spdk_bdev_close(desc);
879 : 0 : return rc;
880 : : }
881 : :
882 : : void
883 : 0 : delete_bdev_daos(const char *bdev_name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
884 : : {
885 : : int rc;
886 : :
887 : 0 : rc = spdk_bdev_unregister_by_name(bdev_name, &daos_if, cb_fn, cb_arg);
888 [ # # ]: 0 : if (rc != 0) {
889 : 0 : cb_fn(cb_arg, rc);
890 : : }
891 : 0 : }
892 : :
893 : : static int
894 : 0 : bdev_daos_get_engine(void)
895 : : {
896 : 0 : int rc = 0;
897 : :
898 : 0 : pthread_mutex_lock(&g_bdev_daos_init_mutex);
899 [ # # ]: 0 : if (g_bdev_daos_init_count++ > 0) {
900 : 0 : pthread_mutex_unlock(&g_bdev_daos_init_mutex);
901 : 0 : return 0;
902 : : }
903 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "initializing DAOS engine\n");
904 : :
905 : 0 : rc = daos_init();
906 : 0 : pthread_mutex_unlock(&g_bdev_daos_init_mutex);
907 : :
908 [ # # # # ]: 0 : if (rc != -DER_ALREADY && rc) {
909 : 0 : return rc;
910 : : }
911 : 0 : return 0;
912 : : }
913 : :
914 : : static int
915 : 0 : bdev_daos_put_engine(void)
916 : : {
917 : 0 : int rc = 0;
918 : :
919 : 0 : pthread_mutex_lock(&g_bdev_daos_init_mutex);
920 [ # # ]: 0 : if (--g_bdev_daos_init_count > 0) {
921 : 0 : pthread_mutex_unlock(&g_bdev_daos_init_mutex);
922 : 0 : return 0;
923 : : }
924 [ # # ]: 0 : SPDK_DEBUGLOG(bdev_daos, "de-initializing DAOS engine\n");
925 : :
926 : 0 : rc = daos_fini();
927 : 0 : pthread_mutex_unlock(&g_bdev_daos_init_mutex);
928 : :
929 : 0 : return rc;
930 : : }
931 : :
932 : : static int
933 : 137 : bdev_daos_initialize(void)
934 : : {
935 : : /* DAOS engine and client initialization happens
936 : : during the first bdev creation */
937 : 137 : return 0;
938 : : }
939 : :
940 : 151 : SPDK_LOG_REGISTER_COMPONENT(bdev_daos)
|