power sequencing fixes for v7.2-rc1

- 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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmo863gACgkQBZ0uy/82
 hMMNng//TuH8CTmCq7qinR7A1lHyCf+TbJSU5b1VnuP0XfYrYWU/nITcrrMEeKyx
 4otTY0BgaRcxLqQazqm5a7zPopwqVuILuJbOZbim2axb04ctfL8KCKLDaAbYn8OJ
 dzQ7K1Sn7FSU2aK9XDuEIepviA6oaRwj9hTT2hfhNoO9l9gfKzhYDOXe089FBFAd
 qW6ucH4D/9ov2txaCD4+38xksIhyIhcBI4nwT1N/tIVs5S+JuxDI3MD6kHitVOVt
 B0H1Mt1eXAWFYfVBSoanTMwrXLsnXgn8FXLlki7vq9D83IzsYVFLk14cSP00s6Du
 +FwhLm/7xES4qDm8zTyj3I51U5ABCfYMqA+M2RrfEpXkj/Lfn4DrVVJPJVM51RrM
 CQDZ4LTbC+tmOFWsambtU10zCVZqgzhvtrPziong79Qy1wXV4oHOZ/exn2rOnABz
 9f7Ep3A4lBMojXDTL1ZpKrqitFTiCrEEVWlZSOCLWYdZ+Y4x1ARAhjgvWhXzr9jf
 3KrJZ5XiZTi5Gt3sqVP1T4JUlVEJ3czweImBIA5MsNsmQMUIsjwJafyGJ/AO7vWf
 KUZa3Gvln+HNBHlLv/SaS2WB/JJbq809uxFfk8ONu/ywgzgLG+eqvSltLC4Wa6bj
 G7oSbhvW4kHCSgCnVOroeGMakflGTdkQGaCs1/wGvFeLNQGqsY0=
 =cg0c
 -----END PGP SIGNATURE-----

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()
This commit is contained in:
Linus Torvalds 2026-06-25 09:20:26 -07:00
commit ec85be724c
2 changed files with 17 additions and 10 deletions

View File

@ -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);
}

View File

@ -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 */
};