aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Sell <Timothy.Sell@unisys.com>2016-04-08 09:21:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-04-11 21:15:51 -0700
commit4145ba76b1f7f3296cc673c299084145e1267029 (patch)
treea6f868ef06915442258bab975425fd4f9379649c
parent6fac083b8df8450af4550238faa104396ccecf13 (diff)
staging: unisys: visornic: prevent double-unlock of priv_lock
Previously, devdata->priv_lock was being unlocked in visornic_serverdown() both before calling visornic_serverdown_complete(), then again at the end of the function. This bug was corrected. The structure of visornic_serverdown() was also improved to make it easier to follow and to decrease the chance that such bugs will be introduced again. The main-path logic now falls thru down the left-side of the page, with a common error-exit point to handle error conditions. Signed-off-by: Tim Sell <Timothy.Sell@unisys.com> Signed-off-by: David Kershner <david.kershner@unisys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c
index 763738d56c9d..0ec952ac0dac 100644
--- a/drivers/staging/unisys/visornic/visornic_main.c
+++ b/drivers/staging/unisys/visornic/visornic_main.c
@@ -356,28 +356,38 @@ visornic_serverdown(struct visornic_devdata *devdata,
visorbus_state_complete_func complete_func)
{
unsigned long flags;
+ int err;
spin_lock_irqsave(&devdata->priv_lock, flags);
- if (!devdata->server_down && !devdata->server_change_state) {
- if (devdata->going_away) {
- spin_unlock_irqrestore(&devdata->priv_lock, flags);
- dev_dbg(&devdata->dev->device,
- "%s aborting because device removal pending\n",
- __func__);
- return -ENODEV;
- }
- devdata->server_change_state = true;
- devdata->server_down_complete_func = complete_func;
- spin_unlock_irqrestore(&devdata->priv_lock, flags);
- visornic_serverdown_complete(devdata);
- } else if (devdata->server_change_state) {
+ if (devdata->server_change_state) {
dev_dbg(&devdata->dev->device, "%s changing state\n",
__func__);
- spin_unlock_irqrestore(&devdata->priv_lock, flags);
- return -EINVAL;
+ err = -EINVAL;
+ goto err_unlock;
+ }
+ if (devdata->server_down) {
+ dev_dbg(&devdata->dev->device, "%s already down\n",
+ __func__);
+ err = -EINVAL;
+ goto err_unlock;
}
+ if (devdata->going_away) {
+ dev_dbg(&devdata->dev->device,
+ "%s aborting because device removal pending\n",
+ __func__);
+ err = -ENODEV;
+ goto err_unlock;
+ }
+ devdata->server_change_state = true;
+ devdata->server_down_complete_func = complete_func;
spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ visornic_serverdown_complete(devdata);
return 0;
+
+err_unlock:
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ return err;
}
/**