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 0 : vbdev_ocf_volume_open(ocf_volume_t volume, void *opts)
20 : {
21 0 : struct vbdev_ocf_base **priv = ocf_volume_get_priv(volume);
22 : struct vbdev_ocf_base *base;
23 :
24 0 : if (opts) {
25 0 : base = opts;
26 : } else {
27 0 : base = vbdev_ocf_get_base_by_name(ocf_volume_get_uuid(volume)->data);
28 0 : if (base == NULL) {
29 0 : return -ENODEV;
30 : }
31 : }
32 :
33 0 : *priv = base;
34 :
35 0 : return 0;
36 : }
37 :
38 : static void
39 0 : vbdev_ocf_volume_close(ocf_volume_t volume)
40 : {
41 0 : }
42 :
43 : static uint64_t
44 0 : vbdev_ocf_volume_get_length(ocf_volume_t volume)
45 : {
46 0 : struct vbdev_ocf_base *base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(volume));
47 : uint64_t len;
48 :
49 0 : len = base->bdev->blocklen * base->bdev->blockcnt;
50 :
51 0 : return len;
52 : }
53 :
54 : static int
55 0 : vbdev_ocf_volume_io_set_data(struct ocf_io *io, ctx_data_t *data,
56 : uint32_t offset)
57 : {
58 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
59 :
60 0 : io_ctx->offset = offset;
61 0 : io_ctx->data = data;
62 :
63 0 : assert(io_ctx->data != NULL);
64 0 : if (io_ctx->data->iovs && offset >= io_ctx->data->size) {
65 0 : return -ENOBUFS;
66 : }
67 :
68 0 : return 0;
69 : }
70 :
71 : static ctx_data_t *
72 0 : vbdev_ocf_volume_io_get_data(struct ocf_io *io)
73 : {
74 0 : return ocf_get_io_ctx(io)->data;
75 : }
76 :
77 : static void
78 0 : vbdev_ocf_volume_io_get(struct ocf_io *io)
79 : {
80 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
81 :
82 0 : io_ctx->ref++;
83 0 : }
84 :
85 : static void
86 0 : vbdev_ocf_volume_io_put(struct ocf_io *io)
87 : {
88 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
89 :
90 0 : 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 0 : 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 0 : assert(opaque);
144 :
145 0 : io = opaque;
146 0 : io_ctx = ocf_get_io_ctx(io);
147 0 : assert(io_ctx != NULL);
148 :
149 0 : if (!success) {
150 0 : io_ctx->error = io_ctx->error ? : -OCF_ERR_IO;
151 : }
152 :
153 0 : if (io_ctx->iovs_allocated && bdev_io != NULL) {
154 0 : env_free(bdev_io->u.bdev.iovs);
155 : }
156 :
157 0 : 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 0 : if (io->io_queue == NULL && io_ctx->ch != NULL) {
163 0 : spdk_put_io_channel(io_ctx->ch);
164 : }
165 :
166 0 : vbdev_ocf_volume_io_put(io);
167 0 : if (bdev_io) {
168 0 : spdk_bdev_free_io(bdev_io);
169 : }
170 :
171 0 : if (--io_ctx->rq_cnt == 0) {
172 0 : io->end(io, io_ctx->error);
173 : }
174 0 : }
175 :
176 : static int
177 0 : prepare_submit(struct ocf_io *io)
178 : {
179 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
180 : struct vbdev_ocf_qctx *qctx;
181 : struct vbdev_ocf_base *base;
182 0 : ocf_queue_t q = io->io_queue;
183 : ocf_cache_t cache;
184 : struct vbdev_ocf_cache_ctx *cctx;
185 0 : int rc = 0;
186 :
187 0 : io_ctx->rq_cnt++;
188 0 : if (io_ctx->rq_cnt != 1) {
189 0 : return 0;
190 : }
191 :
192 0 : vbdev_ocf_volume_io_get(io);
193 0 : base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(ocf_io_get_volume(io)));
194 :
195 0 : 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 0 : io_ctx->ch = spdk_bdev_get_io_channel(base->desc);
199 0 : if (io_ctx->ch == NULL) {
200 0 : return -EPERM;
201 : }
202 0 : return 0;
203 : }
204 :
205 0 : cache = ocf_queue_get_cache(q);
206 0 : cctx = ocf_cache_get_priv(cache);
207 0 : if (cctx == NULL) {
208 0 : return -EFAULT;
209 : }
210 :
211 0 : if (q == cctx->mngt_queue) {
212 0 : io_ctx->ch = base->management_channel;
213 0 : return 0;
214 : }
215 :
216 0 : qctx = ocf_queue_get_priv(q);
217 0 : if (qctx == NULL) {
218 0 : return -EFAULT;
219 : }
220 :
221 0 : if (base->is_cache) {
222 0 : io_ctx->ch = qctx->cache_ch;
223 : } else {
224 0 : io_ctx->ch = qctx->core_ch;
225 : }
226 :
227 0 : return rc;
228 : }
229 :
230 : static void
231 0 : vbdev_ocf_volume_submit_flush(struct ocf_io *io)
232 : {
233 0 : struct vbdev_ocf_base *base =
234 : *((struct vbdev_ocf_base **)
235 0 : ocf_volume_get_priv(ocf_io_get_volume(io)));
236 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
237 : int status;
238 :
239 0 : status = prepare_submit(io);
240 0 : 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 0 : status = spdk_bdev_flush(
247 : base->desc, io_ctx->ch,
248 0 : io->addr, io->bytes,
249 : vbdev_ocf_volume_submit_io_cb, io);
250 0 : 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 0 : vbdev_ocf_volume_submit_io(struct ocf_io *io)
259 : {
260 0 : struct vbdev_ocf_base *base =
261 : *((struct vbdev_ocf_base **)
262 0 : ocf_volume_get_priv(ocf_io_get_volume(io)));
263 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
264 : struct iovec *iovs;
265 0 : int iovcnt, status = 0, i, offset;
266 : uint64_t addr, len;
267 :
268 0 : if (io->flags == OCF_WRITE_FLUSH) {
269 0 : vbdev_ocf_volume_submit_flush(io);
270 0 : return;
271 : }
272 :
273 0 : status = prepare_submit(io);
274 0 : 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 0 : addr = io->addr;
282 0 : len = io->bytes;
283 0 : offset = io_ctx->offset;
284 :
285 0 : if (len < io_ctx->data->size) {
286 0 : if (io_ctx->data->iovcnt == 1) {
287 0 : if (io->dir == OCF_READ) {
288 0 : status = spdk_bdev_read(base->desc, io_ctx->ch,
289 0 : io_ctx->data->iovs[0].iov_base + offset, addr, len,
290 : vbdev_ocf_volume_submit_io_cb, io);
291 0 : } else if (io->dir == OCF_WRITE) {
292 0 : status = spdk_bdev_write(base->desc, io_ctx->ch,
293 0 : io_ctx->data->iovs[0].iov_base + offset, addr, len,
294 : vbdev_ocf_volume_submit_io_cb, io);
295 : }
296 0 : 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 0 : iovs = io_ctx->data->iovs;
322 0 : iovcnt = io_ctx->data->iovcnt;
323 : }
324 :
325 0 : if (io->dir == OCF_READ) {
326 0 : status = spdk_bdev_readv(base->desc, io_ctx->ch,
327 : iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io);
328 0 : } else if (io->dir == OCF_WRITE) {
329 0 : 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 0 : 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 0 : vbdev_ocf_volume_submit_discard(struct ocf_io *io)
348 : {
349 0 : struct vbdev_ocf_base *base =
350 : *((struct vbdev_ocf_base **)
351 0 : ocf_volume_get_priv(ocf_io_get_volume(io)));
352 0 : struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
353 0 : int status = 0;
354 :
355 0 : status = prepare_submit(io);
356 0 : 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 0 : status = spdk_bdev_unmap(
363 : base->desc, io_ctx->ch,
364 0 : io->addr, io->bytes,
365 : vbdev_ocf_volume_submit_io_cb, io);
366 0 : 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 0 : vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
381 : {
382 0 : 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 0 : vbdev_ocf_volume_init(void)
410 : {
411 0 : return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
412 : }
413 :
414 : void
415 0 : vbdev_ocf_volume_cleanup(void)
416 : {
417 0 : ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
418 0 : }
419 :
420 0 : SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
|