diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-25 09:20:26 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-25 09:20:26 -0700 |
| commit | ec85be724c5c0c2cc392f5681b45da0403ea60ec (patch) | |
| tree | 2c45e9aacfc9b43b796e0c71043d8fbf3bcede3e | |
| parent | da07894d1d2ff9164cff88d15669f1e03e810b5c (diff) | |
| parent | 2d5a7d406ecece5837af1e278ffbbf6c0315560a (diff) | |
| download | ath-ec85be724c5c0c2cc392f5681b45da0403ea60ec.tar.gz | |
Merge tag 'pwrseq-fixes-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull power sequencing fixes from Bartosz Golaszewski:
- fix an ABBA deadlock in pwrseq unregister path
- fix a use-after-free bug in pwrseq core
- sort PCI device IDs in ascending order in pwrseq-pcie-m2
* tag 'pwrseq-fixes-for-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
power: sequencing: fix ABBA deadlock in pwrseq_device_unregister()
power: sequencing: pcie-m2: Sort PCI device IDs in ascending order
pwrseq: core: fix use-after-free in pwrseq_debugfs_seq_next()
| -rw-r--r-- | drivers/power/sequencing/core.c | 23 | ||||
| -rw-r--r-- | drivers/power/sequencing/pwrseq-pcie-m2.c | 4 |
2 files changed, 17 insertions, 10 deletions
diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c index 89694092981f7..02f42da915985 100644 --- a/drivers/power/sequencing/core.c +++ b/drivers/power/sequencing/core.c @@ -543,15 +543,18 @@ void pwrseq_device_unregister(struct pwrseq_device *pwrseq) struct device *dev = &pwrseq->dev; struct pwrseq_target *target; - scoped_guard(mutex, &pwrseq->state_lock) { + scoped_guard(rwsem_write, &pwrseq_sem) { guard(rwsem_write)(&pwrseq->rw_lock); + /* + * Holding rw_lock for write excludes all power on/off callers + * (they hold it for read), so it's safe to read enable_count + * here without taking the state_lock. + */ list_for_each_entry(target, &pwrseq->targets, list) WARN(target->unit->enable_count, "REMOVING POWER SEQUENCER WITH ACTIVE USERS\n"); - guard(rwsem_write)(&pwrseq_sem); - device_del(dev); } @@ -1012,8 +1015,9 @@ static void *pwrseq_debugfs_seq_start(struct seq_file *seq, loff_t *pos) ctx.index = *pos; /* - * We're holding the lock for the entire printout so no need to fiddle - * with device reference count. + * Hold the lock for the entire printout to prevent device removal. + * Reference counts are managed by start()/next()/stop() as required + * by the seq_file contract. */ down_read(&pwrseq_sem); @@ -1021,7 +1025,7 @@ static void *pwrseq_debugfs_seq_start(struct seq_file *seq, loff_t *pos) if (!ctx.index) return NULL; - return ctx.dev; + return get_device(ctx.dev); } static void *pwrseq_debugfs_seq_next(struct seq_file *seq, void *data, @@ -1031,8 +1035,9 @@ static void *pwrseq_debugfs_seq_next(struct seq_file *seq, void *data, ++*pos; - struct device *next __free(put_device) = - bus_find_next_device(&pwrseq_bus, curr); + struct device *next = bus_find_next_device(&pwrseq_bus, curr); + + put_device(curr); return next; } @@ -1081,6 +1086,8 @@ static int pwrseq_debugfs_seq_show(struct seq_file *seq, void *data) static void pwrseq_debugfs_seq_stop(struct seq_file *seq, void *data) { + if (data) + put_device(data); up_read(&pwrseq_sem); } diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c index 94c3f4b7ee36e..b5ed80d03953b 100644 --- a/drivers/power/sequencing/pwrseq-pcie-m2.c +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c @@ -186,10 +186,10 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq, } static const struct pci_device_id pwrseq_m2_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107), - .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1103), .driver_data = (kernel_ulong_t)"qcom,wcn6855-bt" }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x1107), + .driver_data = (kernel_ulong_t)"qcom,wcn7850-bt" }, { } /* Sentinel */ }; |
