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