summaryrefslogtreecommitdiff
path: root/drivers/nvdimm/pfn_devs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvdimm/pfn_devs.c')
-rw-r--r--drivers/nvdimm/pfn_devs.c96
1 files changed, 46 insertions, 50 deletions
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 18ad315581ca..42b172fc5576 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -22,7 +22,7 @@ static void nd_pfn_release(struct device *dev)
dev_dbg(dev, "trace\n");
nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns);
- ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id);
+ ida_free(&nd_region->pfn_ida, nd_pfn->id);
kfree(nd_pfn->uuid);
kfree(nd_pfn);
}
@@ -56,30 +56,26 @@ static ssize_t mode_store(struct device *dev,
{
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc = 0;
+ size_t n = len - 1;
- device_lock(dev);
- nvdimm_bus_lock(dev);
+ guard(device)(dev);
+ guard(nvdimm_bus)(dev);
if (dev->driver)
- rc = -EBUSY;
- else {
- size_t n = len - 1;
-
- if (strncmp(buf, "pmem\n", n) == 0
- || strncmp(buf, "pmem", n) == 0) {
- nd_pfn->mode = PFN_MODE_PMEM;
- } else if (strncmp(buf, "ram\n", n) == 0
- || strncmp(buf, "ram", n) == 0)
- nd_pfn->mode = PFN_MODE_RAM;
- else if (strncmp(buf, "none\n", n) == 0
- || strncmp(buf, "none", n) == 0)
- nd_pfn->mode = PFN_MODE_NONE;
- else
- rc = -EINVAL;
- }
+ return -EBUSY;
+
+ if (strncmp(buf, "pmem\n", n) == 0
+ || strncmp(buf, "pmem", n) == 0) {
+ nd_pfn->mode = PFN_MODE_PMEM;
+ } else if (strncmp(buf, "ram\n", n) == 0
+ || strncmp(buf, "ram", n) == 0)
+ nd_pfn->mode = PFN_MODE_RAM;
+ else if (strncmp(buf, "none\n", n) == 0
+ || strncmp(buf, "none", n) == 0)
+ nd_pfn->mode = PFN_MODE_NONE;
+ else
+ rc = -EINVAL;
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n");
- nvdimm_bus_unlock(dev);
- device_unlock(dev);
return rc ? rc : len;
}
@@ -125,14 +121,12 @@ static ssize_t align_store(struct device *dev,
unsigned long aligns[MAX_NVDIMM_ALIGN] = { [0] = 0, };
ssize_t rc;
- device_lock(dev);
- nvdimm_bus_lock(dev);
+ guard(device)(dev);
+ guard(nvdimm_bus)(dev);
rc = nd_size_select_store(dev, buf, &nd_pfn->align,
nd_pfn_supported_alignments(aligns));
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n");
- nvdimm_bus_unlock(dev);
- device_unlock(dev);
return rc ? rc : len;
}
@@ -168,13 +162,10 @@ static ssize_t namespace_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
- ssize_t rc;
- nvdimm_bus_lock(dev);
- rc = sprintf(buf, "%s\n", nd_pfn->ndns
+ guard(nvdimm_bus)(dev);
+ return sprintf(buf, "%s\n", nd_pfn->ndns
? dev_name(&nd_pfn->ndns->dev) : "");
- nvdimm_bus_unlock(dev);
- return rc;
}
static ssize_t namespace_store(struct device *dev,
@@ -183,13 +174,11 @@ static ssize_t namespace_store(struct device *dev,
struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev);
ssize_t rc;
- device_lock(dev);
- nvdimm_bus_lock(dev);
+ guard(device)(dev);
+ guard(nvdimm_bus)(dev);
rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len);
dev_dbg(dev, "result: %zd wrote: %s%s", rc, buf,
buf[len - 1] == '\n' ? "" : "\n");
- nvdimm_bus_unlock(dev);
- device_unlock(dev);
return rc;
}
@@ -326,7 +315,7 @@ static struct nd_pfn *nd_pfn_alloc(struct nd_region *nd_region)
if (!nd_pfn)
return NULL;
- nd_pfn->id = ida_simple_get(&nd_region->pfn_ida, 0, 0, GFP_KERNEL);
+ nd_pfn->id = ida_alloc(&nd_region->pfn_ida, GFP_KERNEL);
if (nd_pfn->id < 0) {
kfree(nd_pfn);
return NULL;
@@ -367,9 +356,10 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
struct nd_namespace_common *ndns = nd_pfn->ndns;
void *zero_page = page_address(ZERO_PAGE(0));
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
- int num_bad, meta_num, rc, bb_present;
+ int meta_num, rc, bb_present;
sector_t first_bad, meta_start;
struct nd_namespace_io *nsio;
+ sector_t num_bad;
if (nd_pfn->mode != PFN_MODE_PMEM)
return 0;
@@ -394,7 +384,7 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
bb_present = badblocks_check(&nd_region->bb, meta_start,
meta_num, &first_bad, &num_bad);
if (bb_present) {
- dev_dbg(&nd_pfn->dev, "meta: %x badblocks at %llx\n",
+ dev_dbg(&nd_pfn->dev, "meta: %llx badblocks at %llx\n",
num_bad, first_bad);
nsoff = ALIGN_DOWN((nd_region->ndr_start
+ (first_bad << 9)) - nsio->res.start,
@@ -413,7 +403,7 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
}
if (rc) {
dev_err(&nd_pfn->dev,
- "error clearing %x badblocks at %llx\n",
+ "error clearing %llx badblocks at %llx\n",
num_bad, first_bad);
return rc;
}
@@ -452,8 +442,9 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
u64 checksum, offset;
struct resource *res;
enum nd_pfn_mode mode;
+ resource_size_t res_size;
struct nd_namespace_io *nsio;
- unsigned long align, start_pad;
+ unsigned long align, start_pad, end_trunc;
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
struct nd_namespace_common *ndns = nd_pfn->ndns;
const uuid_t *parent_uuid = nd_dev_to_uuid(&ndns->dev);
@@ -503,6 +494,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
align = le32_to_cpu(pfn_sb->align);
offset = le64_to_cpu(pfn_sb->dataoff);
start_pad = le32_to_cpu(pfn_sb->start_pad);
+ end_trunc = le32_to_cpu(pfn_sb->end_trunc);
if (align == 0)
align = 1UL << ilog2(offset);
mode = le32_to_cpu(pfn_sb->mode);
@@ -537,7 +529,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
if (!nd_pfn->uuid) {
/*
- * When probing a namepace via nd_pfn_probe() the uuid
+ * When probing a namespace via nd_pfn_probe() the uuid
* is NULL (see: nd_pfn_devinit()) we init settings from
* pfn_sb
*/
@@ -584,7 +576,8 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
*/
nsio = to_nd_namespace_io(&ndns->dev);
res = &nsio->res;
- if (offset >= resource_size(res)) {
+ res_size = resource_size(res);
+ if (offset >= res_size) {
dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n",
dev_name(&ndns->dev));
return -EOPNOTSUPP;
@@ -598,18 +591,20 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
return -EOPNOTSUPP;
}
- if (!IS_ALIGNED(res->start + le32_to_cpu(pfn_sb->start_pad),
- memremap_compat_align())) {
+ if (!IS_ALIGNED(res->start + start_pad, memremap_compat_align())) {
dev_err(&nd_pfn->dev, "resource start misaligned\n");
return -EOPNOTSUPP;
}
- if (!IS_ALIGNED(res->end + 1 - le32_to_cpu(pfn_sb->end_trunc),
- memremap_compat_align())) {
+ if (!IS_ALIGNED(res->end + 1 - end_trunc, memremap_compat_align())) {
dev_err(&nd_pfn->dev, "resource end misaligned\n");
return -EOPNOTSUPP;
}
+ if (offset >= (res_size - start_pad - end_trunc)) {
+ dev_err(&nd_pfn->dev, "bad offset with small namespace\n");
+ return -EOPNOTSUPP;
+ }
return 0;
}
EXPORT_SYMBOL(nd_pfn_validate);
@@ -633,10 +628,10 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
return -ENODEV;
}
- nvdimm_bus_lock(&ndns->dev);
- nd_pfn = nd_pfn_alloc(nd_region);
- pfn_dev = nd_pfn_devinit(nd_pfn, ndns);
- nvdimm_bus_unlock(&ndns->dev);
+ scoped_guard(nvdimm_bus, &ndns->dev) {
+ nd_pfn = nd_pfn_alloc(nd_region);
+ pfn_dev = nd_pfn_devinit(nd_pfn, ndns);
+ }
if (!pfn_dev)
return -ENOMEM;
pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
@@ -810,7 +805,8 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
else
return -ENXIO;
- if (offset >= size) {
+ if (offset >= (size - end_trunc)) {
+ /* This results in zero size devices */
dev_err(&nd_pfn->dev, "%s unable to satisfy requested alignment\n",
dev_name(&ndns->dev));
return -ENXIO;