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