xref: /spdk/module/bdev/ocf/ctx.c (revision 7506a7aa53d239f533af3bc768f0d2af55e735fe)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <ocf/ocf.h>
34 #include <execinfo.h>
35 
36 #include "spdk/env.h"
37 #include "spdk/log.h"
38 
39 #include "ctx.h"
40 #include "data.h"
41 
42 ocf_ctx_t vbdev_ocf_ctx;
43 
44 static ctx_data_t *
45 vbdev_ocf_ctx_data_alloc(uint32_t pages)
46 {
47 	struct bdev_ocf_data *data;
48 	void *buf;
49 	uint32_t sz;
50 
51 	data = vbdev_ocf_data_alloc(1);
52 
53 	sz = pages * PAGE_SIZE;
54 	buf = spdk_malloc(sz, PAGE_SIZE, NULL,
55 			  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
56 	if (buf == NULL) {
57 		return NULL;
58 	}
59 
60 	vbdev_ocf_iovs_add(data, buf, sz);
61 
62 	data->size = sz;
63 
64 	return data;
65 }
66 
67 static void
68 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
69 {
70 	struct bdev_ocf_data *data = ctx_data;
71 	int i;
72 
73 	if (!data) {
74 		return;
75 	}
76 
77 	for (i = 0; i < data->iovcnt; i++) {
78 		spdk_free(data->iovs[i].iov_base);
79 	}
80 
81 	vbdev_ocf_data_free(data);
82 }
83 
84 static int
85 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
86 {
87 	/* TODO [mlock]: add mlock option */
88 	return 0;
89 }
90 
91 static void
92 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
93 {
94 	/* TODO [mlock]: add mlock option */
95 }
96 
97 static size_t
98 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
99 {
100 	size_t i, len, done = 0;
101 
102 	for (i = 0; i < iovcnt; i++) {
103 		if (offset >= iov[i].iov_len) {
104 			offset -= iov[i].iov_len;
105 			continue;
106 		}
107 
108 		if (iov[i].iov_base == NULL) {
109 			continue;
110 		}
111 
112 		if (done >= size) {
113 			break;
114 		}
115 
116 		len = MIN(size - done, iov[i].iov_len - offset);
117 		memcpy(buf, iov[i].iov_base + offset, len);
118 		buf += len;
119 		done += len;
120 		offset = 0;
121 	}
122 
123 	return done;
124 }
125 
126 static uint32_t
127 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
128 {
129 	struct bdev_ocf_data *s = src;
130 	uint32_t size_local;
131 
132 	size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
133 	s->seek += size_local;
134 
135 	return size_local;
136 }
137 
138 static size_t
139 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
140 {
141 	size_t i, len, done = 0;
142 
143 	for (i = 0; i < iovcnt; i++) {
144 		if (offset >= iov[i].iov_len) {
145 			offset -= iov[i].iov_len;
146 			continue;
147 		}
148 
149 		if (iov[i].iov_base == NULL) {
150 			continue;
151 		}
152 
153 		if (done >= size) {
154 			break;
155 		}
156 
157 		len = MIN(size - done, iov[i].iov_len - offset);
158 		memcpy(iov[i].iov_base + offset, buf, len);
159 		buf += len;
160 		done += len;
161 		offset = 0;
162 	}
163 
164 	return done;
165 }
166 
167 static uint32_t
168 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
169 {
170 	struct bdev_ocf_data *d = dst;
171 	uint32_t size_local;
172 
173 	size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
174 	d->seek += size_local;
175 
176 	return size_local;
177 }
178 
179 static size_t
180 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
181 {
182 	size_t i, len, done = 0;
183 
184 	for (i = 0; i < iovcnt; i++) {
185 		if (offset >= iov[i].iov_len) {
186 			offset -= iov[i].iov_len;
187 			continue;
188 		}
189 
190 		if (iov[i].iov_base == NULL) {
191 			continue;
192 		}
193 
194 		if (done >= size) {
195 			break;
196 		}
197 
198 		len = MIN(size - done, iov[i].iov_len - offset);
199 		memset(iov[i].iov_base + offset, byte, len);
200 		done += len;
201 		offset = 0;
202 	}
203 
204 	return done;
205 }
206 
207 static uint32_t
208 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
209 {
210 	struct bdev_ocf_data *d = dst;
211 	uint32_t size_local;
212 
213 	size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
214 	d->seek += size_local;
215 
216 	return size_local;
217 }
218 
219 static uint32_t
220 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
221 {
222 	struct bdev_ocf_data *d = dst;
223 	uint32_t off = 0;
224 
225 	switch (seek) {
226 	case ctx_data_seek_begin:
227 		off = MIN(offset, d->size);
228 		d->seek = off;
229 		break;
230 	case ctx_data_seek_current:
231 		off = MIN(offset, d->size - d->seek);
232 		d->seek += off;
233 		break;
234 	}
235 
236 	return off;
237 }
238 
239 static uint64_t
240 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to,
241 		       uint64_t from, uint64_t bytes)
242 {
243 	struct bdev_ocf_data *s = src;
244 	struct bdev_ocf_data *d = dst;
245 	uint32_t it_iov = 0;
246 	uint32_t it_off = 0;
247 	uint32_t n, sz;
248 
249 	bytes = MIN(bytes, s->size - from);
250 	bytes = MIN(bytes, d->size - to);
251 	sz = bytes;
252 
253 	while (from || bytes) {
254 		if (s->iovs[it_iov].iov_len == it_off) {
255 			it_iov++;
256 			it_off = 0;
257 			continue;
258 		}
259 
260 		if (from) {
261 			n = MIN(from, s->iovs[it_iov].iov_len);
262 			from -= n;
263 		} else {
264 			n = MIN(bytes, s->iovs[it_iov].iov_len);
265 			buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
266 			bytes -= n;
267 			to += n;
268 		}
269 
270 		it_off += n;
271 	}
272 
273 	return sz;
274 }
275 
276 static void
277 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
278 {
279 	struct bdev_ocf_data *data = ctx_data;
280 	struct iovec *iovs = data->iovs;
281 	int i;
282 
283 	for (i = 0; i < data->iovcnt; i++) {
284 		if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
285 			assert(false);
286 		}
287 	}
288 }
289 
290 int vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
291 {
292 	int rc;
293 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
294 
295 	pthread_mutex_lock(&ctx->lock);
296 	rc = ocf_queue_create(cache, queue, ops);
297 	pthread_mutex_unlock(&ctx->lock);
298 	return rc;
299 }
300 
301 void vbdev_ocf_queue_put(ocf_queue_t queue)
302 {
303 	ocf_cache_t cache = ocf_queue_get_cache(queue);
304 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
305 
306 	pthread_mutex_lock(&ctx->lock);
307 	ocf_queue_put(queue);
308 	pthread_mutex_unlock(&ctx->lock);
309 }
310 
311 void vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
312 {
313 	if (env_atomic_dec_return(&ctx->refcnt) == 0) {
314 		pthread_mutex_destroy(&ctx->lock);
315 		free(ctx);
316 	}
317 }
318 
319 void vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
320 {
321 	env_atomic_inc(&ctx->refcnt);
322 }
323 
324 struct cleaner_priv {
325 	struct spdk_poller *poller;
326 	ocf_queue_t         queue;
327 	uint64_t            next_run;
328 };
329 
330 static int
331 cleaner_poll(void *arg)
332 {
333 	ocf_cleaner_t cleaner = arg;
334 	struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
335 	uint32_t iono = ocf_queue_pending_io(priv->queue);
336 	int i, max = spdk_min(32, iono);
337 
338 	for (i = 0; i < max; i++) {
339 		ocf_queue_run_single(priv->queue);
340 	}
341 
342 	if (spdk_get_ticks() >= priv->next_run) {
343 		ocf_cleaner_run(cleaner, priv->queue);
344 		return SPDK_POLLER_BUSY;
345 	}
346 
347 	if (iono > 0) {
348 		return SPDK_POLLER_BUSY;
349 	} else {
350 		return SPDK_POLLER_IDLE;
351 	}
352 }
353 
354 static void
355 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
356 {
357 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
358 
359 	priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
360 }
361 
362 static void
363 cleaner_queue_kick(ocf_queue_t q)
364 {
365 }
366 
367 static void
368 cleaner_queue_stop(ocf_queue_t q)
369 {
370 	struct cleaner_priv *cpriv = ocf_queue_get_priv(q);
371 
372 	if (cpriv) {
373 		spdk_poller_unregister(&cpriv->poller);
374 		free(cpriv);
375 	}
376 }
377 
378 const struct ocf_queue_ops cleaner_queue_ops = {
379 	.kick_sync = cleaner_queue_kick,
380 	.kick = cleaner_queue_kick,
381 	.stop = cleaner_queue_stop,
382 };
383 
384 static int
385 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
386 {
387 	int rc;
388 	struct cleaner_priv        *priv  = calloc(1, sizeof(*priv));
389 	ocf_cache_t                 cache = ocf_cleaner_get_cache(c);
390 	struct vbdev_ocf_cache_ctx *cctx  = ocf_cache_get_priv(cache);
391 
392 	if (priv == NULL) {
393 		return -ENOMEM;
394 	}
395 
396 	rc = vbdev_ocf_queue_create(cache, &priv->queue, &cleaner_queue_ops);
397 	if (rc) {
398 		free(priv);
399 		return rc;
400 	}
401 
402 	ocf_queue_set_priv(priv->queue, priv);
403 
404 	cctx->cleaner_queue  = priv->queue;
405 
406 	ocf_cleaner_set_cmpl(c, cleaner_cmpl);
407 	ocf_cleaner_set_priv(c, priv);
408 
409 	return 0;
410 }
411 
412 static void
413 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
414 {
415 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
416 
417 	vbdev_ocf_queue_put(priv->queue);
418 }
419 
420 static void
421 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
422 {
423 	struct cleaner_priv *priv  = ocf_cleaner_get_priv(cleaner);
424 
425 	if (priv->poller) {
426 		return;
427 	}
428 
429 	/* We start cleaner poller at the same thread where cache was created
430 	 * TODO: allow user to specify core at which cleaner should run */
431 	priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
432 }
433 
434 /* This function is main way by which OCF communicates with user
435  * We don't want to use SPDK_LOG here because debugging information that is
436  * associated with every print message is not helpful in callback that only prints info
437  * while the real source is somewhere in OCF code */
438 static int
439 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
440 			 const char *fmt, va_list args)
441 {
442 	int spdk_lvl;
443 
444 	switch (lvl) {
445 	case log_emerg:
446 	case log_alert:
447 	case log_crit:
448 	case log_err:
449 		spdk_lvl = SPDK_LOG_ERROR;
450 		break;
451 
452 	case log_warn:
453 		spdk_lvl = SPDK_LOG_WARN;
454 		break;
455 
456 	case log_notice:
457 		spdk_lvl = SPDK_LOG_NOTICE;
458 		break;
459 
460 	case log_info:
461 	case log_debug:
462 	default:
463 		spdk_lvl = SPDK_LOG_INFO;
464 	}
465 
466 	spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
467 	return 0;
468 }
469 
470 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
471 	.name = "OCF SPDK",
472 
473 	.ops = {
474 		.data = {
475 			.alloc = vbdev_ocf_ctx_data_alloc,
476 			.free = vbdev_ocf_ctx_data_free,
477 			.mlock = vbdev_ocf_ctx_data_mlock,
478 			.munlock = vbdev_ocf_ctx_data_munlock,
479 			.read = vbdev_ocf_ctx_data_rd,
480 			.write = vbdev_ocf_ctx_data_wr,
481 			.zero = vbdev_ocf_ctx_data_zero,
482 			.seek = vbdev_ocf_ctx_data_seek,
483 			.copy = vbdev_ocf_ctx_data_cpy,
484 			.secure_erase = vbdev_ocf_ctx_data_secure_erase,
485 		},
486 
487 		.cleaner = {
488 			.init = vbdev_ocf_ctx_cleaner_init,
489 			.stop = vbdev_ocf_ctx_cleaner_stop,
490 			.kick = vbdev_ocf_ctx_cleaner_kick,
491 		},
492 
493 		.logger = {
494 			.print = vbdev_ocf_ctx_log_printf,
495 			.dump_stack = NULL,
496 		},
497 
498 	},
499 };
500 
501 int
502 vbdev_ocf_ctx_init(void)
503 {
504 	int ret;
505 
506 	ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
507 	if (ret < 0) {
508 		return ret;
509 	}
510 
511 	return 0;
512 }
513 
514 void
515 vbdev_ocf_ctx_cleanup(void)
516 {
517 	ocf_ctx_put(vbdev_ocf_ctx);
518 	vbdev_ocf_ctx = NULL;
519 }
520