Loading drivers/nvdimm/Kconfig +13 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,17 @@ config NVDIMM_PFN Select Y if unsure config NVDIMM_DAX bool "NVDIMM DAX: Raw access to persistent memory" default LIBNVDIMM depends on NVDIMM_PFN help Support raw device dax access to a persistent memory namespace. For environments that want to hard partition peristent memory, this capability provides a mechanism to sub-divide a namespace into character devices that can only be accessed via DAX (mmap(2)). Select Y if unsure endif drivers/nvdimm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -23,3 +23,4 @@ libnvdimm-y += label.o libnvdimm-$(CONFIG_ND_CLAIM) += claim.o libnvdimm-$(CONFIG_BTT) += btt_devs.o libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o drivers/nvdimm/blk.c +101 −107 Original line number Diff line number Diff line Loading @@ -21,19 +21,19 @@ #include <linux/sizes.h> #include "nd.h" struct nd_blk_device { struct request_queue *queue; struct gendisk *disk; struct nd_namespace_blk *nsblk; struct nd_blk_region *ndbr; size_t disk_size; u32 sector_size; u32 internal_lbasize; }; static u32 nsblk_meta_size(struct nd_namespace_blk *nsblk) { return nsblk->lbasize - ((nsblk->lbasize >= 4096) ? 4096 : 512); } static u32 nd_blk_meta_size(struct nd_blk_device *blk_dev) static u32 nsblk_internal_lbasize(struct nd_namespace_blk *nsblk) { return blk_dev->nsblk->lbasize - blk_dev->sector_size; return roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT); } static u32 nsblk_sector_size(struct nd_namespace_blk *nsblk) { return nsblk->lbasize - nsblk_meta_size(nsblk); } static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk, Loading @@ -57,20 +57,29 @@ static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk, return SIZE_MAX; } static struct nd_blk_region *to_ndbr(struct nd_namespace_blk *nsblk) { struct nd_region *nd_region; struct device *parent; parent = nsblk->common.dev.parent; nd_region = container_of(parent, struct nd_region, dev); return container_of(nd_region, struct nd_blk_region, nd_region); } #ifdef CONFIG_BLK_DEV_INTEGRITY static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, struct bio_integrity_payload *bip, u64 lba, int rw) static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, u64 lba, int rw) { unsigned int len = nd_blk_meta_size(blk_dev); struct nd_blk_region *ndbr = to_ndbr(nsblk); unsigned int len = nsblk_meta_size(nsblk); resource_size_t dev_offset, ns_offset; struct nd_namespace_blk *nsblk; struct nd_blk_region *ndbr; u32 internal_lbasize, sector_size; int err = 0; nsblk = blk_dev->nsblk; ndbr = blk_dev->ndbr; ns_offset = lba * blk_dev->internal_lbasize + blk_dev->sector_size; internal_lbasize = nsblk_internal_lbasize(nsblk); sector_size = nsblk_sector_size(nsblk); ns_offset = lba * internal_lbasize + sector_size; dev_offset = to_dev_offset(nsblk, ns_offset, len); if (dev_offset == SIZE_MAX) return -EIO; Loading Loading @@ -104,25 +113,26 @@ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, } #else /* CONFIG_BLK_DEV_INTEGRITY */ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, struct bio_integrity_payload *bip, u64 lba, int rw) static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, u64 lba, int rw) { return 0; } #endif static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, static int nsblk_do_bvec(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, struct page *page, unsigned int len, unsigned int off, int rw, sector_t sector) unsigned int len, unsigned int off, int rw, sector_t sector) { struct nd_blk_region *ndbr = blk_dev->ndbr; struct nd_blk_region *ndbr = to_ndbr(nsblk); resource_size_t dev_offset, ns_offset; u32 internal_lbasize, sector_size; int err = 0; void *iobuf; u64 lba; internal_lbasize = nsblk_internal_lbasize(nsblk); sector_size = nsblk_sector_size(nsblk); while (len) { unsigned int cur_len; Loading @@ -132,11 +142,11 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, * Block Window setup/move steps. the do_io routine is capable * of handling len <= PAGE_SIZE. */ cur_len = bip ? min(len, blk_dev->sector_size) : len; cur_len = bip ? min(len, sector_size) : len; lba = div_u64(sector << SECTOR_SHIFT, blk_dev->sector_size); ns_offset = lba * blk_dev->internal_lbasize; dev_offset = to_dev_offset(blk_dev->nsblk, ns_offset, cur_len); lba = div_u64(sector << SECTOR_SHIFT, sector_size); ns_offset = lba * internal_lbasize; dev_offset = to_dev_offset(nsblk, ns_offset, cur_len); if (dev_offset == SIZE_MAX) return -EIO; Loading @@ -147,13 +157,13 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, return err; if (bip) { err = nd_blk_rw_integrity(blk_dev, bip, lba, rw); err = nd_blk_rw_integrity(nsblk, bip, lba, rw); if (err) return err; } len -= cur_len; off += cur_len; sector += blk_dev->sector_size >> SECTOR_SHIFT; sector += sector_size >> SECTOR_SHIFT; } return err; Loading @@ -161,10 +171,8 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct gendisk *disk = bdev->bd_disk; struct bio_integrity_payload *bip; struct nd_blk_device *blk_dev; struct nd_namespace_blk *nsblk; struct bvec_iter iter; unsigned long start; struct bio_vec bvec; Loading @@ -183,17 +191,17 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) } bip = bio_integrity(bio); blk_dev = disk->private_data; nsblk = q->queuedata; rw = bio_data_dir(bio); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { unsigned int len = bvec.bv_len; BUG_ON(len > PAGE_SIZE); err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len, err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len, bvec.bv_offset, rw, iter.bi_sector); if (err) { dev_info(&blk_dev->nsblk->common.dev, dev_dbg(&nsblk->common.dev, "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); Loading @@ -209,17 +217,16 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) return BLK_QC_T_NONE; } static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, static int nsblk_rw_bytes(struct nd_namespace_common *ndns, resource_size_t offset, void *iobuf, size_t n, int rw) { struct nd_blk_device *blk_dev = dev_get_drvdata(ndns->claim); struct nd_namespace_blk *nsblk = blk_dev->nsblk; struct nd_blk_region *ndbr = blk_dev->ndbr; struct nd_namespace_blk *nsblk = to_nd_namespace_blk(&ndns->dev); struct nd_blk_region *ndbr = to_ndbr(nsblk); resource_size_t dev_offset; dev_offset = to_dev_offset(nsblk, offset, n); if (unlikely(offset + n > blk_dev->disk_size)) { if (unlikely(offset + n > nsblk->size)) { dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); return -EFAULT; } Loading @@ -235,52 +242,66 @@ static const struct block_device_operations nd_blk_fops = { .revalidate_disk = nvdimm_revalidate_disk, }; static int nd_blk_attach_disk(struct nd_namespace_common *ndns, struct nd_blk_device *blk_dev) static void nd_blk_release_queue(void *q) { blk_cleanup_queue(q); } static void nd_blk_release_disk(void *disk) { del_gendisk(disk); put_disk(disk); } static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) { struct device *dev = &nsblk->common.dev; resource_size_t available_disk_size; struct request_queue *q; struct gendisk *disk; u64 internal_nlba; internal_nlba = div_u64(blk_dev->disk_size, blk_dev->internal_lbasize); available_disk_size = internal_nlba * blk_dev->sector_size; internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk)); available_disk_size = internal_nlba * nsblk_sector_size(nsblk); blk_dev->queue = blk_alloc_queue(GFP_KERNEL); if (!blk_dev->queue) q = blk_alloc_queue(GFP_KERNEL); if (!q) return -ENOMEM; if (devm_add_action(dev, nd_blk_release_queue, q)) { blk_cleanup_queue(q); return -ENOMEM; } blk_queue_make_request(blk_dev->queue, nd_blk_make_request); blk_queue_max_hw_sectors(blk_dev->queue, UINT_MAX); blk_queue_bounce_limit(blk_dev->queue, BLK_BOUNCE_ANY); blk_queue_logical_block_size(blk_dev->queue, blk_dev->sector_size); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, blk_dev->queue); blk_queue_make_request(q, nd_blk_make_request); blk_queue_max_hw_sectors(q, UINT_MAX); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_logical_block_size(q, nsblk_sector_size(nsblk)); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); q->queuedata = nsblk; disk = blk_dev->disk = alloc_disk(0); if (!disk) { blk_cleanup_queue(blk_dev->queue); disk = alloc_disk(0); if (!disk) return -ENOMEM; if (devm_add_action(dev, nd_blk_release_disk, disk)) { put_disk(disk); return -ENOMEM; } disk->driverfs_dev = &ndns->dev; disk->driverfs_dev = dev; disk->first_minor = 0; disk->fops = &nd_blk_fops; disk->private_data = blk_dev; disk->queue = blk_dev->queue; disk->queue = q; disk->flags = GENHD_FL_EXT_DEVT; nvdimm_namespace_disk_name(ndns, disk->disk_name); nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name); set_capacity(disk, 0); add_disk(disk); if (nd_blk_meta_size(blk_dev)) { int rc = nd_integrity_init(disk, nd_blk_meta_size(blk_dev)); if (nsblk_meta_size(nsblk)) { int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk)); if (rc) { del_gendisk(disk); put_disk(disk); blk_cleanup_queue(blk_dev->queue); if (rc) return rc; } } set_capacity(disk, available_disk_size >> SECTOR_SHIFT); revalidate_disk(disk); Loading @@ -291,56 +312,29 @@ static int nd_blk_probe(struct device *dev) { struct nd_namespace_common *ndns; struct nd_namespace_blk *nsblk; struct nd_blk_device *blk_dev; int rc; ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns); blk_dev = kzalloc(sizeof(*blk_dev), GFP_KERNEL); if (!blk_dev) return -ENOMEM; nsblk = to_nd_namespace_blk(&ndns->dev); blk_dev->disk_size = nvdimm_namespace_capacity(ndns); blk_dev->ndbr = to_nd_blk_region(dev->parent); blk_dev->nsblk = to_nd_namespace_blk(&ndns->dev); blk_dev->internal_lbasize = roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT); blk_dev->sector_size = ((nsblk->lbasize >= 4096) ? 4096 : 512); dev_set_drvdata(dev, blk_dev); ndns->rw_bytes = nd_blk_rw_bytes; nsblk->size = nvdimm_namespace_capacity(ndns); dev_set_drvdata(dev, nsblk); ndns->rw_bytes = nsblk_rw_bytes; if (is_nd_btt(dev)) rc = nvdimm_namespace_attach_btt(ndns); else if (nd_btt_probe(ndns, blk_dev) == 0) { return nvdimm_namespace_attach_btt(ndns); else if (nd_btt_probe(dev, ndns) == 0) { /* we'll come back as btt-blk */ rc = -ENXIO; return -ENXIO; } else rc = nd_blk_attach_disk(ndns, blk_dev); if (rc) kfree(blk_dev); return rc; } static void nd_blk_detach_disk(struct nd_blk_device *blk_dev) { del_gendisk(blk_dev->disk); put_disk(blk_dev->disk); blk_cleanup_queue(blk_dev->queue); return nsblk_attach_disk(nsblk); } static int nd_blk_remove(struct device *dev) { struct nd_blk_device *blk_dev = dev_get_drvdata(dev); if (is_nd_btt(dev)) nvdimm_namespace_detach_btt(to_nd_btt(dev)->ndns); else nd_blk_detach_disk(blk_dev); kfree(blk_dev); nvdimm_namespace_detach_btt(to_nd_btt(dev)); return 0; } Loading drivers/nvdimm/btt.c +7 −13 Original line number Diff line number Diff line Loading @@ -1306,7 +1306,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, struct btt *btt; struct device *dev = &nd_btt->dev; btt = kzalloc(sizeof(struct btt), GFP_KERNEL); btt = devm_kzalloc(dev, sizeof(struct btt), GFP_KERNEL); if (!btt) return NULL; Loading @@ -1321,13 +1321,13 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, ret = discover_arenas(btt); if (ret) { dev_err(dev, "init: error in arena_discover: %d\n", ret); goto out_free; return NULL; } if (btt->init_state != INIT_READY && nd_region->ro) { dev_info(dev, "%s is read-only, unable to init btt metadata\n", dev_name(&nd_region->dev)); goto out_free; return NULL; } else if (btt->init_state != INIT_READY) { btt->num_arenas = (rawsize / ARENA_MAX_SIZE) + ((rawsize % ARENA_MAX_SIZE) ? 1 : 0); Loading @@ -1337,29 +1337,25 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, ret = create_arenas(btt); if (ret) { dev_info(dev, "init: create_arenas: %d\n", ret); goto out_free; return NULL; } ret = btt_meta_init(btt); if (ret) { dev_err(dev, "init: error in meta_init: %d\n", ret); goto out_free; return NULL; } } ret = btt_blk_init(btt); if (ret) { dev_err(dev, "init: error in blk_init: %d\n", ret); goto out_free; return NULL; } btt_debugfs_init(btt); return btt; out_free: kfree(btt); return NULL; } /** Loading @@ -1377,7 +1373,6 @@ static void btt_fini(struct btt *btt) btt_blk_cleanup(btt); free_arenas(btt); debugfs_remove_recursive(btt->debugfs_dir); kfree(btt); } } Loading Loading @@ -1406,9 +1401,8 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns) } EXPORT_SYMBOL(nvdimm_namespace_attach_btt); int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns) int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt) { struct nd_btt *nd_btt = to_nd_btt(ndns->claim); struct btt *btt = nd_btt->btt; btt_fini(btt); Loading drivers/nvdimm/btt_devs.c +11 −13 Original line number Diff line number Diff line Loading @@ -273,10 +273,10 @@ static int __nd_btt_probe(struct nd_btt *nd_btt, return 0; } int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) { int rc; struct device *dev; struct device *btt_dev; struct btt_sb *btt_sb; struct nd_region *nd_region = to_nd_region(ndns->dev.parent); Loading @@ -284,21 +284,19 @@ int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) return -ENODEV; nvdimm_bus_lock(&ndns->dev); dev = __nd_btt_create(nd_region, 0, NULL, ndns); btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); nvdimm_bus_unlock(&ndns->dev); if (!dev) if (!btt_dev) return -ENOMEM; dev_set_drvdata(dev, drvdata); btt_sb = kzalloc(sizeof(*btt_sb), GFP_KERNEL); rc = __nd_btt_probe(to_nd_btt(dev), ndns, btt_sb); kfree(btt_sb); dev_dbg(&ndns->dev, "%s: btt: %s\n", __func__, rc == 0 ? dev_name(dev) : "<none>"); btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); dev_dbg(dev, "%s: btt: %s\n", __func__, rc == 0 ? dev_name(btt_dev) : "<none>"); if (rc < 0) { struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(btt_dev); __nd_detach_ndns(dev, &nd_btt->ndns); put_device(dev); __nd_detach_ndns(btt_dev, &nd_btt->ndns); put_device(btt_dev); } return rc; Loading Loading
drivers/nvdimm/Kconfig +13 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,17 @@ config NVDIMM_PFN Select Y if unsure config NVDIMM_DAX bool "NVDIMM DAX: Raw access to persistent memory" default LIBNVDIMM depends on NVDIMM_PFN help Support raw device dax access to a persistent memory namespace. For environments that want to hard partition peristent memory, this capability provides a mechanism to sub-divide a namespace into character devices that can only be accessed via DAX (mmap(2)). Select Y if unsure endif
drivers/nvdimm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -23,3 +23,4 @@ libnvdimm-y += label.o libnvdimm-$(CONFIG_ND_CLAIM) += claim.o libnvdimm-$(CONFIG_BTT) += btt_devs.o libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o
drivers/nvdimm/blk.c +101 −107 Original line number Diff line number Diff line Loading @@ -21,19 +21,19 @@ #include <linux/sizes.h> #include "nd.h" struct nd_blk_device { struct request_queue *queue; struct gendisk *disk; struct nd_namespace_blk *nsblk; struct nd_blk_region *ndbr; size_t disk_size; u32 sector_size; u32 internal_lbasize; }; static u32 nsblk_meta_size(struct nd_namespace_blk *nsblk) { return nsblk->lbasize - ((nsblk->lbasize >= 4096) ? 4096 : 512); } static u32 nd_blk_meta_size(struct nd_blk_device *blk_dev) static u32 nsblk_internal_lbasize(struct nd_namespace_blk *nsblk) { return blk_dev->nsblk->lbasize - blk_dev->sector_size; return roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT); } static u32 nsblk_sector_size(struct nd_namespace_blk *nsblk) { return nsblk->lbasize - nsblk_meta_size(nsblk); } static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk, Loading @@ -57,20 +57,29 @@ static resource_size_t to_dev_offset(struct nd_namespace_blk *nsblk, return SIZE_MAX; } static struct nd_blk_region *to_ndbr(struct nd_namespace_blk *nsblk) { struct nd_region *nd_region; struct device *parent; parent = nsblk->common.dev.parent; nd_region = container_of(parent, struct nd_region, dev); return container_of(nd_region, struct nd_blk_region, nd_region); } #ifdef CONFIG_BLK_DEV_INTEGRITY static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, struct bio_integrity_payload *bip, u64 lba, int rw) static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, u64 lba, int rw) { unsigned int len = nd_blk_meta_size(blk_dev); struct nd_blk_region *ndbr = to_ndbr(nsblk); unsigned int len = nsblk_meta_size(nsblk); resource_size_t dev_offset, ns_offset; struct nd_namespace_blk *nsblk; struct nd_blk_region *ndbr; u32 internal_lbasize, sector_size; int err = 0; nsblk = blk_dev->nsblk; ndbr = blk_dev->ndbr; ns_offset = lba * blk_dev->internal_lbasize + blk_dev->sector_size; internal_lbasize = nsblk_internal_lbasize(nsblk); sector_size = nsblk_sector_size(nsblk); ns_offset = lba * internal_lbasize + sector_size; dev_offset = to_dev_offset(nsblk, ns_offset, len); if (dev_offset == SIZE_MAX) return -EIO; Loading Loading @@ -104,25 +113,26 @@ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, } #else /* CONFIG_BLK_DEV_INTEGRITY */ static int nd_blk_rw_integrity(struct nd_blk_device *blk_dev, struct bio_integrity_payload *bip, u64 lba, int rw) static int nd_blk_rw_integrity(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, u64 lba, int rw) { return 0; } #endif static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, static int nsblk_do_bvec(struct nd_namespace_blk *nsblk, struct bio_integrity_payload *bip, struct page *page, unsigned int len, unsigned int off, int rw, sector_t sector) unsigned int len, unsigned int off, int rw, sector_t sector) { struct nd_blk_region *ndbr = blk_dev->ndbr; struct nd_blk_region *ndbr = to_ndbr(nsblk); resource_size_t dev_offset, ns_offset; u32 internal_lbasize, sector_size; int err = 0; void *iobuf; u64 lba; internal_lbasize = nsblk_internal_lbasize(nsblk); sector_size = nsblk_sector_size(nsblk); while (len) { unsigned int cur_len; Loading @@ -132,11 +142,11 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, * Block Window setup/move steps. the do_io routine is capable * of handling len <= PAGE_SIZE. */ cur_len = bip ? min(len, blk_dev->sector_size) : len; cur_len = bip ? min(len, sector_size) : len; lba = div_u64(sector << SECTOR_SHIFT, blk_dev->sector_size); ns_offset = lba * blk_dev->internal_lbasize; dev_offset = to_dev_offset(blk_dev->nsblk, ns_offset, cur_len); lba = div_u64(sector << SECTOR_SHIFT, sector_size); ns_offset = lba * internal_lbasize; dev_offset = to_dev_offset(nsblk, ns_offset, cur_len); if (dev_offset == SIZE_MAX) return -EIO; Loading @@ -147,13 +157,13 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, return err; if (bip) { err = nd_blk_rw_integrity(blk_dev, bip, lba, rw); err = nd_blk_rw_integrity(nsblk, bip, lba, rw); if (err) return err; } len -= cur_len; off += cur_len; sector += blk_dev->sector_size >> SECTOR_SHIFT; sector += sector_size >> SECTOR_SHIFT; } return err; Loading @@ -161,10 +171,8 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev, static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) { struct block_device *bdev = bio->bi_bdev; struct gendisk *disk = bdev->bd_disk; struct bio_integrity_payload *bip; struct nd_blk_device *blk_dev; struct nd_namespace_blk *nsblk; struct bvec_iter iter; unsigned long start; struct bio_vec bvec; Loading @@ -183,17 +191,17 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) } bip = bio_integrity(bio); blk_dev = disk->private_data; nsblk = q->queuedata; rw = bio_data_dir(bio); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { unsigned int len = bvec.bv_len; BUG_ON(len > PAGE_SIZE); err = nd_blk_do_bvec(blk_dev, bip, bvec.bv_page, len, err = nsblk_do_bvec(nsblk, bip, bvec.bv_page, len, bvec.bv_offset, rw, iter.bi_sector); if (err) { dev_info(&blk_dev->nsblk->common.dev, dev_dbg(&nsblk->common.dev, "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); Loading @@ -209,17 +217,16 @@ static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio) return BLK_QC_T_NONE; } static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, static int nsblk_rw_bytes(struct nd_namespace_common *ndns, resource_size_t offset, void *iobuf, size_t n, int rw) { struct nd_blk_device *blk_dev = dev_get_drvdata(ndns->claim); struct nd_namespace_blk *nsblk = blk_dev->nsblk; struct nd_blk_region *ndbr = blk_dev->ndbr; struct nd_namespace_blk *nsblk = to_nd_namespace_blk(&ndns->dev); struct nd_blk_region *ndbr = to_ndbr(nsblk); resource_size_t dev_offset; dev_offset = to_dev_offset(nsblk, offset, n); if (unlikely(offset + n > blk_dev->disk_size)) { if (unlikely(offset + n > nsblk->size)) { dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); return -EFAULT; } Loading @@ -235,52 +242,66 @@ static const struct block_device_operations nd_blk_fops = { .revalidate_disk = nvdimm_revalidate_disk, }; static int nd_blk_attach_disk(struct nd_namespace_common *ndns, struct nd_blk_device *blk_dev) static void nd_blk_release_queue(void *q) { blk_cleanup_queue(q); } static void nd_blk_release_disk(void *disk) { del_gendisk(disk); put_disk(disk); } static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) { struct device *dev = &nsblk->common.dev; resource_size_t available_disk_size; struct request_queue *q; struct gendisk *disk; u64 internal_nlba; internal_nlba = div_u64(blk_dev->disk_size, blk_dev->internal_lbasize); available_disk_size = internal_nlba * blk_dev->sector_size; internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk)); available_disk_size = internal_nlba * nsblk_sector_size(nsblk); blk_dev->queue = blk_alloc_queue(GFP_KERNEL); if (!blk_dev->queue) q = blk_alloc_queue(GFP_KERNEL); if (!q) return -ENOMEM; if (devm_add_action(dev, nd_blk_release_queue, q)) { blk_cleanup_queue(q); return -ENOMEM; } blk_queue_make_request(blk_dev->queue, nd_blk_make_request); blk_queue_max_hw_sectors(blk_dev->queue, UINT_MAX); blk_queue_bounce_limit(blk_dev->queue, BLK_BOUNCE_ANY); blk_queue_logical_block_size(blk_dev->queue, blk_dev->sector_size); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, blk_dev->queue); blk_queue_make_request(q, nd_blk_make_request); blk_queue_max_hw_sectors(q, UINT_MAX); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_logical_block_size(q, nsblk_sector_size(nsblk)); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); q->queuedata = nsblk; disk = blk_dev->disk = alloc_disk(0); if (!disk) { blk_cleanup_queue(blk_dev->queue); disk = alloc_disk(0); if (!disk) return -ENOMEM; if (devm_add_action(dev, nd_blk_release_disk, disk)) { put_disk(disk); return -ENOMEM; } disk->driverfs_dev = &ndns->dev; disk->driverfs_dev = dev; disk->first_minor = 0; disk->fops = &nd_blk_fops; disk->private_data = blk_dev; disk->queue = blk_dev->queue; disk->queue = q; disk->flags = GENHD_FL_EXT_DEVT; nvdimm_namespace_disk_name(ndns, disk->disk_name); nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name); set_capacity(disk, 0); add_disk(disk); if (nd_blk_meta_size(blk_dev)) { int rc = nd_integrity_init(disk, nd_blk_meta_size(blk_dev)); if (nsblk_meta_size(nsblk)) { int rc = nd_integrity_init(disk, nsblk_meta_size(nsblk)); if (rc) { del_gendisk(disk); put_disk(disk); blk_cleanup_queue(blk_dev->queue); if (rc) return rc; } } set_capacity(disk, available_disk_size >> SECTOR_SHIFT); revalidate_disk(disk); Loading @@ -291,56 +312,29 @@ static int nd_blk_probe(struct device *dev) { struct nd_namespace_common *ndns; struct nd_namespace_blk *nsblk; struct nd_blk_device *blk_dev; int rc; ndns = nvdimm_namespace_common_probe(dev); if (IS_ERR(ndns)) return PTR_ERR(ndns); blk_dev = kzalloc(sizeof(*blk_dev), GFP_KERNEL); if (!blk_dev) return -ENOMEM; nsblk = to_nd_namespace_blk(&ndns->dev); blk_dev->disk_size = nvdimm_namespace_capacity(ndns); blk_dev->ndbr = to_nd_blk_region(dev->parent); blk_dev->nsblk = to_nd_namespace_blk(&ndns->dev); blk_dev->internal_lbasize = roundup(nsblk->lbasize, INT_LBASIZE_ALIGNMENT); blk_dev->sector_size = ((nsblk->lbasize >= 4096) ? 4096 : 512); dev_set_drvdata(dev, blk_dev); ndns->rw_bytes = nd_blk_rw_bytes; nsblk->size = nvdimm_namespace_capacity(ndns); dev_set_drvdata(dev, nsblk); ndns->rw_bytes = nsblk_rw_bytes; if (is_nd_btt(dev)) rc = nvdimm_namespace_attach_btt(ndns); else if (nd_btt_probe(ndns, blk_dev) == 0) { return nvdimm_namespace_attach_btt(ndns); else if (nd_btt_probe(dev, ndns) == 0) { /* we'll come back as btt-blk */ rc = -ENXIO; return -ENXIO; } else rc = nd_blk_attach_disk(ndns, blk_dev); if (rc) kfree(blk_dev); return rc; } static void nd_blk_detach_disk(struct nd_blk_device *blk_dev) { del_gendisk(blk_dev->disk); put_disk(blk_dev->disk); blk_cleanup_queue(blk_dev->queue); return nsblk_attach_disk(nsblk); } static int nd_blk_remove(struct device *dev) { struct nd_blk_device *blk_dev = dev_get_drvdata(dev); if (is_nd_btt(dev)) nvdimm_namespace_detach_btt(to_nd_btt(dev)->ndns); else nd_blk_detach_disk(blk_dev); kfree(blk_dev); nvdimm_namespace_detach_btt(to_nd_btt(dev)); return 0; } Loading
drivers/nvdimm/btt.c +7 −13 Original line number Diff line number Diff line Loading @@ -1306,7 +1306,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, struct btt *btt; struct device *dev = &nd_btt->dev; btt = kzalloc(sizeof(struct btt), GFP_KERNEL); btt = devm_kzalloc(dev, sizeof(struct btt), GFP_KERNEL); if (!btt) return NULL; Loading @@ -1321,13 +1321,13 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, ret = discover_arenas(btt); if (ret) { dev_err(dev, "init: error in arena_discover: %d\n", ret); goto out_free; return NULL; } if (btt->init_state != INIT_READY && nd_region->ro) { dev_info(dev, "%s is read-only, unable to init btt metadata\n", dev_name(&nd_region->dev)); goto out_free; return NULL; } else if (btt->init_state != INIT_READY) { btt->num_arenas = (rawsize / ARENA_MAX_SIZE) + ((rawsize % ARENA_MAX_SIZE) ? 1 : 0); Loading @@ -1337,29 +1337,25 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize, ret = create_arenas(btt); if (ret) { dev_info(dev, "init: create_arenas: %d\n", ret); goto out_free; return NULL; } ret = btt_meta_init(btt); if (ret) { dev_err(dev, "init: error in meta_init: %d\n", ret); goto out_free; return NULL; } } ret = btt_blk_init(btt); if (ret) { dev_err(dev, "init: error in blk_init: %d\n", ret); goto out_free; return NULL; } btt_debugfs_init(btt); return btt; out_free: kfree(btt); return NULL; } /** Loading @@ -1377,7 +1373,6 @@ static void btt_fini(struct btt *btt) btt_blk_cleanup(btt); free_arenas(btt); debugfs_remove_recursive(btt->debugfs_dir); kfree(btt); } } Loading Loading @@ -1406,9 +1401,8 @@ int nvdimm_namespace_attach_btt(struct nd_namespace_common *ndns) } EXPORT_SYMBOL(nvdimm_namespace_attach_btt); int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns) int nvdimm_namespace_detach_btt(struct nd_btt *nd_btt) { struct nd_btt *nd_btt = to_nd_btt(ndns->claim); struct btt *btt = nd_btt->btt; btt_fini(btt); Loading
drivers/nvdimm/btt_devs.c +11 −13 Original line number Diff line number Diff line Loading @@ -273,10 +273,10 @@ static int __nd_btt_probe(struct nd_btt *nd_btt, return 0; } int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) int nd_btt_probe(struct device *dev, struct nd_namespace_common *ndns) { int rc; struct device *dev; struct device *btt_dev; struct btt_sb *btt_sb; struct nd_region *nd_region = to_nd_region(ndns->dev.parent); Loading @@ -284,21 +284,19 @@ int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) return -ENODEV; nvdimm_bus_lock(&ndns->dev); dev = __nd_btt_create(nd_region, 0, NULL, ndns); btt_dev = __nd_btt_create(nd_region, 0, NULL, ndns); nvdimm_bus_unlock(&ndns->dev); if (!dev) if (!btt_dev) return -ENOMEM; dev_set_drvdata(dev, drvdata); btt_sb = kzalloc(sizeof(*btt_sb), GFP_KERNEL); rc = __nd_btt_probe(to_nd_btt(dev), ndns, btt_sb); kfree(btt_sb); dev_dbg(&ndns->dev, "%s: btt: %s\n", __func__, rc == 0 ? dev_name(dev) : "<none>"); btt_sb = devm_kzalloc(dev, sizeof(*btt_sb), GFP_KERNEL); rc = __nd_btt_probe(to_nd_btt(btt_dev), ndns, btt_sb); dev_dbg(dev, "%s: btt: %s\n", __func__, rc == 0 ? dev_name(btt_dev) : "<none>"); if (rc < 0) { struct nd_btt *nd_btt = to_nd_btt(dev); struct nd_btt *nd_btt = to_nd_btt(btt_dev); __nd_detach_ndns(dev, &nd_btt->ndns); put_device(dev); __nd_detach_ndns(btt_dev, &nd_btt->ndns); put_device(btt_dev); } return rc; Loading