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