afs: Wait for outstanding async calls before closing rxrpc socket
The afs filesystem needs to wait for any outstanding asynchronous calls
(such as FS.GiveUpCallBacks cleaning up the callbacks lodged with a server)
to complete before closing the AF_RXRPC socket when unloading the module.
This may occur if the module is removed too quickly after unmounting all
filesystems. This will produce an error report that looks like:
AFS: Assertion failed
1 == 0 is false
0x1 == 0x0 is false
------------[ cut here ]------------
kernel BUG at ../fs/afs/rxrpc.c:135!
...
RIP: 0010:[<ffffffffa004111c>] afs_close_socket+0xec/0x107 [kafs]
...
Call Trace:
[<ffffffffa004a160>] afs_exit+0x1f/0x57 [kafs]
[<ffffffff810c30a0>] SyS_delete_module+0xec/0x17d
[<ffffffff81610417>] entry_SYSCALL_64_fastpath+0x12/0x6b
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index b506428..b4d337a 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -65,6 +65,12 @@
call->async_workfn(call);
}
+static int afs_wait_atomic_t(atomic_t *p)
+{
+ schedule();
+ return 0;
+}
+
/*
* open an RxRPC socket and bind it to be a server for callback notifications
* - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT
@@ -126,13 +132,16 @@
{
_enter("");
+ wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t,
+ TASK_UNINTERRUPTIBLE);
+ _debug("no outstanding calls");
+
sock_release(afs_socket);
_debug("dework");
destroy_workqueue(afs_async_calls);
ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0);
- ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0);
_leave("");
}
@@ -178,8 +187,6 @@
{
_debug("DONE %p{%s} [%d]",
call, call->type->name, atomic_read(&afs_outstanding_calls));
- if (atomic_dec_return(&afs_outstanding_calls) == -1)
- BUG();
ASSERTCMP(call->rxcall, ==, NULL);
ASSERT(!work_pending(&call->async_work));
@@ -188,6 +195,9 @@
kfree(call->request);
kfree(call);
+
+ if (atomic_dec_and_test(&afs_outstanding_calls))
+ wake_up_atomic_t(&afs_outstanding_calls);
}
/*