118 lines
4.0 KiB
Diff
118 lines
4.0 KiB
Diff
From 25af39d59d2ff4a5e5bc872b8d4c451bbeffa312 Mon Sep 17 00:00:00 2001
|
|
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
|
Date: Wed, 3 Feb 2016 16:43:56 -0500
|
|
Subject: [PATCH 4/4] xen/pcifront: Fix mysterious crashes when NUMA locality
|
|
information was extracted.
|
|
|
|
Occasionaly PV guests would crash with:
|
|
|
|
pciback 0000:00:00.1: Xen PCI mapped GSI0 to IRQ16
|
|
BUG: unable to handle kernel paging request at 0000000d1a8c0be0
|
|
.. snip..
|
|
<ffffffff8139ce1b>] find_next_bit+0xb/0x10
|
|
[<ffffffff81387f22>] cpumask_next_and+0x22/0x40
|
|
[<ffffffff813c1ef8>] pci_device_probe+0xb8/0x120
|
|
[<ffffffff81529097>] ? driver_sysfs_add+0x77/0xa0
|
|
[<ffffffff815293e4>] driver_probe_device+0x1a4/0x2d0
|
|
[<ffffffff813c1ddd>] ? pci_match_device+0xdd/0x110
|
|
[<ffffffff81529657>] __device_attach_driver+0xa7/0xb0
|
|
[<ffffffff815295b0>] ? __driver_attach+0xa0/0xa0
|
|
[<ffffffff81527622>] bus_for_each_drv+0x62/0x90
|
|
[<ffffffff8152978d>] __device_attach+0xbd/0x110
|
|
[<ffffffff815297fb>] device_attach+0xb/0x10
|
|
[<ffffffff813b75ac>] pci_bus_add_device+0x3c/0x70
|
|
[<ffffffff813b7618>] pci_bus_add_devices+0x38/0x80
|
|
[<ffffffff813dc34e>] pcifront_scan_root+0x13e/0x1a0
|
|
[<ffffffff817a0692>] pcifront_backend_changed+0x262/0x60b
|
|
[<ffffffff814644c6>] ? xenbus_gather+0xd6/0x160
|
|
[<ffffffff8120900f>] ? put_object+0x2f/0x50
|
|
[<ffffffff81465c1d>] xenbus_otherend_changed+0x9d/0xa0
|
|
[<ffffffff814678ee>] backend_changed+0xe/0x10
|
|
[<ffffffff81463a28>] xenwatch_thread+0xc8/0x190
|
|
[<ffffffff810f22f0>] ? woken_wake_function+0x10/0x10
|
|
|
|
which was the result of two things:
|
|
|
|
When we call pci_scan_root_bus we would pass in 'sd' (sysdata)
|
|
pointer which was an 'pcifront_sd' structure. However in the
|
|
pci_device_add it expects that the 'sd' is 'struct sysdata' and
|
|
sets the dev->node to what is in sd->node (offset 4):
|
|
|
|
set_dev_node(&dev->dev, pcibus_to_node(bus));
|
|
|
|
__pcibus_to_node(const struct pci_bus *bus)
|
|
{
|
|
const struct pci_sysdata *sd = bus->sysdata;
|
|
|
|
return sd->node;
|
|
}
|
|
|
|
However our structure was pcifront_sd which had nothing at that
|
|
offset:
|
|
|
|
struct pcifront_sd {
|
|
int domain; /* 0 4 */
|
|
/* XXX 4 bytes hole, try to pack */
|
|
struct pcifront_device * pdev; /* 8 8 */
|
|
}
|
|
|
|
That is an hole - filled with garbage as we used kmalloc instead of
|
|
kzalloc (the second problem).
|
|
|
|
This patch fixes the issue by:
|
|
1) Use kzalloc to initialize to a well known state.
|
|
2) Put 'struct pci_sysdata' at the start of 'pcifront_sd'. That
|
|
way access to the 'node' will access the right offset.
|
|
|
|
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
|
---
|
|
drivers/pci/xen-pcifront.c | 11 +++++++----
|
|
1 file changed, 7 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
|
|
index c777b97..66d197d 100644
|
|
--- a/drivers/pci/xen-pcifront.c
|
|
+++ b/drivers/pci/xen-pcifront.c
|
|
@@ -53,7 +53,7 @@ struct pcifront_device {
|
|
};
|
|
|
|
struct pcifront_sd {
|
|
- int domain;
|
|
+ struct pci_sysdata sd;
|
|
struct pcifront_device *pdev;
|
|
};
|
|
|
|
@@ -67,7 +67,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd,
|
|
unsigned int domain, unsigned int bus,
|
|
struct pcifront_device *pdev)
|
|
{
|
|
- sd->domain = domain;
|
|
+ /* Because we do not expose that information via XenBus. */
|
|
+ sd->sd.node = first_online_node;
|
|
+ sd->sd.domain = domain;
|
|
sd->pdev = pdev;
|
|
}
|
|
|
|
@@ -468,8 +470,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
|
|
dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
|
|
domain, bus);
|
|
|
|
- bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
|
|
- sd = kmalloc(sizeof(*sd), GFP_KERNEL);
|
|
+ bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL);
|
|
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
|
|
if (!bus_entry || !sd) {
|
|
err = -ENOMEM;
|
|
goto err_out;
|
|
@@ -576,6 +578,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
|
|
free_root_bus_devs(bus_entry->bus);
|
|
|
|
kfree(bus_entry->bus->sysdata);
|
|
+ bus_entry->bus->sysdata = NULL;
|
|
|
|
device_unregister(bus_entry->bus->bridge);
|
|
pci_remove_bus(bus_entry->bus);
|
|
--
|
|
2.1.0
|
|
|