diff options
Diffstat (limited to 'drivers/nvdimm')
-rw-r--r-- | drivers/nvdimm/bus.c | 9 | ||||
-rw-r--r-- | drivers/nvdimm/claim.c | 23 | ||||
-rw-r--r-- | drivers/nvdimm/core.c | 3 | ||||
-rw-r--r-- | drivers/nvdimm/dax_devs.c | 35 | ||||
-rw-r--r-- | drivers/nvdimm/dimm_devs.c | 5 | ||||
-rw-r--r-- | drivers/nvdimm/nd-core.h | 3 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 11 | ||||
-rw-r--r-- | drivers/nvdimm/pfn.h | 1 | ||||
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 40 | ||||
-rw-r--r-- | drivers/nvdimm/pmem.c | 3 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 5 |
11 files changed, 103 insertions, 35 deletions
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 04c2c3f..f085f8b 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -124,9 +124,10 @@ static int nvdimm_bus_remove(struct device *dev) struct nd_device_driver *nd_drv = to_nd_device_driver(dev->driver); struct module *provider = to_bus_provider(dev); struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); - int rc; + int rc = 0; - rc = nd_drv->remove(dev); + if (nd_drv->remove) + rc = nd_drv->remove(dev); nd_region_disable(nvdimm_bus, dev); dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, @@ -296,8 +297,8 @@ int __nd_driver_register(struct nd_device_driver *nd_drv, struct module *owner, return -EINVAL; } - if (!nd_drv->probe || !nd_drv->remove) { - pr_debug("->probe() and ->remove() must be specified\n"); + if (!nd_drv->probe) { + pr_debug("%s ->probe() must be specified\n", mod_name); return -EINVAL; } diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 5f53db5..8b2e3c4 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -93,6 +93,25 @@ static bool is_idle(struct device *dev, struct nd_namespace_common *ndns) return true; } +struct nd_pfn *to_nd_pfn_safe(struct device *dev) +{ + /* + * pfn device attributes are re-used by dax device instances, so we + * need to be careful to correct device-to-nd_pfn conversion. + */ + if (is_nd_pfn(dev)) + return to_nd_pfn(dev); + + if (is_nd_dax(dev)) { + struct nd_dax *nd_dax = to_nd_dax(dev); + + return &nd_dax->nd_pfn; + } + + WARN_ON(1); + return NULL; +} + static void nd_detach_and_reset(struct device *dev, struct nd_namespace_common **_ndns) { @@ -106,8 +125,8 @@ static void nd_detach_and_reset(struct device *dev, nd_btt->lbasize = 0; kfree(nd_btt->uuid); nd_btt->uuid = NULL; - } else if (is_nd_pfn(dev)) { - struct nd_pfn *nd_pfn = to_nd_pfn(dev); + } else if (is_nd_pfn(dev) || is_nd_dax(dev)) { + struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); kfree(nd_pfn->uuid); nd_pfn->uuid = NULL; diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index e8688a1..be89764 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -648,6 +648,9 @@ static __exit void libnvdimm_exit(void) nd_region_exit(); nvdimm_exit(); nvdimm_bus_exit(); + nd_region_devs_exit(); + nvdimm_devs_exit(); + ida_destroy(&nd_ida); } MODULE_LICENSE("GPL v2"); diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c index f90f754..45fa82c 100644 --- a/drivers/nvdimm/dax_devs.c +++ b/drivers/nvdimm/dax_devs.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/mm.h> #include "nd-core.h" +#include "pfn.h" #include "nd.h" static void nd_dax_release(struct device *dev) @@ -97,3 +98,37 @@ struct device *nd_dax_create(struct nd_region *nd_region) __nd_device_register(dev); return dev; } + +int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) +{ + int rc; + struct nd_dax *nd_dax; + struct device *dax_dev; + struct nd_pfn *nd_pfn; + struct nd_pfn_sb *pfn_sb; + struct nd_region *nd_region = to_nd_region(ndns->dev.parent); + + if (ndns->force_raw) + return -ENODEV; + + nvdimm_bus_lock(&ndns->dev); + nd_dax = nd_dax_alloc(nd_region); + nd_pfn = &nd_dax->nd_pfn; + dax_dev = nd_pfn_devinit(nd_pfn, ndns); + nvdimm_bus_unlock(&ndns->dev); + if (!dax_dev) + return -ENOMEM; + pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); + nd_pfn->pfn_sb = pfn_sb; + rc = nd_pfn_validate(nd_pfn, DAX_SIG); + dev_dbg(dev, "%s: dax: %s\n", __func__, + rc == 0 ? dev_name(dax_dev) : "<none>"); + if (rc < 0) { + __nd_detach_ndns(dax_dev, &nd_pfn->ndns); + put_device(dax_dev); + } else + __nd_device_register(dax_dev); + + return rc; +} +EXPORT_SYMBOL(nd_dax_probe); diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 79a35a0..bbde28d 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -552,3 +552,8 @@ int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count) return 0; } EXPORT_SYMBOL_GPL(nvdimm_bus_check_dimm_count); + +void __exit nvdimm_devs_exit(void) +{ + ida_destroy(&dimm_ida); +} diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 86d985c..284cdaa 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -49,6 +49,8 @@ bool is_nd_blk(struct device *dev); struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev); int __init nvdimm_bus_init(void); void nvdimm_bus_exit(void); +void nvdimm_devs_exit(void); +void nd_region_devs_exit(void); void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev); struct nd_region; void nd_region_create_blk_seed(struct nd_region *nd_region); @@ -92,4 +94,5 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, ssize_t nd_namespace_store(struct device *dev, struct nd_namespace_common **_ndns, const char *buf, size_t len); +struct nd_pfn *to_nd_pfn_safe(struct device *dev); #endif /* __ND_CORE_H__ */ diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 46910b8..d0ac93c 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -232,7 +232,7 @@ bool is_nd_pfn(struct device *dev); struct device *nd_pfn_create(struct nd_region *nd_region); struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn, struct nd_namespace_common *ndns); -int nd_pfn_validate(struct nd_pfn *nd_pfn); +int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig); extern struct attribute_group nd_pfn_attribute_group; #else static inline int nd_pfn_probe(struct device *dev, @@ -251,7 +251,7 @@ static inline struct device *nd_pfn_create(struct nd_region *nd_region) return NULL; } -static inline int nd_pfn_validate(struct nd_pfn *nd_pfn) +static inline int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) { return -ENODEV; } @@ -259,9 +259,16 @@ static inline int nd_pfn_validate(struct nd_pfn *nd_pfn) struct nd_dax *to_nd_dax(struct device *dev); #if IS_ENABLED(CONFIG_NVDIMM_DAX) +int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns); bool is_nd_dax(struct device *dev); struct device *nd_dax_create(struct nd_region *nd_region); #else +static inline int nd_dax_probe(struct device *dev, + struct nd_namespace_common *ndns) +{ + return -ENODEV; +} + static inline bool is_nd_dax(struct device *dev) { return false; diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h index 9d2704c..dde9853 100644 --- a/drivers/nvdimm/pfn.h +++ b/drivers/nvdimm/pfn.h @@ -19,6 +19,7 @@ #define PFN_SIG_LEN 16 #define PFN_SIG "NVDIMM_PFN_INFO\0" +#define DAX_SIG "NVDIMM_DAX_INFO\0" struct nd_pfn_sb { u8 signature[PFN_SIG_LEN]; diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 2248056..f7718ec 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -54,25 +54,6 @@ struct nd_pfn *to_nd_pfn(struct device *dev) } EXPORT_SYMBOL(to_nd_pfn); -static struct nd_pfn *to_nd_pfn_safe(struct device *dev) -{ - /* - * pfn device attributes are re-used by dax device instances, so we - * need to be careful to correct device-to-nd_pfn conversion. - */ - if (is_nd_pfn(dev)) - return to_nd_pfn(dev); - - if (is_nd_dax(dev)) { - struct nd_dax *nd_dax = to_nd_dax(dev); - - return &nd_dax->nd_pfn; - } - - WARN_ON(1); - return NULL; -} - static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -360,7 +341,7 @@ struct device *nd_pfn_create(struct nd_region *nd_region) return dev; } -int nd_pfn_validate(struct nd_pfn *nd_pfn) +int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) { u64 checksum, offset; struct nd_namespace_io *nsio; @@ -377,7 +358,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn) if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb))) return -ENXIO; - if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) != 0) + if (memcmp(pfn_sb->signature, sig, PFN_SIG_LEN) != 0) return -ENODEV; checksum = le64_to_cpu(pfn_sb->checksum); @@ -416,6 +397,8 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn) return -ENODEV; } + if (nd_pfn->align == 0) + nd_pfn->align = le32_to_cpu(pfn_sb->align); if (nd_pfn->align > nvdimm_namespace_capacity(ndns)) { dev_err(&nd_pfn->dev, "alignment: %lx exceeds capacity %llx\n", nd_pfn->align, nvdimm_namespace_capacity(ndns)); @@ -436,8 +419,8 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn) return -EBUSY; } - nd_pfn->align = le32_to_cpu(pfn_sb->align); - if (!is_power_of_2(offset) || offset < PAGE_SIZE) { + if ((nd_pfn->align && !IS_ALIGNED(offset, nd_pfn->align)) + || !IS_ALIGNED(offset, PAGE_SIZE)) { dev_err(&nd_pfn->dev, "bad offset: %#llx dax disabled\n", offset); return -ENXIO; @@ -467,7 +450,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns) pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); nd_pfn = to_nd_pfn(pfn_dev); nd_pfn->pfn_sb = pfn_sb; - rc = nd_pfn_validate(nd_pfn); + rc = nd_pfn_validate(nd_pfn, PFN_SIG); dev_dbg(dev, "%s: pfn: %s\n", __func__, rc == 0 ? dev_name(pfn_dev) : "<none>"); if (rc < 0) { @@ -552,6 +535,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) struct nd_pfn_sb *pfn_sb; unsigned long npfns; phys_addr_t offset; + const char *sig; u64 checksum; int rc; @@ -560,7 +544,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) return -ENOMEM; nd_pfn->pfn_sb = pfn_sb; - rc = nd_pfn_validate(nd_pfn); + if (is_nd_dax(&nd_pfn->dev)) + sig = DAX_SIG; + else + sig = PFN_SIG; + rc = nd_pfn_validate(nd_pfn, sig); if (rc != -ENODEV) return rc; @@ -635,7 +623,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) pfn_sb->mode = cpu_to_le32(nd_pfn->mode); pfn_sb->dataoff = cpu_to_le64(offset); pfn_sb->npfns = cpu_to_le64(npfns); - memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN); + memcpy(pfn_sb->signature, sig, PFN_SIG_LEN); memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); pfn_sb->version_major = cpu_to_le16(1); diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index d9a0dbc..042baec 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -320,7 +320,8 @@ static int nd_pmem_probe(struct device *dev) return pmem_attach_disk(dev, ndns); /* if we find a valid info-block we'll come back as that personality */ - if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0) + if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0 + || nd_dax_probe(dev, ndns) == 0) return -ENXIO; /* ...otherwise we're just a raw pmem device */ diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 9e1b054..40fcfea 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -793,3 +793,8 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus, __func__); } EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); + +void __exit nd_region_devs_exit(void) +{ + ida_destroy(®ion_ida); +} |