aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshi Kani <toshi.kani@hpe.com>2017-04-25 19:04:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-20 08:28:42 -0400
commitc171b24fe508e0a3e9d2935f321b82541d0f09c0 (patch)
tree6fe54b3ce8fbea4628f94de77a61bec7d4626cb1
parent5b6e7f353290ca9b042090e0913caa71c2180d35 (diff)
libnvdimm, pmem: fix a NULL pointer BUG in nd_pmem_notify
commit b2518c78ce76896f0f8f7940bf02104b227e1709 upstream. The following BUG was observed when nd_pmem_notify() was called for a BTT device. The use of a pmem_device pointer is not valid with BTT. BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 IP: nd_pmem_notify+0x30/0xf0 [nd_pmem] Call Trace: nd_device_notify+0x40/0x50 child_notify+0x10/0x20 device_for_each_child+0x50/0x90 nd_region_notify+0x20/0x30 nd_device_notify+0x40/0x50 nvdimm_region_notify+0x27/0x30 acpi_nfit_scrub+0x341/0x590 [nfit] process_one_work+0x197/0x450 worker_thread+0x4e/0x4a0 kthread+0x109/0x140 Fix nd_pmem_notify() by setting nd_region and badblocks pointers properly for BTT. Cc: Vishal Verma <vishal.l.verma@intel.com> Fixes: 719994660c24 ("libnvdimm: async notification support") Signed-off-by: Toshi Kani <toshi.kani@hpe.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/nvdimm/pmem.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 24618431a14b..b4808590870c 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -383,12 +383,12 @@ static void nd_pmem_shutdown(struct device *dev)
383 383
384static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) 384static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
385{ 385{
386 struct pmem_device *pmem = dev_get_drvdata(dev); 386 struct nd_region *nd_region;
387 struct nd_region *nd_region = to_region(pmem);
388 resource_size_t offset = 0, end_trunc = 0; 387 resource_size_t offset = 0, end_trunc = 0;
389 struct nd_namespace_common *ndns; 388 struct nd_namespace_common *ndns;
390 struct nd_namespace_io *nsio; 389 struct nd_namespace_io *nsio;
391 struct resource res; 390 struct resource res;
391 struct badblocks *bb;
392 392
393 if (event != NVDIMM_REVALIDATE_POISON) 393 if (event != NVDIMM_REVALIDATE_POISON)
394 return; 394 return;
@@ -397,20 +397,33 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
397 struct nd_btt *nd_btt = to_nd_btt(dev); 397 struct nd_btt *nd_btt = to_nd_btt(dev);
398 398
399 ndns = nd_btt->ndns; 399 ndns = nd_btt->ndns;
400 } else if (is_nd_pfn(dev)) { 400 nd_region = to_nd_region(ndns->dev.parent);
401 struct nd_pfn *nd_pfn = to_nd_pfn(dev); 401 nsio = to_nd_namespace_io(&ndns->dev);
402 struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; 402 bb = &nsio->bb;
403 } else {
404 struct pmem_device *pmem = dev_get_drvdata(dev);
403 405
404 ndns = nd_pfn->ndns; 406 nd_region = to_region(pmem);
405 offset = pmem->data_offset + __le32_to_cpu(pfn_sb->start_pad); 407 bb = &pmem->bb;
406 end_trunc = __le32_to_cpu(pfn_sb->end_trunc); 408
407 } else 409 if (is_nd_pfn(dev)) {
408 ndns = to_ndns(dev); 410 struct nd_pfn *nd_pfn = to_nd_pfn(dev);
411 struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
412
413 ndns = nd_pfn->ndns;
414 offset = pmem->data_offset +
415 __le32_to_cpu(pfn_sb->start_pad);
416 end_trunc = __le32_to_cpu(pfn_sb->end_trunc);
417 } else {
418 ndns = to_ndns(dev);
419 }
420
421 nsio = to_nd_namespace_io(&ndns->dev);
422 }
409 423
410 nsio = to_nd_namespace_io(&ndns->dev);
411 res.start = nsio->res.start + offset; 424 res.start = nsio->res.start + offset;
412 res.end = nsio->res.end - end_trunc; 425 res.end = nsio->res.end - end_trunc;
413 nvdimm_badblocks_populate(nd_region, &pmem->bb, &res); 426 nvdimm_badblocks_populate(nd_region, bb, &res);
414} 427}
415 428
416MODULE_ALIAS("pmem"); 429MODULE_ALIAS("pmem");