* [PATCH 1/9] w1: use the bus mutex for the "rw" file
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 2/9] w1: remove the master's files before taking its locks Greg Kroah-Hartman
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
Commit b02f8bede217 ("W1: split master mutex to avoid deadlocks.") gave
the bus a mutex of its own, because the lock which protects the list of
slaves is held while a slave is removed, which waits for the sysfs
callbacks of the slave, so these must not take it. It converted all the
slave drivers, but not the "rw" file of the default family in w1.c,
which still takes the mutex of the master to talk on the bus. That has
two consequences:
- A deadlock. w1_process() holds the mutex of the master while it
searches the bus and detaches the slaves which have gone:
w1_process() read() of .../rw
mutex_lock(&dev->mutex) kernfs active reference
w1_search_process() rw_read()
w1_slave_detach() mutex_lock(&master->mutex)
w1_unref_slave() waits
device_unregister()
waits for the reference
The file is readable for everybody.
- The accesses through this file are not serialised with those of the
slave drivers, which take bus_mutex, so that two transactions can get
mixed up on the wire.
Take bus_mutex here as well. It also excludes the search, which takes it
for every pass.
Fixes: b02f8bede217 ("W1: split master mutex to avoid deadlocks.")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/w1.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index c16946642789..fe7b73d2a553 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -116,7 +116,7 @@ static ssize_t rw_write(struct file *filp, struct kobject *kobj,
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
if (w1_reset_select_slave(sl)) {
count = 0;
goto out_up;
@@ -125,7 +125,7 @@ static ssize_t rw_write(struct file *filp, struct kobject *kobj,
w1_write_block(sl->master, buf, count);
out_up:
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
@@ -135,9 +135,9 @@ static ssize_t rw_read(struct file *filp, struct kobject *kobj,
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
w1_read_block(sl->master, buf, count);
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 2/9] w1: remove the master's files before taking its locks
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 1/9] w1: use the bus mutex for the "rw" file Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 3/9] w1: ds2482: set the strong pull-up with its byte Greg Kroah-Hartman
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
__w1_remove_master_device() calls w1_destroy_master_attributes() with
both the mutex of the master and list_mutex held. Removing the files
waits for the callbacks which are running, and nearly all of them take
one of these two locks:
__w1_remove_master_device() read() of .../w1_master_slaves
mutex_lock(&dev->mutex) kernfs active reference
mutex_lock(&dev->list_mutex) w1_master_attribute_show_slaves()
w1_destroy_master_attributes() mutex_lock(&md->list_mutex)
sysfs_remove_group() waits
waits for the reference
The files are readable for everybody, and a bus master goes away when, for
instance, a DS2490 USB adapter is unplugged.
Remove the files first, before the locks are taken. That has to be done
before the slaves are detached and not afterwards: as long as the files
exist, a write to w1_master_add could attach a new slave behind the back
of this function, which would then wait for the reference count of the
master for ever. And it is done before the thread is stopped, because a
write to w1_master_search wakes the thread up.
Fixes: c30c9b15187e ("W1: fix deadlocks and remove w1_control_thread")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/w1_int.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 19a0ea28e9f3..3fcc9ee56727 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -176,6 +176,13 @@ void __w1_remove_master_device(struct w1_master *dev)
mutex_unlock(&w1_mlock);
set_bit(W1_ABORT_SEARCH, &dev->flags);
+
+ /*
+ * This waits for the callbacks, which take the locks below. One of
+ * them wakes the thread up.
+ */
+ w1_destroy_master_attributes(dev);
+
kthread_stop(dev->thread);
mutex_lock(&dev->mutex);
@@ -185,7 +192,6 @@ void __w1_remove_master_device(struct w1_master *dev)
w1_slave_detach(sl);
mutex_lock(&dev->list_mutex);
}
- w1_destroy_master_attributes(dev);
mutex_unlock(&dev->list_mutex);
mutex_unlock(&dev->mutex);
atomic_dec(&dev->refcnt);
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 3/9] w1: ds2482: set the strong pull-up with its byte
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 1/9] w1: use the bus mutex for the "rw" file Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 2/9] w1: remove the master's files before taking its locks Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 4/9] w1: ds28e04: use the bus mutex to talk on the bus Greg Kroah-Hartman
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
The eight channels of a DS2482-800 are eight independent 1-wire masters
for the w1 core, but share one I2C device. Each bus operation consists of
several I2C transfers: select the channel, send the command, poll the
status, set the read pointer, read the result. access_lock keeps the
operations of the channels apart.
ds2482_w1_set_pullup() polls the status, writes the configuration and
polls again without the lock. Polling sets the read pointer of the device
to the status register. In the middle of a read on another channel, after
that one has set the pointer to the data register, this makes the read
return the status instead of the data. The cached copy of the pointer in
pdev->read_prt can go wrong as well.
The lock alone is not enough. The strong pull-up is a setting of the
whole chip which is used up by the next byte. If an operation of another
channel gets in before the byte it was meant for, that channel gets the
pull-up, and the sensor converts without power.
So only note the request in ds2482_w1_set_pullup(), and write the
configuration in ds2482_w1_write_byte(), under the lock and after the
channel has been selected. The w1 core calls the former right before the
latter, under the bus mutex of the channel.
Fixes: 9c95bb6f25ff ("w1: ds2482: Added 1-Wire pull-up support to the driver")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/masters/ds2482.c | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index cbd11bc61274..5498bb04f7ce 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -103,6 +103,7 @@ struct ds2482_data;
struct ds2482_w1_chan {
struct ds2482_data *pdev;
u8 channel;
+ bool spu; /* strong pullup after the next byte */
struct w1_bus_master w1_bm;
};
@@ -336,6 +337,19 @@ static void ds2482_w1_write_byte(void *data, u8 byte)
if (pdev->w1_count > 1)
ds2482_set_channel(pdev, pchan->channel);
+ if (pchan->spu) {
+ pchan->spu = false;
+ /* the wait above and this one are crucial, otherwise devices
+ * might not be powered long enough, causing e.g. a w1_therm
+ * sensor to provide wrong conversion results
+ */
+ /* note: it seems like both SPU and APU have to be set! */
+ ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(DS2482_REG_CFG_SPU |
+ DS2482_REG_CFG_APU));
+ ds2482_wait_1wire_idle(pdev);
+ }
+
/* Send the write byte command */
ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte);
@@ -420,27 +434,19 @@ static u8 ds2482_w1_reset_bus(void *data)
static u8 ds2482_w1_set_pullup(void *data, int delay)
{
struct ds2482_w1_chan *pchan = data;
- struct ds2482_data *pdev = pchan->pdev;
- u8 retval = 1;
/* if delay is non-zero activate the pullup,
* the strong pullup will be automatically deactivated
* by the master, so do not explicitly deactive it
+ *
+ * The setting is used up by the next byte on any channel of the chip:
+ * ds2482_w1_write_byte() makes it, in one go with the byte.
*/
- if (delay) {
- /* both waits are crucial, otherwise devices might not be
- * powered long enough, causing e.g. a w1_therm sensor to
- * provide wrong conversion results
- */
- ds2482_wait_1wire_idle(pdev);
- /* note: it seems like both SPU and APU have to be set! */
- retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
- ds2482_calculate_config(DS2482_REG_CFG_SPU |
- DS2482_REG_CFG_APU));
- ds2482_wait_1wire_idle(pdev);
- }
+ if (!delay)
+ return 1;
- return retval;
+ pchan->spu = true;
+ return 0;
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 4/9] w1: ds28e04: use the bus mutex to talk on the bus
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (2 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 3/9] w1: ds2482: set the strong pull-up with its byte Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 5/9] w1: ds2805: " Greg Kroah-Hartman
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
Since commit b02f8bede217 ("W1: split master mutex to avoid deadlocks.")
the slave drivers serialise their accesses to the bus with bus_mutex.
This driver, which was merged shortly afterwards, takes the mutex of the
master in the callbacks of its eeprom and pio files instead.
That mutex is held while a slave which has disappeared from the bus is
removed, which waits for the sysfs callbacks of the slave to return. A
callback which is waiting for the mutex at that moment never does: both
tasks are stuck, and with them the thread of the bus master.
Besides, it does not keep the other slave drivers off the bus, so that two
transactions can get mixed up on the wire.
Fixes: fbf7f7b4e2ae ("w1: Add 1-wire slave device driver for DS28E04-100")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/slaves/w1_ds28e04.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
index 3b3c0789e1ad..30fb8415b659 100644
--- a/drivers/w1/slaves/w1_ds28e04.c
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -123,7 +123,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
if (count == 0)
return 0;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
if (w1_enable_crccheck) {
min_page = (off >> W1_PAGE_BITS);
@@ -140,7 +140,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
}
out_up:
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
@@ -253,7 +253,7 @@ static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
}
}
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
/* Can only write data to one page at a time */
idx = 0;
@@ -271,7 +271,7 @@ static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
}
out_up:
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
@@ -290,9 +290,9 @@ static ssize_t pio_read(struct file *filp, struct kobject *kobj,
if (off != 0 || count != 1 || buf == NULL)
return -EINVAL;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf);
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return ret;
}
@@ -310,11 +310,11 @@ static ssize_t pio_write(struct file *filp, struct kobject *kobj,
if (off != 0 || count != 1 || buf == NULL)
return -EINVAL;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
/* Write the PIO data */
if (w1_reset_select_slave(sl)) {
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return -1;
}
@@ -328,7 +328,7 @@ static ssize_t pio_write(struct file *filp, struct kobject *kobj,
w1_read_block(sl->master, &ack, sizeof(ack));
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
/* check for acknowledgement */
if (ack != 0xAA)
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 5/9] w1: ds2805: use the bus mutex to talk on the bus
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (3 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 4/9] w1: ds28e04: use the bus mutex to talk on the bus Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 6/9] w1: netlink: drop the slave after the bus is unlocked Greg Kroah-Hartman
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
Since commit b02f8bede217 ("W1: split master mutex to avoid deadlocks.")
the slave drivers serialise their accesses to the bus with bus_mutex.
This driver takes the mutex of the master in the callbacks of its eeprom
file instead.
That mutex is held while a slave which has disappeared from the bus is
removed, which waits for the sysfs callbacks of the slave to return. A
callback which is waiting for the mutex at that moment never does: both
tasks are stuck, and with them the thread of the bus master.
Besides, it does not keep the other slave drivers off the bus, so that two
transactions can get mixed up on the wire.
Fixes: f6887531c0c6 ("drivers: w1: Add 1w slave driver for DS28E05 EEPROM")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/slaves/w1_ds2805.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/w1/slaves/w1_ds2805.c b/drivers/w1/slaves/w1_ds2805.c
index 9c86b7985d0b..bfcc02ecbdb9 100644
--- a/drivers/w1/slaves/w1_ds2805.c
+++ b/drivers/w1/slaves/w1_ds2805.c
@@ -102,7 +102,7 @@ static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj,
if (count == 0)
return 0;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
/* read directly from the EEPROM in chunks of W1_F0D_READ_MAXLEN */
while (todo > 0) {
@@ -123,7 +123,7 @@ static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj,
off += W1_F0D_READ_MAXLEN;
}
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
@@ -211,7 +211,7 @@ static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj,
if (count == 0)
return 0;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&sl->master->bus_mutex);
/* Can only write data in blocks of the size of the scratchpad */
addr = off;
@@ -256,7 +256,7 @@ static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj,
}
out_up:
- mutex_unlock(&sl->master->mutex);
+ mutex_unlock(&sl->master->bus_mutex);
return count;
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 6/9] w1: netlink: drop the slave after the bus is unlocked
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (4 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 5/9] w1: ds2805: " Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 7/9] w1: don't hold list_mutex while a slave is torn down Greg Kroah-Hartman
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
w1_process_cb() executes the commands of a netlink message with bus_mutex
held, and drops the reference to the slave which the message was
addressed to before it unlocks the mutex. If the slave has been detached
in the meantime, this is the last reference, and w1_unref_slave() tears
the slave down on the spot. That waits
- in device_unregister(), for the sysfs callbacks of the slave which are
running, and
- in w1_therm_remove_slave(), for the readers which have taken a
reference to the family data,
and both kinds take bus_mutex to talk to the slave. Whoever is waiting
for the mutex at that moment is never going to finish, and neither is the
thread of the bus master.
Unlock the bus first. The reference keeps the slave, and with it the
master, alive until then.
Fixes: d3a8a9dbb903 ("w1: hold bus_mutex in netlink and search")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/w1_netlink.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index e6b59d921076..40fbb96a793e 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -478,15 +478,17 @@ static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
if (!cmd || err)
w1_netlink_queue_status(node->block, node->msg, cmd, err);
+ dev->priv = NULL;
+ mutex_unlock(&dev->bus_mutex);
+
/* ref taken in w1_search_slave or w1_search_master_id when building
- * the block
+ * the block. If it is the last one, the slave is removed, which waits
+ * for users of the bus.
*/
if (sl)
w1_unref_slave(sl);
else
atomic_dec(&dev->refcnt);
- dev->priv = NULL;
- mutex_unlock(&dev->bus_mutex);
mutex_lock(&dev->list_mutex);
list_del(&async_cmd->async_entry);
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 7/9] w1: don't hold list_mutex while a slave is torn down
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (5 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 6/9] w1: netlink: drop the slave after the bus is unlocked Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 8/9] w1: w1_therm: lock the list of slaves for the bulk read Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 9/9] w1: w1_therm: leave the slaves of other families alone Greg Kroah-Hartman
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
When the last reference to a slave is dropped, w1_unref_slave() holds
list_mutex of the master until the slave has been freed. In between it
calls the ->remove_slave() callback of the family driver and
device_unregister(). Both wait for others: for the sysfs callbacks
which are running, and in the case of w1_therm also for the file
therm_bulk_read of the master and for everybody who is talking to the
sensor. None of those can therefore take list_mutex, although the
callbacks of therm_bulk_read walk the list which it protects.
The mutex is only needed to make the decrement of the reference count and
the removal from the list one step for w1_search_slave() and
w1_slave_search_device(), which look the slave up in the list and, in the
first case, take a reference. Once the slave is off the list, nobody can
find it any more. Drop the mutex at that point.
The callers which hold the mutex of the master, which serialises
attaching and detaching, are not affected. The one which does not is
w1_process_cb(), when it drops the last reference to a slave which has
been detached while a netlink command for it was queued. Somebody who
attaches a slave with the same ID through sysfs or netlink at that very
moment used to wait until the old device was gone. Now the registration
of the new device may fail because the name is still in use.
This is a preparation for "w1: w1_therm: lock the list of slaves for the
bulk read".
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/w1.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index fe7b73d2a553..4eb785c643c9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -781,16 +781,24 @@ int w1_unref_slave(struct w1_slave *sl)
{
struct w1_master *dev = sl->master;
int refcnt;
+
+ /*
+ * Once it is off the list nobody can find the slave and take a new
+ * reference. The lock must not be held any longer than that: the rest
+ * waits for sysfs callbacks and for users of the family data.
+ */
mutex_lock(&dev->list_mutex);
refcnt = atomic_sub_return(1, &sl->refcnt);
+ if (refcnt == 0)
+ list_del(&sl->w1_slave_entry);
+ mutex_unlock(&dev->list_mutex);
+
if (refcnt == 0) {
struct w1_netlink_msg msg;
dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
sl->name, sl);
- list_del(&sl->w1_slave_entry);
-
memset(&msg, 0, sizeof(msg));
memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
msg.type = W1_SLAVE_REMOVE;
@@ -804,7 +812,6 @@ int w1_unref_slave(struct w1_slave *sl)
kfree(sl);
}
atomic_dec(&dev->refcnt);
- mutex_unlock(&dev->list_mutex);
return refcnt;
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 8/9] w1: w1_therm: lock the list of slaves for the bulk read
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (6 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 7/9] w1: don't hold list_mutex while a slave is torn down Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
2026-10-27 16:04 ` [PATCH 9/9] w1: w1_therm: leave the slaves of other families alone Greg Kroah-Hartman
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
The callbacks of the file therm_bulk_read walk the list of the slaves of
the master, trigger_bulk_read() three times and therm_bulk_read_show()
once, without the list_mutex which protects it. In the meantime the
thread of the master may find out that a sensor has gone:
write to therm_bulk_read w1_process()
trigger_bulk_read() w1_slave_detach()
list_for_each_entry(sl, ...) w1_unref_slave()
bulk_read_slave(sl) list_del()
w1_therm_remove_slave()
kfree(sl->family_data)
kfree(sl)
SLAVE_CONVERT_TRIGGERED(sl) = 1
The walk reads, and writes to, memory which has been freed, and follows
the poisoned list pointers.
Take list_mutex around each of the four walks. No pointer to a slave is
kept from one walk to the next.
This could not be done as long as w1_unref_slave() held the mutex while
it waited, in w1_therm_remove_slave(), for these very callbacks and for
the readers of the sensor, who need the bus_mutex which
trigger_bulk_read() holds around its second walk. Now nothing is waited
for with list_mutex held, and none of the other mutexes of the subsystem
is taken under it, so it can be nested inside bus_mutex.
Fixes: 57c76221d5af ("w1_therm: adding bulk read support to trigger multiple conversion on bus")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/slaves/w1_therm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index d96b224e2215..6db0b534b338 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -1495,6 +1495,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
* and compute duration of conversion for these devices
* so we can apply a strong pullup if required
*/
+ mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
if (!sl->family_data)
goto error;
@@ -1508,6 +1509,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
w1_strong_pullup));
}
}
+ mutex_unlock(&dev_master->list_mutex);
/*
* t_conv is the max conversion time required on the bus
@@ -1534,11 +1536,13 @@ static int trigger_bulk_read(struct w1_master *dev_master)
w1_write_8(dev_master, W1_CONVERT_TEMP);
/* set a flag to instruct that converT pending */
+ mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl,
&dev_master->slist, w1_slave_entry) {
if (bulk_read_support(sl))
SLAVE_CONVERT_TRIGGERED(sl) = -1;
}
+ mutex_unlock(&dev_master->list_mutex);
if (strong_pullup) { /* some device need pullup */
sleep_rem = msleep_interruptible(t_conv);
@@ -1564,10 +1568,12 @@ static int trigger_bulk_read(struct w1_master *dev_master)
mutex_unlock(&dev_master->bus_mutex);
set_flag:
/* set a flag to register convsersion is done */
+ mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
if (bulk_read_support(sl))
SLAVE_CONVERT_TRIGGERED(sl) = 1;
}
+ mutex_unlock(&dev_master->list_mutex);
error:
return ret;
}
@@ -1932,6 +1938,7 @@ static ssize_t therm_bulk_read_show(struct device *device,
struct w1_slave *sl = NULL;
int ret = 0;
+ mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
if (sl->family_data) {
if (bulk_read_support(sl)) {
@@ -1946,6 +1953,7 @@ static ssize_t therm_bulk_read_show(struct device *device,
}
}
show_result:
+ mutex_unlock(&dev_master->list_mutex);
return sprintf(buf, "%d\n", ret);
}
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 9/9] w1: w1_therm: leave the slaves of other families alone
2026-10-27 16:04 [PATCH 0/9] w1: a bunch of llm-found fixes Greg Kroah-Hartman
` (7 preceding siblings ...)
2026-10-27 16:04 ` [PATCH 8/9] w1: w1_therm: lock the list of slaves for the bulk read Greg Kroah-Hartman
@ 2026-10-27 16:04 ` Greg Kroah-Hartman
8 siblings, 0 replies; 10+ messages in thread
From: Greg Kroah-Hartman @ 2026-10-27 16:04 UTC (permalink / raw)
To: Krzysztof Kozlowski; +Cc: Josef Bacik, linux-kernel, Greg Kroah-Hartman, stable
From: Josef Bacik <josef@toxicpanda.com>
The file therm_bulk_read belongs to the bus master. Its callbacks walk
all the slaves of the bus and look at sl->family_data as if every slave
were a temperature sensor. A 1-wire bus can carry other devices too:
- The family data of a slave which is driven by another driver, such as
w1_ds2433, w1_ds250x, w1_ds28e04 or w1_ds28e17, is a structure of that
driver. bulk_read_support() takes whatever is at the offset of
specific_functions for a pointer and dereferences it, and if the
result happens not to be 0, the callbacks write the state of the
conversion into that foreign structure.
- For a slave without family data, which is the case for most of the
other drivers and for the default family, trigger_bulk_read() gives up
with -ENODEV. A single serial number chip on the bus is enough to
make the bulk read unusable for all the sensors.
Only look at the slaves whose family is one of ours. A bulk conversion
now works on a bus with other devices.
Fixes: 57c76221d5af ("w1_therm: adding bulk read support to trigger multiple conversion on bus")
Cc: stable <stable@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/w1/slaves/w1_therm.c | 37 +++++++++++++++++++++++--------------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 6db0b534b338..d8751b29f420 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -906,6 +906,19 @@ static inline bool bulk_read_support(struct w1_slave *sl)
return false; /* No device family */
}
+/**
+ * bulk_read_slave() - check if a slave of the bus takes part in a bulk read
+ * @sl: any slave on the list of the master
+ *
+ * The family data of the slaves of other families is none of our business.
+ *
+ * Return: true if it is one of our devices and supports bulk read
+ */
+static bool bulk_read_slave(struct w1_slave *sl)
+{
+ return device_family(sl) && sl->family_data && bulk_read_support(sl);
+}
+
/**
* conversion_time() - get the Tconv for the slave
* @sl: device to get the conversion time
@@ -1497,9 +1510,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
*/
mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
- if (!sl->family_data)
- goto error;
- if (bulk_read_support(sl)) {
+ if (bulk_read_slave(sl)) {
int t_cur = conversion_time(sl);
t_conv = max(t_cur, t_conv);
@@ -1539,7 +1550,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl,
&dev_master->slist, w1_slave_entry) {
- if (bulk_read_support(sl))
+ if (bulk_read_slave(sl))
SLAVE_CONVERT_TRIGGERED(sl) = -1;
}
mutex_unlock(&dev_master->list_mutex);
@@ -1570,7 +1581,7 @@ static int trigger_bulk_read(struct w1_master *dev_master)
/* set a flag to register convsersion is done */
mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
- if (bulk_read_support(sl))
+ if (bulk_read_slave(sl))
SLAVE_CONVERT_TRIGGERED(sl) = 1;
}
mutex_unlock(&dev_master->list_mutex);
@@ -1940,16 +1951,14 @@ static ssize_t therm_bulk_read_show(struct device *device,
mutex_lock(&dev_master->list_mutex);
list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
- if (sl->family_data) {
- if (bulk_read_support(sl)) {
- if (SLAVE_CONVERT_TRIGGERED(sl) == -1) {
- ret = -1;
- goto show_result;
- }
- if (SLAVE_CONVERT_TRIGGERED(sl) == 1)
- /* continue to check other slaves */
- ret = 1;
+ if (bulk_read_slave(sl)) {
+ if (SLAVE_CONVERT_TRIGGERED(sl) == -1) {
+ ret = -1;
+ goto show_result;
}
+ if (SLAVE_CONVERT_TRIGGERED(sl) == 1)
+ /* continue to check other slaves */
+ ret = 1;
}
}
show_result:
--
2.56.0
^ permalink raw reply [flat|nested] 10+ messages in thread