diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/nvdimm/pfn_devs.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index f7718ec685fa..cea8350fbc7e 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c | |||
| @@ -344,6 +344,8 @@ struct device *nd_pfn_create(struct nd_region *nd_region) | |||
| 344 | int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | 344 | int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) |
| 345 | { | 345 | { |
| 346 | u64 checksum, offset; | 346 | u64 checksum, offset; |
| 347 | unsigned long align; | ||
| 348 | enum nd_pfn_mode mode; | ||
| 347 | struct nd_namespace_io *nsio; | 349 | struct nd_namespace_io *nsio; |
| 348 | struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; | 350 | struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; |
| 349 | struct nd_namespace_common *ndns = nd_pfn->ndns; | 351 | struct nd_namespace_common *ndns = nd_pfn->ndns; |
| @@ -386,22 +388,50 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | |||
| 386 | return -ENXIO; | 388 | return -ENXIO; |
| 387 | } | 389 | } |
| 388 | 390 | ||
| 391 | align = le32_to_cpu(pfn_sb->align); | ||
| 392 | offset = le64_to_cpu(pfn_sb->dataoff); | ||
| 393 | if (align == 0) | ||
| 394 | align = 1UL << ilog2(offset); | ||
| 395 | mode = le32_to_cpu(pfn_sb->mode); | ||
| 396 | |||
| 389 | if (!nd_pfn->uuid) { | 397 | if (!nd_pfn->uuid) { |
| 390 | /* from probe we allocate */ | 398 | /* |
| 399 | * When probing a namepace via nd_pfn_probe() the uuid | ||
| 400 | * is NULL (see: nd_pfn_devinit()) we init settings from | ||
| 401 | * pfn_sb | ||
| 402 | */ | ||
| 391 | nd_pfn->uuid = kmemdup(pfn_sb->uuid, 16, GFP_KERNEL); | 403 | nd_pfn->uuid = kmemdup(pfn_sb->uuid, 16, GFP_KERNEL); |
| 392 | if (!nd_pfn->uuid) | 404 | if (!nd_pfn->uuid) |
| 393 | return -ENOMEM; | 405 | return -ENOMEM; |
| 406 | nd_pfn->align = align; | ||
| 407 | nd_pfn->mode = mode; | ||
| 394 | } else { | 408 | } else { |
| 395 | /* from init we validate */ | 409 | /* |
| 410 | * When probing a pfn / dax instance we validate the | ||
| 411 | * live settings against the pfn_sb | ||
| 412 | */ | ||
| 396 | if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0) | 413 | if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0) |
| 397 | return -ENODEV; | 414 | return -ENODEV; |
| 415 | |||
| 416 | /* | ||
| 417 | * If the uuid validates, but other settings mismatch | ||
| 418 | * return EINVAL because userspace has managed to change | ||
| 419 | * the configuration without specifying new | ||
| 420 | * identification. | ||
| 421 | */ | ||
| 422 | if (nd_pfn->align != align || nd_pfn->mode != mode) { | ||
| 423 | dev_err(&nd_pfn->dev, | ||
| 424 | "init failed, settings mismatch\n"); | ||
| 425 | dev_dbg(&nd_pfn->dev, "align: %lx:%lx mode: %d:%d\n", | ||
| 426 | nd_pfn->align, align, nd_pfn->mode, | ||
| 427 | mode); | ||
| 428 | return -EINVAL; | ||
| 429 | } | ||
| 398 | } | 430 | } |
| 399 | 431 | ||
| 400 | if (nd_pfn->align == 0) | 432 | if (align > nvdimm_namespace_capacity(ndns)) { |
| 401 | nd_pfn->align = le32_to_cpu(pfn_sb->align); | ||
| 402 | if (nd_pfn->align > nvdimm_namespace_capacity(ndns)) { | ||
| 403 | dev_err(&nd_pfn->dev, "alignment: %lx exceeds capacity %llx\n", | 433 | dev_err(&nd_pfn->dev, "alignment: %lx exceeds capacity %llx\n", |
| 404 | nd_pfn->align, nvdimm_namespace_capacity(ndns)); | 434 | align, nvdimm_namespace_capacity(ndns)); |
| 405 | return -EINVAL; | 435 | return -EINVAL; |
| 406 | } | 436 | } |
| 407 | 437 | ||
| @@ -411,7 +441,6 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | |||
| 411 | * namespace has changed since the pfn superblock was | 441 | * namespace has changed since the pfn superblock was |
| 412 | * established. | 442 | * established. |
| 413 | */ | 443 | */ |
| 414 | offset = le64_to_cpu(pfn_sb->dataoff); | ||
| 415 | nsio = to_nd_namespace_io(&ndns->dev); | 444 | nsio = to_nd_namespace_io(&ndns->dev); |
| 416 | if (offset >= resource_size(&nsio->res)) { | 445 | if (offset >= resource_size(&nsio->res)) { |
| 417 | dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n", | 446 | dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n", |
| @@ -419,10 +448,11 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) | |||
| 419 | return -EBUSY; | 448 | return -EBUSY; |
| 420 | } | 449 | } |
| 421 | 450 | ||
| 422 | if ((nd_pfn->align && !IS_ALIGNED(offset, nd_pfn->align)) | 451 | if ((align && !IS_ALIGNED(offset, align)) |
| 423 | || !IS_ALIGNED(offset, PAGE_SIZE)) { | 452 | || !IS_ALIGNED(offset, PAGE_SIZE)) { |
| 424 | dev_err(&nd_pfn->dev, "bad offset: %#llx dax disabled\n", | 453 | dev_err(&nd_pfn->dev, |
| 425 | offset); | 454 | "bad offset: %#llx dax disabled align: %#lx\n", |
| 455 | offset, align); | ||
| 426 | return -ENXIO; | 456 | return -ENXIO; |
| 427 | } | 457 | } |
| 428 | 458 | ||
| @@ -502,7 +532,6 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn, | |||
| 502 | res->start += start_pad; | 532 | res->start += start_pad; |
| 503 | res->end -= end_trunc; | 533 | res->end -= end_trunc; |
| 504 | 534 | ||
| 505 | nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode); | ||
| 506 | if (nd_pfn->mode == PFN_MODE_RAM) { | 535 | if (nd_pfn->mode == PFN_MODE_RAM) { |
| 507 | if (offset < SZ_8K) | 536 | if (offset < SZ_8K) |
| 508 | return ERR_PTR(-EINVAL); | 537 | return ERR_PTR(-EINVAL); |
