Skip to content

Commit

Permalink
firmware: Correct handling of fw_state_wait() return value
Browse files Browse the repository at this point in the history
When request_firmware() finds an already open firmware object it will
wait for that object to become fully loaded and then check the status.
As __fw_state_wait_common() succeeds the timeout value returned will be
truncated in _request_firmware_prepare() and interpreted as -EPERM.

Prior to "firmware: do not use fw_lock for fw_state protection" the code
did test if we where in the "done" state before sleeping, causing this
particular code path to succeed, in some cases.

As the callers are interested in the result of the wait and not the
remaining timeout the return value of __fw_state_wait_common() is
changed to signal "done" or "error", which simplifies the logic in
_request_firmware_load() as well.

Fixes: 5b02962 ("firmware: do not use fw_lock for fw_state protection")
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Acked-by: Luis R. Rodriguez <mcgrof@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
andersson authored and gregkh committed Dec 8, 2016
1 parent 64df114 commit 5d47ec0
Showing 1 changed file with 6 additions and 7 deletions.
13 changes: 6 additions & 7 deletions drivers/base/firmware_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static inline bool __fw_state_is_done(enum fw_status status)
return status == FW_STATUS_DONE || status == FW_STATUS_ABORTED;
}

static long __fw_state_wait_common(struct fw_state *fw_st, long timeout)
static int __fw_state_wait_common(struct fw_state *fw_st, long timeout)
{
long ret;

Expand All @@ -136,8 +136,10 @@ static long __fw_state_wait_common(struct fw_state *fw_st, long timeout)
timeout);
if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
return -ENOENT;
if (!ret)
return -ETIMEDOUT;

return ret;
return ret < 0 ? ret : 0;
}

static void __fw_state_set(struct fw_state *fw_st,
Expand Down Expand Up @@ -1017,14 +1019,11 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
timeout = MAX_JIFFY_OFFSET;
}

timeout = fw_state_wait_timeout(&buf->fw_st, timeout);
if (timeout == -ERESTARTSYS || !timeout) {
retval = timeout;
retval = fw_state_wait_timeout(&buf->fw_st, timeout);
if (retval < 0) {
mutex_lock(&fw_lock);
fw_load_abort(fw_priv);
mutex_unlock(&fw_lock);
} else if (timeout > 0) {
retval = 0;
}

if (fw_state_is_aborted(&buf->fw_st))
Expand Down

0 comments on commit 5d47ec0

Please sign in to comment.