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