Commit 1b40e09a authored by Dan Williams's avatar Dan Williams

libnvdimm: blk labels and namespace instantiation

A blk label set describes a namespace comprised of one or more
discontiguous dpa ranges on a single dimm.  They may alias with one or
more pmem interleave sets that include the given dimm.

This is the runtime/volatile configuration infrastructure for sysfs
manipulation of 'alt_name', 'uuid', 'size', and 'sector_size'.  A later
patch will make these settings persistent by writing back the label(s).

Unlike pmem namespaces, multiple blk namespaces can be created per
region.  Once a blk namespace has been created a new seed device
(unconfigured child of a parent blk region) is instantiated.  As long as
a region has 'available_size' != 0 new child namespaces may be created.

Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Neil Brown <neilb@suse.de>
Acked-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent bf9bccc1
...@@ -173,6 +173,46 @@ int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, ...@@ -173,6 +173,46 @@ int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
return 0; return 0;
} }
ssize_t nd_sector_size_show(unsigned long current_lbasize,
const unsigned long *supported, char *buf)
{
ssize_t len = 0;
int i;
for (i = 0; supported[i]; i++)
if (current_lbasize == supported[i])
len += sprintf(buf + len, "[%ld] ", supported[i]);
else
len += sprintf(buf + len, "%ld ", supported[i]);
len += sprintf(buf + len, "\n");
return len;
}
ssize_t nd_sector_size_store(struct device *dev, const char *buf,
unsigned long *current_lbasize, const unsigned long *supported)
{
unsigned long lbasize;
int rc, i;
if (dev->driver)
return -EBUSY;
rc = kstrtoul(buf, 0, &lbasize);
if (rc)
return rc;
for (i = 0; supported[i]; i++)
if (lbasize == supported[i])
break;
if (supported[i]) {
*current_lbasize = lbasize;
return 0;
} else {
return -EINVAL;
}
}
static ssize_t commands_show(struct device *dev, static ssize_t commands_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
......
...@@ -289,6 +289,42 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, ...@@ -289,6 +289,42 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data,
} }
EXPORT_SYMBOL_GPL(nvdimm_create); EXPORT_SYMBOL_GPL(nvdimm_create);
/**
* nd_blk_available_dpa - account the unused dpa of BLK region
* @nd_mapping: container of dpa-resource-root + labels
*
* Unlike PMEM, BLK namespaces can occupy discontiguous DPA ranges.
*/
resource_size_t nd_blk_available_dpa(struct nd_mapping *nd_mapping)
{
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
resource_size_t map_end, busy = 0, available;
struct resource *res;
if (!ndd)
return 0;
map_end = nd_mapping->start + nd_mapping->size - 1;
for_each_dpa_resource(ndd, res)
if (res->start >= nd_mapping->start && res->start < map_end) {
resource_size_t end = min(map_end, res->end);
busy += end - res->start + 1;
} else if (res->end >= nd_mapping->start
&& res->end <= map_end) {
busy += res->end - nd_mapping->start;
} else if (nd_mapping->start > res->start
&& nd_mapping->start < res->end) {
/* total eclipse of the BLK region mapping */
busy += nd_mapping->size;
}
available = map_end - nd_mapping->start + 1;
if (busy < available)
return available - busy;
return 0;
}
/** /**
* nd_pmem_available_dpa - for the given dimm+region account unallocated dpa * nd_pmem_available_dpa - for the given dimm+region account unallocated dpa
* @nd_mapping: container of dpa-resource-root + labels * @nd_mapping: container of dpa-resource-root + labels
......
This diff is collapsed.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/libnvdimm.h> #include <linux/libnvdimm.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/nd.h>
extern struct list_head nvdimm_bus_list; extern struct list_head nvdimm_bus_list;
extern struct mutex nvdimm_bus_list_mutex; extern struct mutex nvdimm_bus_list_mutex;
...@@ -48,6 +49,8 @@ struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev); ...@@ -48,6 +49,8 @@ struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev);
int __init nvdimm_bus_init(void); int __init nvdimm_bus_init(void);
void nvdimm_bus_exit(void); void nvdimm_bus_exit(void);
void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev); 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);
void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev); void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev);
int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus);
void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus);
...@@ -64,8 +67,13 @@ struct nvdimm_drvdata; ...@@ -64,8 +67,13 @@ struct nvdimm_drvdata;
struct nd_mapping; struct nd_mapping;
resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
struct nd_mapping *nd_mapping, resource_size_t *overlap); struct nd_mapping *nd_mapping, resource_size_t *overlap);
resource_size_t nd_blk_available_dpa(struct nd_mapping *nd_mapping);
resource_size_t nd_region_available_dpa(struct nd_region *nd_region); resource_size_t nd_region_available_dpa(struct nd_region *nd_region);
resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd, resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,
struct nd_label_id *label_id); struct nd_label_id *label_id);
struct nd_mapping;
struct resource *nsblk_add_resource(struct nd_region *nd_region,
struct nvdimm_drvdata *ndd, struct nd_namespace_blk *nsblk,
resource_size_t start);
void get_ndd(struct nvdimm_drvdata *ndd); void get_ndd(struct nvdimm_drvdata *ndd);
#endif /* __ND_CORE_H__ */ #endif /* __ND_CORE_H__ */
...@@ -73,6 +73,7 @@ static inline struct nd_namespace_index *to_next_namespace_index( ...@@ -73,6 +73,7 @@ static inline struct nd_namespace_index *to_next_namespace_index(
struct nd_region { struct nd_region {
struct device dev; struct device dev;
struct ida ns_ida;
struct device *ns_seed; struct device *ns_seed;
u16 ndr_mappings; u16 ndr_mappings;
u64 ndr_size; u64 ndr_size;
...@@ -102,6 +103,10 @@ void nd_device_register(struct device *dev); ...@@ -102,6 +103,10 @@ void nd_device_register(struct device *dev);
void nd_device_unregister(struct device *dev, enum nd_async_mode mode); void nd_device_unregister(struct device *dev, enum nd_async_mode mode);
int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf, int nd_uuid_store(struct device *dev, u8 **uuid_out, const char *buf,
size_t len); size_t len);
ssize_t nd_sector_size_show(unsigned long current_lbasize,
const unsigned long *supported, char *buf);
ssize_t nd_sector_size_store(struct device *dev, const char *buf,
unsigned long *current_lbasize, const unsigned long *supported);
int __init nvdimm_init(void); int __init nvdimm_init(void);
int __init nd_region_init(void); int __init nd_region_init(void);
void nvdimm_exit(void); void nvdimm_exit(void);
......
...@@ -118,7 +118,12 @@ static int is_uuid_busy(struct device *dev, void *data) ...@@ -118,7 +118,12 @@ static int is_uuid_busy(struct device *dev, void *data)
break; break;
} }
case ND_DEVICE_NAMESPACE_BLK: { case ND_DEVICE_NAMESPACE_BLK: {
/* TODO: blk namespace support */ struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
if (!nsblk->uuid)
break;
if (memcmp(uuid, nsblk->uuid, NSLABEL_UUID_LEN) == 0)
return -EBUSY;
break; break;
} }
default: default:
...@@ -230,7 +235,7 @@ resource_size_t nd_region_available_dpa(struct nd_region *nd_region) ...@@ -230,7 +235,7 @@ resource_size_t nd_region_available_dpa(struct nd_region *nd_region)
goto retry; goto retry;
} }
} else if (is_nd_blk(&nd_region->dev)) { } else if (is_nd_blk(&nd_region->dev)) {
/* TODO: BLK Namespace support */ available += nd_blk_available_dpa(nd_mapping);
} }
} }
...@@ -360,6 +365,13 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, ...@@ -360,6 +365,13 @@ static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus,
nd_mapping->ndd = NULL; nd_mapping->ndd = NULL;
atomic_dec(&nvdimm->busy); atomic_dec(&nvdimm->busy);
} }
} else if (dev->parent && is_nd_blk(dev->parent) && probe) {
struct nd_region *nd_region = to_nd_region(dev->parent);
nvdimm_bus_lock(dev);
if (nd_region->ns_seed == dev)
nd_region_create_blk_seed(nd_region);
nvdimm_bus_unlock(dev);
} }
} }
...@@ -533,6 +545,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, ...@@ -533,6 +545,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
nd_region->ndr_mappings = ndr_desc->num_mappings; nd_region->ndr_mappings = ndr_desc->num_mappings;
nd_region->provider_data = ndr_desc->provider_data; nd_region->provider_data = ndr_desc->provider_data;
nd_region->nd_set = ndr_desc->nd_set; nd_region->nd_set = ndr_desc->nd_set;
ida_init(&nd_region->ns_ida);
dev = &nd_region->dev; dev = &nd_region->dev;
dev_set_name(dev, "region%d", nd_region->id); dev_set_name(dev, "region%d", nd_region->id);
dev->parent = &nvdimm_bus->dev; dev->parent = &nvdimm_bus->dev;
......
...@@ -27,6 +27,9 @@ enum { ...@@ -27,6 +27,9 @@ enum {
ND_CMD_MAX_ENVELOPE = 16, ND_CMD_MAX_ENVELOPE = 16,
ND_CMD_ARS_STATUS_MAX = SZ_4K, ND_CMD_ARS_STATUS_MAX = SZ_4K,
ND_MAX_MAPPINGS = 32, ND_MAX_MAPPINGS = 32,
/* mark newly adjusted resources as requiring a label update */
DPA_RESOURCE_ADJUSTED = 1 << 0,
}; };
extern struct attribute_group nvdimm_bus_attribute_group; extern struct attribute_group nvdimm_bus_attribute_group;
......
...@@ -50,6 +50,26 @@ struct nd_namespace_pmem { ...@@ -50,6 +50,26 @@ struct nd_namespace_pmem {
u8 *uuid; u8 *uuid;
}; };
/**
* struct nd_namespace_blk - namespace for dimm-bounded persistent memory
* @dev: namespace device creation by the nd region driver
* @alt_name: namespace name supplied in the dimm label
* @uuid: namespace name supplied in the dimm label
* @id: ida allocated id
* @lbasize: blk namespaces have a native sector size when btt not present
* @num_resources: number of dpa extents to claim
* @res: discontiguous dpa extents for given dimm
*/
struct nd_namespace_blk {
struct device dev;
char *alt_name;
u8 *uuid;
int id;
unsigned long lbasize;
int num_resources;
struct resource **res;
};
static inline struct nd_namespace_io *to_nd_namespace_io(struct device *dev) static inline struct nd_namespace_io *to_nd_namespace_io(struct device *dev)
{ {
return container_of(dev, struct nd_namespace_io, dev); return container_of(dev, struct nd_namespace_io, dev);
...@@ -62,6 +82,11 @@ static inline struct nd_namespace_pmem *to_nd_namespace_pmem(struct device *dev) ...@@ -62,6 +82,11 @@ static inline struct nd_namespace_pmem *to_nd_namespace_pmem(struct device *dev)
return container_of(nsio, struct nd_namespace_pmem, nsio); return container_of(nsio, struct nd_namespace_pmem, nsio);
} }
static inline struct nd_namespace_blk *to_nd_namespace_blk(struct device *dev)
{
return container_of(dev, struct nd_namespace_blk, dev);
}
#define MODULE_ALIAS_ND_DEVICE(type) \ #define MODULE_ALIAS_ND_DEVICE(type) \
MODULE_ALIAS("nd:t" __stringify(type) "*") MODULE_ALIAS("nd:t" __stringify(type) "*")
#define ND_DEVICE_MODALIAS_FMT "nd:t%d" #define ND_DEVICE_MODALIAS_FMT "nd:t%d"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment