xref: /spdk/module/bdev/ocf/volume.c (revision 318515b44ec8b67f83bcc9ca83f0c7d5ea919e62)
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 vbdev_ocf_volume_open(ocf_volume_t volume, void *opts)
20 {
21 	struct vbdev_ocf_base **priv = ocf_volume_get_priv(volume);
22 	struct vbdev_ocf_base *base;
23 
24 	if (opts) {
25 		base = opts;
26 	} else {
27 		base = vbdev_ocf_get_base_by_name(ocf_volume_get_uuid(volume)->data);
28 		if (base == NULL) {
29 			return -ENODEV;
30 		}
31 	}
32 
33 	*priv = base;
34 
35 	return 0;
36 }
37 
38 static void
39 vbdev_ocf_volume_close(ocf_volume_t volume)
40 {
41 }
42 
43 static uint64_t
44 vbdev_ocf_volume_get_length(ocf_volume_t volume)
45 {
46 	struct vbdev_ocf_base *base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(volume));
47 	uint64_t len;
48 
49 	len = base->bdev->blocklen * base->bdev->blockcnt;
50 
51 	return len;
52 }
53 
54 static int
55 get_starting_vec(struct iovec *iovs, int iovcnt, uint64_t *offset)
56 {
57 	int i;
58 	size_t off;
59 
60 	off = *offset;
61 
62 	for (i = 0; i < iovcnt; i++) {
63 		if (off < iovs[i].iov_len) {
64 			*offset = off;
65 			return i;
66 		}
67 		off -= iovs[i].iov_len;
68 	}
69 
70 	return -1;
71 }
72 
73 static void
74 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 	i = 0;
82 
83 	while (bytes > 0) {
84 		curr_base = orig_vec[i].iov_base + offset;
85 		len = MIN(bytes, orig_vec[i].iov_len - offset);
86 
87 		cpy_vec[i].iov_base = curr_base;
88 		cpy_vec[i].iov_len = len;
89 
90 		bytes -= len;
91 		offset = 0;
92 		i++;
93 	}
94 }
95 
96 static unsigned int
97 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
98 {
99 	return 131072;
100 }
101 
102 static void
103 vbdev_forward_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
104 {
105 	ocf_forward_token_t token = (ocf_forward_token_t) opaque;
106 
107 	assert(token);
108 
109 	spdk_bdev_free_io(bdev_io);
110 
111 	ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
112 }
113 
114 static void
115 vbdev_forward_io_free_iovs_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
116 {
117 	env_free(bdev_io->u.bdev.iovs);
118 	vbdev_forward_io_cb(bdev_io, success, opaque);
119 }
120 
121 static struct spdk_io_channel *
122 vbdev_forward_get_channel(ocf_volume_t volume, ocf_forward_token_t token)
123 {
124 	struct vbdev_ocf_base *base =
125 		*((struct vbdev_ocf_base **)
126 		  ocf_volume_get_priv(volume));
127 	ocf_queue_t queue = ocf_forward_get_io_queue(token);
128 	struct vbdev_ocf_qctx *qctx;
129 
130 	if (unlikely(ocf_queue_is_mngt(queue))) {
131 		return base->management_channel;
132 	}
133 
134 	qctx = ocf_queue_get_priv(queue);
135 	if (unlikely(qctx == NULL)) {
136 		return NULL;
137 	}
138 
139 	return (base->is_cache) ? qctx->cache_ch : qctx->core_ch;
140 }
141 
142 static void
143 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 	struct vbdev_ocf_base *base =
148 		*((struct vbdev_ocf_base **)
149 		  ocf_volume_get_priv(volume));
150 	struct bdev_ocf_data *data = ocf_forward_get_data(token);
151 	struct spdk_io_channel *ch;
152 	spdk_bdev_io_completion_cb cb = vbdev_forward_io_cb;
153 	bool iovs_allocated = false;
154 	int iovcnt, skip, status = -1;
155 	struct iovec *iovs;
156 
157 	ch = vbdev_forward_get_channel(volume, token);
158 	if (unlikely(ch == NULL)) {
159 		ocf_forward_end(token, -EFAULT);
160 		return;
161 	}
162 
163 	if (bytes == data->size) {
164 		iovs = data->iovs;
165 		iovcnt = data->iovcnt;
166 	} else {
167 		skip = get_starting_vec(data->iovs, data->iovcnt, &offset);
168 		if (skip < 0) {
169 			SPDK_ERRLOG("Offset bigger than data size\n");
170 			ocf_forward_end(token, -OCF_ERR_IO);
171 			return;
172 		}
173 
174 		iovcnt = data->iovcnt - skip;
175 
176 		iovs_allocated = true;
177 		cb = vbdev_forward_io_free_iovs_cb;
178 		iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
179 
180 		if (!iovs) {
181 			SPDK_ERRLOG("Allocation failed\n");
182 			ocf_forward_end(token, -OCF_ERR_NO_MEM);
183 			return;
184 		}
185 
186 		initialize_cpy_vector(iovs, data->iovcnt, &data->iovs[skip],
187 				      iovcnt, offset, bytes);
188 	}
189 
190 	if (dir == OCF_READ) {
191 		status = spdk_bdev_readv(base->desc, ch, iovs, iovcnt,
192 					 addr, bytes, cb, (void *) token);
193 	} else if (dir == OCF_WRITE) {
194 		status = spdk_bdev_writev(base->desc, ch, iovs, iovcnt,
195 					  addr, bytes, cb, (void *) token);
196 	}
197 
198 	if (unlikely(status)) {
199 		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 		if (iovs_allocated) {
202 			env_free(iovs);
203 		}
204 		ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
205 	}
206 }
207 
208 static void
209 vbdev_forward_flush(ocf_volume_t volume, ocf_forward_token_t token)
210 {
211 	struct vbdev_ocf_base *base =
212 		*((struct vbdev_ocf_base **)
213 		  ocf_volume_get_priv(volume));
214 	struct spdk_io_channel *ch;
215 	uint64_t bytes = base->bdev->blockcnt * base->bdev->blocklen;
216 	int status;
217 
218 	ch = vbdev_forward_get_channel(volume, token);
219 	if (unlikely(ch == NULL)) {
220 		ocf_forward_end(token, -EFAULT);
221 		return;
222 	}
223 
224 	status = spdk_bdev_flush(
225 			 base->desc, ch, 0, bytes,
226 			 vbdev_forward_io_cb, (void *)token);
227 	if (unlikely(status)) {
228 		SPDK_ERRLOG("Submission failed with status=%d\n", status);
229 		ocf_forward_end(token, (status == -ENOMEM) ? -OCF_ERR_NO_MEM : -OCF_ERR_IO);
230 	}
231 }
232 
233 static void
234 vbdev_forward_discard(ocf_volume_t volume, ocf_forward_token_t token,
235 		      uint64_t addr, uint64_t bytes)
236 {
237 	struct vbdev_ocf_base *base =
238 		*((struct vbdev_ocf_base **)
239 		  ocf_volume_get_priv(volume));
240 	struct spdk_io_channel *ch;
241 	int status = 0;
242 
243 	ch = vbdev_forward_get_channel(volume, token);
244 	if (unlikely(ch == NULL)) {
245 		ocf_forward_end(token, -EFAULT);
246 		return;
247 	}
248 
249 	status = spdk_bdev_unmap(
250 			 base->desc, ch, addr, bytes,
251 			 vbdev_forward_io_cb, (void *)token);
252 	if (unlikely(status)) {
253 		SPDK_ERRLOG("Submission failed with status=%d\n", status);
254 		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 vbdev_forward_io_simple_cb(struct spdk_bdev_io *bdev_io, bool success, void *opaque)
265 {
266 	struct vbdev_forward_io_simple_ctx *ctx = opaque;
267 	ocf_forward_token_t token = ctx->token;
268 
269 	assert(token);
270 
271 	spdk_bdev_free_io(bdev_io);
272 	spdk_put_io_channel(ctx->ch);
273 	env_free(ctx);
274 
275 	ocf_forward_end(token, success ? 0 : -OCF_ERR_IO);
276 }
277 
278 static void
279 vbdev_forward_io_simple(ocf_volume_t volume, ocf_forward_token_t token,
280 			int dir, uint64_t addr, uint64_t bytes)
281 {
282 	struct vbdev_ocf_base *base =
283 		*((struct vbdev_ocf_base **)
284 		  ocf_volume_get_priv(volume));
285 	struct bdev_ocf_data *data = ocf_forward_get_data(token);
286 	struct vbdev_forward_io_simple_ctx *ctx;
287 	int status = -1;
288 
289 	ctx = env_malloc(sizeof(*ctx), ENV_MEM_NOIO);
290 	if (unlikely(!ctx)) {
291 		ocf_forward_end(token, -OCF_ERR_NO_MEM);
292 		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 	ctx->ch = spdk_bdev_get_io_channel(base->desc);
298 	if (unlikely(ctx->ch == NULL)) {
299 		env_free(ctx);
300 		ocf_forward_end(token, -EFAULT);
301 		return;
302 	}
303 
304 	ctx->token = token;
305 
306 	if (dir == OCF_READ) {
307 		status = spdk_bdev_readv(base->desc, ctx->ch, data->iovs,
308 					 data->iovcnt, addr, bytes,
309 					 vbdev_forward_io_simple_cb, ctx);
310 	} else if (dir == OCF_WRITE) {
311 		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 	if (unlikely(status)) {
317 		SPDK_ERRLOG("Submission failed with status=%d\n", status);
318 		spdk_put_io_channel(ctx->ch);
319 		env_free(ctx);
320 		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 vbdev_ocf_volume_init(void)
344 {
345 	return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
346 }
347 
348 void
349 vbdev_ocf_volume_cleanup(void)
350 {
351 	ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
352 }
353 
354 SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
355