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 0 : struct bdev_ocf_data *data;
23 0 : void *buf;
24 0 : 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 0 : }
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 0 : 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 0 : }
59 :
60 0 : vbdev_ocf_data_free(data);
61 0 : }
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 0 : }
101 :
102 0 : return done;
103 0 : }
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 0 : 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 0 : }
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 0 : }
142 :
143 0 : return done;
144 0 : }
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 0 : 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 0 : }
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 0 : }
182 :
183 0 : return done;
184 0 : }
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 0 : 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 0 : }
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 : case ctx_data_seek_begin:
206 0 : off = MIN(offset, d->size);
207 0 : d->seek = off;
208 0 : break;
209 : 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 0 : }
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 0 : 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 0 : } 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 0 : }
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 0 : 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 0 : }
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 :
273 0 : return ocf_queue_create(cache, queue, ops);
274 : }
275 :
276 : int
277 0 : vbdev_ocf_queue_create_mngt(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
278 : {
279 0 : return ocf_queue_create_mngt(cache, queue, ops);
280 : }
281 :
282 : void
283 0 : vbdev_ocf_queue_put(ocf_queue_t queue)
284 : {
285 0 : ocf_queue_put(queue);
286 0 : }
287 :
288 : void
289 0 : vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
290 : {
291 0 : if (env_atomic_dec_return(&ctx->refcnt) == 0) {
292 0 : free(ctx);
293 0 : }
294 0 : }
295 :
296 : void
297 0 : vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
298 : {
299 0 : env_atomic_inc(&ctx->refcnt);
300 0 : }
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 0 : cleaner_poll(void *arg)
310 : {
311 0 : ocf_cleaner_t cleaner = arg;
312 0 : struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
313 :
314 0 : if (spdk_get_ticks() >= priv->next_run) {
315 0 : ocf_cleaner_run(cleaner, priv->mngt_queue);
316 0 : return SPDK_POLLER_BUSY;
317 : }
318 :
319 0 : return SPDK_POLLER_IDLE;
320 0 : }
321 :
322 : static void
323 0 : cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
324 : {
325 0 : struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
326 :
327 0 : priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
328 0 : }
329 :
330 : static int
331 0 : vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
332 : {
333 0 : struct cleaner_priv *priv = calloc(1, sizeof(*priv));
334 0 : ocf_cache_t cache = ocf_cleaner_get_cache(c);
335 0 : struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache);
336 :
337 0 : if (priv == NULL) {
338 0 : return -ENOMEM;
339 : }
340 :
341 0 : priv->mngt_queue = cctx->mngt_queue;
342 :
343 0 : ocf_cleaner_set_cmpl(c, cleaner_cmpl);
344 0 : ocf_cleaner_set_priv(c, priv);
345 :
346 0 : return 0;
347 0 : }
348 :
349 : static void
350 0 : vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
351 : {
352 0 : struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
353 :
354 0 : if (priv) {
355 0 : spdk_poller_unregister(&priv->poller);
356 0 : free(priv);
357 0 : }
358 0 : }
359 :
360 : static void
361 0 : vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
362 : {
363 0 : struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
364 :
365 0 : if (priv->poller) {
366 0 : 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 0 : priv->poller = SPDK_POLLER_REGISTER(cleaner_poll, cleaner, 0);
372 0 : }
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 0 : vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
380 : const char *fmt, va_list args)
381 : {
382 0 : int spdk_lvl;
383 :
384 0 : switch (lvl) {
385 : case log_emerg:
386 : case log_alert:
387 : case log_crit:
388 : case log_err:
389 0 : spdk_lvl = SPDK_LOG_ERROR;
390 0 : break;
391 :
392 : case log_warn:
393 0 : spdk_lvl = SPDK_LOG_WARN;
394 0 : break;
395 :
396 : case log_notice:
397 0 : spdk_lvl = SPDK_LOG_NOTICE;
398 0 : break;
399 :
400 : case log_info:
401 0 : case log_debug:
402 : default:
403 0 : spdk_lvl = SPDK_LOG_INFO;
404 0 : }
405 :
406 0 : spdk_vlog(spdk_lvl, NULL, -1, NULL, fmt, args);
407 0 : return 0;
408 0 : }
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 0 : vbdev_ocf_ctx_init(void)
443 : {
444 0 : int ret;
445 :
446 0 : ret = ocf_ctx_create(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
447 0 : if (ret < 0) {
448 0 : return ret;
449 : }
450 :
451 0 : return 0;
452 0 : }
453 :
454 : void
455 0 : vbdev_ocf_ctx_cleanup(void)
456 : {
457 0 : ocf_ctx_put(vbdev_ocf_ctx);
458 0 : vbdev_ocf_ctx = NULL;
459 0 : }
|