summaryrefslogtreecommitdiff
path: root/drivers/nvdimm/dimm_devs.c
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2018-12-14 01:36:18 +0300
committerDan Williams <dan.j.williams@intel.com>2018-12-21 23:44:41 +0300
commit7d988097c546187ada602cc9bccd0f03d473eb8f (patch)
treeb12b12421f99c50d61fdf2485981933ed7ff5dcd /drivers/nvdimm/dimm_devs.c
parent64e77c8c047fb91ea8c7800c1238108a72f0bf9c (diff)
downloadlinux-7d988097c546187ada602cc9bccd0f03d473eb8f.tar.xz
acpi/nfit, libnvdimm/security: Add security DSM overwrite support
Add support for the NVDIMM_FAMILY_INTEL "ovewrite" capability as described by the Intel DSM spec v1.7. This will allow triggering of overwrite on Intel NVDIMMs. The overwrite operation can take tens of minutes. When the overwrite DSM is issued successfully, the NVDIMMs will be unaccessible. The kernel will do backoff polling to detect when the overwrite process is completed. According to the DSM spec v1.7, the 128G NVDIMMs can take up to 15mins to perform overwrite and larger DIMMs will take longer. Given that overwrite puts the DIMM in an indeterminate state until it completes introduce the NDD_SECURITY_OVERWRITE flag to prevent other operations from executing when overwrite is happening. The NDD_WORK_PENDING flag is added to denote that there is a device reference on the nvdimm device for an async workqueue thread context. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm/dimm_devs.c')
-rw-r--r--drivers/nvdimm/dimm_devs.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index bc432b7c17b8..6affa270abd3 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -395,7 +395,8 @@ static ssize_t security_show(struct device *dev,
C( OP_FREEZE, "freeze", 1), \
C( OP_DISABLE, "disable", 2), \
C( OP_UPDATE, "update", 3), \
- C( OP_ERASE, "erase", 2)
+ C( OP_ERASE, "erase", 2), \
+ C( OP_OVERWRITE, "overwrite", 2)
#undef C
#define C(a, b, c) a
enum nvdimmsec_op_ids { OPS };
@@ -452,6 +453,9 @@ static ssize_t __security_store(struct device *dev, const char *buf, size_t len)
} else if (i == OP_ERASE) {
dev_dbg(dev, "erase %u\n", key);
rc = nvdimm_security_erase(nvdimm, key);
+ } else if (i == OP_OVERWRITE) {
+ dev_dbg(dev, "overwrite %u\n", key);
+ rc = nvdimm_security_overwrite(nvdimm, key);
} else
return -EINVAL;
@@ -503,7 +507,8 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n)
/* Are there any state mutation ops? */
if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable
|| nvdimm->sec.ops->change_key
- || nvdimm->sec.ops->erase)
+ || nvdimm->sec.ops->erase
+ || nvdimm->sec.ops->overwrite)
return a->mode;
return 0444;
}
@@ -546,6 +551,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
dev->devt = MKDEV(nvdimm_major, nvdimm->id);
dev->groups = groups;
nvdimm->sec.ops = sec_ops;
+ nvdimm->sec.overwrite_tmo = 0;
+ INIT_DELAYED_WORK(&nvdimm->dwork, nvdimm_security_overwrite_query);
/*
* Security state must be initialized before device_add() for
* attribute visibility.
@@ -557,6 +564,22 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
}
EXPORT_SYMBOL_GPL(__nvdimm_create);
+int nvdimm_security_setup_events(struct nvdimm *nvdimm)
+{
+ nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd,
+ "security");
+ if (!nvdimm->sec.overwrite_state)
+ return -ENODEV;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvdimm_security_setup_events);
+
+int nvdimm_in_overwrite(struct nvdimm *nvdimm)
+{
+ return test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags);
+}
+EXPORT_SYMBOL_GPL(nvdimm_in_overwrite);
+
int nvdimm_security_freeze(struct nvdimm *nvdimm)
{
int rc;
@@ -569,6 +592,11 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm)
if (nvdimm->sec.state < 0)
return -EIO;
+ if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) {
+ dev_warn(&nvdimm->dev, "Overwrite operation in progress.\n");
+ return -EBUSY;
+ }
+
rc = nvdimm->sec.ops->freeze(nvdimm);
nvdimm->sec.state = nvdimm_security_state(nvdimm);