diff options
author | David Fries <David@Fries.net> | 2014-01-15 23:29:26 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-07 18:40:18 -0500 |
commit | d3a8a9dbb903c73a7ec2deae4c9b7d74b6834f4c (patch) | |
tree | 49128d16abf121d8ae8c555a17a1339a09ff7585 /drivers/w1 | |
parent | b3be177a19f0f9e4f0deb473cef0e95e1254f2e9 (diff) |
w1: hold bus_mutex in netlink and search
The bus_mutex needs to be taken to serialize access to a specific bus.
netlink wasn't updated when bus_mutex was added and was calling
without that lock held, and not all of the masters were holding the
bus_mutex in a search. This was causing the ds2490 hardware to stop
responding when both netlink and /sys slaves were executing bus
commands at the same time.
Signed-off-by: David Fries <David@Fries.net>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/w1')
-rw-r--r-- | drivers/w1/masters/ds1wm.c | 4 | ||||
-rw-r--r-- | drivers/w1/masters/ds2490.c | 8 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 13 |
3 files changed, 20 insertions, 5 deletions
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 02df3b1381d2..b077b8b42758 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c | |||
@@ -326,13 +326,14 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, | |||
326 | unsigned slaves_found = 0; | 326 | unsigned slaves_found = 0; |
327 | unsigned int pass = 0; | 327 | unsigned int pass = 0; |
328 | 328 | ||
329 | mutex_lock(&master_dev->bus_mutex); | ||
329 | dev_dbg(&ds1wm_data->pdev->dev, "search begin\n"); | 330 | dev_dbg(&ds1wm_data->pdev->dev, "search begin\n"); |
330 | while (true) { | 331 | while (true) { |
331 | ++pass; | 332 | ++pass; |
332 | if (pass > 100) { | 333 | if (pass > 100) { |
333 | dev_dbg(&ds1wm_data->pdev->dev, | 334 | dev_dbg(&ds1wm_data->pdev->dev, |
334 | "too many attempts (100), search aborted\n"); | 335 | "too many attempts (100), search aborted\n"); |
335 | return; | 336 | break; |
336 | } | 337 | } |
337 | 338 | ||
338 | mutex_lock(&master_dev->bus_mutex); | 339 | mutex_lock(&master_dev->bus_mutex); |
@@ -439,6 +440,7 @@ static void ds1wm_search(void *data, struct w1_master *master_dev, | |||
439 | dev_dbg(&ds1wm_data->pdev->dev, | 440 | dev_dbg(&ds1wm_data->pdev->dev, |
440 | "pass: %d total: %d search done ms d bit pos: %d\n", pass, | 441 | "pass: %d total: %d search done ms d bit pos: %d\n", pass, |
441 | slaves_found, ms_discrep_bit); | 442 | slaves_found, ms_discrep_bit); |
443 | mutex_unlock(&master_dev->bus_mutex); | ||
442 | } | 444 | } |
443 | 445 | ||
444 | /* --------------------------------------------------------------------- */ | 446 | /* --------------------------------------------------------------------- */ |
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index db0bf3229bb6..7404ad3062b7 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c | |||
@@ -727,9 +727,11 @@ static void ds9490r_search(void *data, struct w1_master *master, | |||
727 | */ | 727 | */ |
728 | u64 buf[2*64/8]; | 728 | u64 buf[2*64/8]; |
729 | 729 | ||
730 | mutex_lock(&master->bus_mutex); | ||
731 | |||
730 | /* address to start searching at */ | 732 | /* address to start searching at */ |
731 | if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0) | 733 | if (ds_send_data(dev, (u8 *)&master->search_id, 8) < 0) |
732 | return; | 734 | goto search_out; |
733 | master->search_id = 0; | 735 | master->search_id = 0; |
734 | 736 | ||
735 | value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F | | 737 | value = COMM_SEARCH_ACCESS | COMM_IM | COMM_RST | COMM_SM | COMM_F | |
@@ -739,7 +741,7 @@ static void ds9490r_search(void *data, struct w1_master *master, | |||
739 | search_limit = 0; | 741 | search_limit = 0; |
740 | index = search_type | (search_limit << 8); | 742 | index = search_type | (search_limit << 8); |
741 | if (ds_send_control(dev, value, index) < 0) | 743 | if (ds_send_control(dev, value, index) < 0) |
742 | return; | 744 | goto search_out; |
743 | 745 | ||
744 | do { | 746 | do { |
745 | schedule_timeout(jtime); | 747 | schedule_timeout(jtime); |
@@ -791,6 +793,8 @@ static void ds9490r_search(void *data, struct w1_master *master, | |||
791 | master->max_slave_count); | 793 | master->max_slave_count); |
792 | set_bit(W1_WARN_MAX_COUNT, &master->flags); | 794 | set_bit(W1_WARN_MAX_COUNT, &master->flags); |
793 | } | 795 | } |
796 | search_out: | ||
797 | mutex_unlock(&master->bus_mutex); | ||
794 | } | 798 | } |
795 | 799 | ||
796 | #if 0 | 800 | #if 0 |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index a5dc21934cf2..5234964fe001 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -246,11 +246,16 @@ static int w1_process_command_master(struct w1_master *dev, | |||
246 | { | 246 | { |
247 | int err = -EINVAL; | 247 | int err = -EINVAL; |
248 | 248 | ||
249 | /* drop bus_mutex for search (does it's own locking), and add/remove | ||
250 | * which doesn't use the bus | ||
251 | */ | ||
249 | switch (req_cmd->cmd) { | 252 | switch (req_cmd->cmd) { |
250 | case W1_CMD_SEARCH: | 253 | case W1_CMD_SEARCH: |
251 | case W1_CMD_ALARM_SEARCH: | 254 | case W1_CMD_ALARM_SEARCH: |
252 | case W1_CMD_LIST_SLAVES: | 255 | case W1_CMD_LIST_SLAVES: |
256 | mutex_unlock(&dev->bus_mutex); | ||
253 | err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); | 257 | err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); |
258 | mutex_lock(&dev->bus_mutex); | ||
254 | break; | 259 | break; |
255 | case W1_CMD_READ: | 260 | case W1_CMD_READ: |
256 | case W1_CMD_WRITE: | 261 | case W1_CMD_WRITE: |
@@ -262,8 +267,12 @@ static int w1_process_command_master(struct w1_master *dev, | |||
262 | break; | 267 | break; |
263 | case W1_CMD_SLAVE_ADD: | 268 | case W1_CMD_SLAVE_ADD: |
264 | case W1_CMD_SLAVE_REMOVE: | 269 | case W1_CMD_SLAVE_REMOVE: |
270 | mutex_unlock(&dev->bus_mutex); | ||
271 | mutex_lock(&dev->mutex); | ||
265 | err = w1_process_command_addremove(dev, req_msg, req_hdr, | 272 | err = w1_process_command_addremove(dev, req_msg, req_hdr, |
266 | req_cmd); | 273 | req_cmd); |
274 | mutex_unlock(&dev->mutex); | ||
275 | mutex_lock(&dev->bus_mutex); | ||
267 | break; | 276 | break; |
268 | default: | 277 | default: |
269 | err = -EINVAL; | 278 | err = -EINVAL; |
@@ -400,7 +409,7 @@ static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) | |||
400 | struct w1_slave *sl = node->sl; | 409 | struct w1_slave *sl = node->sl; |
401 | struct w1_netlink_cmd *cmd = NULL; | 410 | struct w1_netlink_cmd *cmd = NULL; |
402 | 411 | ||
403 | mutex_lock(&dev->mutex); | 412 | mutex_lock(&dev->bus_mutex); |
404 | dev->portid = node->block->portid; | 413 | dev->portid = node->block->portid; |
405 | if (sl && w1_reset_select_slave(sl)) | 414 | if (sl && w1_reset_select_slave(sl)) |
406 | err = -ENODEV; | 415 | err = -ENODEV; |
@@ -437,7 +446,7 @@ static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) | |||
437 | else | 446 | else |
438 | atomic_dec(&dev->refcnt); | 447 | atomic_dec(&dev->refcnt); |
439 | dev->portid = 0; | 448 | dev->portid = 0; |
440 | mutex_unlock(&dev->mutex); | 449 | mutex_unlock(&dev->bus_mutex); |
441 | 450 | ||
442 | mutex_lock(&dev->list_mutex); | 451 | mutex_lock(&dev->list_mutex); |
443 | list_del(&async_cmd->async_entry); | 452 | list_del(&async_cmd->async_entry); |