diff options
author | David Howells <dhowells@redhat.com> | 2014-05-21 17:48:05 +0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2014-05-21 17:48:05 +0400 |
commit | 6c67c7c38cf32c2a9cbccb6b21aadf61a85fbfb4 (patch) | |
tree | d7e2b13f2ff270892babb8bc01799d71aded154c /fs/afs/rxrpc.c | |
parent | 60b5f90d0fac7585f1a43ccdad06787b97eda0ab (diff) | |
download | linux-6c67c7c38cf32c2a9cbccb6b21aadf61a85fbfb4.tar.xz |
AFS: Fix cache manager service handlers
Fix the cache manager RPC service handlers. The afs_send_empty_reply() and
afs_send_simple_reply() functions:
(a) Kill the call and free up the buffers associated with it if they fail.
(b) Return with call intact if it they succeed.
However, none of the callers actually check the result or clean up if
successful - and may use the now non-existent data if it fails.
This was detected by Dan Carpenter using a static checker:
The patch 08e0e7c82eea: "[AF_RXRPC]: Make the in-kernel AFS
filesystem use AF_RXRPC." from Apr 26, 2007, leads to the following
static checker warning:
"fs/afs/cmservice.c:155 SRXAFSCB_CallBack()
warn: 'call' was already freed."
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/rxrpc.c')
-rw-r--r-- | fs/afs/rxrpc.c | 43 |
1 files changed, 21 insertions, 22 deletions
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index ef943df73b8c..9226a6674d7f 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -184,6 +184,19 @@ static void afs_free_call(struct afs_call *call) } /* + * End a call + */ +static void afs_end_call(struct afs_call *call) +{ + if (call->rxcall) { + rxrpc_kernel_end_call(call->rxcall); + call->rxcall = NULL; + } + call->type->destructor(call); + afs_free_call(call); +} + +/* * allocate a call with flat request and reply buffers */ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, @@ -383,11 +396,8 @@ error_do_abort: rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); while ((skb = skb_dequeue(&call->rx_queue))) afs_free_skb(skb); - rxrpc_kernel_end_call(rxcall); - call->rxcall = NULL; error_kill_call: - call->type->destructor(call); - afs_free_call(call); + afs_end_call(call); _leave(" = %d", ret); return ret; } @@ -509,12 +519,8 @@ static void afs_deliver_to_call(struct afs_call *call) if (call->state >= AFS_CALL_COMPLETE) { while ((skb = skb_dequeue(&call->rx_queue))) afs_free_skb(skb); - if (call->incoming) { - rxrpc_kernel_end_call(call->rxcall); - call->rxcall = NULL; - call->type->destructor(call); - afs_free_call(call); - } + if (call->incoming) + afs_end_call(call); } _leave(""); @@ -564,10 +570,7 @@ static int afs_wait_for_call_to_complete(struct afs_call *call) } _debug("call complete"); - rxrpc_kernel_end_call(call->rxcall); - call->rxcall = NULL; - call->type->destructor(call); - afs_free_call(call); + afs_end_call(call); _leave(" = %d", ret); return ret; } @@ -790,10 +793,7 @@ void afs_send_empty_reply(struct afs_call *call) _debug("oom"); rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); default: - rxrpc_kernel_end_call(call->rxcall); - call->rxcall = NULL; - call->type->destructor(call); - afs_free_call(call); + afs_end_call(call); _leave(" [error]"); return; } @@ -823,17 +823,16 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) call->state = AFS_CALL_AWAIT_ACK; n = rxrpc_kernel_send_data(call->rxcall, &msg, len); if (n >= 0) { + /* Success */ _leave(" [replied]"); return; } + if (n == -ENOMEM) { _debug("oom"); rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); } - rxrpc_kernel_end_call(call->rxcall); - call->rxcall = NULL; - call->type->destructor(call); - afs_free_call(call); + afs_end_call(call); _leave(" [error]"); } |