PCI: Fix pci_register_host_bridge() device_register() error handling
PATCH 1/2 PCI: Fix pci_register_host_bridge() device_register() error handling
If device_register() has an error, we should bail out of pci_register_host_bridge() rather than continuing on.
--- drivers/pci/probe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/pci/probe.c +3 -2
@@ -909,9 +909,10 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) goto free; err =device_register (&bridge->dev); -if (err) +if (err) {put_device (&bridge->dev); - + goto free; + } bus->bridge =get_device (&bridge->dev);device_enable_async_suspend (bus->bridge);pci_set_bus_of_node (bus);
Signature · 1 line
2.20.1
PATCH 2/2 PCI: Fix pci_host_bridge struct device release/free handling
The PCI code has several paths where the struct pci_host_bridge is freed directly. This is wrong because it contains a struct device which is refcounted and should be freed using put_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit 7b5436635800 ("PCI: add generic device into pci_host_bridge struct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.
The problem is a struct device should never be freed directly once device_initialize() is called and a ref is held, but that doesn't happen until pci_register_host_bridge(). There's then a window between allocating the host bridge and pci_register_host_bridge() where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to split device_register() into device_initialize() and device_add() calls, so that the host bridge struct is always freed by using a put_device().
devm_pci_alloc_host_bridge() is using devm_kzalloc() to allocate struct pci_host_bridge which will be freed directly. Instead, we can use a custom devres action to call put_device().
--- drivers/pci/probe.c | 36 +++++++++++++++++++----------------- drivers/pci/remove.c | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)
drivers/pci/probe.c +19 -17
@@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)return b; } -static void devm_pci_release_host_bridge_dev (struct device *dev) +static void pci_release_host_bridge_dev (struct device *dev) {struct pci_host_bridge *bridge =to_pci_host_bridge (dev);
@@ -574,12 +574,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)pci_free_resource_list (&bridge->windows);pci_free_resource_list (&bridge->dma_ranges); -} - -static void pci_release_host_bridge_dev (struct device *dev) -{ -devm_pci_release_host_bridge_dev (dev); -kfree (to_pci_host_bridge (dev)); +kfree (bridge); }static void pci_init_host_bridge (struct pci_host_bridge *bridge)
@@ -599,6 +594,8 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_pme =1 ; bridge->native_ltr =1 ; bridge->native_dpc =1 ; + +device_initialize (&bridge->dev); }struct pci_host_bridge *pci_alloc_host_bridge (size_t priv)
@@ -616,17 +613,25 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) }EXPORT_SYMBOL (pci_alloc_host_bridge); +static void devm_pci_alloc_host_bridge_release (void *data) +{ +pci_free_host_bridge (data); +} +struct pci_host_bridge *devm_pci_alloc_host_bridge (struct device *dev,size_t priv) { +int ret;struct pci_host_bridge *bridge; - bridge =devm_kzalloc (dev,sizeof (*bridge) + priv,GFP_KERNEL ); + bridge =pci_alloc_host_bridge (priv);if (!bridge)return NULL ; -pci_init_host_bridge (bridge); - bridge->dev.release = devm_pci_release_host_bridge_dev; + ret =devm_add_action_or_reset (dev, devm_pci_alloc_host_bridge_release, + bridge); +if (ret) +return NULL ;return bridge; }
@@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);void pci_free_host_bridge (struct pci_host_bridge *bridge) { -pci_free_resource_list (&bridge->windows); -pci_free_resource_list (&bridge->dma_ranges); - -kfree (bridge); +put_device (&bridge->dev); }EXPORT_SYMBOL (pci_free_host_bridge);
@@ -908,7 +910,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)if (err) goto free; - err =device_register (&bridge->dev); + err =device_add (&bridge->dev);if (err) {put_device (&bridge->dev); goto free;
@@ -978,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) unregister:put_device (&bridge->dev); -device_unregister (&bridge->dev); +device_del (&bridge->dev); free:kfree (bus);
@@ -2953,7 +2955,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,return bridge->bus; err_out: -kfree (bridge); +put_device (&bridge->dev);return NULL ; }EXPORT_SYMBOL_GPL (pci_create_root_bus);
drivers/pci/remove.c +1 -1
@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus) host_bridge->bus =NULL ;/* remove the host bridge */ -device_unregister (&host_bridge->dev); +device_del (&host_bridge->dev); }EXPORT_SYMBOL_GPL (pci_remove_root_bus);
Signature · 1 line
2.20.1
Re: [PATCH 2/2] PCI: Fix pci_host_bridge struct device release/free handling
Quoted 18 lines · Rob Herring
The PCI code has several paths where the struct
pci_host_bridgeis freed directly. This is wrong because it contains a struct device which is refcounted and should be freed usingput_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit7b5436635800("PCI: add generic device intopci_host_bridgestruct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.The problem is a struct device should never be freed directly once
device_initialize()is called and a ref is held, but that doesn't happen untilpci_register_host_bridge(). There's then a window between allocating the host bridge andpci_register_host_bridge()where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to splitdevice_register()intodevice_initialize()anddevice_add()calls, so that the host bridge struct is always freed by using aput_device().
Quoted 8 lines
devm_pci_alloc_host_bridge()is usingdevm_kzalloc()to allocate structpci_host_bridgewhich will be freed directly. Instead, we can use a custom devres action to callput_device().Reported-by Anders Roxell <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>
Thank you Rob for fixing this so quickly!
I applied both patches and I couldn't see the use-after-free anymore.
Cheers,
Anders
Quoted 124 lines
--- drivers/pci/probe.c | 36 +++++++++++++++++++----------------- drivers/pci/remove.c | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)drivers/pci/probe.c +19
-17@@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)return b; } -static void devm_pci_release_host_bridge_dev (struct device *dev) +static void pci_release_host_bridge_dev (struct device *dev) {struct pci_host_bridge *bridge =to_pci_host_bridge (dev);@@ -574,12 +574,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)pci_free_resource_list (&bridge->windows);pci_free_resource_list (&bridge->dma_ranges); -} - -static void pci_release_host_bridge_dev (struct device *dev) -{ -devm_pci_release_host_bridge_dev (dev); -kfree (to_pci_host_bridge (dev)); +kfree (bridge); }static void pci_init_host_bridge (struct pci_host_bridge *bridge)@@ -599,6 +594,8 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_pme =1 ; bridge->native_ltr =1 ; bridge->native_dpc =1 ; + +device_initialize (&bridge->dev); }struct pci_host_bridge *pci_alloc_host_bridge (size_t priv)@@ -616,17 +613,25 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) }EXPORT_SYMBOL (pci_alloc_host_bridge); +static void devm_pci_alloc_host_bridge_release (void *data) +{ +pci_free_host_bridge (data); +} +struct pci_host_bridge *devm_pci_alloc_host_bridge (struct device *dev,size_t priv) { +int ret;struct pci_host_bridge *bridge; - bridge =devm_kzalloc (dev,sizeof (*bridge) + priv,GFP_KERNEL ); + bridge =pci_alloc_host_bridge (priv);if (!bridge)return NULL ; -pci_init_host_bridge (bridge); - bridge->dev.release = devm_pci_release_host_bridge_dev; + ret =devm_add_action_or_reset (dev, devm_pci_alloc_host_bridge_release, + bridge); +if (ret) +return NULL ;return bridge; }@@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);void pci_free_host_bridge (struct pci_host_bridge *bridge) { -pci_free_resource_list (&bridge->windows); -pci_free_resource_list (&bridge->dma_ranges); - -kfree (bridge); +put_device (&bridge->dev); }EXPORT_SYMBOL (pci_free_host_bridge);@@ -908,7 +910,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)if (err) goto free; - err =device_register (&bridge->dev); + err =device_add (&bridge->dev);if (err) {put_device (&bridge->dev); goto free;@@ -978,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) unregister:put_device (&bridge->dev); -device_unregister (&bridge->dev); +device_del (&bridge->dev); free:kfree (bus);@@ -2953,7 +2955,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,return bridge->bus; err_out: -kfree (bridge); +put_device (&bridge->dev);return NULL ; }EXPORT_SYMBOL_GPL (pci_create_root_bus);drivers/pci/remove.c +1
-2@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus) host_bridge->bus =NULL ;/* remove the host bridge */ -device_unregister (&host_bridge->dev); +device_del (&host_bridge->dev); }EXPORT_SYMBOL_GPL (pci_remove_root_bus); --2.20.1
Re: [PATCH 2/2] PCI: Fix pci_host_bridge struct device release/free handling
In reply to Rob HerringQuoted 117 lines · Rob Herring
The PCI code has several paths where the struct
pci_host_bridgeis freed directly. This is wrong because it contains a struct device which is refcounted and should be freed usingput_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit7b5436635800("PCI: add generic device intopci_host_bridgestruct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.The problem is a struct device should never be freed directly once
device_initialize()is called and a ref is held, but that doesn't happen untilpci_register_host_bridge(). There's then a window between allocating the host bridge andpci_register_host_bridge()where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to splitdevice_register()intodevice_initialize()anddevice_add()calls, so that the host bridge struct is always freed by using aput_device().
devm_pci_alloc_host_bridge()is usingdevm_kzalloc()to allocate structpci_host_bridgewhich will be freed directly. Instead, we can use a custom devres action to callput_device().Reported-by Anders Roxell <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>--- drivers/pci/probe.c | 36 +++++++++++++++++++----------------- drivers/pci/remove.c | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)drivers/pci/probe.c +17
-15@@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)return b; } -static void devm_pci_release_host_bridge_dev (struct device *dev) +static void pci_release_host_bridge_dev (struct device *dev) {struct pci_host_bridge *bridge =to_pci_host_bridge (dev);@@ -574,12 +574,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)pci_free_resource_list (&bridge->windows);pci_free_resource_list (&bridge->dma_ranges); -} - -static void pci_release_host_bridge_dev (struct device *dev) -{ -devm_pci_release_host_bridge_dev (dev); -kfree (to_pci_host_bridge (dev)); +kfree (bridge); }static void pci_init_host_bridge (struct pci_host_bridge *bridge)@@ -599,6 +594,8 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_pme =1 ; bridge->native_ltr =1 ; bridge->native_dpc =1 ; + +device_initialize (&bridge->dev); }struct pci_host_bridge *pci_alloc_host_bridge (size_t priv)@@ -616,17 +613,25 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) }EXPORT_SYMBOL (pci_alloc_host_bridge); +static void devm_pci_alloc_host_bridge_release (void *data) +{ +pci_free_host_bridge (data); +} +struct pci_host_bridge *devm_pci_alloc_host_bridge (struct device *dev,size_t priv) { +int ret;struct pci_host_bridge *bridge; - bridge =devm_kzalloc (dev,sizeof (*bridge) + priv,GFP_KERNEL ); + bridge =pci_alloc_host_bridge (priv);if (!bridge)return NULL ; -pci_init_host_bridge (bridge); - bridge->dev.release = devm_pci_release_host_bridge_dev; + ret =devm_add_action_or_reset (dev, devm_pci_alloc_host_bridge_release, + bridge); +if (ret) +return NULL ;return bridge; }@@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);void pci_free_host_bridge (struct pci_host_bridge *bridge) { -pci_free_resource_list (&bridge->windows); -pci_free_resource_list (&bridge->dma_ranges); - -kfree (bridge); +put_device (&bridge->dev); }EXPORT_SYMBOL (pci_free_host_bridge);@@ -908,7 +910,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)if (err) goto free; - err =device_register (&bridge->dev); + err =device_add (&bridge->dev);if (err) {put_device (&bridge->dev); goto free;
drivers/pci/probe.c static int pci_register_host_bridge(struct pci_host_bridge *bridge) · line 983
Quoted 5 lines
drivers/pci/probe.c +1
-1@@ -978,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) unregister:put_device (&bridge->dev); -device_unregister (&bridge->dev); +device_del (&bridge->dev);
I think we need to execute device_del() first, then put_device().
Thank you for fixing this code path.
Lorenzo
Quoted 26 lines
drivers/pci/probe.c +1
-1free:kfree (bus);@@ -2953,7 +2955,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,return bridge->bus; err_out: -kfree (bridge); +put_device (&bridge->dev);return NULL ; }EXPORT_SYMBOL_GPL (pci_create_root_bus);drivers/pci/remove.c +1
-1@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus) host_bridge->bus =NULL ;/* remove the host bridge */ -device_unregister (&host_bridge->dev); +device_del (&host_bridge->dev); }EXPORT_SYMBOL_GPL (pci_remove_root_bus);Signature · 1 line
2.20.1
Re: [PATCH 2/2] PCI: Fix pci_host_bridge struct device release/free handling
Quoted 31 lines · Lorenzo Pieralisi
Quoted 29 lines · Rob Herring
The PCI code has several paths where the struct
pci_host_bridgeis freed directly. This is wrong because it contains a struct device which is refcounted and should be freed usingput_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit7b5436635800("PCI: add generic device intopci_host_bridgestruct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.The problem is a struct device should never be freed directly once
device_initialize()is called and a ref is held, but that doesn't happen untilpci_register_host_bridge(). There's then a window between allocating the host bridge andpci_register_host_bridge()where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to splitdevice_register()intodevice_initialize()anddevice_add()calls, so that the host bridge struct is always freed by using aput_device().
devm_pci_alloc_host_bridge()is usingdevm_kzalloc()to allocate structpci_host_bridgewhich will be freed directly. Instead, we can use a custom devres action to callput_device().Reported-by Anders Roxell <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>--- drivers/pci/probe.c | 36 +++++++++++++++++++----------------- drivers/pci/remove.c | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)
[...]
Quoted 11 lines
Quoted 11 lines
drivers/pci/probe.c +1
-1@@ -908,7 +910,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)if (err) goto free; - err =device_register (&bridge->dev); + err =device_add (&bridge->dev);if (err) {put_device (&bridge->dev); goto free;@@ -978,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
Quoted 6 lines
drivers/pci/probe.c static int pci_register_host_bridge(struct pci_host_bridge *bridge) · line 983
Quoted 4 lines
drivers/pci/probe.c +1
-1unregister:put_device (&bridge->dev); -device_unregister (&bridge->dev); +device_del (&bridge->dev);I think we need to execute
device_del()first, thenput_device().
No, because after the device_add, there's a get_device() adding the bridge ptr to the bus. So the put_device here is for that. The final put_device() is in the bridge free or devm action.
Rob
Re: [PATCH 2/2] PCI: Fix pci_host_bridge struct device release/free handling
In reply to Rob HerringQuoted 21 lines · Rob Herring
The PCI code has several paths where the struct
pci_host_bridgeis freed directly. This is wrong because it contains a struct device which is refcounted and should be freed usingput_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit7b5436635800("PCI: add generic device intopci_host_bridgestruct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.The problem is a struct device should never be freed directly once
device_initialize()is called and a ref is held, but that doesn't happen untilpci_register_host_bridge(). There's then a window between allocating the host bridge andpci_register_host_bridge()where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to splitdevice_register()intodevice_initialize()anddevice_add()calls, so that the host bridge struct is always freed by using aput_device().
devm_pci_alloc_host_bridge()is usingdevm_kzalloc()to allocate structpci_host_bridgewhich will be freed directly. Instead, we can use a custom devres action to callput_device().
Quoted 8 lines
Reported-by Anders Roxell <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>--- drivers/pci/probe.c | 36 +++++++++++++++++++----------------- drivers/pci/remove.c | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-)
Quoted 119 lines
drivers/pci/probe.c +19
-17@@ -565,7 +565,7 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)return b; } -static void devm_pci_release_host_bridge_dev (struct device *dev) +static void pci_release_host_bridge_dev (struct device *dev) {struct pci_host_bridge *bridge =to_pci_host_bridge (dev);@@ -574,12 +574,7 @@ static void devm_pci_release_host_bridge_dev(struct device *dev)pci_free_resource_list (&bridge->windows);pci_free_resource_list (&bridge->dma_ranges); -} - -static void pci_release_host_bridge_dev (struct device *dev) -{ -devm_pci_release_host_bridge_dev (dev); -kfree (to_pci_host_bridge (dev)); +kfree (bridge); }static void pci_init_host_bridge (struct pci_host_bridge *bridge)@@ -599,6 +594,8 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge) bridge->native_pme =1 ; bridge->native_ltr =1 ; bridge->native_dpc =1 ; + +device_initialize (&bridge->dev); }struct pci_host_bridge *pci_alloc_host_bridge (size_t priv)@@ -616,17 +613,25 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) }EXPORT_SYMBOL (pci_alloc_host_bridge); +static void devm_pci_alloc_host_bridge_release (void *data) +{ +pci_free_host_bridge (data); +} +struct pci_host_bridge *devm_pci_alloc_host_bridge (struct device *dev,size_t priv) { +int ret;struct pci_host_bridge *bridge; - bridge =devm_kzalloc (dev,sizeof (*bridge) + priv,GFP_KERNEL ); + bridge =pci_alloc_host_bridge (priv);if (!bridge)return NULL ; -pci_init_host_bridge (bridge); - bridge->dev.release = devm_pci_release_host_bridge_dev; + ret =devm_add_action_or_reset (dev, devm_pci_alloc_host_bridge_release, + bridge); +if (ret) +return NULL ;return bridge; }@@ -634,10 +639,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge);void pci_free_host_bridge (struct pci_host_bridge *bridge) { -pci_free_resource_list (&bridge->windows); -pci_free_resource_list (&bridge->dma_ranges); - -kfree (bridge); +put_device (&bridge->dev); }EXPORT_SYMBOL (pci_free_host_bridge);@@ -908,7 +910,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)if (err) goto free; - err =device_register (&bridge->dev); + err =device_add (&bridge->dev);if (err) {put_device (&bridge->dev); goto free;@@ -978,7 +980,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) unregister:put_device (&bridge->dev); -device_unregister (&bridge->dev); +device_del (&bridge->dev); free:kfree (bus);@@ -2953,7 +2955,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,return bridge->bus; err_out: -kfree (bridge); +put_device (&bridge->dev);return NULL ; }EXPORT_SYMBOL_GPL (pci_create_root_bus);drivers/pci/remove.c +1
-1@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus) host_bridge->bus =NULL ;/* remove the host bridge */ -device_unregister (&host_bridge->dev); +device_del (&host_bridge->dev); }EXPORT_SYMBOL_GPL (pci_remove_root_bus);Signature · 1 line
2.20.1
Re: [PATCH 2/2] PCI: Fix pci_host_bridge struct device release/free handling
In reply to Rob HerringQuoted 18 lines · Rob Herring
The PCI code has several paths where the struct
pci_host_bridgeis freed directly. This is wrong because it contains a struct device which is refcounted and should be freed usingput_device(). This can result in use-after-free errors. I think this problem has existed since 2012 with commit7b5436635800("PCI: add generic device intopci_host_bridgestruct"). It generally hasn't mattered as most host bridge drivers are still built-in and can't unbind.The problem is a struct device should never be freed directly once
device_initialize()is called and a ref is held, but that doesn't happen untilpci_register_host_bridge(). There's then a window between allocating the host bridge andpci_register_host_bridge()where kfree should be used. This is fragile and requires callers to do the right thing. To fix this, we need to splitdevice_register()intodevice_initialize()anddevice_add()calls, so that the host bridge struct is always freed by using aput_device().
Quoted 8 lines
devm_pci_alloc_host_bridge()is usingdevm_kzalloc()to allocate structpci_host_bridgewhich will be freed directly. Instead, we can use a custom devres action to callput_device().Reported-by Anders Roxell <[email protected]>Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>
Thanks for working your way through that bit of code and fixing my mistakes!
Your description makes a lot of sense and the code looks reasonable, but I don't understand my own work enough any more to be sure I didn't miss anything.
Quoted 10 lines · Rob Herring
If
device_register()has an error, we should bail out ofpci_register_host_bridge()rather than continuing on.Fixes 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface")Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>--- drivers/pci/probe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Quoted 20 lines
drivers/pci/probe.c +3
-2@@ -909,9 +909,10 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) goto free; err =device_register (&bridge->dev); -if (err) +if (err) {put_device (&bridge->dev); - + goto free; + } bus->bridge =get_device (&bridge->dev);device_enable_async_suspend (bus->bridge);pci_set_bus_of_node (bus);Signature · 1 line
2.20.1
Quoted 9 lines · Rob Herring
If
device_register()has an error, we should bail out ofpci_register_host_bridge()rather than continuing on.Fixes 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface")Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>---
Quoted 7 lines · Rob Herring
If
device_register()has an error, we should bail out ofpci_register_host_bridge()rather than continuing on.Fixes 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface")Cc Arnd Bergmann <[email protected]>Cc Bjorn Helgaas <[email protected]>Signed-off-by Rob Herring <[email protected]>
Both applied to pci/enumeration for v5.8, thanks!
Quoted 24 lines
--- drivers/pci/probe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)drivers/pci/probe.c +3
-2@@ -909,9 +909,10 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) goto free; err =device_register (&bridge->dev); -if (err) +if (err) {put_device (&bridge->dev); - + goto free; + } bus->bridge =get_device (&bridge->dev);device_enable_async_suspend (bus->bridge);pci_set_bus_of_node (bus);Signature · 1 line
2.20.1