xref: /spdk/module/bdev/ocf/ctx.c (revision 60982c759db49b4f4579f16e3b24df0725ba4b94)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2018 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include <ocf/ocf.h>
7 #ifdef SPDK_HAVE_EXECINFO_H
8 #include <execinfo.h>
9 #endif
10 
11 #include "spdk/env.h"
12 #include "spdk/log.h"
13 
14 #include "ctx.h"
15 #include "data.h"
16 
17 ocf_ctx_t vbdev_ocf_ctx;
18 
19 static ctx_data_t *
20 vbdev_ocf_ctx_data_alloc(uint32_t pages)
21 {
22 	struct bdev_ocf_data *data;
23 	void *buf;
24 	uint32_t sz;
25 
26 	data = vbdev_ocf_data_alloc(1);
27 	if (data == NULL) {
28 		return NULL;
29 	}
30 
31 	sz = pages * PAGE_SIZE;
32 	buf = spdk_malloc(sz, PAGE_SIZE, NULL,
33 			  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
34 	if (buf == NULL) {
35 		vbdev_ocf_data_free(data);
36 		return NULL;
37 	}
38 
39 	vbdev_ocf_iovs_add(data, buf, sz);
40 
41 	data->size = sz;
42 
43 	return data;
44 }
45 
46 static void
47 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
48 {
49 	struct bdev_ocf_data *data = ctx_data;
50 	int i;
51 
52 	if (!data) {
53 		return;
54 	}
55 
56 	for (i = 0; i < data->iovcnt; i++) {
57 		spdk_free(data->iovs[i].iov_base);
58 	}
59 
60 	vbdev_ocf_data_free(data);
61 }
62 
63 static int
64 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
65 {
66 	/* TODO [mlock]: add mlock option */
67 	return 0;
68 }
69 
70 static void
71 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
72 {
73 	/* TODO [mlock]: add mlock option */
74 }
75 
76 static size_t
77 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
78 {
79 	size_t i, len, done = 0;
80 
81 	for (i = 0; i < iovcnt; i++) {
82 		if (offset >= iov[i].iov_len) {
83 			offset -= iov[i].iov_len;
84 			continue;
85 		}
86 
87 		if (iov[i].iov_base == NULL) {
88 			continue;
89 		}
90 
91 		if (done >= size) {
92 			break;
93 		}
94 
95 		len = MIN(size - done, iov[i].iov_len - offset);
96 		memcpy(buf, iov[i].iov_base + offset, len);
97 		buf += len;
98 		done += len;
99 		offset = 0;
100 	}
101 
102 	return done;
103 }
104 
105 static uint32_t
106 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
107 {
108 	struct bdev_ocf_data *s = src;
109 	uint32_t size_local;
110 
111 	size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
112 	s->seek += size_local;
113 
114 	return size_local;
115 }
116 
117 static size_t
118 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
119 {
120 	size_t i, len, done = 0;
121 
122 	for (i = 0; i < iovcnt; i++) {
123 		if (offset >= iov[i].iov_len) {
124 			offset -= iov[i].iov_len;
125 			continue;
126 		}
127 
128 		if (iov[i].iov_base == NULL) {
129 			continue;
130 		}
131 
132 		if (done >= size) {
133 			break;
134 		}
135 
136 		len = MIN(size - done, iov[i].iov_len - offset);
137 		memcpy(iov[i].iov_base + offset, buf, len);
138 		buf += len;
139 		done += len;
140 		offset = 0;
141 	}
142 
143 	return done;
144 }
145 
146 static uint32_t
147 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
148 {
149 	struct bdev_ocf_data *d = dst;
150 	uint32_t size_local;
151 
152 	size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
153 	d->seek += size_local;
154 
155 	return size_local;
156 }
157 
158 static size_t
159 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
160 {
161 	size_t i, len, done = 0;
162 
163 	for (i = 0; i < iovcnt; i++) {
164 		if (offset >= iov[i].iov_len) {
165 			offset -= iov[i].iov_len;
166 			continue;
167 		}
168 
169 		if (iov[i].iov_base == NULL) {
170 			continue;
171 		}
172 
173 		if (done >= size) {
174 			break;
175 		}
176 
177 		len = MIN(size - done, iov[i].iov_len - offset);
178 		memset(iov[i].iov_base + offset, byte, len);
179 		done += len;
180 		offset = 0;
181 	}
182 
183 	return done;
184 }
185 
186 static uint32_t
187 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
188 {
189 	struct bdev_ocf_data *d = dst;
190 	uint32_t size_local;
191 
192 	size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
193 	d->seek += size_local;
194 
195 	return size_local;
196 }
197 
198 static uint32_t
199 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
200 {
201 	struct bdev_ocf_data *d = dst;
202 	uint32_t off = 0;
203 
204 	switch (seek) {
205 	case ctx_data_seek_begin:
206 		off = MIN(offset, d->size);
207 		d->seek = off;
208 		break;
209 	case ctx_data_seek_current:
210 		off = MIN(offset, d->size - d->seek);
211 		d->seek += off;
212 		break;
213 	}
214 
215 	return off;
216 }
217 
218 static uint64_t
219 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to,
220 		       uint64_t from, uint64_t bytes)
221 {
222 	struct bdev_ocf_data *s = src;
223 	struct bdev_ocf_data *d = dst;
224 	uint32_t it_iov = 0;
225 	uint32_t it_off = 0;
226 	uint32_t n, sz;
227 
228 	bytes = MIN(bytes, s->size - from);
229 	bytes = MIN(bytes, d->size - to);
230 	sz = bytes;
231 
232 	while (from || bytes) {
233 		if (s->iovs[it_iov].iov_len == it_off) {
234 			it_iov++;
235 			it_off = 0;
236 			continue;
237 		}
238 
239 		if (from) {
240 			n = MIN(from, s->iovs[it_iov].iov_len);
241 			from -= n;
242 		} else {
243 			n = MIN(bytes, s->iovs[it_iov].iov_len);
244 			buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
245 			bytes -= n;
246 			to += n;
247 		}
248 
249 		it_off += n;
250 	}
251 
252 	return sz;
253 }
254 
255 static void
256 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
257 {
258 	struct bdev_ocf_data *data = ctx_data;
259 	struct iovec *iovs = data->iovs;
260 	int i;
261 
262 	for (i = 0; i < data->iovcnt; i++) {
263 		if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
264 			assert(false);
265 		}
266 	}
267 }
268 
269 int
270 vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
271 {
272 	int rc;
273 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
274 
275 	pthread_mutex_lock(&ctx->lock);
276 	rc = ocf_queue_create(cache, queue, ops);
277 	pthread_mutex_unlock(&ctx->lock);
278 	return rc;
279 }
280 
281 void
282 vbdev_ocf_queue_put(ocf_queue_t queue)
283 {
284 	ocf_cache_t cache = ocf_queue_get_cache(queue);
285 	struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
286 
287 	pthread_mutex_lock(&ctx->lock);
288 	ocf_queue_put(queue);
289 	pthread_mutex_unlock(&ctx->lock);
290 }
291 
292 void
293 vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
294 {
295 	if (env_atomic_dec_return(&ctx->refcnt) == 0) {
296 		pthread_mutex_destroy(&ctx->lock);
297 		free(ctx);
298 	}
299 }
300 
301 void
302 vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
303 {
304 	env_atomic_inc(&ctx->refcnt);
305 }
306 
307 struct cleaner_priv {
308 	struct spdk_poller *poller;
309 	ocf_queue_t         mngt_queue;
310 	uint64_t            next_run;
311 };
312 
313 static int
314 cleaner_poll(void *arg)
315 {
316 	ocf_cleaner_t cleaner = arg;
317 	struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
318 
319 	if (spdk_get_ticks() >= priv->next_run) {
320 		ocf_cleaner_run(cleaner, priv->mngt_queue);
321 		return SPDK_POLLER_BUSY;
322 	}
323 
324 	return SPDK_POLLER_IDLE;
325 }
326 
327 static void
328 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
329 {
330 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
331 
332 	priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
333 }
334 
335 static int
336 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
337 {
338 	struct cleaner_priv        *priv  = calloc(1, sizeof(*priv));
339 	ocf_cache_t                 cache = ocf_cleaner_get_cache(c);
340 	struct vbdev_ocf_cache_ctx *cctx  = ocf_cache_get_priv(cache);
341 
342 	if (priv == NULL) {
343 		return -ENOMEM;
344 	}
345 
346 	priv->mngt_queue = cctx->mngt_queue;
347 
348 	ocf_cleaner_set_cmpl(c, cleaner_cmpl);
349 	ocf_cleaner_set_priv(c, priv);
350 
351 	return 0;
352 }
353 
354 static void
355 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
356 {
357 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
358 
359 	if (priv) {
360 		spdk_poller_unregister(&priv->poller);
361 		free(priv);
362 	}
363 }
364 
365 static void
366 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
367 {
368 	struct cleaner_priv *priv  = ocf_cleaner_get_priv(cleaner);
369 
370 	if (priv->poller) {
371 		return;
372 	}
373 
374 	/* We start cleaner poller at the same thread where cache was created
375 	 * TODO: allow user to specify core at which cleaner should run */
376 	priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
377 }
378 
379 /* This function is main way by which OCF communicates with user
380  * We don't want to use SPDK_LOG here because debugging information that is
381  * associated with every print message is not helpful in callback that only prints info
382  * while the real source is somewhere in OCF code */
383 static int
384 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
385 			 const char *fmt, va_list args)
386 {
387 	int spdk_lvl;
388 
389 	switch (lvl) {
390 	case log_emerg:
391 	case log_alert:
392 	case log_crit:
393 	case log_err:
394 		spdk_lvl = SPDK_LOG_ERROR;
395 		break;
396 
397 	case log_warn:
398 		spdk_lvl = SPDK_LOG_WARN;
399 		break;
400 
401 	case log_notice:
402 		spdk_lvl = SPDK_LOG_NOTICE;
403 		break;
404 
405 	case log_info:
406 	case log_debug:
407 	default:
408 		spdk_lvl = SPDK_LOG_INFO;
409 	}
410 
411 	spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
412 	return 0;
413 }
414 
415 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
416 	.name = "OCF SPDK",
417 
418 	.ops = {
419 		.data = {
420 			.alloc = vbdev_ocf_ctx_data_alloc,
421 			.free = vbdev_ocf_ctx_data_free,
422 			.mlock = vbdev_ocf_ctx_data_mlock,
423 			.munlock = vbdev_ocf_ctx_data_munlock,
424 			.read = vbdev_ocf_ctx_data_rd,
425 			.write = vbdev_ocf_ctx_data_wr,
426 			.zero = vbdev_ocf_ctx_data_zero,
427 			.seek = vbdev_ocf_ctx_data_seek,
428 			.copy = vbdev_ocf_ctx_data_cpy,
429 			.secure_erase = vbdev_ocf_ctx_data_secure_erase,
430 		},
431 
432 		.cleaner = {
433 			.init = vbdev_ocf_ctx_cleaner_init,
434 			.stop = vbdev_ocf_ctx_cleaner_stop,
435 			.kick = vbdev_ocf_ctx_cleaner_kick,
436 		},
437 
438 		.logger = {
439 			.print = vbdev_ocf_ctx_log_printf,
440 			.dump_stack = NULL,
441 		},
442 
443 	},
444 };
445 
446 int
447 vbdev_ocf_ctx_init(void)
448 {
449 	int ret;
450 
451 	ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
452 	if (ret < 0) {
453 		return ret;
454 	}
455 
456 	return 0;
457 }
458 
459 void
460 vbdev_ocf_ctx_cleanup(void)
461 {
462 	ocf_ctx_put(vbdev_ocf_ctx);
463 	vbdev_ocf_ctx = NULL;
464 }
465