diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-01 18:15:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-01 18:15:03 -0400 |
commit | f3683ccd12ac625cee12650ca8595c7b9cb16d77 (patch) | |
tree | f4e0d694e4a4da60b90b5b79950196684dd67923 | |
parent | 6e5c4f13a53d8b126f5636cb29b1c80d10d6838e (diff) | |
parent | 1bcbf42d2732b3fdaa8559b0dfc91567769e23c8 (diff) |
Merge branch 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm fixes from Dan Williams:
"1/ Two regression fixes since v4.6: one for the byte order of a sysfs
attribute (bz121161) and another for QEMU 2.6's NVDIMM _DSM (ACPI
Device Specific Method) implementation that gets tripped up by new
auto-probing behavior in the NFIT driver.
2/ A fix tagged for -stable that stops the kernel from
clobbering/ignoring changes to the configuration of a 'pfn'
instance ("struct page" driver). For example changing the
alignment from 2M to 1G may silently revert to 2M if that value is
currently stored on media.
3/ A fix from Eric for an xfstests failure in dax. It is not
currently tagged for -stable since it requires an 8-exabyte file
system to trigger, and there appear to be no user visible side
effects"
* 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
nfit: fix format interface code byte order
dax: fix offset overflow in dax_io
acpi, nfit: fix acpi_check_dsm() vs zero functions implemented
libnvdimm, pfn, dax: fix initialization vs autodetect for mode + alignment
-rw-r--r-- | drivers/acpi/nfit.c | 12 | ||||
-rw-r--r-- | drivers/acpi/nfit.h | 10 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 6 | ||||
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 51 | ||||
-rw-r--r-- | fs/dax.c | 7 |
5 files changed, 60 insertions, 26 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 2215fc847fa9..ac6ddcc080d4 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c | |||
@@ -928,7 +928,7 @@ static ssize_t format_show(struct device *dev, | |||
928 | { | 928 | { |
929 | struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); | 929 | struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); |
930 | 930 | ||
931 | return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->code)); | 931 | return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code)); |
932 | } | 932 | } |
933 | static DEVICE_ATTR_RO(format); | 933 | static DEVICE_ATTR_RO(format); |
934 | 934 | ||
@@ -961,8 +961,8 @@ static ssize_t format1_show(struct device *dev, | |||
961 | continue; | 961 | continue; |
962 | if (nfit_dcr->dcr->code == dcr->code) | 962 | if (nfit_dcr->dcr->code == dcr->code) |
963 | continue; | 963 | continue; |
964 | rc = sprintf(buf, "%#x\n", | 964 | rc = sprintf(buf, "0x%04x\n", |
965 | be16_to_cpu(nfit_dcr->dcr->code)); | 965 | le16_to_cpu(nfit_dcr->dcr->code)); |
966 | break; | 966 | break; |
967 | } | 967 | } |
968 | if (rc != ENXIO) | 968 | if (rc != ENXIO) |
@@ -1131,11 +1131,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
1131 | 1131 | ||
1132 | /* | 1132 | /* |
1133 | * Until standardization materializes we need to consider up to 3 | 1133 | * Until standardization materializes we need to consider up to 3 |
1134 | * different command sets. Note, that checking for function0 (bit0) | 1134 | * different command sets. Note, that checking for zero functions |
1135 | * tells us if any commands are reachable through this uuid. | 1135 | * tells us if any commands might be reachable through this uuid. |
1136 | */ | 1136 | */ |
1137 | for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++) | 1137 | for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_HPE2; i++) |
1138 | if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1)) | 1138 | if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 0)) |
1139 | break; | 1139 | break; |
1140 | 1140 | ||
1141 | /* limit the supported commands to those that are publicly documented */ | 1141 | /* limit the supported commands to those that are publicly documented */ |
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 11cb38348aef..02b9ea1e8d2e 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h | |||
@@ -53,12 +53,12 @@ enum nfit_uuids { | |||
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * Region format interface codes are stored as an array of bytes in the | 56 | * Region format interface codes are stored with the interface as the |
57 | * NFIT DIMM Control Region structure | 57 | * LSB and the function as the MSB. |
58 | */ | 58 | */ |
59 | #define NFIT_FIC_BYTE cpu_to_be16(0x101) /* byte-addressable energy backed */ | 59 | #define NFIT_FIC_BYTE cpu_to_le16(0x101) /* byte-addressable energy backed */ |
60 | #define NFIT_FIC_BLK cpu_to_be16(0x201) /* block-addressable non-energy backed */ | 60 | #define NFIT_FIC_BLK cpu_to_le16(0x201) /* block-addressable non-energy backed */ |
61 | #define NFIT_FIC_BYTEN cpu_to_be16(0x301) /* byte-addressable non-energy backed */ | 61 | #define NFIT_FIC_BYTEN cpu_to_le16(0x301) /* byte-addressable non-energy backed */ |
62 | 62 | ||
63 | enum { | 63 | enum { |
64 | NFIT_BLK_READ_FLUSH = 1, | 64 | NFIT_BLK_READ_FLUSH = 1, |
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 22c09952e177..b4de130f2d57 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c | |||
@@ -680,9 +680,6 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) | |||
680 | u64 mask = 0; | 680 | u64 mask = 0; |
681 | union acpi_object *obj; | 681 | union acpi_object *obj; |
682 | 682 | ||
683 | if (funcs == 0) | ||
684 | return false; | ||
685 | |||
686 | obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); | 683 | obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); |
687 | if (!obj) | 684 | if (!obj) |
688 | return false; | 685 | return false; |
@@ -695,6 +692,9 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs) | |||
695 | mask |= (((u64)obj->buffer.pointer[i]) << (i * 8)); | 692 | mask |= (((u64)obj->buffer.pointer[i]) << (i * 8)); |
696 | ACPI_FREE(obj); | 693 | ACPI_FREE(obj); |
697 | 694 | ||
695 | if (funcs == 0) | ||
696 | return true; | ||
697 | |||
698 | /* | 698 | /* |
699 | * Bit 0 indicates whether there's support for any functions other than | 699 | * Bit 0 indicates whether there's support for any functions other than |
700 | * function 0 for the specified UUID and revision. | 700 | * function 0 for the specified UUID and revision. |
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); |
@@ -208,7 +208,12 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter, | |||
208 | dax.addr += first; | 208 | dax.addr += first; |
209 | size = map_len - first; | 209 | size = map_len - first; |
210 | } | 210 | } |
211 | max = min(pos + size, end); | 211 | /* |
212 | * pos + size is one past the last offset for IO, | ||
213 | * so pos + size can overflow loff_t at extreme offsets. | ||
214 | * Cast to u64 to catch this and get the true minimum. | ||
215 | */ | ||
216 | max = min_t(u64, pos + size, end); | ||
212 | } | 217 | } |
213 | 218 | ||
214 | if (iov_iter_rw(iter) == WRITE) { | 219 | if (iov_iter_rw(iter) == WRITE) { |