Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/bdev.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/thread.h"
11 : : #include "spdk/json.h"
12 : : #include "spdk/string.h"
13 : : #include "spdk/likely.h"
14 : :
15 : : #include "spdk/bdev_module.h"
16 : : #include "spdk/log.h"
17 : :
18 : : #include "bdev_null.h"
19 : :
20 : : struct null_bdev {
21 : : struct spdk_bdev bdev;
22 : : TAILQ_ENTRY(null_bdev) tailq;
23 : : };
24 : :
25 : : struct null_io_channel {
26 : : struct spdk_poller *poller;
27 : : TAILQ_HEAD(, spdk_bdev_io) io;
28 : : };
29 : :
30 : : static TAILQ_HEAD(, null_bdev) g_null_bdev_head = TAILQ_HEAD_INITIALIZER(g_null_bdev_head);
31 : : static void *g_null_read_buf;
32 : :
33 : : static int bdev_null_initialize(void);
34 : : static void bdev_null_finish(void);
35 : :
36 : : static struct spdk_bdev_module null_if = {
37 : : .name = "null",
38 : : .module_init = bdev_null_initialize,
39 : : .module_fini = bdev_null_finish,
40 : : .async_fini = true,
41 : : };
42 : :
43 : 2065 : SPDK_BDEV_MODULE_REGISTER(null, &null_if)
44 : :
45 : : static int
46 : 146 : bdev_null_destruct(void *ctx)
47 : : {
48 : 146 : struct null_bdev *bdev = ctx;
49 : :
50 [ + + ]: 146 : TAILQ_REMOVE(&g_null_bdev_head, bdev, tailq);
51 : 146 : free(bdev->bdev.name);
52 : 146 : free(bdev);
53 : :
54 : 146 : return 0;
55 : : }
56 : :
57 : : static bool
58 : 0 : bdev_null_abort_io(struct null_io_channel *ch, struct spdk_bdev_io *bio_to_abort)
59 : : {
60 : : struct spdk_bdev_io *bdev_io;
61 : :
62 [ # # ]: 0 : TAILQ_FOREACH(bdev_io, &ch->io, module_link) {
63 [ # # ]: 0 : if (bdev_io == bio_to_abort) {
64 [ # # ]: 0 : TAILQ_REMOVE(&ch->io, bio_to_abort, module_link);
65 : 0 : spdk_bdev_io_complete(bio_to_abort, SPDK_BDEV_IO_STATUS_ABORTED);
66 : 0 : return true;
67 : : }
68 : : }
69 : :
70 : 0 : return false;
71 : : }
72 : :
73 : : static void
74 : 8410559 : bdev_null_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
75 : : {
76 : 8410559 : struct null_io_channel *ch = spdk_io_channel_get_ctx(_ch);
77 : 8410559 : struct spdk_bdev *bdev = bdev_io->bdev;
78 : 4250371 : struct spdk_dif_ctx dif_ctx;
79 : 4250371 : struct spdk_dif_error err_blk;
80 : : int rc;
81 : 4250371 : struct spdk_dif_ctx_init_ext_opts dif_opts;
82 : :
83 [ + + ]: 8410559 : if (SPDK_DIF_DISABLE != bdev->dif_type &&
84 [ - + ]: 480588 : (SPDK_BDEV_IO_TYPE_READ == bdev_io->type ||
85 [ # # ]: 0 : SPDK_BDEV_IO_TYPE_WRITE == bdev_io->type)) {
86 : 480588 : dif_opts.size = SPDK_SIZEOF(&dif_opts, dif_pi_format);
87 : 480588 : dif_opts.dif_pi_format = SPDK_DIF_PI_FORMAT_16;
88 : 961176 : rc = spdk_dif_ctx_init(&dif_ctx,
89 : : bdev->blocklen,
90 : : bdev->md_len,
91 [ - + ]: 480588 : bdev->md_interleave,
92 [ - + ]: 480588 : bdev->dif_is_head_of_md,
93 : : bdev->dif_type,
94 : : bdev->dif_check_flags,
95 : 480588 : bdev_io->u.bdev.offset_blocks & 0xFFFFFFFF,
96 : : 0xFFFF, 0, 0, 0, &dif_opts);
97 [ - + ]: 480588 : if (0 != rc) {
98 : 0 : SPDK_ERRLOG("Failed to initialize DIF context, error %d\n", rc);
99 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
100 : 0 : return;
101 : : }
102 : : }
103 : :
104 [ + + - - : 8410559 : switch (bdev_io->type) {
- ]
105 : 7630490 : case SPDK_BDEV_IO_TYPE_READ:
106 [ + + ]: 7630490 : if (bdev_io->u.bdev.iovs[0].iov_base == NULL) {
107 [ - + ]: 340773 : assert(bdev_io->u.bdev.iovcnt == 1);
108 [ + - ]: 340773 : if (spdk_likely(bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen <=
109 : : SPDK_BDEV_LARGE_BUF_MAX_SIZE)) {
110 : 340773 : bdev_io->u.bdev.iovs[0].iov_base = g_null_read_buf;
111 : 340773 : bdev_io->u.bdev.iovs[0].iov_len = bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen;
112 : : } else {
113 : 0 : SPDK_ERRLOG("Overflow occurred. Read I/O size %" PRIu64 " was larger than permitted %d\n",
114 : : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
115 : : SPDK_BDEV_LARGE_BUF_MAX_SIZE);
116 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
117 : 0 : return;
118 : : }
119 : : }
120 [ + + ]: 7630490 : if (SPDK_DIF_DISABLE != bdev->dif_type) {
121 : 480588 : rc = spdk_dif_generate(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
122 : 480588 : bdev_io->u.bdev.num_blocks, &dif_ctx);
123 [ - + ]: 480588 : if (0 != rc) {
124 : 0 : SPDK_ERRLOG("IO DIF generation failed: lba %" PRIu64 ", num_block %" PRIu64 "\n",
125 : : bdev_io->u.bdev.offset_blocks,
126 : : bdev_io->u.bdev.num_blocks);
127 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
128 : 0 : return;
129 : : }
130 : : }
131 : 7630490 : TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link);
132 : 7630490 : break;
133 : 780069 : case SPDK_BDEV_IO_TYPE_WRITE:
134 [ - + ]: 780069 : if (SPDK_DIF_DISABLE != bdev->dif_type) {
135 : 0 : rc = spdk_dif_verify(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
136 : 0 : bdev_io->u.bdev.num_blocks, &dif_ctx, &err_blk);
137 [ # # ]: 0 : if (0 != rc) {
138 : 0 : SPDK_ERRLOG("IO DIF verification failed: lba %" PRIu64 ", num_blocks %" PRIu64 ", "
139 : : "err_type %u, expected %lu, actual %lu, err_offset %u\n",
140 : : bdev_io->u.bdev.offset_blocks,
141 : : bdev_io->u.bdev.num_blocks,
142 : : err_blk.err_type,
143 : : err_blk.expected,
144 : : err_blk.actual,
145 : : err_blk.err_offset);
146 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
147 : 0 : return;
148 : : }
149 : : }
150 : 780069 : TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link);
151 : 780069 : break;
152 : 0 : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
153 : : case SPDK_BDEV_IO_TYPE_RESET:
154 : 0 : TAILQ_INSERT_TAIL(&ch->io, bdev_io, module_link);
155 : 0 : break;
156 : 0 : case SPDK_BDEV_IO_TYPE_ABORT:
157 [ # # ]: 0 : if (bdev_null_abort_io(ch, bdev_io->u.abort.bio_to_abort)) {
158 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
159 : : } else {
160 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
161 : : }
162 : 0 : break;
163 : 0 : case SPDK_BDEV_IO_TYPE_FLUSH:
164 : : case SPDK_BDEV_IO_TYPE_UNMAP:
165 : : default:
166 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
167 : 0 : break;
168 : : }
169 : : }
170 : :
171 : : static bool
172 : 27770 : bdev_null_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
173 : : {
174 [ + + ]: 27770 : switch (io_type) {
175 : 8800 : case SPDK_BDEV_IO_TYPE_READ:
176 : : case SPDK_BDEV_IO_TYPE_WRITE:
177 : : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
178 : : case SPDK_BDEV_IO_TYPE_RESET:
179 : : case SPDK_BDEV_IO_TYPE_ABORT:
180 : 8800 : return true;
181 : 18970 : case SPDK_BDEV_IO_TYPE_FLUSH:
182 : : case SPDK_BDEV_IO_TYPE_UNMAP:
183 : : default:
184 : 18970 : return false;
185 : : }
186 : : }
187 : :
188 : : static struct spdk_io_channel *
189 : 6766 : bdev_null_get_io_channel(void *ctx)
190 : : {
191 : 6766 : return spdk_get_io_channel(&g_null_bdev_head);
192 : : }
193 : :
194 : : static void
195 : 28 : bdev_null_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
196 : : {
197 : 28 : spdk_json_write_object_begin(w);
198 : :
199 : 28 : spdk_json_write_named_string(w, "method", "bdev_null_create");
200 : :
201 : 28 : spdk_json_write_named_object_begin(w, "params");
202 : 28 : spdk_json_write_named_string(w, "name", bdev->name);
203 : 28 : spdk_json_write_named_uint64(w, "num_blocks", bdev->blockcnt);
204 : 28 : spdk_json_write_named_uint32(w, "block_size", bdev->blocklen);
205 : 28 : spdk_json_write_named_uint32(w, "physical_block_size", bdev->phys_blocklen);
206 : 28 : spdk_json_write_named_uint32(w, "md_size", bdev->md_len);
207 : 28 : spdk_json_write_named_uint32(w, "dif_type", bdev->dif_type);
208 [ - + ]: 28 : spdk_json_write_named_bool(w, "dif_is_head_of_md", bdev->dif_is_head_of_md);
209 : 28 : spdk_json_write_named_uuid(w, "uuid", &bdev->uuid);
210 : 28 : spdk_json_write_object_end(w);
211 : :
212 : 28 : spdk_json_write_object_end(w);
213 : 28 : }
214 : :
215 : : static const struct spdk_bdev_fn_table null_fn_table = {
216 : : .destruct = bdev_null_destruct,
217 : : .submit_request = bdev_null_submit_request,
218 : : .io_type_supported = bdev_null_io_type_supported,
219 : : .get_io_channel = bdev_null_get_io_channel,
220 : : .write_config_json = bdev_null_write_config_json,
221 : : };
222 : :
223 : : int
224 : 146 : bdev_null_create(struct spdk_bdev **bdev, const struct spdk_null_bdev_opts *opts)
225 : : {
226 : : struct null_bdev *null_disk;
227 : : uint32_t data_block_size;
228 : : int rc;
229 : :
230 [ - + ]: 146 : if (!opts) {
231 : 0 : SPDK_ERRLOG("No options provided for Null bdev.\n");
232 : 0 : return -EINVAL;
233 : : }
234 : :
235 [ + - ]: 146 : switch (opts->md_size) {
236 : 146 : case 0:
237 : : case 8:
238 : : case 16:
239 : : case 32:
240 : : case 64:
241 : : case 128:
242 : 146 : break;
243 : 0 : default:
244 : 0 : SPDK_ERRLOG("metadata size %u is not supported\n", opts->md_size);
245 : 0 : return -EINVAL;
246 : : }
247 : :
248 [ + + + - ]: 146 : if (opts->md_interleave) {
249 [ - + ]: 146 : if (opts->block_size < opts->md_size) {
250 : 0 : SPDK_ERRLOG("Interleaved metadata size can not be greater than block size.\n");
251 : 0 : return -EINVAL;
252 : : }
253 : 146 : data_block_size = opts->block_size - opts->md_size;
254 : : } else {
255 [ # # ]: 0 : if (opts->md_size != 0) {
256 : 0 : SPDK_ERRLOG("Metadata in separate buffer is not supported\n");
257 : 0 : return -ENOTSUP;
258 : : }
259 : 0 : data_block_size = opts->block_size;
260 : : }
261 : :
262 [ - + ]: 146 : if (data_block_size % 512 != 0) {
263 : 0 : SPDK_ERRLOG("Data block size %u is not a multiple of 512.\n", opts->block_size);
264 : 0 : return -EINVAL;
265 : : }
266 : :
267 [ - + ]: 146 : if (opts->num_blocks == 0) {
268 : 0 : SPDK_ERRLOG("Disk must be more than 0 blocks\n");
269 : 0 : return -EINVAL;
270 : : }
271 : :
272 : 146 : null_disk = calloc(1, sizeof(*null_disk));
273 [ - + ]: 146 : if (!null_disk) {
274 : 0 : SPDK_ERRLOG("could not allocate null_bdev\n");
275 : 0 : return -ENOMEM;
276 : : }
277 : :
278 [ - + ]: 146 : null_disk->bdev.name = strdup(opts->name);
279 [ - + ]: 146 : if (!null_disk->bdev.name) {
280 : 0 : free(null_disk);
281 : 0 : return -ENOMEM;
282 : : }
283 : 146 : null_disk->bdev.product_name = "Null disk";
284 : :
285 : 146 : null_disk->bdev.write_cache = 0;
286 : 146 : null_disk->bdev.blocklen = opts->block_size;
287 : 146 : null_disk->bdev.phys_blocklen = opts->physical_block_size;
288 : 146 : null_disk->bdev.blockcnt = opts->num_blocks;
289 : 146 : null_disk->bdev.md_len = opts->md_size;
290 [ - + ]: 146 : null_disk->bdev.md_interleave = opts->md_interleave;
291 : 146 : null_disk->bdev.dif_type = opts->dif_type;
292 [ - + ]: 146 : null_disk->bdev.dif_is_head_of_md = opts->dif_is_head_of_md;
293 : : /* Current block device layer API does not propagate
294 : : * any DIF related information from user. So, we can
295 : : * not generate or verify Application Tag.
296 : : */
297 [ + + + - ]: 146 : switch (opts->dif_type) {
298 : 24 : case SPDK_DIF_TYPE1:
299 : : case SPDK_DIF_TYPE2:
300 : 24 : null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK |
301 : : SPDK_DIF_FLAGS_REFTAG_CHECK;
302 : 24 : break;
303 : 6 : case SPDK_DIF_TYPE3:
304 : 6 : null_disk->bdev.dif_check_flags = SPDK_DIF_FLAGS_GUARD_CHECK;
305 : 6 : break;
306 : 116 : case SPDK_DIF_DISABLE:
307 : 116 : break;
308 : : }
309 : :
310 : 146 : null_disk->bdev.uuid = *opts->uuid;
311 : 146 : null_disk->bdev.ctxt = null_disk;
312 : 146 : null_disk->bdev.fn_table = &null_fn_table;
313 : 146 : null_disk->bdev.module = &null_if;
314 : :
315 : 146 : rc = spdk_bdev_register(&null_disk->bdev);
316 [ - + ]: 146 : if (rc) {
317 : 0 : free(null_disk->bdev.name);
318 : 0 : free(null_disk);
319 : 0 : return rc;
320 : : }
321 : :
322 : 146 : *bdev = &(null_disk->bdev);
323 : :
324 : 146 : TAILQ_INSERT_TAIL(&g_null_bdev_head, null_disk, tailq);
325 : :
326 : 146 : return rc;
327 : : }
328 : :
329 : : void
330 : 58 : bdev_null_delete(const char *bdev_name, spdk_delete_null_complete cb_fn, void *cb_arg)
331 : : {
332 : : int rc;
333 : :
334 : 58 : rc = spdk_bdev_unregister_by_name(bdev_name, &null_if, cb_fn, cb_arg);
335 [ - + ]: 58 : if (rc != 0) {
336 : 0 : cb_fn(cb_arg, rc);
337 : : }
338 : 58 : }
339 : :
340 : : static int
341 : 148297994 : null_io_poll(void *arg)
342 : : {
343 : 148297994 : struct null_io_channel *ch = arg;
344 : 34744147 : TAILQ_HEAD(, spdk_bdev_io) io;
345 : : struct spdk_bdev_io *bdev_io;
346 : :
347 : 148297994 : TAILQ_INIT(&io);
348 [ - + + + ]: 148297994 : TAILQ_SWAP(&ch->io, &io, spdk_bdev_io, module_link);
349 : :
350 [ + + ]: 148297994 : if (TAILQ_EMPTY(&io)) {
351 : 147680036 : return SPDK_POLLER_IDLE;
352 : : }
353 : :
354 [ + + ]: 9028513 : while (!TAILQ_EMPTY(&io)) {
355 : 8410559 : bdev_io = TAILQ_FIRST(&io);
356 [ + + ]: 8410559 : TAILQ_REMOVE(&io, bdev_io, module_link);
357 : 8410559 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
358 : : }
359 : :
360 : 617954 : return SPDK_POLLER_BUSY;
361 : : }
362 : :
363 : : static int
364 : 6038 : null_bdev_create_cb(void *io_device, void *ctx_buf)
365 : : {
366 : 6038 : struct null_io_channel *ch = ctx_buf;
367 : :
368 : 6038 : TAILQ_INIT(&ch->io);
369 : 6038 : ch->poller = SPDK_POLLER_REGISTER(null_io_poll, ch, 0);
370 : :
371 : 6038 : return 0;
372 : : }
373 : :
374 : : static void
375 : 6038 : null_bdev_destroy_cb(void *io_device, void *ctx_buf)
376 : : {
377 : 6038 : struct null_io_channel *ch = ctx_buf;
378 : :
379 : 6038 : spdk_poller_unregister(&ch->poller);
380 : 6038 : }
381 : :
382 : : static int
383 : 1973 : bdev_null_initialize(void)
384 : : {
385 : : /*
386 : : * This will be used if upper layer expects us to allocate the read buffer.
387 : : * Instead of using a real rbuf from the bdev pool, just always point to
388 : : * this same zeroed buffer.
389 : : */
390 : 1973 : g_null_read_buf = spdk_zmalloc(SPDK_BDEV_LARGE_BUF_MAX_SIZE, 0, NULL,
391 : : SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
392 [ - + ]: 1973 : if (g_null_read_buf == NULL) {
393 : 0 : return -1;
394 : : }
395 : :
396 : : /*
397 : : * We need to pick some unique address as our "io device" - so just use the
398 : : * address of the global tailq.
399 : : */
400 : 1973 : spdk_io_device_register(&g_null_bdev_head, null_bdev_create_cb, null_bdev_destroy_cb,
401 : : sizeof(struct null_io_channel), "null_bdev");
402 : :
403 : 1973 : return 0;
404 : : }
405 : :
406 : : static void
407 : 0 : dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
408 : : {
409 : 0 : }
410 : :
411 : : int
412 : 97 : bdev_null_resize(const char *bdev_name, const uint64_t new_size_in_mb)
413 : : {
414 : 8 : struct spdk_bdev_desc *desc;
415 : : struct spdk_bdev *bdev;
416 : : uint64_t current_size_in_mb;
417 : : uint64_t new_size_in_byte;
418 : 97 : int rc = 0;
419 : :
420 : 97 : rc = spdk_bdev_open_ext(bdev_name, false, dummy_bdev_event_cb, NULL, &desc);
421 [ - + ]: 97 : if (rc != 0) {
422 : 0 : SPDK_ERRLOG("failed to open bdev; %s.\n", bdev_name);
423 : 0 : return rc;
424 : : }
425 : :
426 : 97 : bdev = spdk_bdev_desc_get_bdev(desc);
427 : :
428 [ - + ]: 97 : if (bdev->module != &null_if) {
429 : 0 : rc = -EINVAL;
430 : 0 : goto exit;
431 : : }
432 : :
433 : 97 : current_size_in_mb = bdev->blocklen * bdev->blockcnt / (1024 * 1024);
434 [ - + ]: 97 : if (new_size_in_mb < current_size_in_mb) {
435 : 0 : SPDK_ERRLOG("The new bdev size must not be smaller than current bdev size.\n");
436 : 0 : rc = -EINVAL;
437 : 0 : goto exit;
438 : : }
439 : :
440 : 97 : new_size_in_byte = new_size_in_mb * 1024 * 1024;
441 : :
442 [ - + ]: 97 : rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_byte / bdev->blocklen);
443 [ + - ]: 97 : if (rc != 0) {
444 : 0 : SPDK_ERRLOG("failed to notify block cnt change.\n");
445 : : }
446 : :
447 : 97 : exit:
448 : 97 : spdk_bdev_close(desc);
449 : 97 : return rc;
450 : : }
451 : :
452 : : static void
453 : 1973 : _bdev_null_finish_cb(void *arg)
454 : : {
455 : 1973 : spdk_free(g_null_read_buf);
456 : 1973 : spdk_bdev_module_fini_done();
457 : 1973 : }
458 : :
459 : : static void
460 : 1973 : bdev_null_finish(void)
461 : : {
462 [ - + ]: 1973 : if (g_null_read_buf == NULL) {
463 : 0 : spdk_bdev_module_fini_done();
464 : 0 : return;
465 : : }
466 : 1973 : spdk_io_device_unregister(&g_null_bdev_head, _bdev_null_finish_cb);
467 : : }
468 : :
469 : 2065 : SPDK_LOG_REGISTER_COMPONENT(bdev_null)
|