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 0 : struct vbdev_ocf_base *base;
23 :
24 0 : if (opts) {
25 0 : base = opts;
26 0 : } 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 0 : }
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 0 : uint64_t len;
48 :
49 0 : len = base->bdev->blocklen * base->bdev->blockcnt;
50 :
51 0 : return len;
52 0 : }
53 :
54 : static int
55 0 : get_starting_vec(struct iovec *iovs, int iovcnt, uint64_t *offset)
56 : {
57 0 : int i;
58 0 : size_t off;
59 :
60 0 : off = *offset;
61 :
62 0 : for (i = 0; i < iovcnt; i++) {
63 0 : if (off < iovs[i].iov_len) {
64 0 : *offset = off;
65 0 : return i;
66 : }
67 0 : off -= iovs[i].iov_len;
68 0 : }
69 :
70 0 : return -1;
71 0 : }
72 :
73 : static void
74 0 : 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 0 : void *curr_base;
79 0 : int len, i;
80 :
81 0 : i = 0;
82 :
83 0 : while (bytes > 0) {
84 0 : curr_base = orig_vec[i].iov_base + offset;
85 0 : len = MIN(bytes, orig_vec[i].iov_len - offset);
86 :
87 0 : cpy_vec[i].iov_base = curr_base;
88 0 : cpy_vec[i].iov_len = len;
89 :
90 0 : bytes -= len;
91 0 : offset = 0;
92 0 : i++;
93 : }
94 0 : }
95 :
96 : static unsigned int
97 0 : vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
98 : {
99 0 : return 131072;
100 : }
101 :
102 : static void
103 0 : vbdev_forward_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
104 : {
105 0 : ocf_forward_token_t token = (ocf_forward_token_t) opaque;
106 :
107 0 : assert(token);
108 :
109 0 : spdk_bdev_free_io(bdev_io);
110 :
111 0 : ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
112 0 : }
113 :
114 : static void
115 0 : vbdev_forward_io_free_iovs_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
116 : {
117 0 : env_free(bdev_io->u.bdev.iovs);
118 0 : vbdev_forward_io_cb(bdev_io, success, opaque);
119 0 : }
120 :
121 : static struct spdk_io_channel *
122 0 : vbdev_forward_get_channel(ocf_volume_t volume, ocf_forward_token_t token)
123 : {
124 0 : struct vbdev_ocf_base *base =
125 0 : *((struct vbdev_ocf_base **)
126 0 : ocf_volume_get_priv(volume));
127 0 : ocf_queue_t queue = ocf_forward_get_io_queue(token);
128 0 : struct vbdev_ocf_qctx *qctx;
129 :
130 0 : if (unlikely(ocf_queue_is_mngt(queue))) {
131 0 : return base->management_channel;
132 : }
133 :
134 0 : qctx = ocf_queue_get_priv(queue);
135 0 : if (unlikely(qctx == NULL)) {
136 0 : return NULL;
137 : }
138 :
139 0 : return (base->is_cache) ? qctx->cache_ch : qctx->core_ch;
140 0 : }
141 :
142 : static void
143 0 : 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 0 : struct vbdev_ocf_base *base =
148 0 : *((struct vbdev_ocf_base **)
149 0 : ocf_volume_get_priv(volume));
150 0 : struct bdev_ocf_data *data = ocf_forward_get_data(token);
151 0 : struct spdk_io_channel *ch;
152 0 : spdk_bdev_io_completion_cb cb = vbdev_forward_io_cb;
153 0 : bool iovs_allocated = false;
154 0 : int iovcnt, skip, status = -1;
155 0 : struct iovec *iovs;
156 :
157 0 : ch = vbdev_forward_get_channel(volume, token);
158 0 : if (unlikely(ch == NULL)) {
159 0 : ocf_forward_end(token, -EFAULT);
160 0 : return;
161 : }
162 :
163 0 : if (bytes == data->size) {
164 0 : iovs = data->iovs;
165 0 : iovcnt = data->iovcnt;
166 0 : } else {
167 0 : skip = get_starting_vec(data->iovs, data->iovcnt, &offset);
168 0 : 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 0 : iovcnt = data->iovcnt - skip;
175 :
176 0 : iovs_allocated = true;
177 0 : cb = vbdev_forward_io_free_iovs_cb;
178 0 : iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
179 :
180 0 : 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 0 : initialize_cpy_vector(iovs, data->iovcnt, &data->iovs[skip],
187 0 : iovcnt, offset, bytes);
188 : }
189 :
190 0 : if (dir == OCF_READ) {
191 0 : status = spdk_bdev_readv(base->desc, ch, iovs, iovcnt,
192 0 : addr, bytes, cb, (void *) token);
193 0 : } else if (dir == OCF_WRITE) {
194 0 : status = spdk_bdev_writev(base->desc, ch, iovs, iovcnt,
195 0 : addr, bytes, cb, (void *) token);
196 0 : }
197 :
198 0 : 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 0 : }
204 0 : ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
205 0 : }
206 0 : }
207 :
208 : static void
209 0 : vbdev_forward_flush(ocf_volume_t volume, ocf_forward_token_t token)
210 : {
211 0 : struct vbdev_ocf_base *base =
212 0 : *((struct vbdev_ocf_base **)
213 0 : ocf_volume_get_priv(volume));
214 0 : struct spdk_io_channel *ch;
215 0 : uint64_t bytes = base->bdev->blockcnt * base->bdev->blocklen;
216 0 : int status;
217 :
218 0 : ch = vbdev_forward_get_channel(volume, token);
219 0 : if (unlikely(ch == NULL)) {
220 0 : ocf_forward_end(token, -EFAULT);
221 0 : return;
222 : }
223 :
224 0 : status = spdk_bdev_flush(
225 0 : base->desc, ch, 0, bytes,
226 0 : vbdev_forward_io_cb, (void *)token);
227 0 : 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 0 : }
231 0 : }
232 :
233 : static void
234 0 : vbdev_forward_discard(ocf_volume_t volume, ocf_forward_token_t token,
235 : uint64_t addr, uint64_t bytes)
236 : {
237 0 : struct vbdev_ocf_base *base =
238 0 : *((struct vbdev_ocf_base **)
239 0 : ocf_volume_get_priv(volume));
240 0 : struct spdk_io_channel *ch;
241 0 : int status = 0;
242 :
243 0 : ch = vbdev_forward_get_channel(volume, token);
244 0 : if (unlikely(ch == NULL)) {
245 0 : ocf_forward_end(token, -EFAULT);
246 0 : return;
247 : }
248 :
249 0 : status = spdk_bdev_unmap(
250 0 : base->desc, ch, addr, bytes,
251 0 : vbdev_forward_io_cb, (void *)token);
252 0 : 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 0 : }
256 0 : }
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 0 : vbdev_forward_io_simple_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
265 : {
266 0 : struct vbdev_forward_io_simple_ctx *ctx = opaque;
267 0 : ocf_forward_token_t token = ctx->token;
268 :
269 0 : assert(token);
270 :
271 0 : spdk_bdev_free_io(bdev_io);
272 0 : spdk_put_io_channel(ctx->ch);
273 0 : env_free(ctx);
274 :
275 0 : ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
276 0 : }
277 :
278 : static void
279 0 : vbdev_forward_io_simple(ocf_volume_t volume, ocf_forward_token_t token,
280 : int dir, uint64_t addr, uint64_t bytes)
281 : {
282 0 : struct vbdev_ocf_base *base =
283 0 : *((struct vbdev_ocf_base **)
284 0 : ocf_volume_get_priv(volume));
285 0 : struct bdev_ocf_data *data = ocf_forward_get_data(token);
286 0 : struct vbdev_forward_io_simple_ctx *ctx;
287 0 : int status = -1;
288 :
289 0 : ctx = env_malloc(sizeof(*ctx), ENV_MEM_NOIO);
290 0 : 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 0 : ctx->ch = spdk_bdev_get_io_channel(base->desc);
298 0 : if (unlikely(ctx->ch == NULL)) {
299 0 : env_free(ctx);
300 0 : ocf_forward_end(token, -EFAULT);
301 0 : return;
302 : }
303 :
304 0 : ctx->token = token;
305 :
306 0 : if (dir == OCF_READ) {
307 0 : status = spdk_bdev_readv(base->desc, ctx->ch, data->iovs,
308 0 : data->iovcnt, addr, bytes,
309 0 : 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 0 : data->iovcnt, addr, bytes,
313 0 : vbdev_forward_io_simple_cb, ctx);
314 0 : }
315 :
316 0 : 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 0 : }
322 0 : }
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 0 : vbdev_ocf_volume_init(void)
344 : {
345 0 : return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
346 : }
347 :
348 : void
349 0 : vbdev_ocf_volume_cleanup(void)
350 : {
351 0 : ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
352 0 : }
353 :
354 0 : SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
|