]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/bdev/ocf/ctx.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / lib / bdev / ocf / ctx.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 #include <ocf/ocf.h>
34 #include <execinfo.h>
35
36 #include "spdk/env.h"
37 #include "spdk_internal/log.h"
38
39 #include "ctx.h"
40 #include "ocf_env.h"
41 #include "data.h"
42
43 ocf_ctx_t vbdev_ocf_ctx;
44
45 static ctx_data_t *
46 vbdev_ocf_ctx_data_alloc(uint32_t pages)
47 {
48 struct bdev_ocf_data *data;
49 void *buf;
50 uint32_t sz;
51
52 data = vbdev_ocf_data_alloc(1);
53
54 sz = pages * PAGE_SIZE;
55 buf = spdk_malloc(sz, PAGE_SIZE, NULL,
56 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
57 if (buf == NULL) {
58 return NULL;
59 }
60
61 vbdev_ocf_iovs_add(data, buf, sz);
62
63 data->size = sz;
64
65 return data;
66 }
67
68 static void
69 vbdev_ocf_ctx_data_free(ctx_data_t *ctx_data)
70 {
71 struct bdev_ocf_data *data = ctx_data;
72 int i;
73
74 if (!data) {
75 return;
76 }
77
78 for (i = 0; i < data->iovcnt; i++) {
79 spdk_free(data->iovs[i].iov_base);
80 }
81
82 vbdev_ocf_data_free(data);
83 }
84
85 static int
86 vbdev_ocf_ctx_data_mlock(ctx_data_t *ctx_data)
87 {
88 /* TODO [mlock]: add mlock option */
89 return 0;
90 }
91
92 static void
93 vbdev_ocf_ctx_data_munlock(ctx_data_t *ctx_data)
94 {
95 /* TODO [mlock]: add mlock option */
96 }
97
98 static size_t
99 iovec_flatten(struct iovec *iov, size_t iovcnt, void *buf, size_t size, size_t offset)
100 {
101 size_t i, len, done = 0;
102
103 for (i = 0; i < iovcnt; i++) {
104 if (offset >= iov[i].iov_len) {
105 offset -= iov[i].iov_len;
106 continue;
107 }
108
109 if (iov[i].iov_base == NULL) {
110 continue;
111 }
112
113 if (done >= size) {
114 break;
115 }
116
117 len = MIN(size - done, iov[i].iov_len - offset);
118 memcpy(buf, iov[i].iov_base + offset, len);
119 buf += len;
120 done += len;
121 offset = 0;
122 }
123
124 return done;
125 }
126
127 static uint32_t
128 vbdev_ocf_ctx_data_rd(void *dst, ctx_data_t *src, uint32_t size)
129 {
130 struct bdev_ocf_data *s = src;
131 uint32_t size_local;
132
133 size_local = iovec_flatten(s->iovs, s->iovcnt, dst, size, s->seek);
134 s->seek += size_local;
135
136 return size_local;
137 }
138
139 static size_t
140 buf_to_iovec(const void *buf, size_t size, struct iovec *iov, size_t iovcnt, size_t offset)
141 {
142 size_t i, len, done = 0;
143
144 for (i = 0; i < iovcnt; i++) {
145 if (offset >= iov[i].iov_len) {
146 offset -= iov[i].iov_len;
147 continue;
148 }
149
150 if (iov[i].iov_base == NULL) {
151 continue;
152 }
153
154 if (done >= size) {
155 break;
156 }
157
158 len = MIN(size - done, iov[i].iov_len - offset);
159 memcpy(iov[i].iov_base + offset, buf, len);
160 buf += len;
161 done += len;
162 offset = 0;
163 }
164
165 return done;
166 }
167
168 static uint32_t
169 vbdev_ocf_ctx_data_wr(ctx_data_t *dst, const void *src, uint32_t size)
170 {
171 struct bdev_ocf_data *d = dst;
172 uint32_t size_local;
173
174 size_local = buf_to_iovec(src, size, d->iovs, d->iovcnt, d->seek);
175 d->seek += size_local;
176
177 return size_local;
178 }
179
180 static size_t
181 iovset(struct iovec *iov, size_t iovcnt, int byte, size_t size, size_t offset)
182 {
183 size_t i, len, done = 0;
184
185 for (i = 0; i < iovcnt; i++) {
186 if (offset >= iov[i].iov_len) {
187 offset -= iov[i].iov_len;
188 continue;
189 }
190
191 if (iov[i].iov_base == NULL) {
192 continue;
193 }
194
195 if (done >= size) {
196 break;
197 }
198
199 len = MIN(size - done, iov[i].iov_len - offset);
200 memset(iov[i].iov_base + offset, byte, len);
201 done += len;
202 offset = 0;
203 }
204
205 return done;
206 }
207
208 static uint32_t
209 vbdev_ocf_ctx_data_zero(ctx_data_t *dst, uint32_t size)
210 {
211 struct bdev_ocf_data *d = dst;
212 uint32_t size_local;
213
214 size_local = iovset(d->iovs, d->iovcnt, 0, size, d->seek);
215 d->seek += size_local;
216
217 return size_local;
218 }
219
220 static uint32_t
221 vbdev_ocf_ctx_data_seek(ctx_data_t *dst, ctx_data_seek_t seek, uint32_t offset)
222 {
223 struct bdev_ocf_data *d = dst;
224 uint32_t off = 0;
225
226 switch (seek) {
227 case ctx_data_seek_begin:
228 off = MIN(offset, d->size);
229 d->seek = off;
230 break;
231 case ctx_data_seek_current:
232 off = MIN(offset, d->size - d->seek);
233 d->seek += off;
234 break;
235 }
236
237 return off;
238 }
239
240 static uint64_t
241 vbdev_ocf_ctx_data_cpy(ctx_data_t *dst, ctx_data_t *src, uint64_t to,
242 uint64_t from, uint64_t bytes)
243 {
244 struct bdev_ocf_data *s = src;
245 struct bdev_ocf_data *d = dst;
246 uint32_t it_iov = 0;
247 uint32_t it_off = 0;
248 uint32_t n, sz;
249
250 bytes = MIN(bytes, s->size - from);
251 bytes = MIN(bytes, d->size - to);
252 sz = bytes;
253
254 while (from || bytes) {
255 if (s->iovs[it_iov].iov_len == it_off) {
256 it_iov++;
257 it_off = 0;
258 continue;
259 }
260
261 if (from) {
262 n = MIN(from, s->iovs[it_iov].iov_len);
263 from -= n;
264 } else {
265 n = MIN(bytes, s->iovs[it_iov].iov_len);
266 buf_to_iovec(s->iovs[it_iov].iov_base + it_off, n, d->iovs, d->iovcnt, to);
267 bytes -= n;
268 to += n;
269 }
270
271 it_off += n;
272 }
273
274 return sz;
275 }
276
277 static void
278 vbdev_ocf_ctx_data_secure_erase(ctx_data_t *ctx_data)
279 {
280 struct bdev_ocf_data *data = ctx_data;
281 struct iovec *iovs = data->iovs;
282 int i;
283
284 for (i = 0; i < data->iovcnt; i++) {
285 if (env_memset(iovs[i].iov_base, iovs[i].iov_len, 0)) {
286 assert(false);
287 }
288 }
289 }
290
291 int vbdev_ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue, const struct ocf_queue_ops *ops)
292 {
293 int rc;
294 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
295
296 pthread_mutex_lock(&ctx->lock);
297 rc = ocf_queue_create(cache, queue, ops);
298 pthread_mutex_unlock(&ctx->lock);
299 return rc;
300 }
301
302 void vbdev_ocf_queue_put(ocf_queue_t queue)
303 {
304 ocf_cache_t cache = ocf_queue_get_cache(queue);
305 struct vbdev_ocf_cache_ctx *ctx = ocf_cache_get_priv(cache);
306
307 pthread_mutex_lock(&ctx->lock);
308 ocf_queue_put(queue);
309 pthread_mutex_unlock(&ctx->lock);
310 }
311
312 void vbdev_ocf_cache_ctx_put(struct vbdev_ocf_cache_ctx *ctx)
313 {
314 if (env_atomic_dec_return(&ctx->refcnt) == 0) {
315 pthread_mutex_destroy(&ctx->lock);
316 free(ctx);
317 }
318 }
319
320 void vbdev_ocf_cache_ctx_get(struct vbdev_ocf_cache_ctx *ctx)
321 {
322 env_atomic_inc(&ctx->refcnt);
323 }
324
325 struct cleaner_priv {
326 struct spdk_poller *poller;
327 ocf_queue_t queue;
328 uint64_t next_run;
329 };
330
331 static int
332 cleaner_poll(void *arg)
333 {
334 ocf_cleaner_t cleaner = arg;
335 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
336 uint32_t iono = ocf_queue_pending_io(priv->queue);
337 int i, max = spdk_min(32, iono);
338
339 for (i = 0; i < max; i++) {
340 ocf_queue_run_single(priv->queue);
341 }
342
343 if (spdk_get_ticks() >= priv->next_run) {
344 ocf_cleaner_run(cleaner, priv->queue);
345 return 1;
346 }
347
348 if (iono > 0) {
349 return 1;
350 } else {
351 return 0;
352 }
353 }
354
355 static void
356 cleaner_cmpl(ocf_cleaner_t c, uint32_t interval)
357 {
358 struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
359
360 priv->next_run = spdk_get_ticks() + ((interval * spdk_get_ticks_hz()) / 1000);
361 }
362
363 static void
364 cleaner_queue_kick(ocf_queue_t q)
365 {
366 }
367
368 static void
369 cleaner_queue_stop(ocf_queue_t q)
370 {
371 struct cleaner_priv *cpriv = ocf_queue_get_priv(q);
372
373 if (cpriv) {
374 spdk_poller_unregister(&cpriv->poller);
375 free(cpriv);
376 }
377 }
378
379 const struct ocf_queue_ops cleaner_queue_ops = {
380 .kick_sync = cleaner_queue_kick,
381 .kick = cleaner_queue_kick,
382 .stop = cleaner_queue_stop,
383 };
384
385 static int
386 vbdev_ocf_ctx_cleaner_init(ocf_cleaner_t c)
387 {
388 int rc;
389 struct cleaner_priv *priv = calloc(1, sizeof(*priv));
390 ocf_cache_t cache = ocf_cleaner_get_cache(c);
391 struct vbdev_ocf_cache_ctx *cctx = ocf_cache_get_priv(cache);
392
393 if (priv == NULL) {
394 return -ENOMEM;
395 }
396
397 rc = vbdev_ocf_queue_create(cache, &priv->queue, &cleaner_queue_ops);
398 if (rc) {
399 free(priv);
400 return rc;
401 }
402
403 ocf_queue_set_priv(priv->queue, priv);
404
405 cctx->cleaner_queue = priv->queue;
406
407 ocf_cleaner_set_cmpl(c, cleaner_cmpl);
408 ocf_cleaner_set_priv(c, priv);
409
410 return 0;
411 }
412
413 static void
414 vbdev_ocf_ctx_cleaner_stop(ocf_cleaner_t c)
415 {
416 struct cleaner_priv *priv = ocf_cleaner_get_priv(c);
417
418 vbdev_ocf_queue_put(priv->queue);
419 }
420
421 static void
422 vbdev_ocf_ctx_cleaner_kick(ocf_cleaner_t cleaner)
423 {
424 struct cleaner_priv *priv = ocf_cleaner_get_priv(cleaner);
425
426 if (priv->poller) {
427 return;
428 }
429
430 /* We start cleaner poller at the same thread where cache was created
431 * TODO: allow user to specify core at which cleaner should run */
432 priv->poller = spdk_poller_register(cleaner_poll, cleaner, 0);
433 }
434
435 static void
436 vbdev_ocf_md_kick(void *ctx)
437 {
438 ocf_metadata_updater_t mu = ctx;
439 ocf_cache_t cache = ocf_metadata_updater_get_cache(mu);
440
441 if (ocf_cache_is_running(cache)) {
442 ocf_metadata_updater_run(mu);
443 }
444 }
445
446 static int
447 vbdev_ocf_volume_updater_init(ocf_metadata_updater_t mu)
448 {
449 struct spdk_thread *md_thread = spdk_get_thread();
450
451 ocf_metadata_updater_set_priv(mu, md_thread);
452
453 return 0;
454 }
455
456 static void
457 vbdev_ocf_volume_updater_stop(ocf_metadata_updater_t mu)
458 {
459
460 }
461
462 static void
463 vbdev_ocf_volume_updater_kick(ocf_metadata_updater_t mu)
464 {
465 struct spdk_thread *md_thread = ocf_metadata_updater_get_priv(mu);
466
467 /* We need to send message to updater thread because
468 * kick can happen from any thread */
469 spdk_thread_send_msg(md_thread, vbdev_ocf_md_kick, mu);
470 }
471
472 /* This function is main way by which OCF communicates with user
473 * We don't want to use SPDK_LOG here because debugging information that is
474 * associated with every print message is not helpful in callback that only prints info
475 * while the real source is somewhere in OCF code */
476 static int
477 vbdev_ocf_ctx_log_printf(ocf_logger_t logger, ocf_logger_lvl_t lvl,
478 const char *fmt, va_list args)
479 {
480 FILE *lfile = stdout;
481
482 if (lvl > log_info) {
483 return 0;
484 }
485
486 if (lvl <= log_warn) {
487 lfile = stderr;
488 }
489
490 return vfprintf(lfile, fmt, args);
491 }
492
493 static const struct ocf_ctx_config vbdev_ocf_ctx_cfg = {
494 .name = "OCF SPDK",
495
496 .ops = {
497 .data = {
498 .alloc = vbdev_ocf_ctx_data_alloc,
499 .free = vbdev_ocf_ctx_data_free,
500 .mlock = vbdev_ocf_ctx_data_mlock,
501 .munlock = vbdev_ocf_ctx_data_munlock,
502 .read = vbdev_ocf_ctx_data_rd,
503 .write = vbdev_ocf_ctx_data_wr,
504 .zero = vbdev_ocf_ctx_data_zero,
505 .seek = vbdev_ocf_ctx_data_seek,
506 .copy = vbdev_ocf_ctx_data_cpy,
507 .secure_erase = vbdev_ocf_ctx_data_secure_erase,
508 },
509
510 .metadata_updater = {
511 .init = vbdev_ocf_volume_updater_init,
512 .stop = vbdev_ocf_volume_updater_stop,
513 .kick = vbdev_ocf_volume_updater_kick,
514 },
515
516 .cleaner = {
517 .init = vbdev_ocf_ctx_cleaner_init,
518 .stop = vbdev_ocf_ctx_cleaner_stop,
519 .kick = vbdev_ocf_ctx_cleaner_kick,
520 },
521
522 .logger = {
523 .print = vbdev_ocf_ctx_log_printf,
524 .dump_stack = NULL,
525 },
526
527 },
528 };
529
530 int
531 vbdev_ocf_ctx_init(void)
532 {
533 int ret;
534
535 ret = ocf_ctx_init(&vbdev_ocf_ctx, &vbdev_ocf_ctx_cfg);
536 if (ret < 0) {
537 return ret;
538 }
539
540 return 0;
541 }
542
543 void
544 vbdev_ocf_ctx_cleanup(void)
545 {
546 ocf_ctx_exit(vbdev_ocf_ctx);
547 vbdev_ocf_ctx = NULL;
548 }
549
550 SPDK_LOG_REGISTER_COMPONENT("ocf_ocfctx", SPDK_LOG_OCFCTX)