xref: /spdk/module/bdev/ocf/ctx.c (revision 8bb0ded3e55c182cea67af1f6790f8de5f38c05f)
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 "ocf_env.h"
41 #include "data.h"
42 
43 ocf_ctx_t vbdev_ocf_ctx;
44 
45 static ctx_data_t *
46 vbdev_ocf_ctx_data_alloc(uint32_t pages)
47 {
48 	struct bdev_ocf_data *data;
49 	void *buf;
50 	uint32_t sz;
51 
52 	data = vbdev_ocf_data_alloc(1);
53 
54 	sz = pages * PAGE_SIZE;
55 	buf = spdk_malloc(sz, PAGE_SIZE, NULL,
56 			  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
57 	if (buf == NULL) {
58 		return NULL;
59 	}
60 
61 	vbdev_ocf_iovs_add(data, buf, sz);
62 
63 	data->size = sz;
64 
65 	return data;
66 }
67 
68 static void
69 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
70 {
71 	struct bdev_ocf_data *data = ctx_data;
72 	int i;
73 
74 	if (!data) {
75 		return;
76 	}
77 
78 	for (i = 0; i < data->iovcnt; i++) {
79 		spdk_free(data->iovs[i].iov_base);
80 	}
81 
82 	vbdev_ocf_data_free(data);
83 }
84 
85 static int
86 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
87 {
88 	/* TODO [mlock]: add mlock option */
89 	return 0;
90 }
91 
92 static void
93 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
94 {
95 	/* TODO [mlock]: add mlock option */
96 }
97 
98 static size_t
99 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
100 {
101 	size_t i, len, done = 0;
102 
103 	for (i = 0; i < iovcnt; i++) {
104 		if (offset >= iov[i].iov_len) {
105 			offset -= iov[i].iov_len;
106 			continue;
107 		}
108 
109 		if (iov[i].iov_base == NULL) {
110 			continue;
111 		}
112 
113 		if (done >= size) {
114 			break;
115 		}
116 
117 		len = MIN(size - done, iov[i].iov_len - offset);
118 		memcpy(buf, iov[i].iov_base + offset, len);
119 		buf += len;
120 		done += len;
121 		offset = 0;
122 	}
123 
124 	return done;
125 }
126 
127 static uint32_t
128 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
129 {
130 	struct bdev_ocf_data *s = src;
131 	uint32_t size_local;
132 
133 	size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
134 	s->seek += size_local;
135 
136 	return size_local;
137 }
138 
139 static size_t
140 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
141 {
142 	size_t i, len, done = 0;
143 
144 	for (i = 0; i < iovcnt; i++) {
145 		if (offset >= iov[i].iov_len) {
146 			offset -= iov[i].iov_len;
147 			continue;
148 		}
149 
150 		if (iov[i].iov_base == NULL) {
151 			continue;
152 		}
153 
154 		if (done >= size) {
155 			break;
156 		}
157 
158 		len = MIN(size - done, iov[i].iov_len - offset);
159 		memcpy(iov[i].iov_base + offset, buf, len);
160 		buf += len;
161 		done += len;
162 		offset = 0;
163 	}
164 
165 	return done;
166 }
167 
168 static uint32_t
169 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
170 {
171 	struct bdev_ocf_data *d = dst;
172 	uint32_t size_local;
173 
174 	size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
175 	d->seek += size_local;
176 
177 	return size_local;
178 }
179 
180 static size_t
181 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
182 {
183 	size_t i, len, done = 0;
184 
185 	for (i = 0; i < iovcnt; i++) {
186 		if (offset >= iov[i].iov_len) {
187 			offset -= iov[i].iov_len;
188 			continue;
189 		}
190 
191 		if (iov[i].iov_base == NULL) {
192 			continue;
193 		}
194 
195 		if (done >= size) {
196 			break;
197 		}
198 
199 		len = MIN(size - done, iov[i].iov_len - offset);
200 		memset(iov[i].iov_base + offset, byte, len);
201 		done += len;
202 		offset = 0;
203 	}
204 
205 	return done;
206 }
207 
208 static uint32_t
209 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
210 {
211 	struct bdev_ocf_data *d = dst;
212 	uint32_t size_local;
213 
214 	size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
215 	d->seek += size_local;
216 
217 	return size_local;
218 }
219 
220 static uint32_t
221 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
222 {
223 	struct bdev_ocf_data *d = dst;
224 	uint32_t off = 0;
225 
226 	switch (seek) {
227 	case ctx_data_seek_begin:
228 		off = MIN(offset, d->size);
229 		d->seek = off;
230 		break;
231 	case ctx_data_seek_current:
232 		off = MIN(offset, d->size - d->seek);
233 		d->seek += off;
234 		break;
235 	}
236 
237 	return off;
238 }
239 
240 static uint64_t
241 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to,
242 		       uint64_t from, uint64_t bytes)
243 {
244 	struct bdev_ocf_data *s = src;
245 	struct bdev_ocf_data *d = dst;
246 	uint32_t it_iov = 0;
247 	uint32_t it_off = 0;
248 	uint32_t n, sz;
249 
250 	bytes = MIN(bytes, s->size - from);
251 	bytes = MIN(bytes, d->size - to);
252 	sz = bytes;
253 
254 	while (from || bytes) {
255 		if (s->iovs[it_iov].iov_len == it_off) {
256 			it_iov++;
257 			it_off = 0;
258 			continue;
259 		}
260 
261 		if (from) {
262 			n = MIN(from, s->iovs[it_iov].iov_len);
263 			from -= n;
264 		} else {
265 			n = MIN(bytes, s->iovs[it_iov].iov_len);
266 			buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
267 			bytes -= n;
268 			to += n;
269 		}
270 
271 		it_off += n;
272 	}
273 
274 	return sz;
275 }
276 
277 static void
278 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
279 {
280 	struct bdev_ocf_data *data = ctx_data;
281 	struct iovec *iovs = data->iovs;
282 	int i;
283 
284 	for (i = 0; i < data->iovcnt; i++) {
285 		if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
286 			assert(false);
287 		}
288 	}
289 }
290 
291 int vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
292 {
293 	int rc;
294 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
295 
296 	pthread_mutex_lock(&ctx->lock);
297 	rc = ocf_queue_create(cache, queue, ops);
298 	pthread_mutex_unlock(&ctx->lock);
299 	return rc;
300 }
301 
302 void vbdev_ocf_queue_put(ocf_queue_t queue)
303 {
304 	ocf_cache_t cache = ocf_queue_get_cache(queue);
305 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
306 
307 	pthread_mutex_lock(&ctx->lock);
308 	ocf_queue_put(queue);
309 	pthread_mutex_unlock(&ctx->lock);
310 }
311 
312 void vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
313 {
314 	if (env_atomic_dec_return(&ctx->refcnt) == 0) {
315 		pthread_mutex_destroy(&ctx->lock);
316 		free(ctx);
317 	}
318 }
319 
320 void vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
321 {
322 	env_atomic_inc(&ctx->refcnt);
323 }
324 
325 struct cleaner_priv {
326 	struct spdk_poller *poller;
327 	ocf_queue_t         queue;
328 	uint64_t            next_run;
329 };
330 
331 static int
332 cleaner_poll(void *arg)
333 {
334 	ocf_cleaner_t cleaner = arg;
335 	struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
336 	uint32_t iono = ocf_queue_pending_io(priv->queue);
337 	int i, max = spdk_min(32, iono);
338 
339 	for (i = 0; i < max; i++) {
340 		ocf_queue_run_single(priv->queue);
341 	}
342 
343 	if (spdk_get_ticks() >= priv->next_run) {
344 		ocf_cleaner_run(cleaner, priv->queue);
345 		return SPDK_POLLER_BUSY;
346 	}
347 
348 	if (iono > 0) {
349 		return SPDK_POLLER_BUSY;
350 	} else {
351 		return SPDK_POLLER_IDLE;
352 	}
353 }
354 
355 static void
356 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
357 {
358 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
359 
360 	priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
361 }
362 
363 static void
364 cleaner_queue_kick(ocf_queue_t q)
365 {
366 }
367 
368 static void
369 cleaner_queue_stop(ocf_queue_t q)
370 {
371 	struct cleaner_priv *cpriv = ocf_queue_get_priv(q);
372 
373 	if (cpriv) {
374 		spdk_poller_unregister(&cpriv->poller);
375 		free(cpriv);
376 	}
377 }
378 
379 const struct ocf_queue_ops cleaner_queue_ops = {
380 	.kick_sync = cleaner_queue_kick,
381 	.kick = cleaner_queue_kick,
382 	.stop = cleaner_queue_stop,
383 };
384 
385 static int
386 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
387 {
388 	int rc;
389 	struct cleaner_priv        *priv  = calloc(1, sizeof(*priv));
390 	ocf_cache_t                 cache = ocf_cleaner_get_cache(c);
391 	struct vbdev_ocf_cache_ctx *cctx  = ocf_cache_get_priv(cache);
392 
393 	if (priv == NULL) {
394 		return -ENOMEM;
395 	}
396 
397 	rc = vbdev_ocf_queue_create(cache, &priv->queue, &cleaner_queue_ops);
398 	if (rc) {
399 		free(priv);
400 		return rc;
401 	}
402 
403 	ocf_queue_set_priv(priv->queue, priv);
404 
405 	cctx->cleaner_queue  = priv->queue;
406 
407 	ocf_cleaner_set_cmpl(c, cleaner_cmpl);
408 	ocf_cleaner_set_priv(c, priv);
409 
410 	return 0;
411 }
412 
413 static void
414 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
415 {
416 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
417 
418 	vbdev_ocf_queue_put(priv->queue);
419 }
420 
421 static void
422 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
423 {
424 	struct cleaner_priv *priv  = ocf_cleaner_get_priv(cleaner);
425 
426 	if (priv->poller) {
427 		return;
428 	}
429 
430 	/* We start cleaner poller at the same thread where cache was created
431 	 * TODO: allow user to specify core at which cleaner should run */
432 	priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
433 }
434 
435 static void
436 vbdev_ocf_md_kick(void *ctx)
437 {
438 	ocf_metadata_updater_t mu = ctx;
439 	ocf_cache_t cache = ocf_metadata_updater_get_cache(mu);
440 
441 	ocf_metadata_updater_run(mu);
442 
443 	/* Decrease cache ref count after metadata has been updated */
444 	ocf_mngt_cache_put(cache);
445 }
446 
447 static int
448 vbdev_ocf_volume_updater_init(ocf_metadata_updater_t mu)
449 {
450 	struct spdk_thread *md_thread = spdk_get_thread();
451 
452 	ocf_metadata_updater_set_priv(mu, md_thread);
453 
454 	return 0;
455 }
456 
457 static void
458 vbdev_ocf_volume_updater_stop(ocf_metadata_updater_t mu)
459 {
460 
461 }
462 
463 static void
464 vbdev_ocf_volume_updater_kick(ocf_metadata_updater_t mu)
465 {
466 	struct spdk_thread *md_thread = ocf_metadata_updater_get_priv(mu);
467 	ocf_cache_t cache = ocf_metadata_updater_get_cache(mu);
468 
469 	/* Increase cache ref count prior sending a message to a thread
470 	 * for metadata update */
471 	ocf_mngt_cache_get(cache);
472 
473 	/* We need to send message to updater thread because
474 	 * kick can happen from any thread */
475 	spdk_thread_send_msg(md_thread, vbdev_ocf_md_kick, mu);
476 }
477 
478 /* This function is main way by which OCF communicates with user
479  * We don't want to use SPDK_LOG here because debugging information that is
480  * associated with every print message is not helpful in callback that only prints info
481  * while the real source is somewhere in OCF code */
482 static int
483 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
484 			 const char *fmt, va_list args)
485 {
486 	int spdk_lvl;
487 
488 	switch (lvl) {
489 	case log_emerg:
490 	case log_alert:
491 	case log_crit:
492 	case log_err:
493 		spdk_lvl = SPDK_LOG_ERROR;
494 		break;
495 
496 	case log_warn:
497 		spdk_lvl = SPDK_LOG_WARN;
498 		break;
499 
500 	case log_notice:
501 		spdk_lvl = SPDK_LOG_NOTICE;
502 		break;
503 
504 	case log_info:
505 	case log_debug:
506 	default:
507 		spdk_lvl = SPDK_LOG_INFO;
508 	}
509 
510 	spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
511 	return 0;
512 }
513 
514 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
515 	.name = "OCF SPDK",
516 
517 	.ops = {
518 		.data = {
519 			.alloc = vbdev_ocf_ctx_data_alloc,
520 			.free = vbdev_ocf_ctx_data_free,
521 			.mlock = vbdev_ocf_ctx_data_mlock,
522 			.munlock = vbdev_ocf_ctx_data_munlock,
523 			.read = vbdev_ocf_ctx_data_rd,
524 			.write = vbdev_ocf_ctx_data_wr,
525 			.zero = vbdev_ocf_ctx_data_zero,
526 			.seek = vbdev_ocf_ctx_data_seek,
527 			.copy = vbdev_ocf_ctx_data_cpy,
528 			.secure_erase = vbdev_ocf_ctx_data_secure_erase,
529 		},
530 
531 		.metadata_updater = {
532 			.init = vbdev_ocf_volume_updater_init,
533 			.stop = vbdev_ocf_volume_updater_stop,
534 			.kick = vbdev_ocf_volume_updater_kick,
535 		},
536 
537 		.cleaner = {
538 			.init = vbdev_ocf_ctx_cleaner_init,
539 			.stop = vbdev_ocf_ctx_cleaner_stop,
540 			.kick = vbdev_ocf_ctx_cleaner_kick,
541 		},
542 
543 		.logger = {
544 			.print = vbdev_ocf_ctx_log_printf,
545 			.dump_stack = NULL,
546 		},
547 
548 	},
549 };
550 
551 int
552 vbdev_ocf_ctx_init(void)
553 {
554 	int ret;
555 
556 	ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
557 	if (ret < 0) {
558 		return ret;
559 	}
560 
561 	return 0;
562 }
563 
564 void
565 vbdev_ocf_ctx_cleanup(void)
566 {
567 	ocf_ctx_put(vbdev_ocf_ctx);
568 	vbdev_ocf_ctx = NULL;
569 }
570