aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/rxrpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/rxrpc.c')
-rw-r--r--fs/afs/rxrpc.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index b50642870a43..63cd9f939f19 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -65,6 +65,12 @@ static void afs_async_workfn(struct work_struct *work)
65 call->async_workfn(call); 65 call->async_workfn(call);
66} 66}
67 67
68static int afs_wait_atomic_t(atomic_t *p)
69{
70 schedule();
71 return 0;
72}
73
68/* 74/*
69 * open an RxRPC socket and bind it to be a server for callback notifications 75 * open an RxRPC socket and bind it to be a server for callback notifications
70 * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 76 * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT
@@ -126,13 +132,16 @@ void afs_close_socket(void)
126{ 132{
127 _enter(""); 133 _enter("");
128 134
135 wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t,
136 TASK_UNINTERRUPTIBLE);
137 _debug("no outstanding calls");
138
129 sock_release(afs_socket); 139 sock_release(afs_socket);
130 140
131 _debug("dework"); 141 _debug("dework");
132 destroy_workqueue(afs_async_calls); 142 destroy_workqueue(afs_async_calls);
133 143
134 ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0); 144 ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0);
135 ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0);
136 _leave(""); 145 _leave("");
137} 146}
138 147
@@ -178,8 +187,6 @@ static void afs_free_call(struct afs_call *call)
178{ 187{
179 _debug("DONE %p{%s} [%d]", 188 _debug("DONE %p{%s} [%d]",
180 call, call->type->name, atomic_read(&afs_outstanding_calls)); 189 call, call->type->name, atomic_read(&afs_outstanding_calls));
181 if (atomic_dec_return(&afs_outstanding_calls) == -1)
182 BUG();
183 190
184 ASSERTCMP(call->rxcall, ==, NULL); 191 ASSERTCMP(call->rxcall, ==, NULL);
185 ASSERT(!work_pending(&call->async_work)); 192 ASSERT(!work_pending(&call->async_work));
@@ -188,6 +195,9 @@ static void afs_free_call(struct afs_call *call)
188 195
189 kfree(call->request); 196 kfree(call->request);
190 kfree(call); 197 kfree(call);
198
199 if (atomic_dec_and_test(&afs_outstanding_calls))
200 wake_up_atomic_t(&afs_outstanding_calls);
191} 201}
192 202
193/* 203/*
@@ -420,9 +430,11 @@ error_kill_call:
420} 430}
421 431
422/* 432/*
423 * handles intercepted messages that were arriving in the socket's Rx queue 433 * Handles intercepted messages that were arriving in the socket's Rx queue.
424 * - called with the socket receive queue lock held to ensure message ordering 434 *
425 * - called with softirqs disabled 435 * Called from the AF_RXRPC call processor in waitqueue process context. For
436 * each call, it is guaranteed this will be called in order of packet to be
437 * delivered.
426 */ 438 */
427static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID, 439static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,
428 struct sk_buff *skb) 440 struct sk_buff *skb)
@@ -513,6 +525,12 @@ static void afs_deliver_to_call(struct afs_call *call)
513 call->state = AFS_CALL_ABORTED; 525 call->state = AFS_CALL_ABORTED;
514 _debug("Rcv ABORT %u -> %d", abort_code, call->error); 526 _debug("Rcv ABORT %u -> %d", abort_code, call->error);
515 break; 527 break;
528 case RXRPC_SKB_MARK_LOCAL_ABORT:
529 abort_code = rxrpc_kernel_get_abort_code(skb);
530 call->error = call->type->abort_to_error(abort_code);
531 call->state = AFS_CALL_ABORTED;
532 _debug("Loc ABORT %u -> %d", abort_code, call->error);
533 break;
516 case RXRPC_SKB_MARK_NET_ERROR: 534 case RXRPC_SKB_MARK_NET_ERROR:
517 call->error = -rxrpc_kernel_get_error_number(skb); 535 call->error = -rxrpc_kernel_get_error_number(skb);
518 call->state = AFS_CALL_ERROR; 536 call->state = AFS_CALL_ERROR;