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/eisa/pci_eisa.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/eisa/pci_eisa.c')
| -rw-r--r-- | drivers/eisa/pci_eisa.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c new file mode 100644 index 000000000..8173e60bb --- /dev/null +++ b/drivers/eisa/pci_eisa.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Minimalist driver for a generic PCI-to-EISA bridge. + * + * (C) 2003 Marc Zyngier <maz@wild-wind.fr.eu.org> + * + * Ivan Kokshaysky <ink@jurassic.park.msu.ru> : + * Generalisation from i82375 to PCI_CLASS_BRIDGE_EISA. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/eisa.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/init.h> + +/* There is only *one* pci_eisa device per machine, right ? */ +static struct eisa_root_device pci_eisa_root; + +static int __init pci_eisa_init(struct pci_dev *pdev) +{ + struct resource *res, *bus_res = NULL; + int rc; + + if ((rc = pci_enable_device (pdev))) { + dev_err(&pdev->dev, "Could not enable device\n"); + return rc; + } + + /* + * The Intel 82375 PCI-EISA bridge is a subtractive-decode PCI + * device, so the resources available on EISA are the same as those + * available on the 82375 bus. This works the same as a PCI-PCI + * bridge in subtractive-decode mode (see pci_read_bridge_bases()). + * We assume other PCI-EISA bridges are similar. + * + * eisa_root_register() can only deal with a single io port resource, + * so we use the first valid io port resource. + */ + pci_bus_for_each_resource(pdev->bus, res) + if (res && (res->flags & IORESOURCE_IO)) { + bus_res = res; + break; + } + + if (!bus_res) { + dev_err(&pdev->dev, "No resources available\n"); + return -1; + } + + pci_eisa_root.dev = &pdev->dev; + pci_eisa_root.res = bus_res; + pci_eisa_root.bus_base_addr = bus_res->start; + pci_eisa_root.slots = EISA_MAX_SLOTS; + pci_eisa_root.dma_mask = pdev->dma_mask; + dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root); + + if (eisa_root_register (&pci_eisa_root)) { + dev_err(&pdev->dev, "Could not register EISA root\n"); + return -1; + } + + return 0; +} + +/* + * We have to call pci_eisa_init_early() before pnpacpi_init()/isapnp_init(). + * Otherwise pnp resource will get enabled early and could prevent eisa + * to be initialized. + * Also need to make sure pci_eisa_init_early() is called after + * x86/pci_subsys_init(). + * So need to use subsys_initcall_sync with it. + */ +static int __init pci_eisa_init_early(void) +{ + struct pci_dev *dev = NULL; + int ret; + + for_each_pci_dev(dev) + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) { + ret = pci_eisa_init(dev); + if (ret) + return ret; + } + + return 0; +} +subsys_initcall_sync(pci_eisa_init_early); |
