|
| 1 | +rxrpc: Fix I/O thread startup getting skipped |
| 2 | + |
| 3 | +jira LE-1907 |
| 4 | +Rebuild_History Non-Buildable kernel-5.14.0-284.30.1.el9_2 |
| 5 | +commit-author David Howells < [email protected]> |
| 6 | +commit 8fbcc83334a7b5b42b6bc1fae2458bf25eb57768 |
| 7 | +Empty-Commit: Cherry-Pick Conflicts during history rebuild. |
| 8 | +Will be included in final tarball splat. Ref for failed cherry-pick at: |
| 9 | +ciq/ciq_backports/kernel-5.14.0-284.30.1.el9_2/8fbcc833.failed |
| 10 | + |
| 11 | +When starting a kthread, the __kthread_create_on_node() function, as called |
| 12 | +from kthread_run(), waits for a completion to indicate that the task_struct |
| 13 | +(or failure state) of the new kernel thread is available before continuing. |
| 14 | + |
| 15 | +This does not wait, however, for the thread function to be invoked and, |
| 16 | +indeed, will skip it if kthread_stop() gets called before it gets there. |
| 17 | + |
| 18 | +If this happens, though, kthread_run() will have returned successfully, |
| 19 | +indicating that the thread was started and returning the task_struct |
| 20 | +pointer. The actual error indication is returned by kthread_stop(). |
| 21 | + |
| 22 | +Note that this is ambiguous, as the caller cannot tell whether the -EINTR |
| 23 | +error code came from kthread() or from the thread function. |
| 24 | + |
| 25 | +This was encountered in the new rxrpc I/O thread, where if the system is |
| 26 | +being pounded hard by, say, syzbot, the check of KTHREAD_SHOULD_STOP can be |
| 27 | +delayed long enough for kthread_stop() to get called when rxrpc releases a |
| 28 | +socket - and this causes an oops because the I/O thread function doesn't |
| 29 | +get started and thus doesn't remove the rxrpc_local struct from the |
| 30 | +local_endpoints list. |
| 31 | + |
| 32 | +Fix this by using a completion to wait for the thread to actually enter |
| 33 | +rxrpc_io_thread(). This makes sure the thread can't be prematurely |
| 34 | +stopped and makes sure the relied-upon cleanup is done. |
| 35 | + |
| 36 | +Fixes: a275da62e8c1 ("rxrpc: Create a per-local endpoint receive queue and I/O thread") |
| 37 | + |
| 38 | + Signed-off-by: David Howells < [email protected]> |
| 39 | +cc: Marc Dionne < [email protected]> |
| 40 | +cc: Hillf Danton < [email protected]> |
| 41 | +Link: https://lore.kernel.org/r/ [email protected]/ |
| 42 | + Signed-off-by: David S. Miller < [email protected]> |
| 43 | +(cherry picked from commit 8fbcc83334a7b5b42b6bc1fae2458bf25eb57768) |
| 44 | + Signed-off-by: Jonathan Maple < [email protected]> |
| 45 | + |
| 46 | +# Conflicts: |
| 47 | +# net/rxrpc/ar-internal.h |
| 48 | +# net/rxrpc/io_thread.c |
| 49 | +# net/rxrpc/local_object.c |
| 50 | +diff --cc net/rxrpc/ar-internal.h |
| 51 | +index 46ce41afb431,37f3aec784cc..000000000000 |
| 52 | +--- a/net/rxrpc/ar-internal.h |
| 53 | ++++ b/net/rxrpc/ar-internal.h |
| 54 | +@@@ -279,13 -286,12 +279,18 @@@ struct rxrpc_local |
| 55 | + struct rxrpc_net *rxnet; /* The network ns in which this resides */ |
| 56 | + struct hlist_node link; |
| 57 | + struct socket *socket; /* my UDP socket */ |
| 58 | +++<<<<<<< HEAD |
| 59 | + + struct work_struct processor; |
| 60 | + + struct list_head ack_tx_queue; /* List of ACKs that need sending */ |
| 61 | + + spinlock_t ack_tx_lock; /* ACK list lock */ |
| 62 | +++======= |
| 63 | ++ struct task_struct *io_thread; |
| 64 | ++ struct completion io_thread_ready; /* Indication that the I/O thread started */ |
| 65 | +++>>>>>>> 8fbcc83334a7 (rxrpc: Fix I/O thread startup getting skipped) |
| 66 | + struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */ |
| 67 | + struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */ |
| 68 | + - struct sk_buff_head rx_queue; /* Received packets */ |
| 69 | + - struct list_head call_attend_q; /* Calls requiring immediate attention */ |
| 70 | + + struct sk_buff_head reject_queue; /* packets awaiting rejection */ |
| 71 | + + struct sk_buff_head event_queue; /* endpoint event packets awaiting processing */ |
| 72 | + struct rb_root client_bundles; /* Client connection bundles by socket params */ |
| 73 | + spinlock_t client_bundles_lock; /* Lock for client_bundles */ |
| 74 | + spinlock_t lock; /* access lock */ |
| 75 | +diff --cc net/rxrpc/local_object.c |
| 76 | +index 846558613c7f,270b63d8f37a..000000000000 |
| 77 | +--- a/net/rxrpc/local_object.c |
| 78 | ++++ b/net/rxrpc/local_object.c |
| 79 | +@@@ -83,12 -96,10 +83,18 @@@ static struct rxrpc_local *rxrpc_alloc_ |
| 80 | + atomic_set(&local->active_users, 1); |
| 81 | + local->rxnet = rxnet; |
| 82 | + INIT_HLIST_NODE(&local->link); |
| 83 | + + INIT_WORK(&local->processor, rxrpc_local_processor); |
| 84 | + + INIT_LIST_HEAD(&local->ack_tx_queue); |
| 85 | + + spin_lock_init(&local->ack_tx_lock); |
| 86 | + init_rwsem(&local->defrag_sem); |
| 87 | +++<<<<<<< HEAD |
| 88 | + + skb_queue_head_init(&local->reject_queue); |
| 89 | + + skb_queue_head_init(&local->event_queue); |
| 90 | +++======= |
| 91 | ++ init_completion(&local->io_thread_ready); |
| 92 | ++ skb_queue_head_init(&local->rx_queue); |
| 93 | ++ INIT_LIST_HEAD(&local->call_attend_q); |
| 94 | +++>>>>>>> 8fbcc83334a7 (rxrpc: Fix I/O thread startup getting skipped) |
| 95 | + local->client_bundles = RB_ROOT; |
| 96 | + spin_lock_init(&local->client_bundles_lock); |
| 97 | + spin_lock_init(&local->lock); |
| 98 | +@@@ -170,8 -183,24 +176,20 @@@ static int rxrpc_open_socket(struct rxr |
| 99 | + BUG(); |
| 100 | + } |
| 101 | + |
| 102 | +++<<<<<<< HEAD |
| 103 | +++======= |
| 104 | ++ io_thread = kthread_run(rxrpc_io_thread, local, |
| 105 | ++ "krxrpcio/%u", ntohs(udp_conf.local_udp_port)); |
| 106 | ++ if (IS_ERR(io_thread)) { |
| 107 | ++ ret = PTR_ERR(io_thread); |
| 108 | ++ goto error_sock; |
| 109 | ++ } |
| 110 | ++ |
| 111 | ++ wait_for_completion(&local->io_thread_ready); |
| 112 | ++ local->io_thread = io_thread; |
| 113 | +++>>>>>>> 8fbcc83334a7 (rxrpc: Fix I/O thread startup getting skipped) |
| 114 | + _leave(" = 0"); |
| 115 | + return 0; |
| 116 | + - |
| 117 | + -error_sock: |
| 118 | + - kernel_sock_shutdown(local->socket, SHUT_RDWR); |
| 119 | + - local->socket->sk->sk_user_data = NULL; |
| 120 | + - sock_release(local->socket); |
| 121 | + - local->socket = NULL; |
| 122 | + - return ret; |
| 123 | + } |
| 124 | + |
| 125 | + /* |
| 126 | +* Unmerged path net/rxrpc/io_thread.c |
| 127 | +* Unmerged path net/rxrpc/ar-internal.h |
| 128 | +* Unmerged path net/rxrpc/io_thread.c |
| 129 | +* Unmerged path net/rxrpc/local_object.c |
0 commit comments