| From foo@baz Mon Dec 18 14:12:35 CET 2017 |
| From: "William A. Kennington III" <wak@google.com> |
| Date: Fri, 22 Sep 2017 16:58:00 -0700 |
| Subject: powerpc/opal: Fix EBUSY bug in acquiring tokens |
| |
| From: "William A. Kennington III" <wak@google.com> |
| |
| |
| [ Upstream commit 71e24d7731a2903b1ae2bba2b2971c654d9c2aa6 ] |
| |
| The current code checks the completion map to look for the first token |
| that is complete. In some cases, a completion can come in but the |
| token can still be on lease to the caller processing the completion. |
| If this completed but unreleased token is the first token found in the |
| bitmap by another tasks trying to acquire a token, then the |
| __test_and_set_bit call will fail since the token will still be on |
| lease. The acquisition will then fail with an EBUSY. |
| |
| This patch reorganizes the acquisition code to look at the |
| opal_async_token_map for an unleased token. If the token has no lease |
| it must have no outstanding completions so we should never see an |
| EBUSY, unless we have leased out too many tokens. Since |
| opal_async_get_token_inrerruptible is protected by a semaphore, we |
| will practically never see EBUSY anymore. |
| |
| Fixes: 8d7248232208 ("powerpc/powernv: Infrastructure to support OPAL async completion") |
| Signed-off-by: William A. Kennington III <wak@google.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/powerpc/platforms/powernv/opal-async.c | 6 +++--- |
| 1 file changed, 3 insertions(+), 3 deletions(-) |
| |
| --- a/arch/powerpc/platforms/powernv/opal-async.c |
| +++ b/arch/powerpc/platforms/powernv/opal-async.c |
| @@ -39,18 +39,18 @@ int __opal_async_get_token(void) |
| int token; |
| |
| spin_lock_irqsave(&opal_async_comp_lock, flags); |
| - token = find_first_bit(opal_async_complete_map, opal_max_async_tokens); |
| + token = find_first_zero_bit(opal_async_token_map, opal_max_async_tokens); |
| if (token >= opal_max_async_tokens) { |
| token = -EBUSY; |
| goto out; |
| } |
| |
| - if (__test_and_set_bit(token, opal_async_token_map)) { |
| + if (!__test_and_clear_bit(token, opal_async_complete_map)) { |
| token = -EBUSY; |
| goto out; |
| } |
| |
| - __clear_bit(token, opal_async_complete_map); |
| + __set_bit(token, opal_async_token_map); |
| |
| out: |
| spin_unlock_irqrestore(&opal_async_comp_lock, flags); |