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