xref: /spdk/module/bdev/ocf/ctx.c (revision 66289a6dbe28217365daa40fd92dcf327871c2e8)
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 
273 	return ocf_queue_create(cache, queue, ops);
274 }
275 
276 int
277 vbdev_ocf_queue_create_mngt(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
278 {
279 	return ocf_queue_create_mngt(cache, queue, ops);
280 }
281 
282 void
283 vbdev_ocf_queue_put(ocf_queue_t queue)
284 {
285 	ocf_queue_put(queue);
286 }
287 
288 void
289 vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
290 {
291 	if (env_atomic_dec_return(&ctx->refcnt) == 0) {
292 		free(ctx);
293 	}
294 }
295 
296 void
297 vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
298 {
299 	env_atomic_inc(&ctx->refcnt);
300 }
301 
302 struct cleaner_priv {
303 	struct spdk_poller *poller;
304 	ocf_queue_t         mngt_queue;
305 	uint64_t            next_run;
306 };
307 
308 static int
309 cleaner_poll(void *arg)
310 {
311 	ocf_cleaner_t cleaner = arg;
312 	struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
313 
314 	if (spdk_get_ticks() >= priv->next_run) {
315 		ocf_cleaner_run(cleaner, priv->mngt_queue);
316 		return SPDK_POLLER_BUSY;
317 	}
318 
319 	return SPDK_POLLER_IDLE;
320 }
321 
322 static void
323 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
324 {
325 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
326 
327 	priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
328 }
329 
330 static int
331 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
332 {
333 	struct cleaner_priv        *priv  = calloc(1, sizeof(*priv));
334 	ocf_cache_t                 cache = ocf_cleaner_get_cache(c);
335 	struct vbdev_ocf_cache_ctx *cctx  = ocf_cache_get_priv(cache);
336 
337 	if (priv == NULL) {
338 		return -ENOMEM;
339 	}
340 
341 	priv->mngt_queue = cctx->mngt_queue;
342 
343 	ocf_cleaner_set_cmpl(c, cleaner_cmpl);
344 	ocf_cleaner_set_priv(c, priv);
345 
346 	return 0;
347 }
348 
349 static void
350 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
351 {
352 	struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
353 
354 	if (priv) {
355 		spdk_poller_unregister(&priv->poller);
356 		free(priv);
357 	}
358 }
359 
360 static void
361 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
362 {
363 	struct cleaner_priv *priv  = ocf_cleaner_get_priv(cleaner);
364 
365 	if (priv->poller) {
366 		return;
367 	}
368 
369 	/* We start cleaner poller at the same thread where cache was created
370 	 * TODO: allow user to specify core at which cleaner should run */
371 	priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
372 }
373 
374 /* This function is main way by which OCF communicates with user
375  * We don't want to use SPDK_LOG here because debugging information that is
376  * associated with every print message is not helpful in callback that only prints info
377  * while the real source is somewhere in OCF code */
378 static int
379 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
380 			 const char *fmt, va_list args)
381 {
382 	int spdk_lvl;
383 
384 	switch (lvl) {
385 	case log_emerg:
386 	case log_alert:
387 	case log_crit:
388 	case log_err:
389 		spdk_lvl = SPDK_LOG_ERROR;
390 		break;
391 
392 	case log_warn:
393 		spdk_lvl = SPDK_LOG_WARN;
394 		break;
395 
396 	case log_notice:
397 		spdk_lvl = SPDK_LOG_NOTICE;
398 		break;
399 
400 	case log_info:
401 	case log_debug:
402 	default:
403 		spdk_lvl = SPDK_LOG_INFO;
404 	}
405 
406 	spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
407 	return 0;
408 }
409 
410 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
411 	.name = "OCF SPDK",
412 
413 	.ops = {
414 		.data = {
415 			.alloc = vbdev_ocf_ctx_data_alloc,
416 			.free = vbdev_ocf_ctx_data_free,
417 			.mlock = vbdev_ocf_ctx_data_mlock,
418 			.munlock = vbdev_ocf_ctx_data_munlock,
419 			.read = vbdev_ocf_ctx_data_rd,
420 			.write = vbdev_ocf_ctx_data_wr,
421 			.zero = vbdev_ocf_ctx_data_zero,
422 			.seek = vbdev_ocf_ctx_data_seek,
423 			.copy = vbdev_ocf_ctx_data_cpy,
424 			.secure_erase = vbdev_ocf_ctx_data_secure_erase,
425 		},
426 
427 		.cleaner = {
428 			.init = vbdev_ocf_ctx_cleaner_init,
429 			.stop = vbdev_ocf_ctx_cleaner_stop,
430 			.kick = vbdev_ocf_ctx_cleaner_kick,
431 		},
432 
433 		.logger = {
434 			.print = vbdev_ocf_ctx_log_printf,
435 			.dump_stack = NULL,
436 		},
437 
438 	},
439 };
440 
441 int
442 vbdev_ocf_ctx_init(void)
443 {
444 	int ret;
445 
446 	ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
447 	if (ret < 0) {
448 		return ret;
449 	}
450 
451 	return 0;
452 }
453 
454 void
455 vbdev_ocf_ctx_cleanup(void)
456 {
457 	ocf_ctx_put(vbdev_ocf_ctx);
458 	vbdev_ocf_ctx = NULL;
459 }
460