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