Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

null_blk: register as a LightNVM device

Add support for registering as a LightNVM device. This allows us to
evaluate the performance of the LightNVM subsystem.

In /drivers/Makefile, LightNVM is moved above block device drivers
to make sure that the LightNVM media managers have been initialized
before drivers under /drivers/block are initialized.

Signed-off-by: Matias Bjørling <m@bjorling.me>
Fix by Jens Axboe to remove unneeded slab cache and the following
memory leak.
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Matias Bjørling and committed by
Jens Axboe
b2b7e001 4736346b

+158 -7
+3
Documentation/block/null_blk.txt
··· 70 70 parameter. 71 71 1: The multi-queue block layer is instantiated with a hardware dispatch 72 72 queue for each CPU node in the system. 73 + 74 + use_lightnvm=[0/1]: Default: 0 75 + Register device with LightNVM. Requires blk-mq to be used.
+1 -1
drivers/Makefile
··· 63 63 obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ 64 64 65 65 obj-$(CONFIG_PARPORT) += parport/ 66 + obj-$(CONFIG_NVM) += lightnvm/ 66 67 obj-y += base/ block/ misc/ mfd/ nfc/ 67 68 obj-$(CONFIG_LIBNVDIMM) += nvdimm/ 68 69 obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ ··· 71 70 obj-y += macintosh/ 72 71 obj-$(CONFIG_IDE) += ide/ 73 72 obj-$(CONFIG_SCSI) += scsi/ 74 - obj-$(CONFIG_NVM) += lightnvm/ 75 73 obj-y += nvme/ 76 74 obj-$(CONFIG_ATA) += ata/ 77 75 obj-$(CONFIG_TARGET_CORE) += target/
+154 -6
drivers/block/null_blk.c
··· 8 8 #include <linux/slab.h> 9 9 #include <linux/blk-mq.h> 10 10 #include <linux/hrtimer.h> 11 + #include <linux/lightnvm.h> 11 12 12 13 struct nullb_cmd { 13 14 struct list_head list; ··· 40 39 41 40 struct nullb_queue *queues; 42 41 unsigned int nr_queues; 42 + char disk_name[DISK_NAME_LEN]; 43 43 }; 44 44 45 45 static LIST_HEAD(nullb_list); ··· 120 118 static int nr_devices = 2; 121 119 module_param(nr_devices, int, S_IRUGO); 122 120 MODULE_PARM_DESC(nr_devices, "Number of devices to register"); 121 + 122 + static bool use_lightnvm; 123 + module_param(use_lightnvm, bool, S_IRUGO); 124 + MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device"); 123 125 124 126 static int irqmode = NULL_IRQ_SOFTIRQ; 125 127 ··· 433 427 { 434 428 list_del_init(&nullb->list); 435 429 430 + if (use_lightnvm) 431 + nvm_unregister(nullb->disk->disk_name); 436 432 del_gendisk(nullb->disk); 437 433 blk_cleanup_queue(nullb->q); 438 434 if (queue_mode == NULL_Q_MQ) ··· 443 435 cleanup_queues(nullb); 444 436 kfree(nullb); 445 437 } 438 + 439 + #ifdef CONFIG_NVM 440 + 441 + static void null_lnvm_end_io(struct request *rq, int error) 442 + { 443 + struct nvm_rq *rqd = rq->end_io_data; 444 + struct nvm_dev *dev = rqd->dev; 445 + 446 + dev->mt->end_io(rqd, error); 447 + 448 + blk_put_request(rq); 449 + } 450 + 451 + static int null_lnvm_submit_io(struct request_queue *q, struct nvm_rq *rqd) 452 + { 453 + struct request *rq; 454 + struct bio *bio = rqd->bio; 455 + 456 + rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0); 457 + if (IS_ERR(rq)) 458 + return -ENOMEM; 459 + 460 + rq->cmd_type = REQ_TYPE_DRV_PRIV; 461 + rq->__sector = bio->bi_iter.bi_sector; 462 + rq->ioprio = bio_prio(bio); 463 + 464 + if (bio_has_data(bio)) 465 + rq->nr_phys_segments = bio_phys_segments(q, bio); 466 + 467 + rq->__data_len = bio->bi_iter.bi_size; 468 + rq->bio = rq->biotail = bio; 469 + 470 + rq->end_io_data = rqd; 471 + 472 + blk_execute_rq_nowait(q, NULL, rq, 0, null_lnvm_end_io); 473 + 474 + return 0; 475 + } 476 + 477 + static int null_lnvm_id(struct request_queue *q, struct nvm_id *id) 478 + { 479 + sector_t size = gb * 1024 * 1024 * 1024ULL; 480 + struct nvm_id_group *grp; 481 + 482 + id->ver_id = 0x1; 483 + id->vmnt = 0; 484 + id->cgrps = 1; 485 + id->cap = 0x3; 486 + id->dom = 0x1; 487 + id->ppat = NVM_ADDRMODE_LINEAR; 488 + 489 + do_div(size, bs); /* convert size to pages */ 490 + grp = &id->groups[0]; 491 + grp->mtype = 0; 492 + grp->fmtype = 1; 493 + grp->num_ch = 1; 494 + grp->num_lun = 1; 495 + grp->num_pln = 1; 496 + grp->num_blk = size / 256; 497 + grp->num_pg = 256; 498 + grp->fpg_sz = bs; 499 + grp->csecs = bs; 500 + grp->trdt = 25000; 501 + grp->trdm = 25000; 502 + grp->tprt = 500000; 503 + grp->tprm = 500000; 504 + grp->tbet = 1500000; 505 + grp->tbem = 1500000; 506 + grp->mpos = 0x010101; /* single plane rwe */ 507 + grp->cpar = hw_queue_depth; 508 + 509 + return 0; 510 + } 511 + 512 + static void *null_lnvm_create_dma_pool(struct request_queue *q, char *name) 513 + { 514 + mempool_t *virtmem_pool; 515 + 516 + virtmem_pool = mempool_create_page_pool(64, 0); 517 + if (!virtmem_pool) { 518 + pr_err("null_blk: Unable to create virtual memory pool\n"); 519 + return NULL; 520 + } 521 + 522 + return virtmem_pool; 523 + } 524 + 525 + static void null_lnvm_destroy_dma_pool(void *pool) 526 + { 527 + mempool_destroy(pool); 528 + } 529 + 530 + static void *null_lnvm_dev_dma_alloc(struct request_queue *q, void *pool, 531 + gfp_t mem_flags, dma_addr_t *dma_handler) 532 + { 533 + return mempool_alloc(pool, mem_flags); 534 + } 535 + 536 + static void null_lnvm_dev_dma_free(void *pool, void *entry, 537 + dma_addr_t dma_handler) 538 + { 539 + mempool_free(entry, pool); 540 + } 541 + 542 + static struct nvm_dev_ops null_lnvm_dev_ops = { 543 + .identity = null_lnvm_id, 544 + .submit_io = null_lnvm_submit_io, 545 + 546 + .create_dma_pool = null_lnvm_create_dma_pool, 547 + .destroy_dma_pool = null_lnvm_destroy_dma_pool, 548 + .dev_dma_alloc = null_lnvm_dev_dma_alloc, 549 + .dev_dma_free = null_lnvm_dev_dma_free, 550 + 551 + /* Simulate nvme protocol restriction */ 552 + .max_phys_sect = 64, 553 + }; 554 + #else 555 + static struct nvm_dev_ops null_lnvm_dev_ops; 556 + #endif /* CONFIG_NVM */ 446 557 447 558 static int null_open(struct block_device *bdev, fmode_t mode) 448 559 { ··· 702 575 queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q); 703 576 queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q); 704 577 705 - disk = nullb->disk = alloc_disk_node(1, home_node); 706 - if (!disk) { 707 - rv = -ENOMEM; 708 - goto out_cleanup_blk_queue; 709 - } 710 578 711 579 mutex_lock(&lock); 712 580 list_add_tail(&nullb->list, &nullb_list); ··· 711 589 blk_queue_logical_block_size(nullb->q, bs); 712 590 blk_queue_physical_block_size(nullb->q, bs); 713 591 592 + sprintf(nullb->disk_name, "nullb%d", nullb->index); 593 + 594 + if (use_lightnvm) { 595 + rv = nvm_register(nullb->q, nullb->disk_name, 596 + &null_lnvm_dev_ops); 597 + if (rv) 598 + goto out_cleanup_blk_queue; 599 + goto done; 600 + } 601 + 602 + disk = nullb->disk = alloc_disk_node(1, home_node); 603 + if (!disk) { 604 + rv = -ENOMEM; 605 + goto out_cleanup_lightnvm; 606 + } 714 607 size = gb * 1024 * 1024 * 1024ULL; 715 608 set_capacity(disk, size >> 9); 716 609 ··· 735 598 disk->fops = &null_fops; 736 599 disk->private_data = nullb; 737 600 disk->queue = nullb->q; 738 - sprintf(disk->disk_name, "nullb%d", nullb->index); 601 + strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN); 602 + 739 603 add_disk(disk); 604 + done: 740 605 return 0; 741 606 607 + out_cleanup_lightnvm: 608 + if (use_lightnvm) 609 + nvm_unregister(nullb->disk_name); 742 610 out_cleanup_blk_queue: 743 611 blk_cleanup_queue(nullb->q); 744 612 out_cleanup_tags: ··· 765 623 pr_warn("null_blk: invalid block size\n"); 766 624 pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE); 767 625 bs = PAGE_SIZE; 626 + } 627 + 628 + if (use_lightnvm && queue_mode != NULL_Q_MQ) { 629 + pr_warn("null_blk: LightNVM only supported for blk-mq\n"); 630 + pr_warn("null_blk: defaults queue mode to blk-mq\n"); 631 + queue_mode = NULL_Q_MQ; 768 632 } 769 633 770 634 if (queue_mode == NULL_Q_MQ && use_per_node_hctx) {