diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2010-01-05 20:56:02 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-01-06 03:14:32 -0500 |
commit | 59b015133cd0034f5904a76969d73476380aac46 (patch) | |
tree | 578643cc919b7e62b5086718d5c3f9b0fee836a9 /drivers/input/mouse/psmouse-base.c | |
parent | abf2a117c67a67fbb611913a31109d0ff66ab073 (diff) |
Input: serio - fix potential deadlock when unbinding drivers
sysfs_remove_group() waits for sysfs attributes to be removed, therefore
we do not need to worry about driver-specific attributes being accessed
after driver has been detached from the device. In fact, attempts to take
serio->drv_mutex in attribute methods may lead to the following deadlock:
sysfs_read_file()
fill_read_buffer()
sysfs_get_active_two()
psmouse_attr_show_helper()
serio_pin_driver()
serio_disconnect_driver()
mutex_lock(&serio->drv_mutex);
<--------> mutex_lock(&serio_drv_mutex);
psmouse_disconnect()
sysfs_remove_group(... psmouse_attr_group);
....
sysfs_deactivate();
wait_for_completion();
Fix this by removing calls to serio_[un]pin_driver() and functions themselves
and using driver-private mutexes to serialize access to attribute's set()
methods that may change device state.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/mouse/psmouse-base.c')
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 32 |
1 files changed, 3 insertions, 29 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 401ac6b6edd4..d59e18b24ede 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -1450,24 +1450,10 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de | |||
1450 | struct serio *serio = to_serio_port(dev); | 1450 | struct serio *serio = to_serio_port(dev); |
1451 | struct psmouse_attribute *attr = to_psmouse_attr(devattr); | 1451 | struct psmouse_attribute *attr = to_psmouse_attr(devattr); |
1452 | struct psmouse *psmouse; | 1452 | struct psmouse *psmouse; |
1453 | int retval; | ||
1454 | |||
1455 | retval = serio_pin_driver(serio); | ||
1456 | if (retval) | ||
1457 | return retval; | ||
1458 | |||
1459 | if (serio->drv != &psmouse_drv) { | ||
1460 | retval = -ENODEV; | ||
1461 | goto out; | ||
1462 | } | ||
1463 | 1453 | ||
1464 | psmouse = serio_get_drvdata(serio); | 1454 | psmouse = serio_get_drvdata(serio); |
1465 | 1455 | ||
1466 | retval = attr->show(psmouse, attr->data, buf); | 1456 | return attr->show(psmouse, attr->data, buf); |
1467 | |||
1468 | out: | ||
1469 | serio_unpin_driver(serio); | ||
1470 | return retval; | ||
1471 | } | 1457 | } |
1472 | 1458 | ||
1473 | ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, | 1459 | ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, |
@@ -1478,18 +1464,9 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev | |||
1478 | struct psmouse *psmouse, *parent = NULL; | 1464 | struct psmouse *psmouse, *parent = NULL; |
1479 | int retval; | 1465 | int retval; |
1480 | 1466 | ||
1481 | retval = serio_pin_driver(serio); | ||
1482 | if (retval) | ||
1483 | return retval; | ||
1484 | |||
1485 | if (serio->drv != &psmouse_drv) { | ||
1486 | retval = -ENODEV; | ||
1487 | goto out_unpin; | ||
1488 | } | ||
1489 | |||
1490 | retval = mutex_lock_interruptible(&psmouse_mutex); | 1467 | retval = mutex_lock_interruptible(&psmouse_mutex); |
1491 | if (retval) | 1468 | if (retval) |
1492 | goto out_unpin; | 1469 | goto out; |
1493 | 1470 | ||
1494 | psmouse = serio_get_drvdata(serio); | 1471 | psmouse = serio_get_drvdata(serio); |
1495 | 1472 | ||
@@ -1519,8 +1496,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev | |||
1519 | 1496 | ||
1520 | out_unlock: | 1497 | out_unlock: |
1521 | mutex_unlock(&psmouse_mutex); | 1498 | mutex_unlock(&psmouse_mutex); |
1522 | out_unpin: | 1499 | out: |
1523 | serio_unpin_driver(serio); | ||
1524 | return retval; | 1500 | return retval; |
1525 | } | 1501 | } |
1526 | 1502 | ||
@@ -1582,9 +1558,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
1582 | } | 1558 | } |
1583 | 1559 | ||
1584 | mutex_unlock(&psmouse_mutex); | 1560 | mutex_unlock(&psmouse_mutex); |
1585 | serio_unpin_driver(serio); | ||
1586 | serio_unregister_child_port(serio); | 1561 | serio_unregister_child_port(serio); |
1587 | serio_pin_driver_uninterruptible(serio); | ||
1588 | mutex_lock(&psmouse_mutex); | 1562 | mutex_lock(&psmouse_mutex); |
1589 | 1563 | ||
1590 | if (serio->drv != &psmouse_drv) { | 1564 | if (serio->drv != &psmouse_drv) { |