Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2018 Intel Corporation.
3 : * All rights reserved.
4 : * Copyright (c) 2021, 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : */
6 :
7 : #include "vbdev_compress.h"
8 :
9 : #include "spdk/reduce.h"
10 : #include "spdk/stdinc.h"
11 : #include "spdk/rpc.h"
12 : #include "spdk/env.h"
13 : #include "spdk/endian.h"
14 : #include "spdk/string.h"
15 : #include "spdk/thread.h"
16 : #include "spdk/util.h"
17 : #include "spdk/bdev_module.h"
18 : #include "spdk/likely.h"
19 : #include "spdk/log.h"
20 : #include "spdk/accel.h"
21 :
22 : #include "spdk/accel_module.h"
23 :
24 :
25 : #define CHUNK_SIZE (1024 * 16)
26 : #define COMP_BDEV_NAME "compress"
27 : #define BACKING_IO_SZ (4 * 1024)
28 :
29 : /* This namespace UUID was generated using uuid_generate() method. */
30 : #define BDEV_COMPRESS_NAMESPACE_UUID "c3fad6da-832f-4cc0-9cdc-5c552b225e7b"
31 :
32 : struct vbdev_comp_delete_ctx {
33 : spdk_delete_compress_complete cb_fn;
34 : void *cb_arg;
35 : int cb_rc;
36 : struct spdk_thread *orig_thread;
37 : };
38 :
39 : /* List of virtual bdevs and associated info for each. */
40 : struct vbdev_compress {
41 : struct spdk_bdev *base_bdev; /* the thing we're attaching to */
42 : struct spdk_bdev_desc *base_desc; /* its descriptor we get from open */
43 : struct spdk_io_channel *base_ch; /* IO channel of base device */
44 : struct spdk_bdev comp_bdev; /* the compression virtual bdev */
45 : struct comp_io_channel *comp_ch; /* channel associated with this bdev */
46 : struct spdk_io_channel *accel_channel; /* to communicate with the accel framework */
47 : struct spdk_thread *reduce_thread;
48 : pthread_mutex_t reduce_lock;
49 : uint32_t ch_count;
50 : TAILQ_HEAD(, spdk_bdev_io) pending_comp_ios; /* outstanding operations to a comp library */
51 : struct spdk_poller *poller; /* completion poller */
52 : struct spdk_reduce_vol_params params; /* params for the reduce volume */
53 : struct spdk_reduce_backing_dev backing_dev; /* backing device info for the reduce volume */
54 : struct spdk_reduce_vol *vol; /* the reduce volume */
55 : struct vbdev_comp_delete_ctx *delete_ctx;
56 : bool orphaned; /* base bdev claimed but comp_bdev not registered */
57 : int reduce_errno;
58 : TAILQ_HEAD(, vbdev_comp_op) queued_comp_ops;
59 : TAILQ_ENTRY(vbdev_compress) link;
60 : struct spdk_thread *thread; /* thread where base device is opened */
61 : };
62 : static TAILQ_HEAD(, vbdev_compress) g_vbdev_comp = TAILQ_HEAD_INITIALIZER(g_vbdev_comp);
63 :
64 : /* The comp vbdev channel struct. It is allocated and freed on my behalf by the io channel code.
65 : */
66 : struct comp_io_channel {
67 : struct spdk_io_channel_iter *iter; /* used with for_each_channel in reset */
68 : };
69 :
70 : /* Per I/O context for the compression vbdev. */
71 : struct comp_bdev_io {
72 : struct comp_io_channel *comp_ch; /* used in completion handling */
73 : struct vbdev_compress *comp_bdev; /* vbdev associated with this IO */
74 : struct spdk_bdev_io_wait_entry bdev_io_wait; /* for bdev_io_wait */
75 : struct spdk_bdev_io *orig_io; /* the original IO */
76 : struct spdk_io_channel *ch; /* for resubmission */
77 : int status; /* save for completion on orig thread */
78 : };
79 :
80 : static void vbdev_compress_examine(struct spdk_bdev *bdev);
81 : static int vbdev_compress_claim(struct vbdev_compress *comp_bdev);
82 : static void vbdev_compress_queue_io(struct spdk_bdev_io *bdev_io);
83 : struct vbdev_compress *_prepare_for_load_init(struct spdk_bdev_desc *bdev_desc, uint32_t lb_size);
84 : static void vbdev_compress_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io);
85 : static void comp_bdev_ch_destroy_cb(void *io_device, void *ctx_buf);
86 : static void vbdev_compress_delete_done(void *cb_arg, int bdeverrno);
87 :
88 : /* for completing rw requests on the orig IO thread. */
89 : static void
90 4 : _reduce_rw_blocks_cb(void *arg)
91 : {
92 4 : struct comp_bdev_io *io_ctx = arg;
93 :
94 4 : if (spdk_likely(io_ctx->status == 0)) {
95 2 : spdk_bdev_io_complete(io_ctx->orig_io, SPDK_BDEV_IO_STATUS_SUCCESS);
96 4 : } else if (io_ctx->status == -ENOMEM) {
97 0 : vbdev_compress_queue_io(spdk_bdev_io_from_ctx(io_ctx));
98 0 : } else {
99 2 : SPDK_ERRLOG("status %d on operation from reduce API\n", io_ctx->status);
100 2 : spdk_bdev_io_complete(io_ctx->orig_io, SPDK_BDEV_IO_STATUS_FAILED);
101 : }
102 4 : }
103 :
104 : /* Completion callback for r/w that were issued via reducelib. */
105 : static void
106 4 : reduce_rw_blocks_cb(void *arg, int reduce_errno)
107 : {
108 4 : struct spdk_bdev_io *bdev_io = arg;
109 4 : struct comp_bdev_io *io_ctx = (struct comp_bdev_io *)bdev_io->driver_ctx;
110 4 : struct spdk_io_channel *ch = spdk_io_channel_from_ctx(io_ctx->comp_ch);
111 4 : struct spdk_thread *orig_thread;
112 :
113 : /* TODO: need to decide which error codes are bdev_io success vs failure;
114 : * example examine calls reading metadata */
115 :
116 4 : io_ctx->status = reduce_errno;
117 :
118 : /* Send this request to the orig IO thread. */
119 4 : orig_thread = spdk_io_channel_get_thread(ch);
120 :
121 4 : spdk_thread_exec_msg(orig_thread, _reduce_rw_blocks_cb, io_ctx);
122 4 : }
123 :
124 : static int
125 0 : _compress_operation(struct spdk_reduce_backing_dev *backing_dev, struct iovec *src_iovs,
126 : int src_iovcnt, struct iovec *dst_iovs,
127 : int dst_iovcnt, bool compress, void *cb_arg)
128 : {
129 0 : struct spdk_reduce_vol_cb_args *reduce_cb_arg = cb_arg;
130 0 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(backing_dev, struct vbdev_compress,
131 : backing_dev);
132 0 : int rc;
133 :
134 0 : if (compress) {
135 0 : assert(dst_iovcnt == 1);
136 0 : rc = spdk_accel_submit_compress(comp_bdev->accel_channel, dst_iovs[0].iov_base, dst_iovs[0].iov_len,
137 0 : src_iovs, src_iovcnt, &reduce_cb_arg->output_size,
138 0 : 0, reduce_cb_arg->cb_fn, reduce_cb_arg->cb_arg);
139 0 : } else {
140 0 : rc = spdk_accel_submit_decompress(comp_bdev->accel_channel, dst_iovs, dst_iovcnt,
141 0 : src_iovs, src_iovcnt, &reduce_cb_arg->output_size,
142 0 : 0, reduce_cb_arg->cb_fn, reduce_cb_arg->cb_arg);
143 : }
144 :
145 0 : return rc;
146 0 : }
147 :
148 : /* Entry point for reduce lib to issue a compress operation. */
149 : static void
150 0 : _comp_reduce_compress(struct spdk_reduce_backing_dev *dev,
151 : struct iovec *src_iovs, int src_iovcnt,
152 : struct iovec *dst_iovs, int dst_iovcnt,
153 : struct spdk_reduce_vol_cb_args *cb_arg)
154 : {
155 0 : int rc;
156 :
157 0 : rc = _compress_operation(dev, src_iovs, src_iovcnt, dst_iovs, dst_iovcnt, true, cb_arg);
158 0 : if (rc) {
159 0 : SPDK_ERRLOG("with compress operation code %d (%s)\n", rc, spdk_strerror(-rc));
160 0 : cb_arg->cb_fn(cb_arg->cb_arg, rc);
161 0 : }
162 0 : }
163 :
164 : /* Entry point for reduce lib to issue a decompress operation. */
165 : static void
166 0 : _comp_reduce_decompress(struct spdk_reduce_backing_dev *dev,
167 : struct iovec *src_iovs, int src_iovcnt,
168 : struct iovec *dst_iovs, int dst_iovcnt,
169 : struct spdk_reduce_vol_cb_args *cb_arg)
170 : {
171 0 : int rc;
172 :
173 0 : rc = _compress_operation(dev, src_iovs, src_iovcnt, dst_iovs, dst_iovcnt, false, cb_arg);
174 0 : if (rc) {
175 0 : SPDK_ERRLOG("with decompress operation code %d (%s)\n", rc, spdk_strerror(-rc));
176 0 : cb_arg->cb_fn(cb_arg->cb_arg, rc);
177 0 : }
178 0 : }
179 :
180 : static void
181 2 : _comp_submit_write(void *ctx)
182 : {
183 2 : struct spdk_bdev_io *bdev_io = ctx;
184 2 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(bdev_io->bdev, struct vbdev_compress,
185 : comp_bdev);
186 :
187 4 : spdk_reduce_vol_writev(comp_bdev->vol, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
188 2 : bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks,
189 2 : reduce_rw_blocks_cb, bdev_io);
190 2 : }
191 :
192 : static void
193 2 : _comp_submit_read(void *ctx)
194 : {
195 2 : struct spdk_bdev_io *bdev_io = ctx;
196 2 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(bdev_io->bdev, struct vbdev_compress,
197 : comp_bdev);
198 :
199 4 : spdk_reduce_vol_readv(comp_bdev->vol, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
200 2 : bdev_io->u.bdev.offset_blocks, bdev_io->u.bdev.num_blocks,
201 2 : reduce_rw_blocks_cb, bdev_io);
202 2 : }
203 :
204 :
205 : /* Callback for getting a buf from the bdev pool in the event that the caller passed
206 : * in NULL, we need to own the buffer so it doesn't get freed by another vbdev module
207 : * beneath us before we're done with it.
208 : */
209 : static void
210 2 : comp_read_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, bool success)
211 : {
212 2 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(bdev_io->bdev, struct vbdev_compress,
213 : comp_bdev);
214 :
215 2 : if (spdk_unlikely(!success)) {
216 0 : SPDK_ERRLOG("Failed to get data buffer\n");
217 0 : reduce_rw_blocks_cb(bdev_io, -ENOMEM);
218 0 : return;
219 : }
220 :
221 2 : spdk_thread_exec_msg(comp_bdev->reduce_thread, _comp_submit_read, bdev_io);
222 2 : }
223 :
224 : /* Called when someone above submits IO to this vbdev. */
225 : static void
226 4 : vbdev_compress_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
227 : {
228 4 : struct comp_bdev_io *io_ctx = (struct comp_bdev_io *)bdev_io->driver_ctx;
229 4 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(bdev_io->bdev, struct vbdev_compress,
230 : comp_bdev);
231 4 : struct comp_io_channel *comp_ch = spdk_io_channel_get_ctx(ch);
232 :
233 4 : memset(io_ctx, 0, sizeof(struct comp_bdev_io));
234 4 : io_ctx->comp_bdev = comp_bdev;
235 4 : io_ctx->comp_ch = comp_ch;
236 4 : io_ctx->orig_io = bdev_io;
237 :
238 4 : switch (bdev_io->type) {
239 : case SPDK_BDEV_IO_TYPE_READ:
240 4 : spdk_bdev_io_get_buf(bdev_io, comp_read_get_buf_cb,
241 2 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
242 2 : return;
243 : case SPDK_BDEV_IO_TYPE_WRITE:
244 2 : spdk_thread_exec_msg(comp_bdev->reduce_thread, _comp_submit_write, bdev_io);
245 2 : return;
246 : /* TODO support RESET in future patch in the series */
247 : case SPDK_BDEV_IO_TYPE_RESET:
248 : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
249 : case SPDK_BDEV_IO_TYPE_UNMAP:
250 0 : case SPDK_BDEV_IO_TYPE_FLUSH:
251 : default:
252 0 : SPDK_ERRLOG("Unknown I/O type %d\n", bdev_io->type);
253 0 : spdk_bdev_io_complete(io_ctx->orig_io, SPDK_BDEV_IO_STATUS_FAILED);
254 0 : break;
255 : }
256 4 : }
257 :
258 : static bool
259 0 : vbdev_compress_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
260 : {
261 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)ctx;
262 :
263 0 : switch (io_type) {
264 : case SPDK_BDEV_IO_TYPE_READ:
265 : case SPDK_BDEV_IO_TYPE_WRITE:
266 0 : return spdk_bdev_io_type_supported(comp_bdev->base_bdev, io_type);
267 : case SPDK_BDEV_IO_TYPE_UNMAP:
268 : case SPDK_BDEV_IO_TYPE_RESET:
269 : case SPDK_BDEV_IO_TYPE_FLUSH:
270 0 : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
271 : default:
272 0 : return false;
273 : }
274 0 : }
275 :
276 : /* Resubmission function used by the bdev layer when a queued IO is ready to be
277 : * submitted.
278 : */
279 : static void
280 0 : vbdev_compress_resubmit_io(void *arg)
281 : {
282 0 : struct spdk_bdev_io *bdev_io = (struct spdk_bdev_io *)arg;
283 0 : struct comp_bdev_io *io_ctx = (struct comp_bdev_io *)bdev_io->driver_ctx;
284 :
285 0 : vbdev_compress_submit_request(io_ctx->ch, bdev_io);
286 0 : }
287 :
288 : /* Used to queue an IO in the event of resource issues. */
289 : static void
290 0 : vbdev_compress_queue_io(struct spdk_bdev_io *bdev_io)
291 : {
292 0 : struct comp_bdev_io *io_ctx = (struct comp_bdev_io *)bdev_io->driver_ctx;
293 0 : int rc;
294 :
295 0 : io_ctx->bdev_io_wait.bdev = bdev_io->bdev;
296 0 : io_ctx->bdev_io_wait.cb_fn = vbdev_compress_resubmit_io;
297 0 : io_ctx->bdev_io_wait.cb_arg = bdev_io;
298 :
299 0 : rc = spdk_bdev_queue_io_wait(bdev_io->bdev, io_ctx->comp_bdev->base_ch, &io_ctx->bdev_io_wait);
300 0 : if (rc) {
301 0 : SPDK_ERRLOG("Queue io failed in vbdev_compress_queue_io, rc=%d.\n", rc);
302 0 : assert(false);
303 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
304 : }
305 0 : }
306 :
307 : /* Callback for unregistering the IO device. */
308 : static void
309 0 : _device_unregister_cb(void *io_device)
310 : {
311 0 : struct vbdev_compress *comp_bdev = io_device;
312 :
313 : /* Done with this comp_bdev. */
314 0 : pthread_mutex_destroy(&comp_bdev->reduce_lock);
315 0 : free(comp_bdev->comp_bdev.name);
316 0 : free(comp_bdev);
317 0 : }
318 :
319 : static void
320 0 : _vbdev_compress_destruct_cb(void *ctx)
321 : {
322 0 : struct vbdev_compress *comp_bdev = ctx;
323 :
324 0 : TAILQ_REMOVE(&g_vbdev_comp, comp_bdev, link);
325 0 : spdk_bdev_module_release_bdev(comp_bdev->base_bdev);
326 : /* Close the underlying bdev on its same opened thread. */
327 0 : spdk_bdev_close(comp_bdev->base_desc);
328 0 : comp_bdev->vol = NULL;
329 0 : if (comp_bdev->orphaned == false) {
330 0 : spdk_io_device_unregister(comp_bdev, _device_unregister_cb);
331 0 : } else {
332 0 : vbdev_compress_delete_done(comp_bdev->delete_ctx, 0);
333 0 : _device_unregister_cb(comp_bdev);
334 : }
335 0 : }
336 :
337 : static void
338 0 : vbdev_compress_destruct_cb(void *cb_arg, int reduce_errno)
339 : {
340 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)cb_arg;
341 :
342 0 : if (reduce_errno) {
343 0 : SPDK_ERRLOG("number %d\n", reduce_errno);
344 0 : } else {
345 0 : if (comp_bdev->thread && comp_bdev->thread != spdk_get_thread()) {
346 0 : spdk_thread_send_msg(comp_bdev->thread,
347 0 : _vbdev_compress_destruct_cb, comp_bdev);
348 0 : } else {
349 0 : _vbdev_compress_destruct_cb(comp_bdev);
350 : }
351 : }
352 0 : }
353 :
354 : static void
355 0 : _reduce_destroy_cb(void *ctx, int reduce_errno)
356 : {
357 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)ctx;
358 :
359 0 : if (reduce_errno) {
360 0 : SPDK_ERRLOG("number %d\n", reduce_errno);
361 0 : }
362 :
363 0 : comp_bdev->vol = NULL;
364 0 : spdk_put_io_channel(comp_bdev->base_ch);
365 0 : if (comp_bdev->orphaned == false) {
366 0 : spdk_bdev_unregister(&comp_bdev->comp_bdev, vbdev_compress_delete_done,
367 0 : comp_bdev->delete_ctx);
368 0 : } else {
369 0 : vbdev_compress_destruct_cb((void *)comp_bdev, 0);
370 : }
371 :
372 0 : }
373 :
374 : static void
375 0 : _delete_vol_unload_cb(void *ctx)
376 : {
377 0 : struct vbdev_compress *comp_bdev = ctx;
378 :
379 : /* FIXME: Assert if these conditions are not satisfied for now. */
380 0 : assert(!comp_bdev->reduce_thread ||
381 : comp_bdev->reduce_thread == spdk_get_thread());
382 :
383 : /* reducelib needs a channel to comm with the backing device */
384 0 : comp_bdev->base_ch = spdk_bdev_get_io_channel(comp_bdev->base_desc);
385 :
386 : /* Clean the device before we free our resources. */
387 0 : spdk_reduce_vol_destroy(&comp_bdev->backing_dev, _reduce_destroy_cb, comp_bdev);
388 0 : }
389 :
390 : /* Called by reduceLib after performing unload vol actions */
391 : static void
392 0 : delete_vol_unload_cb(void *cb_arg, int reduce_errno)
393 : {
394 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)cb_arg;
395 :
396 0 : if (reduce_errno) {
397 0 : SPDK_ERRLOG("number %d\n", reduce_errno);
398 : /* FIXME: callback should be executed. */
399 0 : return;
400 : }
401 :
402 0 : pthread_mutex_lock(&comp_bdev->reduce_lock);
403 0 : if (comp_bdev->reduce_thread && comp_bdev->reduce_thread != spdk_get_thread()) {
404 0 : spdk_thread_send_msg(comp_bdev->reduce_thread,
405 0 : _delete_vol_unload_cb, comp_bdev);
406 0 : pthread_mutex_unlock(&comp_bdev->reduce_lock);
407 0 : } else {
408 0 : pthread_mutex_unlock(&comp_bdev->reduce_lock);
409 :
410 0 : _delete_vol_unload_cb(comp_bdev);
411 : }
412 0 : }
413 :
414 : const char *
415 0 : compress_get_name(const struct vbdev_compress *comp_bdev)
416 : {
417 0 : return comp_bdev->comp_bdev.name;
418 : }
419 :
420 : struct vbdev_compress *
421 0 : compress_bdev_first(void)
422 : {
423 0 : struct vbdev_compress *comp_bdev;
424 :
425 0 : comp_bdev = TAILQ_FIRST(&g_vbdev_comp);
426 :
427 0 : return comp_bdev;
428 0 : }
429 :
430 : struct vbdev_compress *
431 0 : compress_bdev_next(struct vbdev_compress *prev)
432 : {
433 0 : struct vbdev_compress *comp_bdev;
434 :
435 0 : comp_bdev = TAILQ_NEXT(prev, link);
436 :
437 0 : return comp_bdev;
438 0 : }
439 :
440 : bool
441 0 : compress_has_orphan(const char *name)
442 : {
443 0 : struct vbdev_compress *comp_bdev;
444 :
445 0 : TAILQ_FOREACH(comp_bdev, &g_vbdev_comp, link) {
446 0 : if (comp_bdev->orphaned && strcmp(name, comp_bdev->comp_bdev.name) == 0) {
447 0 : return true;
448 : }
449 0 : }
450 0 : return false;
451 0 : }
452 :
453 : /* Called after we've unregistered following a hot remove callback.
454 : * Our finish entry point will be called next.
455 : */
456 : static int
457 0 : vbdev_compress_destruct(void *ctx)
458 : {
459 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)ctx;
460 :
461 0 : if (comp_bdev->vol != NULL) {
462 : /* Tell reducelib that we're done with this volume. */
463 0 : spdk_reduce_vol_unload(comp_bdev->vol, vbdev_compress_destruct_cb, comp_bdev);
464 0 : } else {
465 0 : vbdev_compress_destruct_cb(comp_bdev, 0);
466 : }
467 :
468 0 : return 0;
469 0 : }
470 :
471 : /* We supplied this as an entry point for upper layers who want to communicate to this
472 : * bdev. This is how they get a channel.
473 : */
474 : static struct spdk_io_channel *
475 0 : vbdev_compress_get_io_channel(void *ctx)
476 : {
477 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)ctx;
478 :
479 : /* The IO channel code will allocate a channel for us which consists of
480 : * the SPDK channel structure plus the size of our comp_io_channel struct
481 : * that we passed in when we registered our IO device. It will then call
482 : * our channel create callback to populate any elements that we need to
483 : * update.
484 : */
485 0 : return spdk_get_io_channel(comp_bdev);
486 0 : }
487 :
488 : /* This is the output for bdev_get_bdevs() for this vbdev */
489 : static int
490 0 : vbdev_compress_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
491 : {
492 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)ctx;
493 :
494 0 : spdk_json_write_name(w, "compress");
495 0 : spdk_json_write_object_begin(w);
496 0 : spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&comp_bdev->comp_bdev));
497 0 : spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(comp_bdev->base_bdev));
498 0 : spdk_json_write_object_end(w);
499 :
500 0 : return 0;
501 0 : }
502 :
503 : /* This is used to generate JSON that can configure this module to its current state. */
504 : static int
505 0 : vbdev_compress_config_json(struct spdk_json_write_ctx *w)
506 : {
507 0 : struct vbdev_compress *comp_bdev;
508 0 : const char *module_name = NULL;
509 0 : int rc;
510 :
511 0 : rc = spdk_accel_get_opc_module_name(SPDK_ACCEL_OPC_COMPRESS, &module_name);
512 0 : if (rc) {
513 0 : SPDK_ERRLOG("error getting module name (%d)\n", rc);
514 0 : }
515 :
516 0 : TAILQ_FOREACH(comp_bdev, &g_vbdev_comp, link) {
517 0 : spdk_json_write_object_begin(w);
518 0 : spdk_json_write_named_string(w, "method", "bdev_compress_create");
519 0 : spdk_json_write_named_object_begin(w, "params");
520 0 : spdk_json_write_named_string(w, "base_bdev_name", spdk_bdev_get_name(comp_bdev->base_bdev));
521 0 : spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&comp_bdev->comp_bdev));
522 0 : spdk_json_write_object_end(w);
523 0 : spdk_json_write_object_end(w);
524 0 : }
525 0 : return 0;
526 0 : }
527 :
528 : static void
529 0 : _vbdev_reduce_init_cb(void *ctx)
530 : {
531 0 : struct vbdev_compress *meta_ctx = ctx;
532 0 : int rc;
533 :
534 0 : assert(meta_ctx->base_desc != NULL);
535 :
536 : /* We're done with metadata operations */
537 0 : spdk_put_io_channel(meta_ctx->base_ch);
538 :
539 0 : if (meta_ctx->vol) {
540 0 : rc = vbdev_compress_claim(meta_ctx);
541 0 : if (rc == 0) {
542 0 : return;
543 : }
544 0 : }
545 :
546 : /* Close the underlying bdev on its same opened thread. */
547 0 : spdk_bdev_close(meta_ctx->base_desc);
548 0 : free(meta_ctx);
549 0 : }
550 :
551 : /* Callback from reduce for when init is complete. We'll pass the vbdev_comp struct
552 : * used for initial metadata operations to claim where it will be further filled out
553 : * and added to the global list.
554 : */
555 : static void
556 0 : vbdev_reduce_init_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno)
557 : {
558 0 : struct vbdev_compress *meta_ctx = cb_arg;
559 :
560 0 : if (reduce_errno == 0) {
561 0 : meta_ctx->vol = vol;
562 0 : } else {
563 0 : SPDK_ERRLOG("for vol %s, error %u\n",
564 : spdk_bdev_get_name(meta_ctx->base_bdev), reduce_errno);
565 : }
566 :
567 0 : if (meta_ctx->thread && meta_ctx->thread != spdk_get_thread()) {
568 0 : spdk_thread_send_msg(meta_ctx->thread, _vbdev_reduce_init_cb, meta_ctx);
569 0 : } else {
570 0 : _vbdev_reduce_init_cb(meta_ctx);
571 : }
572 0 : }
573 :
574 : /* Callback for the function used by reduceLib to perform IO to/from the backing device. We just
575 : * call the callback provided by reduceLib when it called the read/write/unmap function and
576 : * free the bdev_io.
577 : */
578 : static void
579 0 : comp_reduce_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *arg)
580 : {
581 0 : struct spdk_reduce_vol_cb_args *cb_args = arg;
582 0 : int reduce_errno;
583 :
584 0 : if (success) {
585 0 : reduce_errno = 0;
586 0 : } else {
587 0 : reduce_errno = -EIO;
588 : }
589 0 : spdk_bdev_free_io(bdev_io);
590 0 : cb_args->cb_fn(cb_args->cb_arg, reduce_errno);
591 0 : }
592 :
593 : /* This is the function provided to the reduceLib for sending reads directly to
594 : * the backing device.
595 : */
596 : static void
597 0 : _comp_reduce_readv(struct spdk_reduce_backing_dev *dev, struct iovec *iov, int iovcnt,
598 : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
599 : {
600 0 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(dev, struct vbdev_compress,
601 : backing_dev);
602 0 : int rc;
603 :
604 0 : rc = spdk_bdev_readv_blocks(comp_bdev->base_desc, comp_bdev->base_ch,
605 0 : iov, iovcnt, lba, lba_count,
606 : comp_reduce_io_cb,
607 0 : args);
608 0 : if (rc) {
609 0 : if (rc == -ENOMEM) {
610 0 : SPDK_ERRLOG("No memory, start to queue io.\n");
611 : /* TODO: there's no bdev_io to queue */
612 0 : } else {
613 0 : SPDK_ERRLOG("submitting readv request\n");
614 : }
615 0 : args->cb_fn(args->cb_arg, rc);
616 0 : }
617 0 : }
618 :
619 : /* This is the function provided to the reduceLib for sending writes directly to
620 : * the backing device.
621 : */
622 : static void
623 0 : _comp_reduce_writev(struct spdk_reduce_backing_dev *dev, struct iovec *iov, int iovcnt,
624 : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
625 : {
626 0 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(dev, struct vbdev_compress,
627 : backing_dev);
628 0 : int rc;
629 :
630 0 : rc = spdk_bdev_writev_blocks(comp_bdev->base_desc, comp_bdev->base_ch,
631 0 : iov, iovcnt, lba, lba_count,
632 : comp_reduce_io_cb,
633 0 : args);
634 0 : if (rc) {
635 0 : if (rc == -ENOMEM) {
636 0 : SPDK_ERRLOG("No memory, start to queue io.\n");
637 : /* TODO: there's no bdev_io to queue */
638 0 : } else {
639 0 : SPDK_ERRLOG("error submitting writev request\n");
640 : }
641 0 : args->cb_fn(args->cb_arg, rc);
642 0 : }
643 0 : }
644 :
645 : /* This is the function provided to the reduceLib for sending unmaps directly to
646 : * the backing device.
647 : */
648 : static void
649 0 : _comp_reduce_unmap(struct spdk_reduce_backing_dev *dev,
650 : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
651 : {
652 0 : struct vbdev_compress *comp_bdev = SPDK_CONTAINEROF(dev, struct vbdev_compress,
653 : backing_dev);
654 0 : int rc;
655 :
656 0 : rc = spdk_bdev_unmap_blocks(comp_bdev->base_desc, comp_bdev->base_ch,
657 0 : lba, lba_count,
658 : comp_reduce_io_cb,
659 0 : args);
660 :
661 0 : if (rc) {
662 0 : if (rc == -ENOMEM) {
663 0 : SPDK_ERRLOG("No memory, start to queue io.\n");
664 : /* TODO: there's no bdev_io to queue */
665 0 : } else {
666 0 : SPDK_ERRLOG("submitting unmap request\n");
667 : }
668 0 : args->cb_fn(args->cb_arg, rc);
669 0 : }
670 0 : }
671 :
672 : /* Called by reduceLib after performing unload vol actions following base bdev hotremove */
673 : static void
674 0 : bdev_hotremove_vol_unload_cb(void *cb_arg, int reduce_errno)
675 : {
676 0 : struct vbdev_compress *comp_bdev = (struct vbdev_compress *)cb_arg;
677 :
678 0 : if (reduce_errno) {
679 0 : SPDK_ERRLOG("number %d\n", reduce_errno);
680 0 : }
681 :
682 0 : comp_bdev->vol = NULL;
683 0 : spdk_bdev_unregister(&comp_bdev->comp_bdev, NULL, NULL);
684 0 : }
685 :
686 : static void
687 0 : vbdev_compress_base_bdev_hotremove_cb(struct spdk_bdev *bdev_find)
688 : {
689 0 : struct vbdev_compress *comp_bdev, *tmp;
690 :
691 0 : TAILQ_FOREACH_SAFE(comp_bdev, &g_vbdev_comp, link, tmp) {
692 0 : if (bdev_find == comp_bdev->base_bdev) {
693 : /* Tell reduceLib that we're done with this volume. */
694 0 : spdk_reduce_vol_unload(comp_bdev->vol, bdev_hotremove_vol_unload_cb, comp_bdev);
695 0 : }
696 0 : }
697 0 : }
698 :
699 : /* Called when the underlying base bdev triggers asynchronous event such as bdev removal. */
700 : static void
701 0 : vbdev_compress_base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
702 : void *event_ctx)
703 : {
704 0 : switch (type) {
705 : case SPDK_BDEV_EVENT_REMOVE:
706 0 : vbdev_compress_base_bdev_hotremove_cb(bdev);
707 0 : break;
708 : default:
709 0 : SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
710 0 : break;
711 : }
712 0 : }
713 :
714 : /* TODO: determine which parms we want user configurable, HC for now
715 : * params.vol_size
716 : * params.chunk_size
717 : * compression PMD, algorithm, window size, comp level, etc.
718 : * DEV_MD_PATH
719 : */
720 :
721 : /* Common function for init and load to allocate and populate the minimal
722 : * information for reducelib to init or load.
723 : */
724 : struct vbdev_compress *
725 0 : _prepare_for_load_init(struct spdk_bdev_desc *bdev_desc, uint32_t lb_size)
726 : {
727 0 : struct vbdev_compress *meta_ctx;
728 0 : struct spdk_bdev *bdev;
729 :
730 0 : meta_ctx = calloc(1, sizeof(struct vbdev_compress));
731 0 : if (meta_ctx == NULL) {
732 0 : SPDK_ERRLOG("failed to alloc init contexts\n");
733 0 : return NULL;
734 : }
735 :
736 0 : meta_ctx->backing_dev.unmap = _comp_reduce_unmap;
737 0 : meta_ctx->backing_dev.readv = _comp_reduce_readv;
738 0 : meta_ctx->backing_dev.writev = _comp_reduce_writev;
739 0 : meta_ctx->backing_dev.compress = _comp_reduce_compress;
740 0 : meta_ctx->backing_dev.decompress = _comp_reduce_decompress;
741 :
742 0 : meta_ctx->base_desc = bdev_desc;
743 0 : bdev = spdk_bdev_desc_get_bdev(bdev_desc);
744 0 : meta_ctx->base_bdev = bdev;
745 :
746 0 : meta_ctx->backing_dev.blocklen = bdev->blocklen;
747 0 : meta_ctx->backing_dev.blockcnt = bdev->blockcnt;
748 :
749 0 : meta_ctx->params.chunk_size = CHUNK_SIZE;
750 0 : if (lb_size == 0) {
751 0 : meta_ctx->params.logical_block_size = bdev->blocklen;
752 0 : } else {
753 0 : meta_ctx->params.logical_block_size = lb_size;
754 : }
755 :
756 0 : meta_ctx->params.backing_io_unit_size = BACKING_IO_SZ;
757 0 : return meta_ctx;
758 0 : }
759 :
760 : /* Call reducelib to initialize a new volume */
761 : static int
762 0 : vbdev_init_reduce(const char *bdev_name, const char *pm_path, uint32_t lb_size)
763 : {
764 0 : struct spdk_bdev_desc *bdev_desc = NULL;
765 0 : struct vbdev_compress *meta_ctx;
766 0 : int rc;
767 :
768 0 : rc = spdk_bdev_open_ext(bdev_name, true, vbdev_compress_base_bdev_event_cb,
769 : NULL, &bdev_desc);
770 0 : if (rc) {
771 0 : SPDK_ERRLOG("could not open bdev %s\n", bdev_name);
772 0 : return rc;
773 : }
774 :
775 0 : meta_ctx = _prepare_for_load_init(bdev_desc, lb_size);
776 0 : if (meta_ctx == NULL) {
777 0 : spdk_bdev_close(bdev_desc);
778 0 : return -EINVAL;
779 : }
780 :
781 : /* Save the thread where the base device is opened */
782 0 : meta_ctx->thread = spdk_get_thread();
783 :
784 0 : meta_ctx->base_ch = spdk_bdev_get_io_channel(meta_ctx->base_desc);
785 :
786 0 : spdk_reduce_vol_init(&meta_ctx->params, &meta_ctx->backing_dev,
787 0 : pm_path,
788 : vbdev_reduce_init_cb,
789 0 : meta_ctx);
790 0 : return 0;
791 0 : }
792 :
793 : /* We provide this callback for the SPDK channel code to create a channel using
794 : * the channel struct we provided in our module get_io_channel() entry point. Here
795 : * we get and save off an underlying base channel of the device below us so that
796 : * we can communicate with the base bdev on a per channel basis. If we needed
797 : * our own poller for this vbdev, we'd register it here.
798 : */
799 : static int
800 0 : comp_bdev_ch_create_cb(void *io_device, void *ctx_buf)
801 : {
802 0 : struct vbdev_compress *comp_bdev = io_device;
803 :
804 : /* Now set the reduce channel if it's not already set. */
805 0 : pthread_mutex_lock(&comp_bdev->reduce_lock);
806 0 : if (comp_bdev->ch_count == 0) {
807 : /* We use this queue to track outstanding IO in our layer. */
808 0 : TAILQ_INIT(&comp_bdev->pending_comp_ios);
809 :
810 : /* We use this to queue up compression operations as needed. */
811 0 : TAILQ_INIT(&comp_bdev->queued_comp_ops);
812 :
813 0 : comp_bdev->base_ch = spdk_bdev_get_io_channel(comp_bdev->base_desc);
814 0 : comp_bdev->reduce_thread = spdk_get_thread();
815 0 : comp_bdev->accel_channel = spdk_accel_get_io_channel();
816 0 : }
817 0 : comp_bdev->ch_count++;
818 0 : pthread_mutex_unlock(&comp_bdev->reduce_lock);
819 :
820 0 : return 0;
821 0 : }
822 :
823 : static void
824 0 : _channel_cleanup(struct vbdev_compress *comp_bdev)
825 : {
826 0 : spdk_put_io_channel(comp_bdev->base_ch);
827 0 : spdk_put_io_channel(comp_bdev->accel_channel);
828 0 : comp_bdev->reduce_thread = NULL;
829 0 : }
830 :
831 : /* Used to reroute destroy_ch to the correct thread */
832 : static void
833 0 : _comp_bdev_ch_destroy_cb(void *arg)
834 : {
835 0 : struct vbdev_compress *comp_bdev = arg;
836 :
837 0 : pthread_mutex_lock(&comp_bdev->reduce_lock);
838 0 : _channel_cleanup(comp_bdev);
839 0 : pthread_mutex_unlock(&comp_bdev->reduce_lock);
840 0 : }
841 :
842 : /* We provide this callback for the SPDK channel code to destroy a channel
843 : * created with our create callback. We just need to undo anything we did
844 : * when we created. If this bdev used its own poller, we'd unregister it here.
845 : */
846 : static void
847 0 : comp_bdev_ch_destroy_cb(void *io_device, void *ctx_buf)
848 : {
849 0 : struct vbdev_compress *comp_bdev = io_device;
850 :
851 0 : pthread_mutex_lock(&comp_bdev->reduce_lock);
852 0 : comp_bdev->ch_count--;
853 0 : if (comp_bdev->ch_count == 0) {
854 : /* Send this request to the thread where the channel was created. */
855 0 : if (comp_bdev->reduce_thread != spdk_get_thread()) {
856 0 : spdk_thread_send_msg(comp_bdev->reduce_thread,
857 0 : _comp_bdev_ch_destroy_cb, comp_bdev);
858 0 : } else {
859 0 : _channel_cleanup(comp_bdev);
860 : }
861 0 : }
862 0 : pthread_mutex_unlock(&comp_bdev->reduce_lock);
863 0 : }
864 :
865 : /* RPC entry point for compression vbdev creation. */
866 : int
867 0 : create_compress_bdev(const char *bdev_name, const char *pm_path, uint32_t lb_size)
868 : {
869 0 : struct vbdev_compress *comp_bdev = NULL;
870 :
871 0 : if ((lb_size != 0) && (lb_size != LB_SIZE_4K) && (lb_size != LB_SIZE_512B)) {
872 0 : SPDK_ERRLOG("Logical block size must be 512 or 4096\n");
873 0 : return -EINVAL;
874 : }
875 :
876 0 : TAILQ_FOREACH(comp_bdev, &g_vbdev_comp, link) {
877 0 : if (strcmp(bdev_name, comp_bdev->base_bdev->name) == 0) {
878 0 : SPDK_ERRLOG("Bass bdev %s already being used for a compress bdev\n", bdev_name);
879 0 : return -EBUSY;
880 : }
881 0 : }
882 0 : return vbdev_init_reduce(bdev_name, pm_path, lb_size);
883 0 : }
884 :
885 : static int
886 0 : vbdev_compress_init(void)
887 : {
888 0 : return 0;
889 : }
890 :
891 : /* Called when the entire module is being torn down. */
892 : static void
893 0 : vbdev_compress_finish(void)
894 : {
895 : /* TODO: unload vol in a future patch */
896 0 : }
897 :
898 : /* During init we'll be asked how much memory we'd like passed to us
899 : * in bev_io structures as context. Here's where we specify how
900 : * much context we want per IO.
901 : */
902 : static int
903 0 : vbdev_compress_get_ctx_size(void)
904 : {
905 0 : return sizeof(struct comp_bdev_io);
906 : }
907 :
908 : /* When we register our bdev this is how we specify our entry points. */
909 : static const struct spdk_bdev_fn_table vbdev_compress_fn_table = {
910 : .destruct = vbdev_compress_destruct,
911 : .submit_request = vbdev_compress_submit_request,
912 : .io_type_supported = vbdev_compress_io_type_supported,
913 : .get_io_channel = vbdev_compress_get_io_channel,
914 : .dump_info_json = vbdev_compress_dump_info_json,
915 : .write_config_json = NULL,
916 : };
917 :
918 : static struct spdk_bdev_module compress_if = {
919 : .name = "compress",
920 : .module_init = vbdev_compress_init,
921 : .get_ctx_size = vbdev_compress_get_ctx_size,
922 : .examine_disk = vbdev_compress_examine,
923 : .module_fini = vbdev_compress_finish,
924 : .config_json = vbdev_compress_config_json
925 : };
926 :
927 1 : SPDK_BDEV_MODULE_REGISTER(compress, &compress_if)
928 :
929 0 : static int _set_compbdev_name(struct vbdev_compress *comp_bdev)
930 : {
931 0 : struct spdk_bdev_alias *aliases;
932 :
933 0 : if (!TAILQ_EMPTY(spdk_bdev_get_aliases(comp_bdev->base_bdev))) {
934 0 : aliases = TAILQ_FIRST(spdk_bdev_get_aliases(comp_bdev->base_bdev));
935 0 : comp_bdev->comp_bdev.name = spdk_sprintf_alloc("COMP_%s", aliases->alias.name);
936 0 : if (!comp_bdev->comp_bdev.name) {
937 0 : SPDK_ERRLOG("could not allocate comp_bdev name for alias\n");
938 0 : return -ENOMEM;
939 : }
940 0 : } else {
941 0 : comp_bdev->comp_bdev.name = spdk_sprintf_alloc("COMP_%s", comp_bdev->base_bdev->name);
942 0 : if (!comp_bdev->comp_bdev.name) {
943 0 : SPDK_ERRLOG("could not allocate comp_bdev name for unique name\n");
944 0 : return -ENOMEM;
945 : }
946 : }
947 0 : return 0;
948 0 : }
949 :
950 : static int
951 0 : vbdev_compress_claim(struct vbdev_compress *comp_bdev)
952 : {
953 0 : struct spdk_uuid ns_uuid;
954 0 : int rc;
955 :
956 0 : if (_set_compbdev_name(comp_bdev)) {
957 0 : return -EINVAL;
958 : }
959 :
960 : /* Note: some of the fields below will change in the future - for example,
961 : * blockcnt specifically will not match (the compressed volume size will
962 : * be slightly less than the base bdev size)
963 : */
964 0 : comp_bdev->comp_bdev.product_name = COMP_BDEV_NAME;
965 0 : comp_bdev->comp_bdev.write_cache = comp_bdev->base_bdev->write_cache;
966 :
967 0 : comp_bdev->comp_bdev.optimal_io_boundary =
968 0 : comp_bdev->params.chunk_size / comp_bdev->params.logical_block_size;
969 :
970 0 : comp_bdev->comp_bdev.split_on_optimal_io_boundary = true;
971 :
972 0 : comp_bdev->comp_bdev.blocklen = comp_bdev->params.logical_block_size;
973 0 : comp_bdev->comp_bdev.blockcnt = comp_bdev->params.vol_size / comp_bdev->comp_bdev.blocklen;
974 0 : assert(comp_bdev->comp_bdev.blockcnt > 0);
975 :
976 : /* This is the context that is passed to us when the bdev
977 : * layer calls in so we'll save our comp_bdev node here.
978 : */
979 0 : comp_bdev->comp_bdev.ctxt = comp_bdev;
980 0 : comp_bdev->comp_bdev.fn_table = &vbdev_compress_fn_table;
981 0 : comp_bdev->comp_bdev.module = &compress_if;
982 :
983 : /* Generate UUID based on namespace UUID + base bdev UUID. */
984 0 : spdk_uuid_parse(&ns_uuid, BDEV_COMPRESS_NAMESPACE_UUID);
985 0 : rc = spdk_uuid_generate_sha1(&comp_bdev->comp_bdev.uuid, &ns_uuid,
986 0 : (const char *)&comp_bdev->base_bdev->uuid, sizeof(struct spdk_uuid));
987 0 : if (rc) {
988 0 : SPDK_ERRLOG("Unable to generate new UUID for compress bdev\n");
989 0 : return -EINVAL;
990 : }
991 :
992 0 : pthread_mutex_init(&comp_bdev->reduce_lock, NULL);
993 :
994 : /* Save the thread where the base device is opened */
995 0 : comp_bdev->thread = spdk_get_thread();
996 :
997 0 : spdk_io_device_register(comp_bdev, comp_bdev_ch_create_cb, comp_bdev_ch_destroy_cb,
998 : sizeof(struct comp_io_channel),
999 0 : comp_bdev->comp_bdev.name);
1000 :
1001 0 : rc = spdk_bdev_module_claim_bdev(comp_bdev->base_bdev, comp_bdev->base_desc,
1002 0 : comp_bdev->comp_bdev.module);
1003 0 : if (rc) {
1004 0 : SPDK_ERRLOG("could not claim bdev %s\n", spdk_bdev_get_name(comp_bdev->base_bdev));
1005 0 : goto error_claim;
1006 : }
1007 :
1008 0 : rc = spdk_bdev_register(&comp_bdev->comp_bdev);
1009 0 : if (rc < 0) {
1010 0 : SPDK_ERRLOG("trying to register bdev\n");
1011 0 : goto error_bdev_register;
1012 : }
1013 :
1014 0 : TAILQ_INSERT_TAIL(&g_vbdev_comp, comp_bdev, link);
1015 :
1016 0 : SPDK_NOTICELOG("registered io_device and virtual bdev for: %s\n", comp_bdev->comp_bdev.name);
1017 :
1018 0 : return 0;
1019 :
1020 : /* Error cleanup paths. */
1021 : error_bdev_register:
1022 0 : spdk_bdev_module_release_bdev(comp_bdev->base_bdev);
1023 : error_claim:
1024 0 : spdk_io_device_unregister(comp_bdev, NULL);
1025 0 : free(comp_bdev->comp_bdev.name);
1026 0 : return rc;
1027 0 : }
1028 :
1029 : static void
1030 0 : _vbdev_compress_delete_done(void *_ctx)
1031 : {
1032 0 : struct vbdev_comp_delete_ctx *ctx = _ctx;
1033 :
1034 0 : ctx->cb_fn(ctx->cb_arg, ctx->cb_rc);
1035 :
1036 0 : free(ctx);
1037 0 : }
1038 :
1039 : static void
1040 0 : vbdev_compress_delete_done(void *cb_arg, int bdeverrno)
1041 : {
1042 0 : struct vbdev_comp_delete_ctx *ctx = cb_arg;
1043 :
1044 0 : ctx->cb_rc = bdeverrno;
1045 :
1046 0 : if (ctx->orig_thread != spdk_get_thread()) {
1047 0 : spdk_thread_send_msg(ctx->orig_thread, _vbdev_compress_delete_done, ctx);
1048 0 : } else {
1049 0 : _vbdev_compress_delete_done(ctx);
1050 : }
1051 0 : }
1052 :
1053 : void
1054 0 : bdev_compress_delete(const char *name, spdk_delete_compress_complete cb_fn, void *cb_arg)
1055 : {
1056 0 : struct vbdev_compress *comp_bdev = NULL;
1057 0 : struct vbdev_comp_delete_ctx *ctx;
1058 :
1059 0 : TAILQ_FOREACH(comp_bdev, &g_vbdev_comp, link) {
1060 0 : if (strcmp(name, comp_bdev->comp_bdev.name) == 0) {
1061 0 : break;
1062 : }
1063 0 : }
1064 :
1065 0 : if (comp_bdev == NULL) {
1066 0 : cb_fn(cb_arg, -ENODEV);
1067 0 : return;
1068 : }
1069 :
1070 0 : ctx = calloc(1, sizeof(*ctx));
1071 0 : if (ctx == NULL) {
1072 0 : SPDK_ERRLOG("Failed to allocate delete context\n");
1073 0 : cb_fn(cb_arg, -ENOMEM);
1074 0 : return;
1075 : }
1076 :
1077 : /* Save these for after the vol is destroyed. */
1078 0 : ctx->cb_fn = cb_fn;
1079 0 : ctx->cb_arg = cb_arg;
1080 0 : ctx->orig_thread = spdk_get_thread();
1081 :
1082 0 : comp_bdev->delete_ctx = ctx;
1083 :
1084 : /* Tell reducelib that we're done with this volume. */
1085 0 : if (comp_bdev->orphaned == false) {
1086 0 : spdk_reduce_vol_unload(comp_bdev->vol, delete_vol_unload_cb, comp_bdev);
1087 0 : } else {
1088 0 : delete_vol_unload_cb(comp_bdev, 0);
1089 : }
1090 0 : }
1091 :
1092 : static void
1093 0 : _vbdev_reduce_load_cb(void *ctx)
1094 : {
1095 0 : struct vbdev_compress *meta_ctx = ctx;
1096 0 : int rc;
1097 :
1098 0 : assert(meta_ctx->base_desc != NULL);
1099 :
1100 : /* Done with metadata operations */
1101 0 : spdk_put_io_channel(meta_ctx->base_ch);
1102 :
1103 0 : if (meta_ctx->reduce_errno == 0) {
1104 0 : rc = vbdev_compress_claim(meta_ctx);
1105 0 : if (rc != 0) {
1106 0 : goto err;
1107 : }
1108 0 : } else if (meta_ctx->reduce_errno == -ENOENT) {
1109 0 : if (_set_compbdev_name(meta_ctx)) {
1110 0 : goto err;
1111 : }
1112 :
1113 : /* Save the thread where the base device is opened */
1114 0 : meta_ctx->thread = spdk_get_thread();
1115 :
1116 0 : meta_ctx->comp_bdev.module = &compress_if;
1117 0 : pthread_mutex_init(&meta_ctx->reduce_lock, NULL);
1118 0 : rc = spdk_bdev_module_claim_bdev(meta_ctx->base_bdev, meta_ctx->base_desc,
1119 0 : meta_ctx->comp_bdev.module);
1120 0 : if (rc) {
1121 0 : SPDK_ERRLOG("could not claim bdev %s\n", spdk_bdev_get_name(meta_ctx->base_bdev));
1122 0 : free(meta_ctx->comp_bdev.name);
1123 0 : goto err;
1124 : }
1125 :
1126 0 : meta_ctx->orphaned = true;
1127 0 : TAILQ_INSERT_TAIL(&g_vbdev_comp, meta_ctx, link);
1128 0 : } else {
1129 0 : if (meta_ctx->reduce_errno != -EILSEQ) {
1130 0 : SPDK_ERRLOG("for vol %s, error %u\n",
1131 : spdk_bdev_get_name(meta_ctx->base_bdev), meta_ctx->reduce_errno);
1132 0 : }
1133 0 : goto err;
1134 : }
1135 :
1136 0 : spdk_bdev_module_examine_done(&compress_if);
1137 0 : return;
1138 :
1139 : err:
1140 : /* Close the underlying bdev on its same opened thread. */
1141 0 : spdk_bdev_close(meta_ctx->base_desc);
1142 0 : free(meta_ctx);
1143 0 : spdk_bdev_module_examine_done(&compress_if);
1144 0 : }
1145 :
1146 : /* Callback from reduce for then load is complete. We'll pass the vbdev_comp struct
1147 : * used for initial metadata operations to claim where it will be further filled out
1148 : * and added to the global list.
1149 : */
1150 : static void
1151 0 : vbdev_reduce_load_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno)
1152 : {
1153 0 : struct vbdev_compress *meta_ctx = cb_arg;
1154 :
1155 0 : if (reduce_errno == 0) {
1156 : /* Update information following volume load. */
1157 0 : meta_ctx->vol = vol;
1158 0 : memcpy(&meta_ctx->params, spdk_reduce_vol_get_params(vol),
1159 : sizeof(struct spdk_reduce_vol_params));
1160 0 : }
1161 :
1162 0 : meta_ctx->reduce_errno = reduce_errno;
1163 :
1164 0 : if (meta_ctx->thread && meta_ctx->thread != spdk_get_thread()) {
1165 0 : spdk_thread_send_msg(meta_ctx->thread, _vbdev_reduce_load_cb, meta_ctx);
1166 0 : } else {
1167 0 : _vbdev_reduce_load_cb(meta_ctx);
1168 : }
1169 :
1170 0 : }
1171 :
1172 : /* Examine_disk entry point: will do a metadata load to see if this is ours,
1173 : * and if so will go ahead and claim it.
1174 : */
1175 : static void
1176 0 : vbdev_compress_examine(struct spdk_bdev *bdev)
1177 : {
1178 0 : struct spdk_bdev_desc *bdev_desc = NULL;
1179 0 : struct vbdev_compress *meta_ctx;
1180 0 : int rc;
1181 :
1182 0 : if (strcmp(bdev->product_name, COMP_BDEV_NAME) == 0) {
1183 0 : spdk_bdev_module_examine_done(&compress_if);
1184 0 : return;
1185 : }
1186 :
1187 0 : rc = spdk_bdev_open_ext(spdk_bdev_get_name(bdev), false,
1188 : vbdev_compress_base_bdev_event_cb, NULL, &bdev_desc);
1189 0 : if (rc) {
1190 0 : SPDK_ERRLOG("could not open bdev %s\n", spdk_bdev_get_name(bdev));
1191 0 : spdk_bdev_module_examine_done(&compress_if);
1192 0 : return;
1193 : }
1194 :
1195 0 : meta_ctx = _prepare_for_load_init(bdev_desc, 0);
1196 0 : if (meta_ctx == NULL) {
1197 0 : spdk_bdev_close(bdev_desc);
1198 0 : spdk_bdev_module_examine_done(&compress_if);
1199 0 : return;
1200 : }
1201 :
1202 : /* Save the thread where the base device is opened */
1203 0 : meta_ctx->thread = spdk_get_thread();
1204 :
1205 0 : meta_ctx->base_ch = spdk_bdev_get_io_channel(meta_ctx->base_desc);
1206 0 : spdk_reduce_vol_load(&meta_ctx->backing_dev, vbdev_reduce_load_cb, meta_ctx);
1207 0 : }
1208 :
1209 1 : SPDK_LOG_REGISTER_COMPONENT(vbdev_compress)
|