Branch data Line data Source code
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 : 71521 : vbdev_ocf_ctx_data_alloc(uint32_t pages)
21 : : {
22 : : struct bdev_ocf_data *data;
23 : : void *buf;
24 : : uint32_t sz;
25 : :
26 : 71521 : data = vbdev_ocf_data_alloc(1);
27 [ - + ]: 71521 : if (data == NULL) {
28 : 0 : return NULL;
29 : : }
30 : :
31 : 71521 : sz = pages * PAGE_SIZE;
32 : 71521 : buf = spdk_malloc(sz, PAGE_SIZE, NULL,
33 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
34 [ - + ]: 71521 : if (buf == NULL) {
35 : 0 : vbdev_ocf_data_free(data);
36 : 0 : return NULL;
37 : : }
38 : :
39 : 71521 : vbdev_ocf_iovs_add(data, buf, sz);
40 : :
41 : 71521 : data->size = sz;
42 : :
43 : 71521 : return data;
44 : : }
45 : :
46 : : static void
47 : 71521 : vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
48 : : {
49 : 71521 : struct bdev_ocf_data *data = ctx_data;
50 : : int i;
51 : :
52 [ - + ]: 71521 : if (!data) {
53 : 0 : return;
54 : : }
55 : :
56 [ + + ]: 143042 : for (i = 0; i < data->iovcnt; i++) {
57 : 71521 : spdk_free(data->iovs[i].iov_base);
58 : : }
59 : :
60 : 71521 : vbdev_ocf_data_free(data);
61 : : }
62 : :
63 : : static int
64 : 12459 : vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
65 : : {
66 : : /* TODO [mlock]: add mlock option */
67 : 12459 : return 0;
68 : : }
69 : :
70 : : static void
71 : 12459 : vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
72 : : {
73 : : /* TODO [mlock]: add mlock option */
74 : 12459 : }
75 : :
76 : : static size_t
77 : 124 : iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
78 : : {
79 : 124 : size_t i, len, done = 0;
80 : :
81 [ + + ]: 248 : for (i = 0; i < iovcnt; i++) {
82 [ - + ]: 124 : if (offset >= iov[i].iov_len) {
83 : 0 : offset -= iov[i].iov_len;
84 : 0 : continue;
85 : : }
86 : :
87 [ - + ]: 124 : if (iov[i].iov_base == NULL) {
88 : 0 : continue;
89 : : }
90 : :
91 [ - + ]: 124 : if (done >= size) {
92 : 0 : break;
93 : : }
94 : :
95 : 124 : len = MIN(size - done, iov[i].iov_len - offset);
96 [ - + - + ]: 124 : memcpy(buf, iov[i].iov_base + offset, len);
97 : 124 : buf += len;
98 : 124 : done += len;
99 : 124 : offset = 0;
100 : : }
101 : :
102 : 124 : return done;
103 : : }
104 : :
105 : : static uint32_t
106 : 124 : vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
107 : : {
108 : 124 : struct bdev_ocf_data *s = src;
109 : : uint32_t size_local;
110 : :
111 : 124 : size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
112 : 124 : s->seek += size_local;
113 : :
114 : 124 : return size_local;
115 : : }
116 : :
117 : : static size_t
118 : 101393 : buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
119 : : {
120 : 101393 : size_t i, len, done = 0;
121 : :
122 [ + + ]: 202786 : for (i = 0; i < iovcnt; i++) {
123 [ - + ]: 101393 : if (offset >= iov[i].iov_len) {
124 : 0 : offset -= iov[i].iov_len;
125 : 0 : continue;
126 : : }
127 : :
128 [ - + ]: 101393 : if (iov[i].iov_base == NULL) {
129 : 0 : continue;
130 : : }
131 : :
132 [ - + ]: 101393 : if (done >= size) {
133 : 0 : break;
134 : : }
135 : :
136 : 101393 : len = MIN(size - done, iov[i].iov_len - offset);
137 [ - + - + ]: 101393 : memcpy(iov[i].iov_base + offset, buf, len);
138 : 101393 : buf += len;
139 : 101393 : done += len;
140 : 101393 : offset = 0;
141 : : }
142 : :
143 : 101393 : return done;
144 : : }
145 : :
146 : : static uint32_t
147 : 89214 : vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
148 : : {
149 : 89214 : struct bdev_ocf_data *d = dst;
150 : : uint32_t size_local;
151 : :
152 : 89214 : size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
153 : 89214 : d->seek += size_local;
154 : :
155 : 89214 : return size_local;
156 : : }
157 : :
158 : : static size_t
159 : 454240 : iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
160 : : {
161 : 454240 : size_t i, len, done = 0;
162 : :
163 [ + + ]: 897254 : for (i = 0; i < iovcnt; i++) {
164 [ + + ]: 454240 : if (offset >= iov[i].iov_len) {
165 : 521 : offset -= iov[i].iov_len;
166 : 521 : continue;
167 : : }
168 : :
169 [ - + ]: 453719 : if (iov[i].iov_base == NULL) {
170 : 0 : continue;
171 : : }
172 : :
173 [ + + ]: 453719 : if (done >= size) {
174 : 11226 : break;
175 : : }
176 : :
177 : 442493 : len = MIN(size - done, iov[i].iov_len - offset);
178 [ - + ]: 442493 : memset(iov[i].iov_base + offset, byte, len);
179 : 442493 : done += len;
180 : 442493 : offset = 0;
181 : : }
182 : :
183 : 454240 : return done;
184 : : }
185 : :
186 : : static uint32_t
187 : 454240 : vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
188 : : {
189 : 454240 : struct bdev_ocf_data *d = dst;
190 : : uint32_t size_local;
191 : :
192 : 454240 : size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
193 : 454240 : d->seek += size_local;
194 : :
195 : 454240 : return size_local;
196 : : }
197 : :
198 : : static uint32_t
199 : 117876 : vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
200 : : {
201 : 117876 : struct bdev_ocf_data *d = dst;
202 : 117876 : uint32_t off = 0;
203 : :
204 [ + - - ]: 117876 : switch (seek) {
205 : 117876 : case ctx_data_seek_begin:
206 : 117876 : off = MIN(offset, d->size);
207 : 117876 : d->seek = off;
208 : 117876 : break;
209 : 0 : case ctx_data_seek_current:
210 : 0 : off = MIN(offset, d->size - d->seek);
211 : 0 : d->seek += off;
212 : 0 : break;
213 : : }
214 : :
215 : 117876 : return off;
216 : : }
217 : :
218 : : static uint64_t
219 : 12179 : 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 : 12179 : struct bdev_ocf_data *s = src;
223 : 12179 : struct bdev_ocf_data *d = dst;
224 : 12179 : uint32_t it_iov = 0;
225 : 12179 : uint32_t it_off = 0;
226 : : uint32_t n, sz;
227 : :
228 : 12179 : bytes = MIN(bytes, s->size - from);
229 : 12179 : bytes = MIN(bytes, d->size - to);
230 : 12179 : sz = bytes;
231 : :
232 [ - + + + ]: 24358 : while (from || bytes) {
233 [ - + ]: 12179 : if (s->iovs[it_iov].iov_len == it_off) {
234 : 0 : it_iov++;
235 : 0 : it_off = 0;
236 : 0 : continue;
237 : : }
238 : :
239 [ - + ]: 12179 : if (from) {
240 : 0 : n = MIN(from, s->iovs[it_iov].iov_len);
241 : 0 : from -= n;
242 : : } else {
243 : 12179 : n = MIN(bytes, s->iovs[it_iov].iov_len);
244 : 12179 : buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
245 : 12179 : bytes -= n;
246 : 12179 : to += n;
247 : : }
248 : :
249 : 12179 : it_off += n;
250 : : }
251 : :
252 : 12179 : return sz;
253 : : }
254 : :
255 : : static void
256 : 12459 : vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
257 : : {
258 : 12459 : struct bdev_ocf_data *data = ctx_data;
259 : 12459 : struct iovec *iovs = data->iovs;
260 : : int i;
261 : :
262 [ + + ]: 24918 : for (i = 0; i < data->iovcnt; i++) {
263 [ - + ]: 12459 : if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
264 : 0 : assert(false);
265 : : }
266 : : }
267 : 12459 : }
268 : :
269 : : int
270 : 71 : vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
271 : : {
272 : : int rc;
273 : 71 : struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
274 : :
275 [ - + ]: 71 : pthread_mutex_lock(&ctx->lock);
276 : 71 : rc = ocf_queue_create(cache, queue, ops);
277 [ - + ]: 71 : pthread_mutex_unlock(&ctx->lock);
278 : 71 : return rc;
279 : : }
280 : :
281 : : void
282 : 71 : vbdev_ocf_queue_put(ocf_queue_t queue)
283 : : {
284 : 71 : ocf_cache_t cache = ocf_queue_get_cache(queue);
285 : 71 : struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
286 : :
287 [ - + ]: 71 : pthread_mutex_lock(&ctx->lock);
288 : 71 : ocf_queue_put(queue);
289 [ - + ]: 71 : pthread_mutex_unlock(&ctx->lock);
290 : 71 : }
291 : :
292 : : void
293 : 25 : vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
294 : : {
295 [ + + ]: 25 : if (env_atomic_dec_return(&ctx->refcnt) == 0) {
296 [ - + ]: 19 : pthread_mutex_destroy(&ctx->lock);
297 : 19 : free(ctx);
298 : : }
299 : 25 : }
300 : :
301 : : void
302 : 25 : vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
303 : : {
304 : 25 : env_atomic_inc(&ctx->refcnt);
305 : 25 : }
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 : 5057740 : cleaner_poll(void *arg)
315 : : {
316 : 5057740 : ocf_cleaner_t cleaner = arg;
317 : 5057740 : struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
318 : :
319 [ + + ]: 5057740 : if (spdk_get_ticks() >= priv->next_run) {
320 : 36 : ocf_cleaner_run(cleaner, priv->mngt_queue);
321 : 36 : return SPDK_POLLER_BUSY;
322 : : }
323 : :
324 : 5057704 : return SPDK_POLLER_IDLE;
325 : : }
326 : :
327 : : static void
328 : 36 : cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
329 : : {
330 : 36 : struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
331 : :
332 : 36 : priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
333 : 36 : }
334 : :
335 : : static int
336 : 19 : vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
337 : : {
338 : 19 : struct cleaner_priv *priv = calloc(1, sizeof(*priv));
339 : 19 : ocf_cache_t cache = ocf_cleaner_get_cache(c);
340 : 19 : struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache);
341 : :
342 [ - + ]: 19 : if (priv == NULL) {
343 : 0 : return -ENOMEM;
344 : : }
345 : :
346 : 19 : priv->mngt_queue = cctx->mngt_queue;
347 : :
348 : 19 : ocf_cleaner_set_cmpl(c, cleaner_cmpl);
349 : 19 : ocf_cleaner_set_priv(c, priv);
350 : :
351 : 19 : return 0;
352 : : }
353 : :
354 : : static void
355 : 19 : vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
356 : : {
357 : 19 : struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
358 : :
359 [ + - ]: 19 : if (priv) {
360 : 19 : spdk_poller_unregister(&priv->poller);
361 : 19 : free(priv);
362 : : }
363 : 19 : }
364 : :
365 : : static void
366 : 19 : vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
367 : : {
368 : 19 : struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
369 : :
370 [ - + ]: 19 : if (priv->poller) {
371 : 0 : 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 : 19 : 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 : 1136 : 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 [ - - - + ]: 1136 : switch (lvl) {
390 : 0 : case log_emerg:
391 : : case log_alert:
392 : : case log_crit:
393 : : case log_err:
394 : 0 : spdk_lvl = SPDK_LOG_ERROR;
395 : 0 : break;
396 : :
397 : 0 : case log_warn:
398 : 0 : spdk_lvl = SPDK_LOG_WARN;
399 : 0 : break;
400 : :
401 : 0 : case log_notice:
402 : 0 : spdk_lvl = SPDK_LOG_NOTICE;
403 : 0 : break;
404 : :
405 : 1136 : case log_info:
406 : : case log_debug:
407 : : default:
408 : 1136 : spdk_lvl = SPDK_LOG_INFO;
409 : : }
410 : :
411 : 1136 : spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
412 : 1136 : 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 : 63 : vbdev_ocf_ctx_init(void)
448 : : {
449 : : int ret;
450 : :
451 : 63 : ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
452 [ - + ]: 63 : if (ret < 0) {
453 : 0 : return ret;
454 : : }
455 : :
456 : 63 : return 0;
457 : : }
458 : :
459 : : void
460 : 63 : vbdev_ocf_ctx_cleanup(void)
461 : : {
462 : 63 : ocf_ctx_put(vbdev_ocf_ctx);
463 : 63 : vbdev_ocf_ctx = NULL;
464 : 63 : }
|