Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

PCI: Flush PCI probe workqueue on cpuset isolated partition change

The HK_TYPE_DOMAIN housekeeping cpumask is now modifiable at runtime. In
order to synchronize against PCI probe works and make sure that no
asynchronous probing is still pending or executing on a newly isolated
CPU, the housekeeping subsystem must flush the PCI probe works.

However the PCI probe works can't be flushed easily since they are
queued to the main per-CPU workqueue pool.

Solve this with creating a PCI probe-specific pool and provide and use
the appropriate flushing API.

Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Marco Crivellari <marco.crivellari@suse.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Waiman Long <longman@redhat.com>
Cc: linux-pci@vger.kernel.org

+21 -1
+16 -1
drivers/pci/pci-driver.c
··· 337 337 return 0; 338 338 } 339 339 340 + static struct workqueue_struct *pci_probe_wq; 341 + 340 342 struct pci_probe_arg { 341 343 struct drv_dev_and_id *ddi; 342 344 struct work_struct work; ··· 409 407 cpu = cpumask_any_and(cpumask_of_node(node), 410 408 wq_domain_mask); 411 409 if (cpu < nr_cpu_ids) { 412 - schedule_work_on(cpu, &arg.work); 410 + struct workqueue_struct *wq = pci_probe_wq; 411 + 412 + if (WARN_ON_ONCE(!wq)) 413 + wq = system_percpu_wq; 414 + queue_work_on(cpu, wq, &arg.work); 413 415 rcu_read_unlock(); 414 416 flush_work(&arg.work); 415 417 error = arg.ret; ··· 429 423 dev->is_probed = 0; 430 424 cpu_hotplug_enable(); 431 425 return error; 426 + } 427 + 428 + void pci_probe_flush_workqueue(void) 429 + { 430 + flush_workqueue(pci_probe_wq); 432 431 } 433 432 434 433 /** ··· 1772 1761 static int __init pci_driver_init(void) 1773 1762 { 1774 1763 int ret; 1764 + 1765 + pci_probe_wq = alloc_workqueue("sync_wq", WQ_PERCPU, 0); 1766 + if (!pci_probe_wq) 1767 + return -ENOMEM; 1775 1768 1776 1769 ret = bus_register(&pci_bus_type); 1777 1770 if (ret)
+3
include/linux/pci.h
··· 1206 1206 struct pci_ops *ops, void *sysdata, 1207 1207 struct list_head *resources); 1208 1208 int pci_host_probe(struct pci_host_bridge *bridge); 1209 + void pci_probe_flush_workqueue(void); 1209 1210 int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); 1210 1211 int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); 1211 1212 void pci_bus_release_busn_res(struct pci_bus *b); ··· 2079 2078 _PCI_NOP(o, dword, u32 x) 2080 2079 _PCI_NOP_ALL(read, *) 2081 2080 _PCI_NOP_ALL(write,) 2081 + 2082 + static inline void pci_probe_flush_workqueue(void) { } 2082 2083 2083 2084 static inline struct pci_dev *pci_get_device(unsigned int vendor, 2084 2085 unsigned int device,
+2
kernel/sched/isolation.c
··· 8 8 * 9 9 */ 10 10 #include <linux/sched/isolation.h> 11 + #include <linux/pci.h> 11 12 #include "sched.h" 12 13 13 14 enum hk_flags { ··· 145 144 146 145 synchronize_rcu(); 147 146 147 + pci_probe_flush_workqueue(); 148 148 mem_cgroup_flush_workqueue(); 149 149 vmstat_flush_workqueue(); 150 150