path: root/drivers/nvdimm/region_devs.c
diff options
authorDan Williams <dan.j.williams@intel.com>2015-06-23 20:08:34 -0400
committerDan Williams <dan.j.williams@intel.com>2015-06-26 11:23:38 -0400
commit581388209405902b56d055f644b4dd124a206112 (patch)
tree2160b6616cf072396067ca654cd5231e139fc304 /drivers/nvdimm/region_devs.c
parent0f51c4fa7f60838a87cd45e8ba144dddcd4c066c (diff)
libnvdimm, nfit: handle unarmed dimms, mark namespaces read-only
Upon detection of an unarmed dimm in a region, arrange for descendant BTT, PMEM, or BLK instances to be read-only. A dimm is primarily marked "unarmed" via flags passed by platform firmware (NFIT). The flags in the NFIT memory device sub-structure indicate the state of the data on the nvdimm relative to its energy source or last "flush to persistence". For the most part there is nothing the driver can do but advertise the state of these flags in sysfs and emit a message if firmware indicates that the contents of the device may be corrupted. However, for the case of ACPI_NFIT_MEM_ARMED, the driver can arrange for the block devices incorporating that nvdimm to be marked read-only. This is a safe default as the data is still available and new writes are held off until the administrator either forces read-write mode, or the energy source becomes armed. A 'read_only' attribute is added to REGION devices to allow for overriding the default read-only policy of all descendant block devices. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm/region_devs.c')
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 2cfb3f74bcbf..482ee3e4e04a 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -345,11 +345,35 @@ static ssize_t btt_seed_show(struct device *dev,
static DEVICE_ATTR_RO(btt_seed);
+static ssize_t read_only_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ struct nd_region *nd_region = to_nd_region(dev);
+ return sprintf(buf, "%d\n", nd_region->ro);
+static ssize_t read_only_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+ bool ro;
+ int rc = strtobool(buf, &ro);
+ struct nd_region *nd_region = to_nd_region(dev);
+ if (rc)
+ return rc;
+ nd_region->ro = ro;
+ return len;
+static DEVICE_ATTR_RW(read_only);
static struct attribute *nd_region_attributes[] = {
+ &dev_attr_read_only.attr,
@@ -641,6 +665,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
struct device *dev;
void *region_buf;
unsigned int i;
+ int ro = 0;
for (i = 0; i < ndr_desc->num_mappings; i++) {
struct nd_mapping *nd_mapping = &ndr_desc->nd_mapping[i];
@@ -652,6 +677,9 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
return NULL;
+ if (nvdimm->flags & NDD_UNARMED)
+ ro = 1;
if (dev_type == &nd_blk_device_type) {
@@ -707,6 +735,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
nd_region->provider_data = ndr_desc->provider_data;
nd_region->nd_set = ndr_desc->nd_set;
nd_region->num_lanes = ndr_desc->num_lanes;
+ nd_region->ro = ro;
dev = &nd_region->dev;