]>
Commit | Line | Data |
---|---|---|
cfb2d848 GKH |
1 | From b2518c78ce76896f0f8f7940bf02104b227e1709 Mon Sep 17 00:00:00 2001 |
2 | From: Toshi Kani <toshi.kani@hpe.com> | |
3 | Date: Tue, 25 Apr 2017 17:04:13 -0600 | |
4 | Subject: libnvdimm, pmem: fix a NULL pointer BUG in nd_pmem_notify | |
5 | ||
6 | From: Toshi Kani <toshi.kani@hpe.com> | |
7 | ||
8 | commit b2518c78ce76896f0f8f7940bf02104b227e1709 upstream. | |
9 | ||
10 | The following BUG was observed when nd_pmem_notify() was called | |
11 | for a BTT device. The use of a pmem_device pointer is not valid | |
12 | with BTT. | |
13 | ||
14 | BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 | |
15 | IP: nd_pmem_notify+0x30/0xf0 [nd_pmem] | |
16 | Call Trace: | |
17 | nd_device_notify+0x40/0x50 | |
18 | child_notify+0x10/0x20 | |
19 | device_for_each_child+0x50/0x90 | |
20 | nd_region_notify+0x20/0x30 | |
21 | nd_device_notify+0x40/0x50 | |
22 | nvdimm_region_notify+0x27/0x30 | |
23 | acpi_nfit_scrub+0x341/0x590 [nfit] | |
24 | process_one_work+0x197/0x450 | |
25 | worker_thread+0x4e/0x4a0 | |
26 | kthread+0x109/0x140 | |
27 | ||
28 | Fix nd_pmem_notify() by setting nd_region and badblocks pointers | |
29 | properly for BTT. | |
30 | ||
31 | Cc: Vishal Verma <vishal.l.verma@intel.com> | |
32 | Fixes: 719994660c24 ("libnvdimm: async notification support") | |
33 | Signed-off-by: Toshi Kani <toshi.kani@hpe.com> | |
34 | Signed-off-by: Dan Williams <dan.j.williams@intel.com> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
36 | ||
37 | --- | |
38 | drivers/nvdimm/pmem.c | 39 ++++++++++++++++++++++++++------------- | |
39 | 1 file changed, 26 insertions(+), 13 deletions(-) | |
40 | ||
41 | --- a/drivers/nvdimm/pmem.c | |
42 | +++ b/drivers/nvdimm/pmem.c | |
43 | @@ -388,12 +388,12 @@ static void nd_pmem_shutdown(struct devi | |
44 | ||
45 | static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) | |
46 | { | |
47 | - struct pmem_device *pmem = dev_get_drvdata(dev); | |
48 | - struct nd_region *nd_region = to_region(pmem); | |
49 | + struct nd_region *nd_region; | |
50 | resource_size_t offset = 0, end_trunc = 0; | |
51 | struct nd_namespace_common *ndns; | |
52 | struct nd_namespace_io *nsio; | |
53 | struct resource res; | |
54 | + struct badblocks *bb; | |
55 | ||
56 | if (event != NVDIMM_REVALIDATE_POISON) | |
57 | return; | |
58 | @@ -402,20 +402,33 @@ static void nd_pmem_notify(struct device | |
59 | struct nd_btt *nd_btt = to_nd_btt(dev); | |
60 | ||
61 | ndns = nd_btt->ndns; | |
62 | - } else if (is_nd_pfn(dev)) { | |
63 | - struct nd_pfn *nd_pfn = to_nd_pfn(dev); | |
64 | - struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; | |
65 | - | |
66 | - ndns = nd_pfn->ndns; | |
67 | - offset = pmem->data_offset + __le32_to_cpu(pfn_sb->start_pad); | |
68 | - end_trunc = __le32_to_cpu(pfn_sb->end_trunc); | |
69 | - } else | |
70 | - ndns = to_ndns(dev); | |
71 | + nd_region = to_nd_region(ndns->dev.parent); | |
72 | + nsio = to_nd_namespace_io(&ndns->dev); | |
73 | + bb = &nsio->bb; | |
74 | + } else { | |
75 | + struct pmem_device *pmem = dev_get_drvdata(dev); | |
76 | + | |
77 | + nd_region = to_region(pmem); | |
78 | + bb = &pmem->bb; | |
79 | + | |
80 | + if (is_nd_pfn(dev)) { | |
81 | + struct nd_pfn *nd_pfn = to_nd_pfn(dev); | |
82 | + struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; | |
83 | + | |
84 | + ndns = nd_pfn->ndns; | |
85 | + offset = pmem->data_offset + | |
86 | + __le32_to_cpu(pfn_sb->start_pad); | |
87 | + end_trunc = __le32_to_cpu(pfn_sb->end_trunc); | |
88 | + } else { | |
89 | + ndns = to_ndns(dev); | |
90 | + } | |
91 | + | |
92 | + nsio = to_nd_namespace_io(&ndns->dev); | |
93 | + } | |
94 | ||
95 | - nsio = to_nd_namespace_io(&ndns->dev); | |
96 | res.start = nsio->res.start + offset; | |
97 | res.end = nsio->res.end - end_trunc; | |
98 | - nvdimm_badblocks_populate(nd_region, &pmem->bb, &res); | |
99 | + nvdimm_badblocks_populate(nd_region, bb, &res); | |
100 | } | |
101 | ||
102 | MODULE_ALIAS("pmem"); |