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