[PATCH v2 14/20] libnd: pmem label sets and namespace instantiation.
A complete label set is a PMEM-label per dimm where all the UUIDs match and the interleave set cookie matches an active interleave set. Present a sysfs ABI for manipulation of a PMEM-namespace's 'alt_name', 'uuid', and 'size' attributes. A later patch will make these settings persistent by writing back the label. Note that PMEM allocations grow forwards from the start of an interleave set (lowest dimm-physical-address (DPA)). BLK-namespaces that alias with a PMEM interleave set will grow allocations backward from the highest DPA. Cc: Greg KH Cc: Neil Brown Signed-off-by: Dan Williams --- drivers/block/nd/bus.c|6 drivers/block/nd/core.c | 64 ++ drivers/block/nd/dimm.c |2 drivers/block/nd/dimm_devs.c | 127 + drivers/block/nd/label.c | 54 ++ drivers/block/nd/label.h |3 drivers/block/nd/libnd.h |2 drivers/block/nd/namespace_devs.c | 1024 + drivers/block/nd/nd-private.h | 14 + drivers/block/nd/nd.h | 33 + drivers/block/nd/pmem.c | 22 + drivers/block/nd/region_devs.c| 145 + include/linux/nd.h| 24 + include/uapi/linux/ndctl.h|4 14 files changed, 1512 insertions(+), 12 deletions(-) diff --git a/drivers/block/nd/bus.c b/drivers/block/nd/bus.c index 8afb8d4a7e81..819259e92468 100644 --- a/drivers/block/nd/bus.c +++ b/drivers/block/nd/bus.c @@ -364,8 +364,10 @@ u32 nd_cmd_out_size(struct nd_dimm *nd_dimm, int cmd, } EXPORT_SYMBOL_GPL(nd_cmd_out_size); -static void wait_nd_bus_probe_idle(struct nd_bus *nd_bus) +void wait_nd_bus_probe_idle(struct device *dev) { + struct nd_bus *nd_bus = walk_to_nd_bus(dev); + do { if (nd_bus->probe_active == 0) break; @@ -384,7 +386,7 @@ static int nd_cmd_clear_to_send(struct nd_dimm *nd_dimm, unsigned int cmd) return 0; nd_bus = walk_to_nd_bus(_dimm->dev); - wait_nd_bus_probe_idle(nd_bus); + wait_nd_bus_probe_idle(_bus->dev); if (atomic_read(_dimm->busy)) return -EBUSY; diff --git a/drivers/block/nd/core.c b/drivers/block/nd/core.c index 603970d0ef3a..cf64b7a50d3a 100644 --- a/drivers/block/nd/core.c +++ b/drivers/block/nd/core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,69 @@ struct nd_bus *walk_to_nd_bus(struct device *nd_dev) return NULL; } +static bool is_uuid_sep(char sep) +{ + if (sep == '\n' || sep == '-' || sep == ':' || sep == '\0') + return true; + return false; +} + +static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, + size_t len) +{ + const char *str = buf; + u8 uuid[16]; + int i; + + for (i = 0; i < 16; i++) { + if (!isxdigit(str[0]) || !isxdigit(str[1])) { + dev_dbg(dev, "%s: pos: %d buf[%zd]: %c buf[%zd]: %c\n", + __func__, i, str - buf, str[0], + str + 1 - buf, str[1]); + return -EINVAL; + } + + uuid[i] = (hex_to_bin(str[0]) << 4) | hex_to_bin(str[1]); + str += 2; + if (is_uuid_sep(*str)) + str++; + } + + memcpy(uuid_out, uuid, sizeof(uuid)); + return 0; +} + +/** + * nd_uuid_store: common implementation for writing 'uuid' sysfs attributes + * @dev: container device for the uuid property + * @uuid_out: uuid buffer to replace + * @buf: raw sysfs buffer to parse + * + * Enforce that uuids can only be changed while the device is disabled + * (driver detached) + * LOCKING: expects device_lock() is held on entry + */ +int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, + size_t len) +{ + u8 uuid[16]; + int rc; + + if (dev->driver) + return -EBUSY; + + rc = nd_uuid_parse(dev, uuid, buf, len); + if (rc) + return rc; + + kfree(*uuid_out); + *uuid_out = kmemdup(uuid, sizeof(uuid), GFP_KERNEL); + if (!(*uuid_out)) + return -ENOMEM; + + return 0; +} + static ssize_t commands_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/block/nd/dimm.c b/drivers/block/nd/dimm.c index 5477176c5de0..e2f964308672 100644 --- a/drivers/block/nd/dimm.c +++ b/drivers/block/nd/dimm.c @@ -86,7 +86,7 @@ static int nd_dimm_remove(struct device *dev) nd_bus_lock(dev); dev_set_drvdata(dev, NULL); for_each_dpa_resource_safe(ndd, res, _r) - __release_region(>dpa, res->start, resource_size(res)); + nd_dimm_free_dpa(ndd, res); nd_bus_unlock(dev); free_data(ndd); diff --git a/drivers/block/nd/dimm_devs.c
[PATCH v2 14/20] libnd: pmem label sets and namespace instantiation.
A complete label set is a PMEM-label per dimm where all the UUIDs match and the interleave set cookie matches an active interleave set. Present a sysfs ABI for manipulation of a PMEM-namespace's 'alt_name', 'uuid', and 'size' attributes. A later patch will make these settings persistent by writing back the label. Note that PMEM allocations grow forwards from the start of an interleave set (lowest dimm-physical-address (DPA)). BLK-namespaces that alias with a PMEM interleave set will grow allocations backward from the highest DPA. Cc: Greg KH gre...@linuxfoundation.org Cc: Neil Brown ne...@suse.de Signed-off-by: Dan Williams dan.j.willi...@intel.com --- drivers/block/nd/bus.c|6 drivers/block/nd/core.c | 64 ++ drivers/block/nd/dimm.c |2 drivers/block/nd/dimm_devs.c | 127 + drivers/block/nd/label.c | 54 ++ drivers/block/nd/label.h |3 drivers/block/nd/libnd.h |2 drivers/block/nd/namespace_devs.c | 1024 + drivers/block/nd/nd-private.h | 14 + drivers/block/nd/nd.h | 33 + drivers/block/nd/pmem.c | 22 + drivers/block/nd/region_devs.c| 145 + include/linux/nd.h| 24 + include/uapi/linux/ndctl.h|4 14 files changed, 1512 insertions(+), 12 deletions(-) diff --git a/drivers/block/nd/bus.c b/drivers/block/nd/bus.c index 8afb8d4a7e81..819259e92468 100644 --- a/drivers/block/nd/bus.c +++ b/drivers/block/nd/bus.c @@ -364,8 +364,10 @@ u32 nd_cmd_out_size(struct nd_dimm *nd_dimm, int cmd, } EXPORT_SYMBOL_GPL(nd_cmd_out_size); -static void wait_nd_bus_probe_idle(struct nd_bus *nd_bus) +void wait_nd_bus_probe_idle(struct device *dev) { + struct nd_bus *nd_bus = walk_to_nd_bus(dev); + do { if (nd_bus-probe_active == 0) break; @@ -384,7 +386,7 @@ static int nd_cmd_clear_to_send(struct nd_dimm *nd_dimm, unsigned int cmd) return 0; nd_bus = walk_to_nd_bus(nd_dimm-dev); - wait_nd_bus_probe_idle(nd_bus); + wait_nd_bus_probe_idle(nd_bus-dev); if (atomic_read(nd_dimm-busy)) return -EBUSY; diff --git a/drivers/block/nd/core.c b/drivers/block/nd/core.c index 603970d0ef3a..cf64b7a50d3a 100644 --- a/drivers/block/nd/core.c +++ b/drivers/block/nd/core.c @@ -13,6 +13,7 @@ #include linux/export.h #include linux/module.h #include linux/device.h +#include linux/ctype.h #include linux/ndctl.h #include linux/mutex.h #include linux/slab.h @@ -106,6 +107,69 @@ struct nd_bus *walk_to_nd_bus(struct device *nd_dev) return NULL; } +static bool is_uuid_sep(char sep) +{ + if (sep == '\n' || sep == '-' || sep == ':' || sep == '\0') + return true; + return false; +} + +static int nd_uuid_parse(struct device *dev, u8 *uuid_out, const char *buf, + size_t len) +{ + const char *str = buf; + u8 uuid[16]; + int i; + + for (i = 0; i 16; i++) { + if (!isxdigit(str[0]) || !isxdigit(str[1])) { + dev_dbg(dev, %s: pos: %d buf[%zd]: %c buf[%zd]: %c\n, + __func__, i, str - buf, str[0], + str + 1 - buf, str[1]); + return -EINVAL; + } + + uuid[i] = (hex_to_bin(str[0]) 4) | hex_to_bin(str[1]); + str += 2; + if (is_uuid_sep(*str)) + str++; + } + + memcpy(uuid_out, uuid, sizeof(uuid)); + return 0; +} + +/** + * nd_uuid_store: common implementation for writing 'uuid' sysfs attributes + * @dev: container device for the uuid property + * @uuid_out: uuid buffer to replace + * @buf: raw sysfs buffer to parse + * + * Enforce that uuids can only be changed while the device is disabled + * (driver detached) + * LOCKING: expects device_lock() is held on entry + */ +int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, + size_t len) +{ + u8 uuid[16]; + int rc; + + if (dev-driver) + return -EBUSY; + + rc = nd_uuid_parse(dev, uuid, buf, len); + if (rc) + return rc; + + kfree(*uuid_out); + *uuid_out = kmemdup(uuid, sizeof(uuid), GFP_KERNEL); + if (!(*uuid_out)) + return -ENOMEM; + + return 0; +} + static ssize_t commands_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/block/nd/dimm.c b/drivers/block/nd/dimm.c index 5477176c5de0..e2f964308672 100644 --- a/drivers/block/nd/dimm.c +++ b/drivers/block/nd/dimm.c @@ -86,7 +86,7 @@ static int nd_dimm_remove(struct device *dev) nd_bus_lock(dev); dev_set_drvdata(dev, NULL); for_each_dpa_resource_safe(ndd, res, _r) - __release_region(ndd-dpa, res-start, resource_size(res)); +