diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /drivers/pci/host-bridge.c | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'drivers/pci/host-bridge.c')
| -rw-r--r-- | drivers/pci/host-bridge.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c new file mode 100644 index 000000000..be5ef6516 --- /dev/null +++ b/drivers/pci/host-bridge.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Host bridge related code + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/module.h> + +#include "pci.h" + +static struct pci_bus *find_pci_root_bus(struct pci_bus *bus) +{ + while (bus->parent) + bus = bus->parent; + + return bus; +} + +struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus) +{ + struct pci_bus *root_bus = find_pci_root_bus(bus); + + return to_pci_host_bridge(root_bus->bridge); +} +EXPORT_SYMBOL_GPL(pci_find_host_bridge); + +struct device *pci_get_host_bridge_device(struct pci_dev *dev) +{ + struct pci_bus *root_bus = find_pci_root_bus(dev->bus); + struct device *bridge = root_bus->bridge; + + kobject_get(&bridge->kobj); + return bridge; +} +EXPORT_SYMBOL_GPL(pci_get_host_bridge_device); + +void pci_put_host_bridge_device(struct device *dev) +{ + kobject_put(&dev->kobj); +} + +void pci_set_host_bridge_release(struct pci_host_bridge *bridge, + void (*release_fn)(struct pci_host_bridge *), + void *release_data) +{ + bridge->release_fn = release_fn; + bridge->release_data = release_data; +} +EXPORT_SYMBOL_GPL(pci_set_host_bridge_release); + +void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, + struct resource *res) +{ + struct pci_host_bridge *bridge = pci_find_host_bridge(bus); + struct resource_entry *window; + resource_size_t offset = 0; + + resource_list_for_each_entry(window, &bridge->windows) { + if (resource_contains(window->res, res)) { + offset = window->offset; + break; + } + } + + region->start = res->start - offset; + region->end = res->end - offset; +} +EXPORT_SYMBOL(pcibios_resource_to_bus); + +static bool region_contains(struct pci_bus_region *region1, + struct pci_bus_region *region2) +{ + return region1->start <= region2->start && region1->end >= region2->end; +} + +void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, + struct pci_bus_region *region) +{ + struct pci_host_bridge *bridge = pci_find_host_bridge(bus); + struct resource_entry *window; + resource_size_t offset = 0; + + resource_list_for_each_entry(window, &bridge->windows) { + struct pci_bus_region bus_region; + + if (resource_type(res) != resource_type(window->res)) + continue; + + bus_region.start = window->res->start - window->offset; + bus_region.end = window->res->end - window->offset; + + if (region_contains(&bus_region, region)) { + offset = window->offset; + break; + } + } + + res->start = region->start + offset; + res->end = region->end + offset; +} +EXPORT_SYMBOL(pcibios_bus_to_resource); |
