diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-21 13:55:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-21 13:55:29 -0400 |
commit | 6cb2e9ee51b5f1539f027346a02904e282b87d4d (patch) | |
tree | bf940785b622e8792ae943af9b92f55c5202612e | |
parent | 10fd71780f7d155f4e35fecfad0ebd4a725a244b (diff) | |
parent | 5b26db95fee3f1ce0d096b2de0ac6f3716171093 (diff) |
Merge tag 'libnvdimm-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams:
"Some reworks to better support nvdimms on powerpc and an nvdimm
security interface update:
- Rework the nvdimm core to accommodate architectures with different
page sizes and ones that can change supported huge page sizes at
boot time rather than a compile time constant.
- Introduce a distinct 'frozen' attribute for the nvdimm security
state since it is independent of the locked state.
- Miscellaneous fixups"
* tag 'libnvdimm-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
libnvdimm: Use PAGE_SIZE instead of SZ_4K for align check
libnvdimm/label: Remove the dpa align check
libnvdimm/pfn_dev: Add page size and struct page size to pfn superblock
libnvdimm/pfn_dev: Add a build check to make sure we notice when struct page size change
libnvdimm/pmem: Advance namespace seed for specific probe errors
libnvdimm/region: Rewrite _probe_success() to _advance_seeds()
libnvdimm/security: Consolidate 'security' operations
libnvdimm/security: Tighten scope of nvdimm->busy vs security operations
libnvdimm/security: Introduce a 'frozen' attribute
libnvdimm, region: Use struct_size() in kzalloc()
tools/testing/nvdimm: Fix fallthrough warning
libnvdimm/of_pmem: Provide a unique name for bus provider
-rw-r--r-- | drivers/acpi/nfit/intel.c | 59 | ||||
-rw-r--r-- | drivers/nvdimm/bus.c | 10 | ||||
-rw-r--r-- | drivers/nvdimm/dimm_devs.c | 134 | ||||
-rw-r--r-- | drivers/nvdimm/label.c | 5 | ||||
-rw-r--r-- | drivers/nvdimm/namespace_devs.c | 40 | ||||
-rw-r--r-- | drivers/nvdimm/nd-core.h | 54 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 4 | ||||
-rw-r--r-- | drivers/nvdimm/of_pmem.c | 2 | ||||
-rw-r--r-- | drivers/nvdimm/pfn.h | 5 | ||||
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 35 | ||||
-rw-r--r-- | drivers/nvdimm/pmem.c | 29 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 83 | ||||
-rw-r--r-- | drivers/nvdimm/security.c | 199 | ||||
-rw-r--r-- | include/linux/libnvdimm.h | 9 | ||||
-rw-r--r-- | tools/testing/nvdimm/dimm_devs.c | 19 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 3 |
16 files changed, 346 insertions, 344 deletions
diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index cddd0fcf622c..1113b679cd7b 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c | |||
@@ -7,10 +7,11 @@ | |||
7 | #include "intel.h" | 7 | #include "intel.h" |
8 | #include "nfit.h" | 8 | #include "nfit.h" |
9 | 9 | ||
10 | static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, | 10 | static unsigned long intel_security_flags(struct nvdimm *nvdimm, |
11 | enum nvdimm_passphrase_type ptype) | 11 | enum nvdimm_passphrase_type ptype) |
12 | { | 12 | { |
13 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 13 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); |
14 | unsigned long security_flags = 0; | ||
14 | struct { | 15 | struct { |
15 | struct nd_cmd_pkg pkg; | 16 | struct nd_cmd_pkg pkg; |
16 | struct nd_intel_get_security_state cmd; | 17 | struct nd_intel_get_security_state cmd; |
@@ -27,7 +28,7 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, | |||
27 | int rc; | 28 | int rc; |
28 | 29 | ||
29 | if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) | 30 | if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) |
30 | return -ENXIO; | 31 | return 0; |
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Short circuit the state retrieval while we are doing overwrite. | 34 | * Short circuit the state retrieval while we are doing overwrite. |
@@ -35,38 +36,42 @@ static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, | |||
35 | * until the overwrite DSM completes. | 36 | * until the overwrite DSM completes. |
36 | */ | 37 | */ |
37 | if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) | 38 | if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) |
38 | return NVDIMM_SECURITY_OVERWRITE; | 39 | return BIT(NVDIMM_SECURITY_OVERWRITE); |
39 | 40 | ||
40 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | 41 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); |
41 | if (rc < 0) | 42 | if (rc < 0 || nd_cmd.cmd.status) { |
42 | return rc; | 43 | pr_err("%s: security state retrieval failed (%d:%#x)\n", |
43 | if (nd_cmd.cmd.status) | 44 | nvdimm_name(nvdimm), rc, nd_cmd.cmd.status); |
44 | return -EIO; | 45 | return 0; |
46 | } | ||
45 | 47 | ||
46 | /* check and see if security is enabled and locked */ | 48 | /* check and see if security is enabled and locked */ |
47 | if (ptype == NVDIMM_MASTER) { | 49 | if (ptype == NVDIMM_MASTER) { |
48 | if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) | 50 | if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) |
49 | return NVDIMM_SECURITY_UNLOCKED; | 51 | set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); |
50 | else if (nd_cmd.cmd.extended_state & | 52 | else |
51 | ND_INTEL_SEC_ESTATE_PLIMIT) | 53 | set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); |
52 | return NVDIMM_SECURITY_FROZEN; | 54 | if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_PLIMIT) |
53 | } else { | 55 | set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); |
54 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) | 56 | return security_flags; |
55 | return -ENXIO; | ||
56 | else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { | ||
57 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) | ||
58 | return NVDIMM_SECURITY_LOCKED; | ||
59 | else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN | ||
60 | || nd_cmd.cmd.state & | ||
61 | ND_INTEL_SEC_STATE_PLIMIT) | ||
62 | return NVDIMM_SECURITY_FROZEN; | ||
63 | else | ||
64 | return NVDIMM_SECURITY_UNLOCKED; | ||
65 | } | ||
66 | } | 57 | } |
67 | 58 | ||
68 | /* this should cover master security disabled as well */ | 59 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) |
69 | return NVDIMM_SECURITY_DISABLED; | 60 | return 0; |
61 | |||
62 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { | ||
63 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN || | ||
64 | nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT) | ||
65 | set_bit(NVDIMM_SECURITY_FROZEN, &security_flags); | ||
66 | |||
67 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) | ||
68 | set_bit(NVDIMM_SECURITY_LOCKED, &security_flags); | ||
69 | else | ||
70 | set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags); | ||
71 | } else | ||
72 | set_bit(NVDIMM_SECURITY_DISABLED, &security_flags); | ||
73 | |||
74 | return security_flags; | ||
70 | } | 75 | } |
71 | 76 | ||
72 | static int intel_security_freeze(struct nvdimm *nvdimm) | 77 | static int intel_security_freeze(struct nvdimm *nvdimm) |
@@ -371,7 +376,7 @@ static void nvdimm_invalidate_cache(void) | |||
371 | #endif | 376 | #endif |
372 | 377 | ||
373 | static const struct nvdimm_security_ops __intel_security_ops = { | 378 | static const struct nvdimm_security_ops __intel_security_ops = { |
374 | .state = intel_security_state, | 379 | .get_flags = intel_security_flags, |
375 | .freeze = intel_security_freeze, | 380 | .freeze = intel_security_freeze, |
376 | .change_key = intel_security_change_key, | 381 | .change_key = intel_security_change_key, |
377 | .disable = intel_security_disable, | 382 | .disable = intel_security_disable, |
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 798c5c4aea9c..75a58a6e9615 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
@@ -95,10 +95,9 @@ static int nvdimm_bus_probe(struct device *dev) | |||
95 | rc = nd_drv->probe(dev); | 95 | rc = nd_drv->probe(dev); |
96 | debug_nvdimm_unlock(dev); | 96 | debug_nvdimm_unlock(dev); |
97 | 97 | ||
98 | if (rc == 0) | 98 | if ((rc == 0 || rc == -EOPNOTSUPP) && |
99 | nd_region_probe_success(nvdimm_bus, dev); | 99 | dev->parent && is_nd_region(dev->parent)) |
100 | else | 100 | nd_region_advance_seeds(to_nd_region(dev->parent), dev); |
101 | nd_region_disable(nvdimm_bus, dev); | ||
102 | nvdimm_bus_probe_end(nvdimm_bus); | 101 | nvdimm_bus_probe_end(nvdimm_bus); |
103 | 102 | ||
104 | dev_dbg(&nvdimm_bus->dev, "END: %s.probe(%s) = %d\n", dev->driver->name, | 103 | dev_dbg(&nvdimm_bus->dev, "END: %s.probe(%s) = %d\n", dev->driver->name, |
@@ -121,7 +120,6 @@ static int nvdimm_bus_remove(struct device *dev) | |||
121 | rc = nd_drv->remove(dev); | 120 | rc = nd_drv->remove(dev); |
122 | debug_nvdimm_unlock(dev); | 121 | debug_nvdimm_unlock(dev); |
123 | } | 122 | } |
124 | nd_region_disable(nvdimm_bus, dev); | ||
125 | 123 | ||
126 | dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, | 124 | dev_dbg(&nvdimm_bus->dev, "%s.remove(%s) = %d\n", dev->driver->name, |
127 | dev_name(dev), rc); | 125 | dev_name(dev), rc); |
@@ -400,7 +398,7 @@ static int child_unregister(struct device *dev, void *data) | |||
400 | 398 | ||
401 | /* We are shutting down. Make state frozen artificially. */ | 399 | /* We are shutting down. Make state frozen artificially. */ |
402 | nvdimm_bus_lock(dev); | 400 | nvdimm_bus_lock(dev); |
403 | nvdimm->sec.state = NVDIMM_SECURITY_FROZEN; | 401 | set_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags); |
404 | if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) | 402 | if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) |
405 | dev_put = true; | 403 | dev_put = true; |
406 | nvdimm_bus_unlock(dev); | 404 | nvdimm_bus_unlock(dev); |
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 29a065e769ea..196aa44c4936 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
@@ -372,106 +372,26 @@ __weak ssize_t security_show(struct device *dev, | |||
372 | { | 372 | { |
373 | struct nvdimm *nvdimm = to_nvdimm(dev); | 373 | struct nvdimm *nvdimm = to_nvdimm(dev); |
374 | 374 | ||
375 | switch (nvdimm->sec.state) { | 375 | if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags)) |
376 | case NVDIMM_SECURITY_DISABLED: | ||
377 | return sprintf(buf, "disabled\n"); | 376 | return sprintf(buf, "disabled\n"); |
378 | case NVDIMM_SECURITY_UNLOCKED: | 377 | if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) |
379 | return sprintf(buf, "unlocked\n"); | 378 | return sprintf(buf, "unlocked\n"); |
380 | case NVDIMM_SECURITY_LOCKED: | 379 | if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags)) |
381 | return sprintf(buf, "locked\n"); | 380 | return sprintf(buf, "locked\n"); |
382 | case NVDIMM_SECURITY_FROZEN: | 381 | if (test_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags)) |
383 | return sprintf(buf, "frozen\n"); | ||
384 | case NVDIMM_SECURITY_OVERWRITE: | ||
385 | return sprintf(buf, "overwrite\n"); | 382 | return sprintf(buf, "overwrite\n"); |
386 | default: | ||
387 | return -ENOTTY; | ||
388 | } | ||
389 | |||
390 | return -ENOTTY; | 383 | return -ENOTTY; |
391 | } | 384 | } |
392 | 385 | ||
393 | #define OPS \ | 386 | static ssize_t frozen_show(struct device *dev, |
394 | C( OP_FREEZE, "freeze", 1), \ | 387 | struct device_attribute *attr, char *buf) |
395 | C( OP_DISABLE, "disable", 2), \ | ||
396 | C( OP_UPDATE, "update", 3), \ | ||
397 | C( OP_ERASE, "erase", 2), \ | ||
398 | C( OP_OVERWRITE, "overwrite", 2), \ | ||
399 | C( OP_MASTER_UPDATE, "master_update", 3), \ | ||
400 | C( OP_MASTER_ERASE, "master_erase", 2) | ||
401 | #undef C | ||
402 | #define C(a, b, c) a | ||
403 | enum nvdimmsec_op_ids { OPS }; | ||
404 | #undef C | ||
405 | #define C(a, b, c) { b, c } | ||
406 | static struct { | ||
407 | const char *name; | ||
408 | int args; | ||
409 | } ops[] = { OPS }; | ||
410 | #undef C | ||
411 | |||
412 | #define SEC_CMD_SIZE 32 | ||
413 | #define KEY_ID_SIZE 10 | ||
414 | |||
415 | static ssize_t __security_store(struct device *dev, const char *buf, size_t len) | ||
416 | { | 388 | { |
417 | struct nvdimm *nvdimm = to_nvdimm(dev); | 389 | struct nvdimm *nvdimm = to_nvdimm(dev); |
418 | ssize_t rc; | ||
419 | char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1], | ||
420 | nkeystr[KEY_ID_SIZE+1]; | ||
421 | unsigned int key, newkey; | ||
422 | int i; | ||
423 | 390 | ||
424 | if (atomic_read(&nvdimm->busy)) | 391 | return sprintf(buf, "%d\n", test_bit(NVDIMM_SECURITY_FROZEN, |
425 | return -EBUSY; | 392 | &nvdimm->sec.flags)); |
426 | |||
427 | rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s" | ||
428 | " %"__stringify(KEY_ID_SIZE)"s" | ||
429 | " %"__stringify(KEY_ID_SIZE)"s", | ||
430 | cmd, keystr, nkeystr); | ||
431 | if (rc < 1) | ||
432 | return -EINVAL; | ||
433 | for (i = 0; i < ARRAY_SIZE(ops); i++) | ||
434 | if (sysfs_streq(cmd, ops[i].name)) | ||
435 | break; | ||
436 | if (i >= ARRAY_SIZE(ops)) | ||
437 | return -EINVAL; | ||
438 | if (ops[i].args > 1) | ||
439 | rc = kstrtouint(keystr, 0, &key); | ||
440 | if (rc >= 0 && ops[i].args > 2) | ||
441 | rc = kstrtouint(nkeystr, 0, &newkey); | ||
442 | if (rc < 0) | ||
443 | return rc; | ||
444 | |||
445 | if (i == OP_FREEZE) { | ||
446 | dev_dbg(dev, "freeze\n"); | ||
447 | rc = nvdimm_security_freeze(nvdimm); | ||
448 | } else if (i == OP_DISABLE) { | ||
449 | dev_dbg(dev, "disable %u\n", key); | ||
450 | rc = nvdimm_security_disable(nvdimm, key); | ||
451 | } else if (i == OP_UPDATE) { | ||
452 | dev_dbg(dev, "update %u %u\n", key, newkey); | ||
453 | rc = nvdimm_security_update(nvdimm, key, newkey, NVDIMM_USER); | ||
454 | } else if (i == OP_ERASE) { | ||
455 | dev_dbg(dev, "erase %u\n", key); | ||
456 | rc = nvdimm_security_erase(nvdimm, key, NVDIMM_USER); | ||
457 | } else if (i == OP_OVERWRITE) { | ||
458 | dev_dbg(dev, "overwrite %u\n", key); | ||
459 | rc = nvdimm_security_overwrite(nvdimm, key); | ||
460 | } else if (i == OP_MASTER_UPDATE) { | ||
461 | dev_dbg(dev, "master_update %u %u\n", key, newkey); | ||
462 | rc = nvdimm_security_update(nvdimm, key, newkey, | ||
463 | NVDIMM_MASTER); | ||
464 | } else if (i == OP_MASTER_ERASE) { | ||
465 | dev_dbg(dev, "master_erase %u\n", key); | ||
466 | rc = nvdimm_security_erase(nvdimm, key, | ||
467 | NVDIMM_MASTER); | ||
468 | } else | ||
469 | return -EINVAL; | ||
470 | |||
471 | if (rc == 0) | ||
472 | rc = len; | ||
473 | return rc; | ||
474 | } | 393 | } |
394 | static DEVICE_ATTR_RO(frozen); | ||
475 | 395 | ||
476 | static ssize_t security_store(struct device *dev, | 396 | static ssize_t security_store(struct device *dev, |
477 | struct device_attribute *attr, const char *buf, size_t len) | 397 | struct device_attribute *attr, const char *buf, size_t len) |
@@ -487,7 +407,7 @@ static ssize_t security_store(struct device *dev, | |||
487 | nd_device_lock(dev); | 407 | nd_device_lock(dev); |
488 | nvdimm_bus_lock(dev); | 408 | nvdimm_bus_lock(dev); |
489 | wait_nvdimm_bus_probe_idle(dev); | 409 | wait_nvdimm_bus_probe_idle(dev); |
490 | rc = __security_store(dev, buf, len); | 410 | rc = nvdimm_security_store(dev, buf, len); |
491 | nvdimm_bus_unlock(dev); | 411 | nvdimm_bus_unlock(dev); |
492 | nd_device_unlock(dev); | 412 | nd_device_unlock(dev); |
493 | 413 | ||
@@ -501,6 +421,7 @@ static struct attribute *nvdimm_attributes[] = { | |||
501 | &dev_attr_commands.attr, | 421 | &dev_attr_commands.attr, |
502 | &dev_attr_available_slots.attr, | 422 | &dev_attr_available_slots.attr, |
503 | &dev_attr_security.attr, | 423 | &dev_attr_security.attr, |
424 | &dev_attr_frozen.attr, | ||
504 | NULL, | 425 | NULL, |
505 | }; | 426 | }; |
506 | 427 | ||
@@ -509,17 +430,24 @@ static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) | |||
509 | struct device *dev = container_of(kobj, typeof(*dev), kobj); | 430 | struct device *dev = container_of(kobj, typeof(*dev), kobj); |
510 | struct nvdimm *nvdimm = to_nvdimm(dev); | 431 | struct nvdimm *nvdimm = to_nvdimm(dev); |
511 | 432 | ||
512 | if (a != &dev_attr_security.attr) | 433 | if (a != &dev_attr_security.attr && a != &dev_attr_frozen.attr) |
513 | return a->mode; | 434 | return a->mode; |
514 | if (nvdimm->sec.state < 0) | 435 | if (!nvdimm->sec.flags) |
515 | return 0; | 436 | return 0; |
516 | /* Are there any state mutation ops? */ | 437 | |
517 | if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable | 438 | if (a == &dev_attr_security.attr) { |
518 | || nvdimm->sec.ops->change_key | 439 | /* Are there any state mutation ops (make writable)? */ |
519 | || nvdimm->sec.ops->erase | 440 | if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable |
520 | || nvdimm->sec.ops->overwrite) | 441 | || nvdimm->sec.ops->change_key |
442 | || nvdimm->sec.ops->erase | ||
443 | || nvdimm->sec.ops->overwrite) | ||
444 | return a->mode; | ||
445 | return 0444; | ||
446 | } | ||
447 | |||
448 | if (nvdimm->sec.ops->freeze) | ||
521 | return a->mode; | 449 | return a->mode; |
522 | return 0444; | 450 | return 0; |
523 | } | 451 | } |
524 | 452 | ||
525 | struct attribute_group nvdimm_attribute_group = { | 453 | struct attribute_group nvdimm_attribute_group = { |
@@ -569,8 +497,8 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, | |||
569 | * attribute visibility. | 497 | * attribute visibility. |
570 | */ | 498 | */ |
571 | /* get security state and extended (master) state */ | 499 | /* get security state and extended (master) state */ |
572 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 500 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
573 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); | 501 | nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER); |
574 | nd_device_register(dev); | 502 | nd_device_register(dev); |
575 | 503 | ||
576 | return nvdimm; | 504 | return nvdimm; |
@@ -588,7 +516,7 @@ int nvdimm_security_setup_events(struct device *dev) | |||
588 | { | 516 | { |
589 | struct nvdimm *nvdimm = to_nvdimm(dev); | 517 | struct nvdimm *nvdimm = to_nvdimm(dev); |
590 | 518 | ||
591 | if (nvdimm->sec.state < 0 || !nvdimm->sec.ops | 519 | if (!nvdimm->sec.flags || !nvdimm->sec.ops |
592 | || !nvdimm->sec.ops->overwrite) | 520 | || !nvdimm->sec.ops->overwrite) |
593 | return 0; | 521 | return 0; |
594 | nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security"); | 522 | nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security"); |
@@ -614,7 +542,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) | |||
614 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze) | 542 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze) |
615 | return -EOPNOTSUPP; | 543 | return -EOPNOTSUPP; |
616 | 544 | ||
617 | if (nvdimm->sec.state < 0) | 545 | if (!nvdimm->sec.flags) |
618 | return -EIO; | 546 | return -EIO; |
619 | 547 | ||
620 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | 548 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { |
@@ -623,7 +551,7 @@ int nvdimm_security_freeze(struct nvdimm *nvdimm) | |||
623 | } | 551 | } |
624 | 552 | ||
625 | rc = nvdimm->sec.ops->freeze(nvdimm); | 553 | rc = nvdimm->sec.ops->freeze(nvdimm); |
626 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 554 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
627 | 555 | ||
628 | return rc; | 556 | return rc; |
629 | } | 557 | } |
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 73e197babc2f..47a4828b8b31 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c | |||
@@ -353,11 +353,6 @@ static bool slot_valid(struct nvdimm_drvdata *ndd, | |||
353 | if (slot != __le32_to_cpu(nd_label->slot)) | 353 | if (slot != __le32_to_cpu(nd_label->slot)) |
354 | return false; | 354 | return false; |
355 | 355 | ||
356 | /* check that DPA allocations are page aligned */ | ||
357 | if ((__le64_to_cpu(nd_label->dpa) | ||
358 | | __le64_to_cpu(nd_label->rawsize)) % SZ_4K) | ||
359 | return false; | ||
360 | |||
361 | /* check checksum */ | 356 | /* check checksum */ |
362 | if (namespace_label_has(ndd, checksum)) { | 357 | if (namespace_label_has(ndd, checksum)) { |
363 | u64 sum, sum_save; | 358 | u64 sum, sum_save; |
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index a16e52251a30..43401325c874 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
@@ -1006,10 +1006,10 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) | |||
1006 | return -ENXIO; | 1006 | return -ENXIO; |
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | div_u64_rem(val, SZ_4K * nd_region->ndr_mappings, &remainder); | 1009 | div_u64_rem(val, PAGE_SIZE * nd_region->ndr_mappings, &remainder); |
1010 | if (remainder) { | 1010 | if (remainder) { |
1011 | dev_dbg(dev, "%llu is not %dK aligned\n", val, | 1011 | dev_dbg(dev, "%llu is not %ldK aligned\n", val, |
1012 | (SZ_4K * nd_region->ndr_mappings) / SZ_1K); | 1012 | (PAGE_SIZE * nd_region->ndr_mappings) / SZ_1K); |
1013 | return -EINVAL; | 1013 | return -EINVAL; |
1014 | } | 1014 | } |
1015 | 1015 | ||
@@ -2462,6 +2462,27 @@ static struct device **create_namespaces(struct nd_region *nd_region) | |||
2462 | return devs; | 2462 | return devs; |
2463 | } | 2463 | } |
2464 | 2464 | ||
2465 | static void deactivate_labels(void *region) | ||
2466 | { | ||
2467 | struct nd_region *nd_region = region; | ||
2468 | int i; | ||
2469 | |||
2470 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
2471 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
2472 | struct nvdimm_drvdata *ndd = nd_mapping->ndd; | ||
2473 | struct nvdimm *nvdimm = nd_mapping->nvdimm; | ||
2474 | |||
2475 | mutex_lock(&nd_mapping->lock); | ||
2476 | nd_mapping_free_labels(nd_mapping); | ||
2477 | mutex_unlock(&nd_mapping->lock); | ||
2478 | |||
2479 | put_ndd(ndd); | ||
2480 | nd_mapping->ndd = NULL; | ||
2481 | if (ndd) | ||
2482 | atomic_dec(&nvdimm->busy); | ||
2483 | } | ||
2484 | } | ||
2485 | |||
2465 | static int init_active_labels(struct nd_region *nd_region) | 2486 | static int init_active_labels(struct nd_region *nd_region) |
2466 | { | 2487 | { |
2467 | int i; | 2488 | int i; |
@@ -2519,16 +2540,17 @@ static int init_active_labels(struct nd_region *nd_region) | |||
2519 | mutex_unlock(&nd_mapping->lock); | 2540 | mutex_unlock(&nd_mapping->lock); |
2520 | } | 2541 | } |
2521 | 2542 | ||
2522 | if (j >= count) | 2543 | if (j < count) |
2523 | continue; | 2544 | break; |
2545 | } | ||
2524 | 2546 | ||
2525 | mutex_lock(&nd_mapping->lock); | 2547 | if (i < nd_region->ndr_mappings) { |
2526 | nd_mapping_free_labels(nd_mapping); | 2548 | deactivate_labels(nd_region); |
2527 | mutex_unlock(&nd_mapping->lock); | ||
2528 | return -ENOMEM; | 2549 | return -ENOMEM; |
2529 | } | 2550 | } |
2530 | 2551 | ||
2531 | return 0; | 2552 | return devm_add_action_or_reset(&nd_region->dev, deactivate_labels, |
2553 | nd_region); | ||
2532 | } | 2554 | } |
2533 | 2555 | ||
2534 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err) | 2556 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err) |
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 0ac52b6eb00e..25fa121104d0 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h | |||
@@ -39,53 +39,40 @@ struct nvdimm { | |||
39 | const char *dimm_id; | 39 | const char *dimm_id; |
40 | struct { | 40 | struct { |
41 | const struct nvdimm_security_ops *ops; | 41 | const struct nvdimm_security_ops *ops; |
42 | enum nvdimm_security_state state; | 42 | unsigned long flags; |
43 | enum nvdimm_security_state ext_state; | 43 | unsigned long ext_flags; |
44 | unsigned int overwrite_tmo; | 44 | unsigned int overwrite_tmo; |
45 | struct kernfs_node *overwrite_state; | 45 | struct kernfs_node *overwrite_state; |
46 | } sec; | 46 | } sec; |
47 | struct delayed_work dwork; | 47 | struct delayed_work dwork; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static inline enum nvdimm_security_state nvdimm_security_state( | 50 | static inline unsigned long nvdimm_security_flags( |
51 | struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype) | 51 | struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype) |
52 | { | 52 | { |
53 | u64 flags; | ||
54 | const u64 state_flags = 1UL << NVDIMM_SECURITY_DISABLED | ||
55 | | 1UL << NVDIMM_SECURITY_LOCKED | ||
56 | | 1UL << NVDIMM_SECURITY_UNLOCKED | ||
57 | | 1UL << NVDIMM_SECURITY_OVERWRITE; | ||
58 | |||
53 | if (!nvdimm->sec.ops) | 59 | if (!nvdimm->sec.ops) |
54 | return -ENXIO; | 60 | return 0; |
55 | 61 | ||
56 | return nvdimm->sec.ops->state(nvdimm, ptype); | 62 | flags = nvdimm->sec.ops->get_flags(nvdimm, ptype); |
63 | /* disabled, locked, unlocked, and overwrite are mutually exclusive */ | ||
64 | dev_WARN_ONCE(&nvdimm->dev, hweight64(flags & state_flags) > 1, | ||
65 | "reported invalid security state: %#llx\n", | ||
66 | (unsigned long long) flags); | ||
67 | return flags; | ||
57 | } | 68 | } |
58 | int nvdimm_security_freeze(struct nvdimm *nvdimm); | 69 | int nvdimm_security_freeze(struct nvdimm *nvdimm); |
59 | #if IS_ENABLED(CONFIG_NVDIMM_KEYS) | 70 | #if IS_ENABLED(CONFIG_NVDIMM_KEYS) |
60 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); | 71 | ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len); |
61 | int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | ||
62 | unsigned int new_keyid, | ||
63 | enum nvdimm_passphrase_type pass_type); | ||
64 | int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | ||
65 | enum nvdimm_passphrase_type pass_type); | ||
66 | int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid); | ||
67 | void nvdimm_security_overwrite_query(struct work_struct *work); | 72 | void nvdimm_security_overwrite_query(struct work_struct *work); |
68 | #else | 73 | #else |
69 | static inline int nvdimm_security_disable(struct nvdimm *nvdimm, | 74 | static inline ssize_t nvdimm_security_store(struct device *dev, |
70 | unsigned int keyid) | 75 | const char *buf, size_t len) |
71 | { | ||
72 | return -EOPNOTSUPP; | ||
73 | } | ||
74 | static inline int nvdimm_security_update(struct nvdimm *nvdimm, | ||
75 | unsigned int keyid, | ||
76 | unsigned int new_keyid, | ||
77 | enum nvdimm_passphrase_type pass_type) | ||
78 | { | ||
79 | return -EOPNOTSUPP; | ||
80 | } | ||
81 | static inline int nvdimm_security_erase(struct nvdimm *nvdimm, | ||
82 | unsigned int keyid, | ||
83 | enum nvdimm_passphrase_type pass_type) | ||
84 | { | ||
85 | return -EOPNOTSUPP; | ||
86 | } | ||
87 | static inline int nvdimm_security_overwrite(struct nvdimm *nvdimm, | ||
88 | unsigned int keyid) | ||
89 | { | 76 | { |
90 | return -EOPNOTSUPP; | 77 | return -EOPNOTSUPP; |
91 | } | 78 | } |
@@ -128,13 +115,12 @@ int __init nvdimm_bus_init(void); | |||
128 | void nvdimm_bus_exit(void); | 115 | void nvdimm_bus_exit(void); |
129 | void nvdimm_devs_exit(void); | 116 | void nvdimm_devs_exit(void); |
130 | void nd_region_devs_exit(void); | 117 | void nd_region_devs_exit(void); |
131 | void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev); | ||
132 | struct nd_region; | 118 | struct nd_region; |
119 | void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev); | ||
133 | void nd_region_create_ns_seed(struct nd_region *nd_region); | 120 | void nd_region_create_ns_seed(struct nd_region *nd_region); |
134 | void nd_region_create_btt_seed(struct nd_region *nd_region); | 121 | void nd_region_create_btt_seed(struct nd_region *nd_region); |
135 | void nd_region_create_pfn_seed(struct nd_region *nd_region); | 122 | void nd_region_create_pfn_seed(struct nd_region *nd_region); |
136 | void nd_region_create_dax_seed(struct nd_region *nd_region); | 123 | void nd_region_create_dax_seed(struct nd_region *nd_region); |
137 | void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev); | ||
138 | int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); | 124 | int nvdimm_bus_create_ndctl(struct nvdimm_bus *nvdimm_bus); |
139 | void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); | 125 | void nvdimm_bus_destroy_ndctl(struct nvdimm_bus *nvdimm_bus); |
140 | void nd_synchronize(void); | 126 | void nd_synchronize(void); |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 1b9955651379..e89af4b2d8e9 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -375,6 +375,10 @@ unsigned int pmem_sector_size(struct nd_namespace_common *ndns); | |||
375 | void nvdimm_badblocks_populate(struct nd_region *nd_region, | 375 | void nvdimm_badblocks_populate(struct nd_region *nd_region, |
376 | struct badblocks *bb, const struct resource *res); | 376 | struct badblocks *bb, const struct resource *res); |
377 | #if IS_ENABLED(CONFIG_ND_CLAIM) | 377 | #if IS_ENABLED(CONFIG_ND_CLAIM) |
378 | |||
379 | /* max struct page size independent of kernel config */ | ||
380 | #define MAX_STRUCT_PAGE_SIZE 64 | ||
381 | |||
378 | int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap); | 382 | int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap); |
379 | int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio); | 383 | int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio); |
380 | void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio); | 384 | void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio); |
diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index a0c8dcfa0bf9..97187d6c0bdb 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c | |||
@@ -42,7 +42,7 @@ static int of_pmem_region_probe(struct platform_device *pdev) | |||
42 | return -ENOMEM; | 42 | return -ENOMEM; |
43 | 43 | ||
44 | priv->bus_desc.attr_groups = bus_attr_groups; | 44 | priv->bus_desc.attr_groups = bus_attr_groups; |
45 | priv->bus_desc.provider_name = "of_pmem"; | 45 | priv->bus_desc.provider_name = kstrdup(pdev->name, GFP_KERNEL); |
46 | priv->bus_desc.module = THIS_MODULE; | 46 | priv->bus_desc.module = THIS_MODULE; |
47 | priv->bus_desc.of_node = np; | 47 | priv->bus_desc.of_node = np; |
48 | 48 | ||
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h index 7381673b7b70..acb19517f678 100644 --- a/drivers/nvdimm/pfn.h +++ b/drivers/nvdimm/pfn.h | |||
@@ -29,7 +29,10 @@ struct nd_pfn_sb { | |||
29 | /* minor-version-2 record the base alignment of the mapping */ | 29 | /* minor-version-2 record the base alignment of the mapping */ |
30 | __le32 align; | 30 | __le32 align; |
31 | /* minor-version-3 guarantee the padding and flags are zero */ | 31 | /* minor-version-3 guarantee the padding and flags are zero */ |
32 | u8 padding[4000]; | 32 | /* minor-version-4 record the page size and struct page size */ |
33 | __le32 page_size; | ||
34 | __le16 page_struct_size; | ||
35 | u8 padding[3994]; | ||
33 | __le64 checksum; | 36 | __le64 checksum; |
34 | }; | 37 | }; |
35 | 38 | ||
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index cb98b8fe786e..bb9cc5cf0873 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c | |||
@@ -460,6 +460,11 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | |||
460 | if (__le16_to_cpu(pfn_sb->version_minor) < 2) | 460 | if (__le16_to_cpu(pfn_sb->version_minor) < 2) |
461 | pfn_sb->align = 0; | 461 | pfn_sb->align = 0; |
462 | 462 | ||
463 | if (__le16_to_cpu(pfn_sb->version_minor) < 4) { | ||
464 | pfn_sb->page_struct_size = cpu_to_le16(64); | ||
465 | pfn_sb->page_size = cpu_to_le32(PAGE_SIZE); | ||
466 | } | ||
467 | |||
463 | switch (le32_to_cpu(pfn_sb->mode)) { | 468 | switch (le32_to_cpu(pfn_sb->mode)) { |
464 | case PFN_MODE_RAM: | 469 | case PFN_MODE_RAM: |
465 | case PFN_MODE_PMEM: | 470 | case PFN_MODE_PMEM: |
@@ -475,6 +480,22 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | |||
475 | align = 1UL << ilog2(offset); | 480 | align = 1UL << ilog2(offset); |
476 | mode = le32_to_cpu(pfn_sb->mode); | 481 | mode = le32_to_cpu(pfn_sb->mode); |
477 | 482 | ||
483 | if ((le32_to_cpu(pfn_sb->page_size) > PAGE_SIZE) && | ||
484 | (mode == PFN_MODE_PMEM)) { | ||
485 | dev_err(&nd_pfn->dev, | ||
486 | "init failed, page size mismatch %d\n", | ||
487 | le32_to_cpu(pfn_sb->page_size)); | ||
488 | return -EOPNOTSUPP; | ||
489 | } | ||
490 | |||
491 | if ((le16_to_cpu(pfn_sb->page_struct_size) < sizeof(struct page)) && | ||
492 | (mode == PFN_MODE_PMEM)) { | ||
493 | dev_err(&nd_pfn->dev, | ||
494 | "init failed, struct page size mismatch %d\n", | ||
495 | le16_to_cpu(pfn_sb->page_struct_size)); | ||
496 | return -EOPNOTSUPP; | ||
497 | } | ||
498 | |||
478 | if (!nd_pfn->uuid) { | 499 | if (!nd_pfn->uuid) { |
479 | /* | 500 | /* |
480 | * When probing a namepace via nd_pfn_probe() the uuid | 501 | * When probing a namepace via nd_pfn_probe() the uuid |
@@ -703,8 +724,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
703 | * The altmap should be padded out to the block size used | 724 | * The altmap should be padded out to the block size used |
704 | * when populating the vmemmap. This *should* be equal to | 725 | * when populating the vmemmap. This *should* be equal to |
705 | * PMD_SIZE for most architectures. | 726 | * PMD_SIZE for most architectures. |
727 | * | ||
728 | * Also make sure size of struct page is less than 64. We | ||
729 | * want to make sure we use large enough size here so that | ||
730 | * we don't have a dynamic reserve space depending on | ||
731 | * struct page size. But we also want to make sure we notice | ||
732 | * when we end up adding new elements to struct page. | ||
706 | */ | 733 | */ |
707 | offset = ALIGN(start + SZ_8K + 64 * npfns, align) - start; | 734 | BUILD_BUG_ON(sizeof(struct page) > MAX_STRUCT_PAGE_SIZE); |
735 | offset = ALIGN(start + SZ_8K + MAX_STRUCT_PAGE_SIZE * npfns, align) | ||
736 | - start; | ||
708 | } else if (nd_pfn->mode == PFN_MODE_RAM) | 737 | } else if (nd_pfn->mode == PFN_MODE_RAM) |
709 | offset = ALIGN(start + SZ_8K, align) - start; | 738 | offset = ALIGN(start + SZ_8K, align) - start; |
710 | else | 739 | else |
@@ -724,9 +753,11 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
724 | memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); | 753 | memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); |
725 | memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); | 754 | memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); |
726 | pfn_sb->version_major = cpu_to_le16(1); | 755 | pfn_sb->version_major = cpu_to_le16(1); |
727 | pfn_sb->version_minor = cpu_to_le16(3); | 756 | pfn_sb->version_minor = cpu_to_le16(4); |
728 | pfn_sb->end_trunc = cpu_to_le32(end_trunc); | 757 | pfn_sb->end_trunc = cpu_to_le32(end_trunc); |
729 | pfn_sb->align = cpu_to_le32(nd_pfn->align); | 758 | pfn_sb->align = cpu_to_le32(nd_pfn->align); |
759 | pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE); | ||
760 | pfn_sb->page_size = cpu_to_le32(PAGE_SIZE); | ||
730 | checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); | 761 | checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); |
731 | pfn_sb->checksum = cpu_to_le64(checksum); | 762 | pfn_sb->checksum = cpu_to_le64(checksum); |
732 | 763 | ||
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 4c121dd03dd9..f9f76f6ba07b 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c | |||
@@ -490,6 +490,7 @@ static int pmem_attach_disk(struct device *dev, | |||
490 | 490 | ||
491 | static int nd_pmem_probe(struct device *dev) | 491 | static int nd_pmem_probe(struct device *dev) |
492 | { | 492 | { |
493 | int ret; | ||
493 | struct nd_namespace_common *ndns; | 494 | struct nd_namespace_common *ndns; |
494 | 495 | ||
495 | ndns = nvdimm_namespace_common_probe(dev); | 496 | ndns = nvdimm_namespace_common_probe(dev); |
@@ -505,12 +506,32 @@ static int nd_pmem_probe(struct device *dev) | |||
505 | if (is_nd_pfn(dev)) | 506 | if (is_nd_pfn(dev)) |
506 | return pmem_attach_disk(dev, ndns); | 507 | return pmem_attach_disk(dev, ndns); |
507 | 508 | ||
508 | /* if we find a valid info-block we'll come back as that personality */ | 509 | ret = nd_btt_probe(dev, ndns); |
509 | if (nd_btt_probe(dev, ndns) == 0 || nd_pfn_probe(dev, ndns) == 0 | 510 | if (ret == 0) |
510 | || nd_dax_probe(dev, ndns) == 0) | ||
511 | return -ENXIO; | 511 | return -ENXIO; |
512 | 512 | ||
513 | /* ...otherwise we're just a raw pmem device */ | 513 | /* |
514 | * We have two failure conditions here, there is no | ||
515 | * info reserver block or we found a valid info reserve block | ||
516 | * but failed to initialize the pfn superblock. | ||
517 | * | ||
518 | * For the first case consider namespace as a raw pmem namespace | ||
519 | * and attach a disk. | ||
520 | * | ||
521 | * For the latter, consider this a success and advance the namespace | ||
522 | * seed. | ||
523 | */ | ||
524 | ret = nd_pfn_probe(dev, ndns); | ||
525 | if (ret == 0) | ||
526 | return -ENXIO; | ||
527 | else if (ret == -EOPNOTSUPP) | ||
528 | return ret; | ||
529 | |||
530 | ret = nd_dax_probe(dev, ndns); | ||
531 | if (ret == 0) | ||
532 | return -ENXIO; | ||
533 | else if (ret == -EOPNOTSUPP) | ||
534 | return ret; | ||
514 | return pmem_attach_disk(dev, ndns); | 535 | return pmem_attach_disk(dev, ndns); |
515 | } | 536 | } |
516 | 537 | ||
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index af30cbe7a8ea..3fd6b59abd33 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
@@ -715,85 +715,37 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping) | |||
715 | } | 715 | } |
716 | 716 | ||
717 | /* | 717 | /* |
718 | * Upon successful probe/remove, take/release a reference on the | 718 | * When a namespace is activated create new seeds for the next |
719 | * associated interleave set (if present), and plant new btt + namespace | 719 | * namespace, or namespace-personality to be configured. |
720 | * seeds. Also, on the removal of a BLK region, notify the provider to | ||
721 | * disable the region. | ||
722 | */ | 720 | */ |
723 | static void nd_region_notify_driver_action(struct nvdimm_bus *nvdimm_bus, | 721 | void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev) |
724 | struct device *dev, bool probe) | ||
725 | { | 722 | { |
726 | struct nd_region *nd_region; | 723 | nvdimm_bus_lock(dev); |
727 | 724 | if (nd_region->ns_seed == dev) { | |
728 | if (!probe && is_nd_region(dev)) { | 725 | nd_region_create_ns_seed(nd_region); |
729 | int i; | 726 | } else if (is_nd_btt(dev)) { |
730 | |||
731 | nd_region = to_nd_region(dev); | ||
732 | for (i = 0; i < nd_region->ndr_mappings; i++) { | ||
733 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | ||
734 | struct nvdimm_drvdata *ndd = nd_mapping->ndd; | ||
735 | struct nvdimm *nvdimm = nd_mapping->nvdimm; | ||
736 | |||
737 | mutex_lock(&nd_mapping->lock); | ||
738 | nd_mapping_free_labels(nd_mapping); | ||
739 | mutex_unlock(&nd_mapping->lock); | ||
740 | |||
741 | put_ndd(ndd); | ||
742 | nd_mapping->ndd = NULL; | ||
743 | if (ndd) | ||
744 | atomic_dec(&nvdimm->busy); | ||
745 | } | ||
746 | } | ||
747 | if (dev->parent && is_nd_region(dev->parent) && probe) { | ||
748 | nd_region = to_nd_region(dev->parent); | ||
749 | nvdimm_bus_lock(dev); | ||
750 | if (nd_region->ns_seed == dev) | ||
751 | nd_region_create_ns_seed(nd_region); | ||
752 | nvdimm_bus_unlock(dev); | ||
753 | } | ||
754 | if (is_nd_btt(dev) && probe) { | ||
755 | struct nd_btt *nd_btt = to_nd_btt(dev); | 727 | struct nd_btt *nd_btt = to_nd_btt(dev); |
756 | 728 | ||
757 | nd_region = to_nd_region(dev->parent); | ||
758 | nvdimm_bus_lock(dev); | ||
759 | if (nd_region->btt_seed == dev) | 729 | if (nd_region->btt_seed == dev) |
760 | nd_region_create_btt_seed(nd_region); | 730 | nd_region_create_btt_seed(nd_region); |
761 | if (nd_region->ns_seed == &nd_btt->ndns->dev) | 731 | if (nd_region->ns_seed == &nd_btt->ndns->dev) |
762 | nd_region_create_ns_seed(nd_region); | 732 | nd_region_create_ns_seed(nd_region); |
763 | nvdimm_bus_unlock(dev); | 733 | } else if (is_nd_pfn(dev)) { |
764 | } | ||
765 | if (is_nd_pfn(dev) && probe) { | ||
766 | struct nd_pfn *nd_pfn = to_nd_pfn(dev); | 734 | struct nd_pfn *nd_pfn = to_nd_pfn(dev); |
767 | 735 | ||
768 | nd_region = to_nd_region(dev->parent); | ||
769 | nvdimm_bus_lock(dev); | ||
770 | if (nd_region->pfn_seed == dev) | 736 | if (nd_region->pfn_seed == dev) |
771 | nd_region_create_pfn_seed(nd_region); | 737 | nd_region_create_pfn_seed(nd_region); |
772 | if (nd_region->ns_seed == &nd_pfn->ndns->dev) | 738 | if (nd_region->ns_seed == &nd_pfn->ndns->dev) |
773 | nd_region_create_ns_seed(nd_region); | 739 | nd_region_create_ns_seed(nd_region); |
774 | nvdimm_bus_unlock(dev); | 740 | } else if (is_nd_dax(dev)) { |
775 | } | ||
776 | if (is_nd_dax(dev) && probe) { | ||
777 | struct nd_dax *nd_dax = to_nd_dax(dev); | 741 | struct nd_dax *nd_dax = to_nd_dax(dev); |
778 | 742 | ||
779 | nd_region = to_nd_region(dev->parent); | ||
780 | nvdimm_bus_lock(dev); | ||
781 | if (nd_region->dax_seed == dev) | 743 | if (nd_region->dax_seed == dev) |
782 | nd_region_create_dax_seed(nd_region); | 744 | nd_region_create_dax_seed(nd_region); |
783 | if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev) | 745 | if (nd_region->ns_seed == &nd_dax->nd_pfn.ndns->dev) |
784 | nd_region_create_ns_seed(nd_region); | 746 | nd_region_create_ns_seed(nd_region); |
785 | nvdimm_bus_unlock(dev); | ||
786 | } | 747 | } |
787 | } | 748 | nvdimm_bus_unlock(dev); |
788 | |||
789 | void nd_region_probe_success(struct nvdimm_bus *nvdimm_bus, struct device *dev) | ||
790 | { | ||
791 | nd_region_notify_driver_action(nvdimm_bus, dev, true); | ||
792 | } | ||
793 | |||
794 | void nd_region_disable(struct nvdimm_bus *nvdimm_bus, struct device *dev) | ||
795 | { | ||
796 | nd_region_notify_driver_action(nvdimm_bus, dev, false); | ||
797 | } | 749 | } |
798 | 750 | ||
799 | static ssize_t mappingN(struct device *dev, char *buf, int n) | 751 | static ssize_t mappingN(struct device *dev, char *buf, int n) |
@@ -992,10 +944,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
992 | struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; | 944 | struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; |
993 | struct nvdimm *nvdimm = mapping->nvdimm; | 945 | struct nvdimm *nvdimm = mapping->nvdimm; |
994 | 946 | ||
995 | if ((mapping->start | mapping->size) % SZ_4K) { | 947 | if ((mapping->start | mapping->size) % PAGE_SIZE) { |
996 | dev_err(&nvdimm_bus->dev, "%s: %s mapping%d is not 4K aligned\n", | 948 | dev_err(&nvdimm_bus->dev, |
997 | caller, dev_name(&nvdimm->dev), i); | 949 | "%s: %s mapping%d is not %ld aligned\n", |
998 | 950 | caller, dev_name(&nvdimm->dev), i, PAGE_SIZE); | |
999 | return NULL; | 951 | return NULL; |
1000 | } | 952 | } |
1001 | 953 | ||
@@ -1025,10 +977,9 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, | |||
1025 | } | 977 | } |
1026 | region_buf = ndbr; | 978 | region_buf = ndbr; |
1027 | } else { | 979 | } else { |
1028 | nd_region = kzalloc(sizeof(struct nd_region) | 980 | nd_region = kzalloc(struct_size(nd_region, mapping, |
1029 | + sizeof(struct nd_mapping) | 981 | ndr_desc->num_mappings), |
1030 | * ndr_desc->num_mappings, | 982 | GFP_KERNEL); |
1031 | GFP_KERNEL); | ||
1032 | region_buf = nd_region; | 983 | region_buf = nd_region; |
1033 | } | 984 | } |
1034 | 985 | ||
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index a570f2263a42..9e45b207ff01 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c | |||
@@ -158,7 +158,7 @@ static int nvdimm_key_revalidate(struct nvdimm *nvdimm) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | nvdimm_put_key(key); | 160 | nvdimm_put_key(key); |
161 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 161 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
164 | 164 | ||
@@ -174,7 +174,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | |||
174 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 174 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
175 | 175 | ||
176 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock | 176 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock |
177 | || nvdimm->sec.state < 0) | 177 | || !nvdimm->sec.flags) |
178 | return -EIO; | 178 | return -EIO; |
179 | 179 | ||
180 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | 180 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { |
@@ -189,7 +189,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | |||
189 | * freeze of the security configuration. I.e. if the OS does not | 189 | * freeze of the security configuration. I.e. if the OS does not |
190 | * have the key, security is being managed pre-OS. | 190 | * have the key, security is being managed pre-OS. |
191 | */ | 191 | */ |
192 | if (nvdimm->sec.state == NVDIMM_SECURITY_UNLOCKED) { | 192 | if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) { |
193 | if (!key_revalidate) | 193 | if (!key_revalidate) |
194 | return 0; | 194 | return 0; |
195 | 195 | ||
@@ -202,7 +202,7 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | |||
202 | rc == 0 ? "success" : "fail"); | 202 | rc == 0 ? "success" : "fail"); |
203 | 203 | ||
204 | nvdimm_put_key(key); | 204 | nvdimm_put_key(key); |
205 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 205 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
206 | return rc; | 206 | return rc; |
207 | } | 207 | } |
208 | 208 | ||
@@ -217,7 +217,25 @@ int nvdimm_security_unlock(struct device *dev) | |||
217 | return rc; | 217 | return rc; |
218 | } | 218 | } |
219 | 219 | ||
220 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | 220 | static int check_security_state(struct nvdimm *nvdimm) |
221 | { | ||
222 | struct device *dev = &nvdimm->dev; | ||
223 | |||
224 | if (test_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags)) { | ||
225 | dev_dbg(dev, "Incorrect security state: %#lx\n", | ||
226 | nvdimm->sec.flags); | ||
227 | return -EIO; | ||
228 | } | ||
229 | |||
230 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
231 | dev_dbg(dev, "Security operation in progress.\n"); | ||
232 | return -EBUSY; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int security_disable(struct nvdimm *nvdimm, unsigned int keyid) | ||
221 | { | 239 | { |
222 | struct device *dev = &nvdimm->dev; | 240 | struct device *dev = &nvdimm->dev; |
223 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 241 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
@@ -229,19 +247,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
229 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 247 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
230 | 248 | ||
231 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable | 249 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable |
232 | || nvdimm->sec.state < 0) | 250 | || !nvdimm->sec.flags) |
233 | return -EOPNOTSUPP; | 251 | return -EOPNOTSUPP; |
234 | 252 | ||
235 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | 253 | rc = check_security_state(nvdimm); |
236 | dev_dbg(dev, "Incorrect security state: %d\n", | 254 | if (rc) |
237 | nvdimm->sec.state); | 255 | return rc; |
238 | return -EIO; | ||
239 | } | ||
240 | |||
241 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
242 | dev_dbg(dev, "Security operation in progress.\n"); | ||
243 | return -EBUSY; | ||
244 | } | ||
245 | 256 | ||
246 | data = nvdimm_get_user_key_payload(nvdimm, keyid, | 257 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
247 | NVDIMM_BASE_KEY, &key); | 258 | NVDIMM_BASE_KEY, &key); |
@@ -253,11 +264,11 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
253 | rc == 0 ? "success" : "fail"); | 264 | rc == 0 ? "success" : "fail"); |
254 | 265 | ||
255 | nvdimm_put_key(key); | 266 | nvdimm_put_key(key); |
256 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 267 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
257 | return rc; | 268 | return rc; |
258 | } | 269 | } |
259 | 270 | ||
260 | int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | 271 | static int security_update(struct nvdimm *nvdimm, unsigned int keyid, |
261 | unsigned int new_keyid, | 272 | unsigned int new_keyid, |
262 | enum nvdimm_passphrase_type pass_type) | 273 | enum nvdimm_passphrase_type pass_type) |
263 | { | 274 | { |
@@ -271,14 +282,12 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | |||
271 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 282 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
272 | 283 | ||
273 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key | 284 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key |
274 | || nvdimm->sec.state < 0) | 285 | || !nvdimm->sec.flags) |
275 | return -EOPNOTSUPP; | 286 | return -EOPNOTSUPP; |
276 | 287 | ||
277 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | 288 | rc = check_security_state(nvdimm); |
278 | dev_dbg(dev, "Incorrect security state: %d\n", | 289 | if (rc) |
279 | nvdimm->sec.state); | 290 | return rc; |
280 | return -EIO; | ||
281 | } | ||
282 | 291 | ||
283 | data = nvdimm_get_user_key_payload(nvdimm, keyid, | 292 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
284 | NVDIMM_BASE_KEY, &key); | 293 | NVDIMM_BASE_KEY, &key); |
@@ -301,15 +310,15 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | |||
301 | nvdimm_put_key(newkey); | 310 | nvdimm_put_key(newkey); |
302 | nvdimm_put_key(key); | 311 | nvdimm_put_key(key); |
303 | if (pass_type == NVDIMM_MASTER) | 312 | if (pass_type == NVDIMM_MASTER) |
304 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, | 313 | nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, |
305 | NVDIMM_MASTER); | 314 | NVDIMM_MASTER); |
306 | else | 315 | else |
307 | nvdimm->sec.state = nvdimm_security_state(nvdimm, | 316 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, |
308 | NVDIMM_USER); | 317 | NVDIMM_USER); |
309 | return rc; | 318 | return rc; |
310 | } | 319 | } |
311 | 320 | ||
312 | int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | 321 | static int security_erase(struct nvdimm *nvdimm, unsigned int keyid, |
313 | enum nvdimm_passphrase_type pass_type) | 322 | enum nvdimm_passphrase_type pass_type) |
314 | { | 323 | { |
315 | struct device *dev = &nvdimm->dev; | 324 | struct device *dev = &nvdimm->dev; |
@@ -322,26 +331,14 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | |||
322 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 331 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
323 | 332 | ||
324 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase | 333 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase |
325 | || nvdimm->sec.state < 0) | 334 | || !nvdimm->sec.flags) |
326 | return -EOPNOTSUPP; | 335 | return -EOPNOTSUPP; |
327 | 336 | ||
328 | if (atomic_read(&nvdimm->busy)) { | 337 | rc = check_security_state(nvdimm); |
329 | dev_dbg(dev, "Unable to secure erase while DIMM active.\n"); | 338 | if (rc) |
330 | return -EBUSY; | 339 | return rc; |
331 | } | ||
332 | |||
333 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
334 | dev_dbg(dev, "Incorrect security state: %d\n", | ||
335 | nvdimm->sec.state); | ||
336 | return -EIO; | ||
337 | } | ||
338 | |||
339 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
340 | dev_dbg(dev, "Security operation in progress.\n"); | ||
341 | return -EBUSY; | ||
342 | } | ||
343 | 340 | ||
344 | if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED | 341 | if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags) |
345 | && pass_type == NVDIMM_MASTER) { | 342 | && pass_type == NVDIMM_MASTER) { |
346 | dev_dbg(dev, | 343 | dev_dbg(dev, |
347 | "Attempt to secure erase in wrong master state.\n"); | 344 | "Attempt to secure erase in wrong master state.\n"); |
@@ -359,11 +356,11 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | |||
359 | rc == 0 ? "success" : "fail"); | 356 | rc == 0 ? "success" : "fail"); |
360 | 357 | ||
361 | nvdimm_put_key(key); | 358 | nvdimm_put_key(key); |
362 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 359 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
363 | return rc; | 360 | return rc; |
364 | } | 361 | } |
365 | 362 | ||
366 | int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | 363 | static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) |
367 | { | 364 | { |
368 | struct device *dev = &nvdimm->dev; | 365 | struct device *dev = &nvdimm->dev; |
369 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 366 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
@@ -375,29 +372,17 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | |||
375 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 372 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
376 | 373 | ||
377 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite | 374 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite |
378 | || nvdimm->sec.state < 0) | 375 | || !nvdimm->sec.flags) |
379 | return -EOPNOTSUPP; | 376 | return -EOPNOTSUPP; |
380 | 377 | ||
381 | if (atomic_read(&nvdimm->busy)) { | ||
382 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); | ||
383 | return -EBUSY; | ||
384 | } | ||
385 | |||
386 | if (dev->driver == NULL) { | 378 | if (dev->driver == NULL) { |
387 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); | 379 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); |
388 | return -EINVAL; | 380 | return -EINVAL; |
389 | } | 381 | } |
390 | 382 | ||
391 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | 383 | rc = check_security_state(nvdimm); |
392 | dev_dbg(dev, "Incorrect security state: %d\n", | 384 | if (rc) |
393 | nvdimm->sec.state); | 385 | return rc; |
394 | return -EIO; | ||
395 | } | ||
396 | |||
397 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
398 | dev_dbg(dev, "Security operation in progress.\n"); | ||
399 | return -EBUSY; | ||
400 | } | ||
401 | 386 | ||
402 | data = nvdimm_get_user_key_payload(nvdimm, keyid, | 387 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
403 | NVDIMM_BASE_KEY, &key); | 388 | NVDIMM_BASE_KEY, &key); |
@@ -412,7 +397,7 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | |||
412 | if (rc == 0) { | 397 | if (rc == 0) { |
413 | set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); | 398 | set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); |
414 | set_bit(NDD_WORK_PENDING, &nvdimm->flags); | 399 | set_bit(NDD_WORK_PENDING, &nvdimm->flags); |
415 | nvdimm->sec.state = NVDIMM_SECURITY_OVERWRITE; | 400 | set_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags); |
416 | /* | 401 | /* |
417 | * Make sure we don't lose device while doing overwrite | 402 | * Make sure we don't lose device while doing overwrite |
418 | * query. | 403 | * query. |
@@ -443,7 +428,7 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) | |||
443 | tmo = nvdimm->sec.overwrite_tmo; | 428 | tmo = nvdimm->sec.overwrite_tmo; |
444 | 429 | ||
445 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite | 430 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite |
446 | || nvdimm->sec.state < 0) | 431 | || !nvdimm->sec.flags) |
447 | return; | 432 | return; |
448 | 433 | ||
449 | rc = nvdimm->sec.ops->query_overwrite(nvdimm); | 434 | rc = nvdimm->sec.ops->query_overwrite(nvdimm); |
@@ -467,8 +452,8 @@ void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) | |||
467 | clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); | 452 | clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); |
468 | clear_bit(NDD_WORK_PENDING, &nvdimm->flags); | 453 | clear_bit(NDD_WORK_PENDING, &nvdimm->flags); |
469 | put_device(&nvdimm->dev); | 454 | put_device(&nvdimm->dev); |
470 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 455 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
471 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); | 456 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER); |
472 | } | 457 | } |
473 | 458 | ||
474 | void nvdimm_security_overwrite_query(struct work_struct *work) | 459 | void nvdimm_security_overwrite_query(struct work_struct *work) |
@@ -480,3 +465,85 @@ void nvdimm_security_overwrite_query(struct work_struct *work) | |||
480 | __nvdimm_security_overwrite_query(nvdimm); | 465 | __nvdimm_security_overwrite_query(nvdimm); |
481 | nvdimm_bus_unlock(&nvdimm->dev); | 466 | nvdimm_bus_unlock(&nvdimm->dev); |
482 | } | 467 | } |
468 | |||
469 | #define OPS \ | ||
470 | C( OP_FREEZE, "freeze", 1), \ | ||
471 | C( OP_DISABLE, "disable", 2), \ | ||
472 | C( OP_UPDATE, "update", 3), \ | ||
473 | C( OP_ERASE, "erase", 2), \ | ||
474 | C( OP_OVERWRITE, "overwrite", 2), \ | ||
475 | C( OP_MASTER_UPDATE, "master_update", 3), \ | ||
476 | C( OP_MASTER_ERASE, "master_erase", 2) | ||
477 | #undef C | ||
478 | #define C(a, b, c) a | ||
479 | enum nvdimmsec_op_ids { OPS }; | ||
480 | #undef C | ||
481 | #define C(a, b, c) { b, c } | ||
482 | static struct { | ||
483 | const char *name; | ||
484 | int args; | ||
485 | } ops[] = { OPS }; | ||
486 | #undef C | ||
487 | |||
488 | #define SEC_CMD_SIZE 32 | ||
489 | #define KEY_ID_SIZE 10 | ||
490 | |||
491 | ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len) | ||
492 | { | ||
493 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
494 | ssize_t rc; | ||
495 | char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1], | ||
496 | nkeystr[KEY_ID_SIZE+1]; | ||
497 | unsigned int key, newkey; | ||
498 | int i; | ||
499 | |||
500 | rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s" | ||
501 | " %"__stringify(KEY_ID_SIZE)"s" | ||
502 | " %"__stringify(KEY_ID_SIZE)"s", | ||
503 | cmd, keystr, nkeystr); | ||
504 | if (rc < 1) | ||
505 | return -EINVAL; | ||
506 | for (i = 0; i < ARRAY_SIZE(ops); i++) | ||
507 | if (sysfs_streq(cmd, ops[i].name)) | ||
508 | break; | ||
509 | if (i >= ARRAY_SIZE(ops)) | ||
510 | return -EINVAL; | ||
511 | if (ops[i].args > 1) | ||
512 | rc = kstrtouint(keystr, 0, &key); | ||
513 | if (rc >= 0 && ops[i].args > 2) | ||
514 | rc = kstrtouint(nkeystr, 0, &newkey); | ||
515 | if (rc < 0) | ||
516 | return rc; | ||
517 | |||
518 | if (i == OP_FREEZE) { | ||
519 | dev_dbg(dev, "freeze\n"); | ||
520 | rc = nvdimm_security_freeze(nvdimm); | ||
521 | } else if (i == OP_DISABLE) { | ||
522 | dev_dbg(dev, "disable %u\n", key); | ||
523 | rc = security_disable(nvdimm, key); | ||
524 | } else if (i == OP_UPDATE || i == OP_MASTER_UPDATE) { | ||
525 | dev_dbg(dev, "%s %u %u\n", ops[i].name, key, newkey); | ||
526 | rc = security_update(nvdimm, key, newkey, i == OP_UPDATE | ||
527 | ? NVDIMM_USER : NVDIMM_MASTER); | ||
528 | } else if (i == OP_ERASE || i == OP_MASTER_ERASE) { | ||
529 | dev_dbg(dev, "%s %u\n", ops[i].name, key); | ||
530 | if (atomic_read(&nvdimm->busy)) { | ||
531 | dev_dbg(dev, "Unable to secure erase while DIMM active.\n"); | ||
532 | return -EBUSY; | ||
533 | } | ||
534 | rc = security_erase(nvdimm, key, i == OP_ERASE | ||
535 | ? NVDIMM_USER : NVDIMM_MASTER); | ||
536 | } else if (i == OP_OVERWRITE) { | ||
537 | dev_dbg(dev, "overwrite %u\n", key); | ||
538 | if (atomic_read(&nvdimm->busy)) { | ||
539 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); | ||
540 | return -EBUSY; | ||
541 | } | ||
542 | rc = security_overwrite(nvdimm, key); | ||
543 | } else | ||
544 | return -EINVAL; | ||
545 | |||
546 | if (rc == 0) | ||
547 | rc = len; | ||
548 | return rc; | ||
549 | } | ||
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 7a64b3ddb408..b6eddf912568 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h | |||
@@ -160,8 +160,11 @@ static inline struct nd_blk_region_desc *to_blk_region_desc( | |||
160 | 160 | ||
161 | } | 161 | } |
162 | 162 | ||
163 | enum nvdimm_security_state { | 163 | /* |
164 | NVDIMM_SECURITY_ERROR = -1, | 164 | * Note that separate bits for locked + unlocked are defined so that |
165 | * 'flags == 0' corresponds to an error / not-supported state. | ||
166 | */ | ||
167 | enum nvdimm_security_bits { | ||
165 | NVDIMM_SECURITY_DISABLED, | 168 | NVDIMM_SECURITY_DISABLED, |
166 | NVDIMM_SECURITY_UNLOCKED, | 169 | NVDIMM_SECURITY_UNLOCKED, |
167 | NVDIMM_SECURITY_LOCKED, | 170 | NVDIMM_SECURITY_LOCKED, |
@@ -182,7 +185,7 @@ enum nvdimm_passphrase_type { | |||
182 | }; | 185 | }; |
183 | 186 | ||
184 | struct nvdimm_security_ops { | 187 | struct nvdimm_security_ops { |
185 | enum nvdimm_security_state (*state)(struct nvdimm *nvdimm, | 188 | unsigned long (*get_flags)(struct nvdimm *nvdimm, |
186 | enum nvdimm_passphrase_type pass_type); | 189 | enum nvdimm_passphrase_type pass_type); |
187 | int (*freeze)(struct nvdimm *nvdimm); | 190 | int (*freeze)(struct nvdimm *nvdimm); |
188 | int (*change_key)(struct nvdimm *nvdimm, | 191 | int (*change_key)(struct nvdimm *nvdimm, |
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c index 2d4baf57822f..57bd27dedf1f 100644 --- a/tools/testing/nvdimm/dimm_devs.c +++ b/tools/testing/nvdimm/dimm_devs.c | |||
@@ -18,24 +18,13 @@ ssize_t security_show(struct device *dev, | |||
18 | * For the test version we need to poll the "hardware" in order | 18 | * For the test version we need to poll the "hardware" in order |
19 | * to get the updated status for unlock testing. | 19 | * to get the updated status for unlock testing. |
20 | */ | 20 | */ |
21 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | 21 | nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
22 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); | ||
23 | 22 | ||
24 | switch (nvdimm->sec.state) { | 23 | if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags)) |
25 | case NVDIMM_SECURITY_DISABLED: | ||
26 | return sprintf(buf, "disabled\n"); | 24 | return sprintf(buf, "disabled\n"); |
27 | case NVDIMM_SECURITY_UNLOCKED: | 25 | if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) |
28 | return sprintf(buf, "unlocked\n"); | 26 | return sprintf(buf, "unlocked\n"); |
29 | case NVDIMM_SECURITY_LOCKED: | 27 | if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags)) |
30 | return sprintf(buf, "locked\n"); | 28 | return sprintf(buf, "locked\n"); |
31 | case NVDIMM_SECURITY_FROZEN: | ||
32 | return sprintf(buf, "frozen\n"); | ||
33 | case NVDIMM_SECURITY_OVERWRITE: | ||
34 | return sprintf(buf, "overwrite\n"); | ||
35 | default: | ||
36 | return -ENOTTY; | ||
37 | } | ||
38 | |||
39 | return -ENOTTY; | 29 | return -ENOTTY; |
40 | } | 30 | } |
41 | |||
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 507e6f4cbb53..bf6422a6af7f 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -428,10 +428,9 @@ static int nd_intel_test_finish_query(struct nfit_test *t, | |||
428 | dev_dbg(dev, "%s: still verifying\n", __func__); | 428 | dev_dbg(dev, "%s: still verifying\n", __func__); |
429 | break; | 429 | break; |
430 | } | 430 | } |
431 | |||
432 | dev_dbg(dev, "%s: transition out verify\n", __func__); | 431 | dev_dbg(dev, "%s: transition out verify\n", __func__); |
433 | fw->state = FW_STATE_UPDATED; | 432 | fw->state = FW_STATE_UPDATED; |
434 | /* we are going to fall through if it's "done" */ | 433 | /* fall through */ |
435 | case FW_STATE_UPDATED: | 434 | case FW_STATE_UPDATED: |
436 | nd_cmd->status = 0; | 435 | nd_cmd->status = 0; |
437 | /* bogus test version */ | 436 | /* bogus test version */ |