xref: /spdk/module/bdev/ocf/volume.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
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 vbdev_ocf_volume_io_set_data(struct ocf_io *io, ctx_data_t *data,
56 			     uint32_t offset)
57 {
58 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
59 
60 	io_ctx->offset = offset;
61 	io_ctx->data = data;
62 
63 	assert(io_ctx->data != NULL);
64 	if (io_ctx->data->iovs && offset >= io_ctx->data->size) {
65 		return -ENOBUFS;
66 	}
67 
68 	return 0;
69 }
70 
71 static ctx_data_t *
72 vbdev_ocf_volume_io_get_data(struct ocf_io *io)
73 {
74 	return ocf_get_io_ctx(io)->data;
75 }
76 
77 static void
78 vbdev_ocf_volume_io_get(struct ocf_io *io)
79 {
80 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
81 
82 	io_ctx->ref++;
83 }
84 
85 static void
86 vbdev_ocf_volume_io_put(struct ocf_io *io)
87 {
88 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
89 
90 	if (--io_ctx->ref) {
91 		return;
92 	}
93 }
94 
95 static int
96 get_starting_vec(struct iovec *iovs, int iovcnt, int *offset)
97 {
98 	int i;
99 	size_t off;
100 
101 	off = *offset;
102 
103 	for (i = 0; i < iovcnt; i++) {
104 		if (off < iovs[i].iov_len) {
105 			*offset = off;
106 			return i;
107 		}
108 		off -= iovs[i].iov_len;
109 	}
110 
111 	return -1;
112 }
113 
114 static void
115 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 	i = 0;
123 
124 	while (bytes > 0) {
125 		curr_base = orig_vec[i].iov_base + offset;
126 		len = MIN(bytes, orig_vec[i].iov_len - offset);
127 
128 		cpy_vec[i].iov_base = curr_base;
129 		cpy_vec[i].iov_len = len;
130 
131 		bytes -= len;
132 		offset = 0;
133 		i++;
134 	}
135 }
136 
137 static void
138 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 	assert(opaque);
144 
145 	io = opaque;
146 	io_ctx = ocf_get_io_ctx(io);
147 	assert(io_ctx != NULL);
148 
149 	if (!success) {
150 		io_ctx->error = io_ctx->error ? : -OCF_ERR_IO;
151 	}
152 
153 	if (io_ctx->iovs_allocated && bdev_io != NULL) {
154 		env_free(bdev_io->u.bdev.iovs);
155 	}
156 
157 	if (io_ctx->error) {
158 		SPDK_DEBUGLOG(vbdev_ocf_volume,
159 			      "base returned error on io submission: %d\n", io_ctx->error);
160 	}
161 
162 	if (io->io_queue == NULL && io_ctx->ch != NULL) {
163 		spdk_put_io_channel(io_ctx->ch);
164 	}
165 
166 	vbdev_ocf_volume_io_put(io);
167 	if (bdev_io) {
168 		spdk_bdev_free_io(bdev_io);
169 	}
170 
171 	if (--io_ctx->rq_cnt == 0) {
172 		io->end(io, io_ctx->error);
173 	}
174 }
175 
176 static int
177 prepare_submit(struct ocf_io *io)
178 {
179 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
180 	struct vbdev_ocf_qctx *qctx;
181 	struct vbdev_ocf_base *base;
182 	ocf_queue_t q = io->io_queue;
183 	ocf_cache_t cache;
184 	struct vbdev_ocf_cache_ctx *cctx;
185 	int rc = 0;
186 
187 	io_ctx->rq_cnt++;
188 	if (io_ctx->rq_cnt != 1) {
189 		return 0;
190 	}
191 
192 	vbdev_ocf_volume_io_get(io);
193 	base = *((struct vbdev_ocf_base **)ocf_volume_get_priv(ocf_io_get_volume(io)));
194 
195 	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 		io_ctx->ch = spdk_bdev_get_io_channel(base->desc);
199 		if (io_ctx->ch == NULL) {
200 			return -EPERM;
201 		}
202 		return 0;
203 	}
204 
205 	cache = ocf_queue_get_cache(q);
206 	cctx = ocf_cache_get_priv(cache);
207 	if (cctx == NULL) {
208 		return -EFAULT;
209 	}
210 
211 	if (q == cctx->mngt_queue) {
212 		io_ctx->ch = base->management_channel;
213 		return 0;
214 	}
215 
216 	qctx = ocf_queue_get_priv(q);
217 	if (qctx == NULL) {
218 		return -EFAULT;
219 	}
220 
221 	if (base->is_cache) {
222 		io_ctx->ch = qctx->cache_ch;
223 	} else {
224 		io_ctx->ch = qctx->core_ch;
225 	}
226 
227 	return rc;
228 }
229 
230 static void
231 vbdev_ocf_volume_submit_flush(struct ocf_io *io)
232 {
233 	struct vbdev_ocf_base *base =
234 		*((struct vbdev_ocf_base **)
235 		  ocf_volume_get_priv(ocf_io_get_volume(io)));
236 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
237 	int status;
238 
239 	status = prepare_submit(io);
240 	if (status) {
241 		SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
242 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
243 		return;
244 	}
245 
246 	status = spdk_bdev_flush(
247 			 base->desc, io_ctx->ch,
248 			 io->addr, io->bytes,
249 			 vbdev_ocf_volume_submit_io_cb, io);
250 	if (status) {
251 		/* Since callback is not called, we need to do it manually to free io structures */
252 		SPDK_ERRLOG("Submission failed with status=%d\n", status);
253 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
254 	}
255 }
256 
257 static void
258 vbdev_ocf_volume_submit_io(struct ocf_io *io)
259 {
260 	struct vbdev_ocf_base *base =
261 		*((struct vbdev_ocf_base **)
262 		  ocf_volume_get_priv(ocf_io_get_volume(io)));
263 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
264 	struct iovec *iovs;
265 	int iovcnt, status = 0, i, offset;
266 	uint64_t addr, len;
267 
268 	if (io->flags == OCF_WRITE_FLUSH) {
269 		vbdev_ocf_volume_submit_flush(io);
270 		return;
271 	}
272 
273 	status = prepare_submit(io);
274 	if (status) {
275 		SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
276 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
277 		return;
278 	}
279 
280 	/* IO fields */
281 	addr = io->addr;
282 	len = io->bytes;
283 	offset = io_ctx->offset;
284 
285 	if (len < io_ctx->data->size) {
286 		if (io_ctx->data->iovcnt == 1) {
287 			if (io->dir == OCF_READ) {
288 				status = spdk_bdev_read(base->desc, io_ctx->ch,
289 							io_ctx->data->iovs[0].iov_base + offset, addr, len,
290 							vbdev_ocf_volume_submit_io_cb, io);
291 			} else if (io->dir == OCF_WRITE) {
292 				status = spdk_bdev_write(base->desc, io_ctx->ch,
293 							 io_ctx->data->iovs[0].iov_base + offset, addr, len,
294 							 vbdev_ocf_volume_submit_io_cb, io);
295 			}
296 			goto end;
297 		} else {
298 			i = get_starting_vec(io_ctx->data->iovs, io_ctx->data->iovcnt, &offset);
299 
300 			if (i < 0) {
301 				SPDK_ERRLOG("offset bigger than data size\n");
302 				vbdev_ocf_volume_submit_io_cb(NULL, false, io);
303 				return;
304 			}
305 
306 			iovcnt = io_ctx->data->iovcnt - i;
307 
308 			io_ctx->iovs_allocated = true;
309 			iovs = env_malloc(sizeof(*iovs) * iovcnt, ENV_MEM_NOIO);
310 
311 			if (!iovs) {
312 				SPDK_ERRLOG("allocation failed\n");
313 				vbdev_ocf_volume_submit_io_cb(NULL, false, io);
314 				return;
315 			}
316 
317 			initialize_cpy_vector(iovs, io_ctx->data->iovcnt, &io_ctx->data->iovs[i],
318 					      iovcnt, offset, len);
319 		}
320 	} else {
321 		iovs = io_ctx->data->iovs;
322 		iovcnt = io_ctx->data->iovcnt;
323 	}
324 
325 	if (io->dir == OCF_READ) {
326 		status = spdk_bdev_readv(base->desc, io_ctx->ch,
327 					 iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io);
328 	} else if (io->dir == OCF_WRITE) {
329 		status = spdk_bdev_writev(base->desc, io_ctx->ch,
330 					  iovs, iovcnt, addr, len, vbdev_ocf_volume_submit_io_cb, io);
331 	}
332 
333 end:
334 	if (status) {
335 		if (status == -ENOMEM) {
336 			io_ctx->error = -OCF_ERR_NO_MEM;
337 		} else {
338 			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 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
343 	}
344 }
345 
346 static void
347 vbdev_ocf_volume_submit_discard(struct ocf_io *io)
348 {
349 	struct vbdev_ocf_base *base =
350 		*((struct vbdev_ocf_base **)
351 		  ocf_volume_get_priv(ocf_io_get_volume(io)));
352 	struct ocf_io_ctx *io_ctx = ocf_get_io_ctx(io);
353 	int status = 0;
354 
355 	status = prepare_submit(io);
356 	if (status) {
357 		SPDK_ERRLOG("Preparing io failed with status=%d\n", status);
358 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
359 		return;
360 	}
361 
362 	status = spdk_bdev_unmap(
363 			 base->desc, io_ctx->ch,
364 			 io->addr, io->bytes,
365 			 vbdev_ocf_volume_submit_io_cb, io);
366 	if (status) {
367 		/* Since callback is not called, we need to do it manually to free io structures */
368 		SPDK_ERRLOG("Submission failed with status=%d\n", status);
369 		vbdev_ocf_volume_submit_io_cb(NULL, false, io);
370 	}
371 }
372 
373 static void
374 vbdev_ocf_volume_submit_metadata(struct ocf_io *io)
375 {
376 	/* Implement with persistent metadata support */
377 }
378 
379 static unsigned int
380 vbdev_ocf_volume_get_max_io_size(ocf_volume_t volume)
381 {
382 	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 vbdev_ocf_volume_init(void)
410 {
411 	return ocf_ctx_register_volume_type(vbdev_ocf_ctx, SPDK_OBJECT, &vbdev_volume_props);
412 }
413 
414 void
415 vbdev_ocf_volume_cleanup(void)
416 {
417 	ocf_ctx_unregister_volume_type(vbdev_ocf_ctx, SPDK_OBJECT);
418 }
419 
420 SPDK_LOG_REGISTER_COMPONENT(vbdev_ocf_volume)
421