Skip to content

Commit 8fbcc83

Browse files
dhowellsdavem330
authored andcommitted
rxrpc: Fix I/O thread startup getting skipped
When starting a kthread, the __kthread_create_on_node() function, as called from kthread_run(), waits for a completion to indicate that the task_struct (or failure state) of the new kernel thread is available before continuing. This does not wait, however, for the thread function to be invoked and, indeed, will skip it if kthread_stop() gets called before it gets there. If this happens, though, kthread_run() will have returned successfully, indicating that the thread was started and returning the task_struct pointer. The actual error indication is returned by kthread_stop(). Note that this is ambiguous, as the caller cannot tell whether the -EINTR error code came from kthread() or from the thread function. This was encountered in the new rxrpc I/O thread, where if the system is being pounded hard by, say, syzbot, the check of KTHREAD_SHOULD_STOP can be delayed long enough for kthread_stop() to get called when rxrpc releases a socket - and this causes an oops because the I/O thread function doesn't get started and thus doesn't remove the rxrpc_local struct from the local_endpoints list. Fix this by using a completion to wait for the thread to actually enter rxrpc_io_thread(). This makes sure the thread can't be prematurely stopped and makes sure the relied-upon cleanup is done. Fixes: a275da6 ("rxrpc: Create a per-local endpoint receive queue and I/O thread") Reported-by: [email protected] Signed-off-by: David Howells <[email protected]> cc: Marc Dionne <[email protected]> cc: Hillf Danton <[email protected]> Link: https://lore.kernel.org/r/[email protected]/ Signed-off-by: David S. Miller <[email protected]>
1 parent eaa0239 commit 8fbcc83

File tree

3 files changed

+5
-0
lines changed

3 files changed

+5
-0
lines changed

net/rxrpc/ar-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ struct rxrpc_local {
287287
struct hlist_node link;
288288
struct socket *socket; /* my UDP socket */
289289
struct task_struct *io_thread;
290+
struct completion io_thread_ready; /* Indication that the I/O thread started */
290291
struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */
291292
struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */
292293
struct sk_buff_head rx_queue; /* Received packets */

net/rxrpc/io_thread.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ int rxrpc_io_thread(void *data)
426426
struct rxrpc_call *call;
427427
struct sk_buff *skb;
428428

429+
complete(&local->io_thread_ready);
430+
429431
skb_queue_head_init(&rx_queue);
430432

431433
set_user_nice(current, MIN_NICE);

net/rxrpc/local_object.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
9797
local->rxnet = rxnet;
9898
INIT_HLIST_NODE(&local->link);
9999
init_rwsem(&local->defrag_sem);
100+
init_completion(&local->io_thread_ready);
100101
skb_queue_head_init(&local->rx_queue);
101102
INIT_LIST_HEAD(&local->call_attend_q);
102103
local->client_bundles = RB_ROOT;
@@ -189,6 +190,7 @@ static int rxrpc_open_socket(struct rxrpc_local *local, struct net *net)
189190
goto error_sock;
190191
}
191192

193+
wait_for_completion(&local->io_thread_ready);
192194
local->io_thread = io_thread;
193195
_leave(" = 0");
194196
return 0;

0 commit comments

Comments
 (0)