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