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 : 170 : vbdev_ocf_volume_open(ocf_volume_t volume, void *opts)
20 : : {
21 : 170 : struct vbdev_ocf_base **priv = ocf_volume_get_priv(volume);
22 : : struct vbdev_ocf_base *base;
23 : :
24 [ + + ]: 170 : if (opts) {
25 : 126 : 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 : 170 : *priv = base;
34 : :
35 : 170 : 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 : 1317154 : vbdev_ocf_volume_get_length(ocf_volume_t volume)
45 : : {
46 : 1317154 : struct vbdev_ocf_base *base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(volume));
47 : : uint64_t len;
48 : :
49 : 1317154 : len = base->bdev->blocklen * base->bdev->blockcnt;
50 : :
51 : 1317154 : return len;
52 : : }
53 : :
54 : : static int
55 : 74756 : get_starting_vec(struct iovec *iovs, int iovcnt, uint64_t *offset)
56 : : {
57 : : int i;
58 : : size_t off;
59 : :
60 : 74756 : off = *offset;
61 : :
62 [ + - ]: 74756 : for (i = 0; i < iovcnt; i++) {
63 [ + - ]: 74756 : if (off < iovs[i].iov_len) {
64 : 74756 : *offset = off;
65 : 74756 : return i;
66 : : }
67 : 0 : off -= iovs[i].iov_len;
68 : : }
69 : :
70 : 0 : return -1;
71 : : }
72 : :
73 : : static void
74 : 74756 : initialize_cpy_vector(struct iovec *cpy_vec, int cpy_vec_len, struct iovec *orig_vec,
75 : : int orig_vec_len,
76 : : size_t offset, size_t bytes)
77 : : {
78 : : void *curr_base;
79 : : int len, i;
80 : :
81 : 74756 : i = 0;
82 : :
83 [ + + ]: 149512 : while (bytes > 0) {
84 : 74756 : curr_base = orig_vec[i].iov_base + offset;
85 : 74756 : len = MIN(bytes, orig_vec[i].iov_len - offset);
86 : :
87 : 74756 : cpy_vec[i].iov_base = curr_base;
88 : 74756 : cpy_vec[i].iov_len = len;
89 : :
90 : 74756 : bytes -= len;
91 : 74756 : offset = 0;
92 : 74756 : i++;
93 : : }
94 : 74756 : }
95 : :
96 : : static unsigned int
97 : 173675 : vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
98 : : {
99 : 173675 : return 131072;
100 : : }
101 : :
102 : : static void
103 : 2080933 : vbdev_forward_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
104 : : {
105 : 2080933 : ocf_forward_token_t token = (ocf_forward_token_t) opaque;
106 : :
107 [ - + ]: 2080933 : assert(token);
108 : :
109 : 2080933 : spdk_bdev_free_io(bdev_io);
110 : :
111 [ + - ]: 2080933 : ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
112 : 2080933 : }
113 : :
114 : : static void
115 : 74756 : vbdev_forward_io_free_iovs_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
116 : : {
117 : 74756 : env_free(bdev_io->u.bdev.iovs);
118 : 74756 : vbdev_forward_io_cb(bdev_io, success, opaque);
119 : 74756 : }
120 : :
121 : : static struct spdk_io_channel *
122 : 2080933 : vbdev_forward_get_channel(ocf_volume_t volume, ocf_forward_token_t token)
123 : : {
124 : 2080933 : struct vbdev_ocf_base *base =
125 : : *((struct vbdev_ocf_base **)
126 : 2080933 : ocf_volume_get_priv(volume));
127 : 2080933 : ocf_queue_t queue = ocf_forward_get_io_queue(token);
128 : : struct vbdev_ocf_qctx *qctx;
129 : :
130 [ + + ]: 2080933 : if (unlikely(ocf_queue_is_mngt(queue))) {
131 : 88046 : return base->management_channel;
132 : : }
133 : :
134 : 1992887 : qctx = ocf_queue_get_priv(queue);
135 [ - + ]: 1992887 : if (unlikely(qctx == NULL)) {
136 : 0 : return NULL;
137 : : }
138 : :
139 [ - + + + ]: 1992887 : return (base->is_cache) ? qctx->cache_ch : qctx->core_ch;
140 : : }
141 : :
142 : : static void
143 : 1084707 : vbdev_forward_io(ocf_volume_t volume, ocf_forward_token_t token,
144 : : int dir, uint64_t addr, uint64_t bytes,
145 : : uint64_t offset)
146 : : {
147 : 1084707 : struct vbdev_ocf_base *base =
148 : : *((struct vbdev_ocf_base **)
149 : 1084707 : ocf_volume_get_priv(volume));
150 : 1084707 : struct bdev_ocf_data *data = ocf_forward_get_data(token);
151 : : struct spdk_io_channel *ch;
152 : 1084707 : spdk_bdev_io_completion_cb cb = vbdev_forward_io_cb;
153 : 1084707 : bool iovs_allocated = false;
154 : 1084707 : int iovcnt, skip, status = -1;
155 : : struct iovec *iovs;
156 : :
157 : 1084707 : ch = vbdev_forward_get_channel(volume, token);
158 [ - + ]: 1084707 : if (unlikely(ch == NULL)) {
159 : 0 : ocf_forward_end(token, -EFAULT);
160 : 0 : return;
161 : : }
162 : :
163 [ + + ]: 1084707 : if (bytes == data->size) {
164 : 1009951 : iovs = data->iovs;
165 : 1009951 : iovcnt = data->iovcnt;
166 : : } else {
167 : 74756 : skip = get_starting_vec(data->iovs, data->iovcnt, &offset);
168 [ - + ]: 74756 : if (skip < 0) {
169 : 0 : SPDK_ERRLOG("Offset bigger than data size\n");
170 : 0 : ocf_forward_end(token, -OCF_ERR_IO);
171 : 0 : return;
172 : : }
173 : :
174 : 74756 : iovcnt = data->iovcnt - skip;
175 : :
176 : 74756 : iovs_allocated = true;
177 : 74756 : cb = vbdev_forward_io_free_iovs_cb;
178 : 74756 : iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
179 : :
180 [ - + ]: 74756 : if (!iovs) {
181 : 0 : SPDK_ERRLOG("Allocation failed\n");
182 : 0 : ocf_forward_end(token, -OCF_ERR_NO_MEM);
183 : 0 : return;
184 : : }
185 : :
186 : 74756 : initialize_cpy_vector(iovs, data->iovcnt, &data->iovs[skip],
187 : : iovcnt, offset, bytes);
188 : : }
189 : :
190 [ + + ]: 1084707 : if (dir == OCF_READ) {
191 : 269535 : status = spdk_bdev_readv(base->desc, ch, iovs, iovcnt,
192 : : addr, bytes, cb, (void *) token);
193 [ + - ]: 815172 : } else if (dir == OCF_WRITE) {
194 : 815172 : status = spdk_bdev_writev(base->desc, ch, iovs, iovcnt,
195 : : addr, bytes, cb, (void *) token);
196 : : }
197 : :
198 [ - + ]: 1084707 : if (unlikely(status)) {
199 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
200 : : /* Since callback is not called, we need to do it manually to free iovs */
201 [ # # ]: 0 : if (iovs_allocated) {
202 : 0 : env_free(iovs);
203 : : }
204 [ # # ]: 0 : ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
205 : : }
206 : : }
207 : :
208 : : static void
209 : 785282 : vbdev_forward_flush(ocf_volume_t volume, ocf_forward_token_t token)
210 : : {
211 : 785282 : struct vbdev_ocf_base *base =
212 : : *((struct vbdev_ocf_base **)
213 : 785282 : ocf_volume_get_priv(volume));
214 : : struct spdk_io_channel *ch;
215 : 785282 : uint64_t bytes = base->bdev->blockcnt * base->bdev->blocklen;
216 : : int status;
217 : :
218 : 785282 : ch = vbdev_forward_get_channel(volume, token);
219 [ - + ]: 785282 : if (unlikely(ch == NULL)) {
220 : 0 : ocf_forward_end(token, -EFAULT);
221 : 0 : return;
222 : : }
223 : :
224 : 785282 : status = spdk_bdev_flush(
225 : : base->desc, ch, 0, bytes,
226 : : vbdev_forward_io_cb, (void *)token);
227 [ - + ]: 785282 : if (unlikely(status)) {
228 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
229 [ # # ]: 0 : ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
230 : : }
231 : : }
232 : :
233 : : static void
234 : 210944 : vbdev_forward_discard(ocf_volume_t volume, ocf_forward_token_t token,
235 : : uint64_t addr, uint64_t bytes)
236 : : {
237 : 210944 : struct vbdev_ocf_base *base =
238 : : *((struct vbdev_ocf_base **)
239 : 210944 : ocf_volume_get_priv(volume));
240 : : struct spdk_io_channel *ch;
241 : 210944 : int status = 0;
242 : :
243 : 210944 : ch = vbdev_forward_get_channel(volume, token);
244 [ - + ]: 210944 : if (unlikely(ch == NULL)) {
245 : 0 : ocf_forward_end(token, -EFAULT);
246 : 0 : return;
247 : : }
248 : :
249 : 210944 : status = spdk_bdev_unmap(
250 : : base->desc, ch, addr, bytes,
251 : : vbdev_forward_io_cb, (void *)token);
252 [ - + ]: 210944 : if (unlikely(status)) {
253 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
254 [ # # ]: 0 : ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
255 : : }
256 : : }
257 : :
258 : : struct vbdev_forward_io_simple_ctx {
259 : : ocf_forward_token_t token;
260 : : struct spdk_io_channel *ch;
261 : : };
262 : :
263 : : static void
264 : 126 : vbdev_forward_io_simple_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
265 : : {
266 : 126 : struct vbdev_forward_io_simple_ctx *ctx = opaque;
267 : 126 : ocf_forward_token_t token = ctx->token;
268 : :
269 [ - + ]: 126 : assert(token);
270 : :
271 : 126 : spdk_bdev_free_io(bdev_io);
272 : 126 : spdk_put_io_channel(ctx->ch);
273 : 126 : env_free(ctx);
274 : :
275 [ + - ]: 126 : ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
276 : 126 : }
277 : :
278 : : static void
279 : 126 : vbdev_forward_io_simple(ocf_volume_t volume, ocf_forward_token_t token,
280 : : int dir, uint64_t addr, uint64_t bytes)
281 : : {
282 : 126 : struct vbdev_ocf_base *base =
283 : : *((struct vbdev_ocf_base **)
284 : 126 : ocf_volume_get_priv(volume));
285 : 126 : struct bdev_ocf_data *data = ocf_forward_get_data(token);
286 : : struct vbdev_forward_io_simple_ctx *ctx;
287 : 126 : int status = -1;
288 : :
289 : 126 : ctx = env_malloc(sizeof(*ctx), ENV_MEM_NOIO);
290 [ - + ]: 126 : if (unlikely(!ctx)) {
291 : 0 : ocf_forward_end(token, -OCF_ERR_NO_MEM);
292 : 0 : return;
293 : : }
294 : :
295 : : /* Forward IO simple is used in context where queue is not available
296 : : * so we have to get io channel ourselves */
297 : 126 : ctx->ch = spdk_bdev_get_io_channel(base->desc);
298 [ - + ]: 126 : if (unlikely(ctx->ch == NULL)) {
299 : 0 : env_free(ctx);
300 : 0 : ocf_forward_end(token, -EFAULT);
301 : 0 : return;
302 : : }
303 : :
304 : 126 : ctx->token = token;
305 : :
306 [ + - ]: 126 : if (dir == OCF_READ) {
307 : 126 : status = spdk_bdev_readv(base->desc, ctx->ch, data->iovs,
308 : : data->iovcnt, addr, bytes,
309 : : vbdev_forward_io_simple_cb, ctx);
310 [ # # ]: 0 : } else if (dir == OCF_WRITE) {
311 : 0 : status = spdk_bdev_writev(base->desc, ctx->ch, data->iovs,
312 : : data->iovcnt, addr, bytes,
313 : : vbdev_forward_io_simple_cb, ctx);
314 : : }
315 : :
316 [ - + ]: 126 : if (unlikely(status)) {
317 : 0 : SPDK_ERRLOG("Submission failed with status=%d\n", status);
318 : 0 : spdk_put_io_channel(ctx->ch);
319 : 0 : env_free(ctx);
320 [ # # ]: 0 : ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
321 : : }
322 : : }
323 : :
324 : : static struct ocf_volume_properties vbdev_volume_props = {
325 : : .name = "SPDK_block_device",
326 : : .volume_priv_size = sizeof(struct vbdev_ocf_base *),
327 : : .caps = {
328 : : .atomic_writes = 0 /* to enable need to have ops->submit_metadata */
329 : : },
330 : : .ops = {
331 : : .open = vbdev_ocf_volume_open,
332 : : .close = vbdev_ocf_volume_close,
333 : : .get_length = vbdev_ocf_volume_get_length,
334 : : .get_max_io_size = vbdev_ocf_volume_get_max_io_size,
335 : : .forward_io = vbdev_forward_io,
336 : : .forward_flush = vbdev_forward_flush,
337 : : .forward_discard = vbdev_forward_discard,
338 : : .forward_io_simple = vbdev_forward_io_simple,
339 : : },
340 : : };
341 : :
342 : : int
343 : 69 : vbdev_ocf_volume_init(void)
344 : : {
345 : 69 : return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
346 : : }
347 : :
348 : : void
349 : 69 : vbdev_ocf_volume_cleanup(void)
350 : : {
351 : 69 : ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
352 : 69 : }
353 : :
354 : 77 : SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
|