Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2019 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <ocf/ocf.h>
7 : :
8 : : #include "spdk/bdev_module.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/thread.h"
11 : : #include "spdk/log.h"
12 : :
13 : : #include "data.h"
14 : : #include "volume.h"
15 : : #include "ctx.h"
16 : : #include "vbdev_ocf.h"
17 : :
18 : : static int
19 : 168 : vbdev_ocf_volume_open(ocf_volume_t volume, void *opts)
20 : : {
21 : 168 : struct vbdev_ocf_base **priv = ocf_volume_get_priv(volume);
22 : : struct vbdev_ocf_base *base;
23 : :
24 [ + + ]: 168 : if (opts) {
25 : 124 : base = opts;
26 : : } else {
27 : 44 : base = vbdev_ocf_get_base_by_name(ocf_volume_get_uuid(volume)->data);
28 [ - + ]: 44 : if (base == NULL) {
29 : 0 : return -ENODEV;
30 : : }
31 : : }
32 : :
33 : 168 : *priv = base;
34 : :
35 : 168 : return 0;
36 : : }
37 : :
38 : : static void
39 : 44 : vbdev_ocf_volume_close(ocf_volume_t volume)
40 : : {
41 : 44 : }
42 : :
43 : : static uint64_t
44 : 1312927 : vbdev_ocf_volume_get_length(ocf_volume_t volume)
45 : : {
46 : 1312927 : struct vbdev_ocf_base *base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(volume));
47 : : uint64_t len;
48 : :
49 : 1312927 : len = base->bdev->blocklen * base->bdev->blockcnt;
50 : :
51 : 1312927 : return len;
52 : : }
53 : :
54 : : static int
55 : 1569203 : vbdev_ocf_volume_io_set_data(struct ocf_io *io, ctx_data_t *data,
56 : : uint32_t offset)
57 : : {
58 : 1569203 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
59 : :
60 : 1569203 : io_ctx->offset = offset;
61 : 1569203 : io_ctx->data = data;
62 : :
63 [ - + ]: 1569203 : assert(io_ctx->data != NULL);
64 [ + + - + ]: 1569203 : if (io_ctx->data->iovs && offset >= io_ctx->data->size) {
65 : 0 : return -ENOBUFS;
66 : : }
67 : :
68 : 1569203 : return 0;
69 : : }
70 : :
71 : : static ctx_data_t *
72 : 124 : vbdev_ocf_volume_io_get_data(struct ocf_io *io)
73 : : {
74 : 124 : return ocf_get_io_ctx(io)->data;
75 : : }
76 : :
77 : : static void
78 : 1984937 : vbdev_ocf_volume_io_get(struct ocf_io *io)
79 : : {
80 : 1984937 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
81 : :
82 : 1984937 : io_ctx->ref++;
83 : 1984937 : }
84 : :
85 : : static void
86 : 1984937 : vbdev_ocf_volume_io_put(struct ocf_io *io)
87 : : {
88 : 1984937 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
89 : :
90 [ - + ]: 1984937 : if (--io_ctx->ref) {
91 : 0 : return;
92 : : }
93 : : }
94 : :
95 : : static int
96 : 0 : get_starting_vec(struct iovec *iovs, int iovcnt, int *offset)
97 : : {
98 : : int i;
99 : : size_t off;
100 : :
101 : 0 : off = *offset;
102 : :
103 [ # # ]: 0 : for (i = 0; i < iovcnt; i++) {
104 [ # # ]: 0 : if (off < iovs[i].iov_len) {
105 : 0 : *offset = off;
106 : 0 : return i;
107 : : }
108 : 0 : off -= iovs[i].iov_len;
109 : : }
110 : :
111 : 0 : return -1;
112 : : }
113 : :
114 : : static void
115 : 0 : initialize_cpy_vector(struct iovec *cpy_vec, int cpy_vec_len, struct iovec *orig_vec,
116 : : int orig_vec_len,
117 : : size_t offset, size_t bytes)
118 : : {
119 : : void *curr_base;
120 : : int len, i;
121 : :
122 : 0 : i = 0;
123 : :
124 [ # # ]: 0 : while (bytes > 0) {
125 : 0 : curr_base = orig_vec[i].iov_base + offset;
126 : 0 : len = MIN(bytes, orig_vec[i].iov_len - offset);
127 : :
128 : 0 : cpy_vec[i].iov_base = curr_base;
129 : 0 : cpy_vec[i].iov_len = len;
130 : :
131 : 0 : bytes -= len;
132 : 0 : offset = 0;
133 : 0 : i++;
134 : : }
135 : 0 : }
136 : :
137 : : static void
138 : 1984937 : vbdev_ocf_volume_submit_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
139 : : {
140 : : struct ocf_io *io;
141 : : struct ocf_io_ctx *io_ctx;
142 : :
143 [ - + ]: 1984937 : assert(opaque);
144 : :
145 : 1984937 : io = opaque;
146 : 1984937 : io_ctx = ocf_get_io_ctx(io);
147 [ - + ]: 1984937 : assert(io_ctx != NULL);
148 : :
149 [ - + ]: 1984937 : if (!success) {
150 [ # # ]: 0 : io_ctx->error = io_ctx->error ? : -OCF_ERR_IO;
151 : : }
152 : :
153 [ - + - + : 1984937 : if (io_ctx->iovs_allocated && bdev_io != NULL) {
- - ]
154 : 0 : env_free(bdev_io->u.bdev.iovs);
155 : : }
156 : :
157 [ - + ]: 1984937 : if (io_ctx->error) {
158 [ # # # # ]: 0 : SPDK_DEBUGLOG(vbdev_ocf_volume,
159 : : "base returned error on io submission: %d\n", io_ctx->error);
160 : : }
161 : :
162 [ + + + - ]: 1984937 : if (io->io_queue == NULL && io_ctx->ch != NULL) {
163 : 302 : spdk_put_io_channel(io_ctx->ch);
164 : : }
165 : :
166 : 1984937 : vbdev_ocf_volume_io_put(io);
167 [ + - ]: 1984937 : if (bdev_io) {
168 : 1984937 : spdk_bdev_free_io(bdev_io);
169 : : }
170 : :
171 [ + - ]: 1984937 : if (--io_ctx->rq_cnt == 0) {
172 : 1984937 : io->end(io, io_ctx->error);
173 : : }
174 : 1984937 : }
175 : :
176 : : static int
177 : 1984937 : prepare_submit(struct ocf_io *io)
178 : : {
179 : 1984937 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
180 : : struct vbdev_ocf_qctx *qctx;
181 : : struct vbdev_ocf_base *base;
182 : 1984937 : ocf_queue_t q = io->io_queue;
183 : : ocf_cache_t cache;
184 : : struct vbdev_ocf_cache_ctx *cctx;
185 : 1984937 : int rc = 0;
186 : :
187 : 1984937 : io_ctx->rq_cnt++;
188 [ - + ]: 1984937 : if (io_ctx->rq_cnt != 1) {
189 : 0 : return 0;
190 : : }
191 : :
192 : 1984937 : vbdev_ocf_volume_io_get(io);
193 : 1984937 : base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(ocf_io_get_volume(io)));
194 : :
195 [ + + ]: 1984937 : if (io->io_queue == NULL) {
196 : : /* In case IO is initiated by OCF, queue is unknown
197 : : * so we have to get io channel ourselves */
198 : 302 : io_ctx->ch = spdk_bdev_get_io_channel(base->desc);
199 [ - + ]: 302 : if (io_ctx->ch == NULL) {
200 : 0 : return -EPERM;
201 : : }
202 : 302 : return 0;
203 : : }
204 : :
205 : 1984635 : cache = ocf_queue_get_cache(q);
206 : 1984635 : cctx = ocf_cache_get_priv(cache);
207 [ - + ]: 1984635 : if (cctx == NULL) {
208 : 0 : return -EFAULT;
209 : : }
210 : :
211 [ + + ]: 1984635 : if (q == cctx->mngt_queue) {
212 : 88076 : io_ctx->ch = base->management_channel;
213 : 88076 : return 0;
214 : : }
215 : :
216 : 1896559 : qctx = ocf_queue_get_priv(q);
217 [ - + ]: 1896559 : if (qctx == NULL) {
218 : 0 : return -EFAULT;
219 : : }
220 : :
221 [ - + + + ]: 1896559 : if (base->is_cache) {
222 : 814322 : io_ctx->ch = qctx->cache_ch;
223 : : } else {
224 : 1082237 : io_ctx->ch = qctx->core_ch;
225 : : }
226 : :
227 : 1896559 : return rc;
228 : : }
229 : :
230 : : static void
231 : 647478 : vbdev_ocf_volume_submit_flush(struct ocf_io *io)
232 : : {
233 : 647478 : struct vbdev_ocf_base *base =
234 : : *((struct vbdev_ocf_base **)
235 : 647478 : ocf_volume_get_priv(ocf_io_get_volume(io)));
236 : 647478 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
237 : : int status;
238 : :
239 : 647478 : status = prepare_submit(io);
240 [ - + ]: 647478 : if (status) {
241 : 0 : SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
242 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
243 : 0 : return;
244 : : }
245 : :
246 : 647478 : status = spdk_bdev_flush(
247 : : base->desc, io_ctx->ch,
248 : 647478 : io->addr, io->bytes,
249 : : vbdev_ocf_volume_submit_io_cb, io);
250 [ - + ]: 647478 : if (status) {
251 : : /* Since callback is not called, we need to do it manually to free io structures */
252 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
253 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
254 : : }
255 : : }
256 : :
257 : : static void
258 : 1385971 : vbdev_ocf_volume_submit_io(struct ocf_io *io)
259 : : {
260 : 1385971 : struct vbdev_ocf_base *base =
261 : : *((struct vbdev_ocf_base **)
262 : 1385971 : ocf_volume_get_priv(ocf_io_get_volume(io)));
263 : 1385971 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
264 : : struct iovec *iovs;
265 : 1385971 : int iovcnt, status = 0, i, offset;
266 : : uint64_t addr, len;
267 : :
268 [ + + ]: 1385971 : if (io->flags == OCF_WRITE_FLUSH) {
269 : 231744 : vbdev_ocf_volume_submit_flush(io);
270 : 231744 : return;
271 : : }
272 : :
273 : 1154227 : status = prepare_submit(io);
274 [ - + ]: 1154227 : if (status) {
275 : 0 : SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
276 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
277 : 0 : return;
278 : : }
279 : :
280 : : /* IO fields */
281 : 1154227 : addr = io->addr;
282 : 1154227 : len = io->bytes;
283 : 1154227 : offset = io_ctx->offset;
284 : :
285 [ + + ]: 1154227 : if (len < io_ctx->data->size) {
286 [ + - ]: 73790 : if (io_ctx->data->iovcnt == 1) {
287 [ + + ]: 73790 : if (io->dir == OCF_READ) {
288 : 36812 : status = spdk_bdev_read(base->desc, io_ctx->ch,
289 : 36812 : io_ctx->data->iovs[0].iov_base + offset, addr, len,
290 : : vbdev_ocf_volume_submit_io_cb, io);
291 [ + - ]: 36978 : } else if (io->dir == OCF_WRITE) {
292 : 36978 : status = spdk_bdev_write(base->desc, io_ctx->ch,
293 : 36978 : io_ctx->data->iovs[0].iov_base + offset, addr, len,
294 : : vbdev_ocf_volume_submit_io_cb, io);
295 : : }
296 : 73790 : goto end;
297 : : } else {
298 : 0 : i = get_starting_vec(io_ctx->data->iovs, io_ctx->data->iovcnt, &offset);
299 : :
300 [ # # ]: 0 : if (i < 0) {
301 : 0 : SPDK_ERRLOG("offset bigger than data size\n");
302 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
303 : 0 : return;
304 : : }
305 : :
306 : 0 : iovcnt = io_ctx->data->iovcnt - i;
307 : :
308 : 0 : io_ctx->iovs_allocated = true;
309 : 0 : iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
310 : :
311 [ # # ]: 0 : if (!iovs) {
312 : 0 : SPDK_ERRLOG("allocation failed\n");
313 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
314 : 0 : return;
315 : : }
316 : :
317 : 0 : initialize_cpy_vector(iovs, io_ctx->data->iovcnt, &io_ctx->data->iovs[i],
318 : : iovcnt, offset, len);
319 : : }
320 : : } else {
321 : 1080437 : iovs = io_ctx->data->iovs;
322 : 1080437 : iovcnt = io_ctx->data->iovcnt;
323 : : }
324 : :
325 [ + + ]: 1080437 : if (io->dir == OCF_READ) {
326 : 270003 : status = spdk_bdev_readv(base->desc, io_ctx->ch,
327 : : iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io);
328 [ - + ]: 810434 : } else if (io->dir == OCF_WRITE) {
329 : 810434 : status = spdk_bdev_writev(base->desc, io_ctx->ch,
330 : : iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io);
331 : : }
332 : :
333 : 0 : end:
334 [ - + ]: 1154227 : if (status) {
335 [ # # ]: 0 : if (status == -ENOMEM) {
336 : 0 : io_ctx->error = -OCF_ERR_NO_MEM;
337 : : } else {
338 : 0 : SPDK_ERRLOG("submission failed with status=%d\n", status);
339 : : }
340 : :
341 : : /* Since callback is not called, we need to do it manually to free io structures */
342 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
343 : : }
344 : : }
345 : :
346 : : static void
347 : 183232 : vbdev_ocf_volume_submit_discard(struct ocf_io *io)
348 : : {
349 : 183232 : struct vbdev_ocf_base *base =
350 : : *((struct vbdev_ocf_base **)
351 : 183232 : ocf_volume_get_priv(ocf_io_get_volume(io)));
352 : 183232 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
353 : 183232 : int status = 0;
354 : :
355 : 183232 : status = prepare_submit(io);
356 [ - + ]: 183232 : if (status) {
357 : 0 : SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
358 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
359 : 0 : return;
360 : : }
361 : :
362 : 183232 : status = spdk_bdev_unmap(
363 : : base->desc, io_ctx->ch,
364 : 183232 : io->addr, io->bytes,
365 : : vbdev_ocf_volume_submit_io_cb, io);
366 [ - + ]: 183232 : if (status) {
367 : : /* Since callback is not called, we need to do it manually to free io structures */
368 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
369 : 0 : vbdev_ocf_volume_submit_io_cb(NULL, false, io);
370 : : }
371 : : }
372 : :
373 : : static void
374 : 0 : vbdev_ocf_volume_submit_metadata(struct ocf_io *io)
375 : : {
376 : : /* Implement with persistent metadata support */
377 : 0 : }
378 : :
379 : : static unsigned int
380 : 176559 : vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
381 : : {
382 : 176559 : return 131072;
383 : : }
384 : :
385 : : static struct ocf_volume_properties vbdev_volume_props = {
386 : : .name = "SPDK_block_device",
387 : : .io_priv_size = sizeof(struct ocf_io_ctx),
388 : : .volume_priv_size = sizeof(struct vbdev_ocf_base *),
389 : : .caps = {
390 : : .atomic_writes = 0 /* to enable need to have ops->submit_metadata */
391 : : },
392 : : .ops = {
393 : : .open = vbdev_ocf_volume_open,
394 : : .close = vbdev_ocf_volume_close,
395 : : .get_length = vbdev_ocf_volume_get_length,
396 : : .submit_io = vbdev_ocf_volume_submit_io,
397 : : .submit_discard = vbdev_ocf_volume_submit_discard,
398 : : .submit_flush = vbdev_ocf_volume_submit_flush,
399 : : .get_max_io_size = vbdev_ocf_volume_get_max_io_size,
400 : : .submit_metadata = vbdev_ocf_volume_submit_metadata,
401 : : },
402 : : .io_ops = {
403 : : .set_data = vbdev_ocf_volume_io_set_data,
404 : : .get_data = vbdev_ocf_volume_io_get_data,
405 : : },
406 : : };
407 : :
408 : : int
409 : 63 : vbdev_ocf_volume_init(void)
410 : : {
411 : 63 : return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
412 : : }
413 : :
414 : : void
415 : 63 : vbdev_ocf_volume_cleanup(void)
416 : : {
417 : 63 : ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
418 : 63 : }
419 : :
420 : 71 : SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
|