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>
This commit is contained in:
Tim Sell 2016-04-08 09:21:10 -04:00 committed by Greg Kroah-Hartman
parent 6fac083b8d
commit 4145ba76b1
1 changed files with 25 additions and 15 deletions

View File

@ -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;
}
/**