diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 14:35:59 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 14:35:59 -0700 |
commit | 12f03ee606914317e7e6a0815e53a48205c31dae (patch) | |
tree | f8579bf77d29b3921e1877e0ae12ec65b5ebc738 /drivers | |
parent | d9241b22b58e012f26dd2244508d9f4837402af0 (diff) | |
parent | 004f1afbe199e6ab20805b95aefd83ccd24bc5c7 (diff) |
Merge tag 'libnvdimm-for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams:
"This update has successfully completed a 0day-kbuild run and has
appeared in a linux-next release. The changes outside of the typical
drivers/nvdimm/ and drivers/acpi/nfit.[ch] paths are related to the
removal of IORESOURCE_CACHEABLE, the introduction of memremap(), and
the introduction of ZONE_DEVICE + devm_memremap_pages().
Summary:
- Introduce ZONE_DEVICE and devm_memremap_pages() as a generic
mechanism for adding device-driver-discovered memory regions to the
kernel's direct map.
This facility is used by the pmem driver to enable pfn_to_page()
operations on the page frames returned by DAX ('direct_access' in
'struct block_device_operations').
For now, the 'memmap' allocation for these "device" pages comes
from "System RAM". Support for allocating the memmap from device
memory will arrive in a later kernel.
- Introduce memremap() to replace usages of ioremap_cache() and
ioremap_wt(). memremap() drops the __iomem annotation for these
mappings to memory that do not have i/o side effects. The
replacement of ioremap_cache() with memremap() is limited to the
pmem driver to ease merging the api change in v4.3.
Completion of the conversion is targeted for v4.4.
- Similar to the usage of memcpy_to_pmem() + wmb_pmem() in the pmem
driver, update the VFS DAX implementation and PMEM api to provide
persistence guarantees for kernel operations on a DAX mapping.
- Convert the ACPI NFIT 'BLK' driver to map the block apertures as
cacheable to improve performance.
- Miscellaneous updates and fixes to libnvdimm including support for
issuing "address range scrub" commands, clarifying the optimal
'sector size' of pmem devices, a clarification of the usage of the
ACPI '_STA' (status) property for DIMM devices, and other minor
fixes"
* tag 'libnvdimm-for-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (34 commits)
libnvdimm, pmem: direct map legacy pmem by default
libnvdimm, pmem: 'struct page' for pmem
libnvdimm, pfn: 'struct page' provider infrastructure
x86, pmem: clarify that ARCH_HAS_PMEM_API implies PMEM mapped WB
add devm_memremap_pages
mm: ZONE_DEVICE for "device memory"
mm: move __phys_to_pfn and __pfn_to_phys to asm/generic/memory_model.h
dax: drop size parameter to ->direct_access()
nd_blk: change aperture mapping from WC to WB
nvdimm: change to use generic kvfree()
pmem, dax: have direct_access use __pmem annotation
dax: update I/O path to do proper PMEM flushing
pmem: add copy_from_iter_pmem() and clear_pmem()
pmem, x86: clean up conditional pmem includes
pmem: remove layer when calling arch_has_wmb_pmem()
pmem, x86: move x86 PMEM API to new pmem.h header
libnvdimm, e820: make CONFIG_X86_PMEM_LEGACY a tristate option
pmem: switch to devm_ allocations
devres: add devm_memremap
libnvdimm, btt: write and validate parent_uuid
...
Diffstat (limited to 'drivers')
38 files changed, 1224 insertions, 367 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 54e9729f9634..5d1015c26ff4 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -417,6 +417,7 @@ config ACPI_NFIT tristate "ACPI NVDIMM Firmware Interface Table (NFIT)" depends on PHYS_ADDR_T_64BIT depends on BLK_DEV + depends on ARCH_HAS_MMIO_FLUSH select LIBNVDIMM help Infrastructure to probe ACPI 6 compliant platforms for diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index cf0fd96a7602..c1b8d03e262e 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -20,6 +20,7 @@ #include <linux/sort.h> #include <linux/pmem.h> #include <linux/io.h> +#include <asm/cacheflush.h> #include "nfit.h" /* @@ -764,9 +765,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, struct acpi_device *adev, *adev_dimm; struct device *dev = acpi_desc->dev; const u8 *uuid = to_nfit_uuid(NFIT_DEV_DIMM); - unsigned long long sta; - int i, rc = -ENODEV; - acpi_status status; + int i; nfit_mem->dsm_mask = acpi_desc->dimm_dsm_force_en; adev = to_acpi_dev(acpi_desc); @@ -781,25 +780,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return force_enable_dimms ? 0 : -ENODEV; } - status = acpi_evaluate_integer(adev_dimm->handle, "_STA", NULL, &sta); - if (status == AE_NOT_FOUND) { - dev_dbg(dev, "%s missing _STA, assuming enabled...\n", - dev_name(&adev_dimm->dev)); - rc = 0; - } else if (ACPI_FAILURE(status)) - dev_err(dev, "%s failed to retrieve_STA, disabling...\n", - dev_name(&adev_dimm->dev)); - else if ((sta & ACPI_STA_DEVICE_ENABLED) == 0) - dev_info(dev, "%s disabled by firmware\n", - dev_name(&adev_dimm->dev)); - else - rc = 0; - for (i = ND_CMD_SMART; i <= ND_CMD_VENDOR; i++) if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) set_bit(i, &nfit_mem->dsm_mask); - return force_enable_dimms ? 0 : rc; + return 0; } static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) @@ -868,6 +853,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) struct acpi_device *adev; int i; + nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en; adev = to_acpi_dev(acpi_desc); if (!adev) return; @@ -1032,7 +1018,7 @@ static u32 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw) if (mmio->num_lines) offset = to_interleave_offset(offset, mmio); - return readl(mmio->base + offset); + return readl(mmio->addr.base + offset); } static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, @@ -1057,11 +1043,11 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, if (mmio->num_lines) offset = to_interleave_offset(offset, mmio); - writeq(cmd, mmio->base + offset); + writeq(cmd, mmio->addr.base + offset); wmb_blk(nfit_blk); if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH) - readq(mmio->base + offset); + readq(mmio->addr.base + offset); } static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, @@ -1093,11 +1079,16 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - memcpy_to_pmem(mmio->aperture + offset, + memcpy_to_pmem(mmio->addr.aperture + offset, iobuf + copied, c); - else + else { + if (nfit_blk->dimm_flags & ND_BLK_READ_FLUSH) + mmio_flush_range((void __force *) + mmio->addr.aperture + offset, c); + memcpy_from_pmem(iobuf + copied, - mmio->aperture + offset, c); + mmio->addr.aperture + offset, c); + } copied += c; len -= c; @@ -1144,7 +1135,10 @@ static void nfit_spa_mapping_release(struct kref *kref) WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex)); dev_dbg(acpi_desc->dev, "%s: SPA%d\n", __func__, spa->range_index); - iounmap(spa_map->iomem); + if (spa_map->type == SPA_MAP_APERTURE) + memunmap((void __force *)spa_map->addr.aperture); + else + iounmap(spa_map->addr.base); release_mem_region(spa->address, spa->length); list_del(&spa_map->list); kfree(spa_map); @@ -1190,7 +1184,7 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, spa_map = find_spa_mapping(acpi_desc, spa); if (spa_map) { kref_get(&spa_map->kref); - return spa_map->iomem; + return spa_map->addr.base; } spa_map = kzalloc(sizeof(*spa_map), GFP_KERNEL); @@ -1206,20 +1200,19 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, if (!res) goto err_mem; - if (type == SPA_MAP_APERTURE) { - /* - * TODO: memremap_pmem() support, but that requires cache - * flushing when the aperture is moved. - */ - spa_map->iomem = ioremap_wc(start, n); - } else - spa_map->iomem = ioremap_nocache(start, n); + spa_map->type = type; + if (type == SPA_MAP_APERTURE) + spa_map->addr.aperture = (void __pmem *)memremap(start, n, + ARCH_MEMREMAP_PMEM); + else + spa_map->addr.base = ioremap_nocache(start, n); + - if (!spa_map->iomem) + if (!spa_map->addr.base) goto err_map; list_add_tail(&spa_map->list, &acpi_desc->spa_maps); - return spa_map->iomem; + return spa_map->addr.base; err_map: release_mem_region(start, n); @@ -1282,7 +1275,7 @@ static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc, nfit_blk->dimm_flags = flags.flags; else if (rc == -ENOTTY) { /* fall back to a conservative default */ - nfit_blk->dimm_flags = ND_BLK_DCR_LATCH; + nfit_blk->dimm_flags = ND_BLK_DCR_LATCH | ND_BLK_READ_FLUSH; rc = 0; } else rc = -ENXIO; @@ -1322,9 +1315,9 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, /* map block aperture memory */ nfit_blk->bdw_offset = nfit_mem->bdw->offset; mmio = &nfit_blk->mmio[BDW]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, + mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, SPA_MAP_APERTURE); - if (!mmio->base) { + if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, nvdimm_name(nvdimm)); return -ENOMEM; @@ -1345,9 +1338,9 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_blk->cmd_offset = nfit_mem->dcr->command_offset; nfit_blk->stat_offset = nfit_mem->dcr->status_offset; mmio = &nfit_blk->mmio[DCR]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, + mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, SPA_MAP_CONTROL); - if (!mmio->base) { + if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, nvdimm_name(nvdimm)); return -ENOMEM; @@ -1379,7 +1372,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, return -ENOMEM; } - if (!arch_has_pmem_api() && !nfit_blk->nvdimm_flush) + if (!arch_has_wmb_pmem() && !nfit_blk->nvdimm_flush) dev_warn(dev, "unable to guarantee persistence of writes\n"); if (mmio->line_size == 0) @@ -1414,7 +1407,7 @@ static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus, for (i = 0; i < 2; i++) { struct nfit_blk_mmio *mmio = &nfit_blk->mmio[i]; - if (mmio->base) + if (mmio->addr.base) nfit_spa_unmap(acpi_desc, mmio->spa); } nd_blk_region_set_provider_data(ndbr, NULL); diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 79b6d83875c1..7e740156b9c2 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -41,6 +41,7 @@ enum nfit_uuids { }; enum { + ND_BLK_READ_FLUSH = 1, ND_BLK_DCR_LATCH = 2, }; @@ -107,6 +108,7 @@ struct acpi_nfit_desc { struct nvdimm_bus *nvdimm_bus; struct device *dev; unsigned long dimm_dsm_force_en; + unsigned long bus_dsm_force_en; int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, void *iobuf, u64 len, int rw); }; @@ -116,12 +118,16 @@ enum nd_blk_mmio_selector { DCR, }; +struct nd_blk_addr { + union { + void __iomem *base; + void __pmem *aperture; + }; +}; + struct nfit_blk { struct nfit_blk_mmio { - union { - void __iomem *base; - void __pmem *aperture; - }; + struct nd_blk_addr addr; u64 size; u64 base_offset; u32 line_size; @@ -148,7 +154,8 @@ struct nfit_spa_mapping { struct acpi_nfit_system_address *spa; struct list_head list; struct kref kref; - void __iomem *iomem; + enum spa_map_type type; + struct nd_blk_addr addr; }; static inline struct nfit_spa_mapping *to_spa_map(struct kref *kref) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index f9ab74505e69..b9794aeeb878 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -374,7 +374,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector, #ifdef CONFIG_BLK_DEV_RAM_DAX static long brd_direct_access(struct block_device *bdev, sector_t sector, - void **kaddr, unsigned long *pfn, long size) + void __pmem **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; @@ -384,13 +384,9 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector, page = brd_insert_page(brd, sector); if (!page) return -ENOSPC; - *kaddr = page_address(page); + *kaddr = (void __pmem *)page_address(page); *pfn = page_to_pfn(page); - /* - * TODO: If size > PAGE_SIZE, we could look to see if the next page in - * the file happens to be mapped to the next page of physical RAM. - */ return PAGE_SIZE; } #else diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h index b713466997a0..f8f2e76d34bf 100644 --- a/drivers/isdn/icn/icn.h +++ b/drivers/isdn/icn/icn.h @@ -38,7 +38,7 @@ typedef struct icn_cdef { #include <linux/errno.h> #include <linux/fs.h> #include <linux/major.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/slab.h> diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 2fc4957cbe7f..a70eb83e68f1 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -41,7 +41,7 @@ #include <linux/fs.h> #include <linux/ioctl.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/mtd/mtd.h> diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 7da266a53979..0802158a3f75 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -24,7 +24,7 @@ #include <linux/rslib.h> #include <linux/moduleparam.h> #include <linux/slab.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 32a216d31141..ab7bda0bb245 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -18,7 +18,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/onenand.h> #include <linux/mtd/partitions.h> -#include <asm/io.h> +#include <linux/io.h> /* * Note: Driver name and platform data format have been updated! diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 72226acb5c0f..53c11621d5b1 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -21,6 +21,7 @@ config BLK_DEV_PMEM default LIBNVDIMM depends on HAS_IOMEM select ND_BTT if BTT + select ND_PFN if NVDIMM_PFN help Memory ranges for PMEM are described by either an NFIT (NVDIMM Firmware Interface Table, see CONFIG_NFIT_ACPI), a @@ -47,12 +48,16 @@ config ND_BLK (CONFIG_ACPI_NFIT), or otherwise exposes BLK-mode capabilities. +config ND_CLAIM + bool + config ND_BTT tristate config BTT bool "BTT: Block Translation Table (atomic sector updates)" default y if LIBNVDIMM + select ND_CLAIM help The Block Translation Table (BTT) provides atomic sector update semantics for persistent memory devices, so that @@ -65,4 +70,22 @@ config BTT Select Y if unsure +config ND_PFN + tristate + +config NVDIMM_PFN + bool "PFN: Map persistent (device) memory" + default LIBNVDIMM + depends on ZONE_DEVICE + select ND_CLAIM + help + Map persistent memory, i.e. advertise it to the memory + management sub-system. By default persistent memory does + not support direct I/O, RDMA, or any other usage that + requires a 'struct page' to mediate an I/O request. This + driver allocates and initializes the infrastructure needed + to support those use cases. + + Select Y if unsure + endif diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 594bb97c867a..ea84d3c4e8e5 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o +obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o nd_pmem-y := pmem.o @@ -9,6 +10,8 @@ nd_btt-y := btt.o nd_blk-y := blk.o +nd_e820-y := e820.o + libnvdimm-y := core.o libnvdimm-y += bus.o libnvdimm-y += dimm_devs.o @@ -17,4 +20,6 @@ libnvdimm-y += region_devs.o libnvdimm-y += region.o libnvdimm-y += namespace_devs.o libnvdimm-y += label.o +libnvdimm-$(CONFIG_ND_CLAIM) += claim.o libnvdimm-$(CONFIG_BTT) += btt_devs.o +libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 341202ed32b4..254239746020 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -583,33 +583,6 @@ static void free_arenas(struct btt *btt) } /* - * This function checks if the metadata layout is valid and error free - */ -static int arena_is_valid(struct arena_info *arena, struct btt_sb *super, - u8 *uuid, u32 lbasize) -{ - u64 checksum; - - if (memcmp(super->uuid, uuid, 16)) - return 0; - - checksum = le64_to_cpu(super->checksum); - super->checksum = 0; - if (checksum != nd_btt_sb_checksum(super)) - return 0; - super->checksum = cpu_to_le64(checksum); - - if (lbasize != le32_to_cpu(super->external_lbasize)) - return 0; - - /* TODO: figure out action for this */ - if ((le32_to_cpu(super->flags) & IB_FLAG_ERROR_MASK) != 0) - dev_info(to_dev(arena), "Found arena with an error flag\n"); - - return 1; -} - -/* * This function reads an existing valid btt superblock and * populates the corresponding arena_info struct */ @@ -632,8 +605,9 @@ static void parse_arena_meta(struct arena_info *arena, struct btt_sb *super, arena->logoff = arena_off + le64_to_cpu(super->logoff); arena->info2off = arena_off + le64_to_cpu(super->info2off); - arena->size = (super->nextoff > 0) ? (le64_to_cpu(super->nextoff)) : - (arena->info2off - arena->infooff + BTT_PG_SIZE); + arena->size = (le64_to_cpu(super->nextoff) > 0) + ? (le64_to_cpu(super->nextoff)) + : (arena->info2off - arena->infooff + BTT_PG_SIZE); arena->flags = le32_to_cpu(super->flags); } @@ -665,8 +639,7 @@ static int discover_arenas(struct btt *btt) if (ret) goto out; - if (!arena_is_valid(arena, super, btt->nd_btt->uuid, - btt->lbasize)) { + if (!nd_btt_arena_is_valid(btt->nd_btt, super)) { if (remaining == btt->rawsize) { btt->init_state = INIT_NOTFOUND; dev_info(to_dev(arena), "No existing arenas\n"); @@ -755,10 +728,13 @@ static int create_arenas(struct btt *btt) * It is only called for an uninitialized arena when a write * to that arena occurs for the first time. */ -static int btt_arena_write_layout(struct arena_info *arena, u8 *uuid) +static int btt_arena_write_layout(struct arena_info *arena) { int ret; + u64 sum; struct btt_sb *super; + struct nd_btt *nd_btt = arena->nd_btt; + const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); ret = btt_map_init(arena); if (ret) @@ -773,7 +749,8 @@ static int btt_arena_write_layout(struct arena_info *arena, u8 *uuid) return -ENOMEM; strncpy(super->signature, BTT_SIG, BTT_SIG_LEN); - memcpy(super->uuid, uuid, 16); + memcpy(super->uuid, nd_btt->uuid, 16); + memcpy(super->parent_uuid, parent_uuid, 16); super->flags = cpu_to_le32(arena->flags); super->version_major = cpu_to_le16(arena->version_major); super->version_minor = cpu_to_le16(arena->version_minor); @@ -794,7 +771,8 @@ static int btt_arena_write_layout(struct arena_info *arena, u8 *uuid) super->info2off = cpu_to_le64(arena->info2off - arena->infooff); super->flags = 0; - super->checksum = cpu_to_le64(nd_btt_sb_checksum(super)); + sum = nd_sb_checksum((struct nd_gen_sb *) super); + super->checksum = cpu_to_le64(sum); ret = btt_info_write(arena, super); @@ -813,7 +791,7 @@ static int btt_meta_init(struct btt *btt) mutex_lock(&btt->init_lock); list_for_each_entry(arena, &btt->arena_list, list) { - ret = btt_arena_write_layout(arena, btt->nd_btt->uuid); + ret = btt_arena_write_layout(arena); if (ret) goto unlock; @@ -1447,8 +1425,6 @@ static int __init nd_btt_init(void) { int rc; - BUILD_BUG_ON(sizeof(struct btt_sb) != SZ_4K); - btt_major = register_blkdev(0, "btt"); if (btt_major < 0) return btt_major; diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h index 75b0d80a6bd9..b2f8651e5395 100644 --- a/drivers/nvdimm/btt.h +++ b/drivers/nvdimm/btt.h @@ -182,4 +182,7 @@ struct btt { int init_state; int num_arenas; }; + +bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super); + #endif diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index 6ac8c0fea3ec..59ad54a63d9f 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c @@ -21,63 +21,13 @@ #include "btt.h" #include "nd.h" -static void __nd_btt_detach_ndns(struct nd_btt *nd_btt) -{ - struct nd_namespace_common *ndns = nd_btt->ndns; - - dev_WARN_ONCE(&nd_btt->dev, !mutex_is_locked(&ndns->dev.mutex) - || ndns->claim != &nd_btt->dev, - "%s: invalid claim\n", __func__); - ndns->claim = NULL; - nd_btt->ndns = NULL; - put_device(&ndns->dev); -} - -static void nd_btt_detach_ndns(struct nd_btt *nd_btt) -{ - struct nd_namespace_common *ndns = nd_btt->ndns; - - if (!ndns) - return; - get_device(&ndns->dev); - device_lock(&ndns->dev); - __nd_btt_detach_ndns(nd_btt); - device_unlock(&ndns->dev); - put_device(&ndns->dev); -} - -static bool __nd_btt_attach_ndns(struct nd_btt *nd_btt, - struct nd_namespace_common *ndns) -{ - if (ndns->claim) - return false; - dev_WARN_ONCE(&nd_btt->dev, !mutex_is_locked(&ndns->dev.mutex) - || nd_btt->ndns, - "%s: invalid claim\n", __func__); - ndns->claim = &nd_btt->dev; - nd_btt->ndns = ndns; - get_device(&ndns->dev); - return true; -} - -static bool nd_btt_attach_ndns(struct nd_btt *nd_btt, - struct nd_namespace_common *ndns) -{ - bool claimed; - - device_lock(&ndns->dev); - claimed = __nd_btt_attach_ndns(nd_btt, ndns); - device_unlock(&ndns->dev); - return claimed; -} - static void nd_btt_release(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_btt *nd_btt = to_nd_btt(dev); dev_dbg(dev, "%s\n", __func__); - nd_btt_detach_ndns(nd_btt); + nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); ida_simple_remove(&nd_region->btt_ida, nd_btt->id); kfree(nd_btt->uuid); kfree(nd_btt); @@ -172,104 +122,15 @@ static ssize_t namespace_show(struct device *dev, return rc; } -static int namespace_match(struct device *dev, void *data) -{ - char *name = data; - - return strcmp(name, dev_name(dev)) == 0; -} - -static bool is_nd_btt_idle(struct device *dev) -{ - struct nd_region *nd_region = to_nd_region(dev->parent); - struct nd_btt *nd_btt = to_nd_btt(dev); - - if (nd_region->btt_seed == dev || nd_btt->ndns || dev->driver) - return false; - return true; -} - -static ssize_t __namespace_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - struct nd_btt *nd_btt = to_nd_btt(dev); - struct nd_namespace_common *ndns; - struct device *found; - char *name; - - if (dev->driver) { - dev_dbg(dev, "%s: -EBUSY\n", __func__); - return -EBUSY; - } - - name = kstrndup(buf, len, GFP_KERNEL); - if (!name) - return -ENOMEM; - strim(name); - - if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0) - /* pass */; - else { - len = -EINVAL; - goto out; - } - - ndns = nd_btt->ndns; - if (strcmp(name, "") == 0) { - /* detach the namespace and destroy / reset the btt device */ - nd_btt_detach_ndns(nd_btt); - if (is_nd_btt_idle(dev)) - nd_device_unregister(dev, ND_ASYNC); - else { - nd_btt->lbasize = 0; - kfree(nd_btt->uuid); - nd_btt->uuid = NULL; - } - goto out; - } else if (ndns) { - dev_dbg(dev, "namespace already set to: %s\n", - dev_name(&ndns->dev)); - len = -EBUSY; - goto out; - } - - found = device_find_child(dev->parent, name, namespace_match); - if (!found) { - dev_dbg(dev, "'%s' not found under %s\n", name, - dev_name(dev->parent)); - len = -ENODEV; - goto out; - } - - ndns = to_ndns(found); - if (__nvdimm_namespace_capacity(ndns) < SZ_16M) { - dev_dbg(dev, "%s too small to host btt\n", name); - len = -ENXIO; - goto out_attach; - } - - WARN_ON_ONCE(!is_nvdimm_bus_locked(&nd_btt->dev)); - if (!nd_btt_attach_ndns(nd_btt, ndns)) { - dev_dbg(dev, "%s already claimed\n", - dev_name(&ndns->dev)); - len = -EBUSY; - } - - out_attach: - put_device(&ndns->dev); /* from device_find_child */ - out: - kfree(name); - return len; -} - static ssize_t namespace_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { + struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; nvdimm_bus_lock(dev); device_lock(dev); - rc = __namespace_store(dev, attr, buf, len); + rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, rc, buf, buf[len - 1] == '\n' ? "" : "\n"); device_unlock(dev); @@ -324,7 +185,7 @@ static struct device *__nd_btt_create(struct nd_region *nd_region, dev->type = &nd_btt_device_type; dev->groups = nd_btt_attribute_groups; device_initialize(&nd_btt->dev); - if (ndns && !__nd_btt_attach_ndns(nd_btt, ndns)) { + if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", __func__, dev_name(ndns->claim)); |