summaryrefslogtreecommitdiffstats
path: root/net/x25/x25_timer.c
diff options
context:
space:
mode:
authorMiguel Ojeda <ojeda@kernel.org>2026-08-16 15:32:33 +0200
committerMiguel Ojeda <ojeda@kernel.org>2026-08-23 21:27:17 +0200
commit5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch)
tree93a1ed1d337bc53adf1e572c2586d347703b286e /net/x25/x25_timer.c
downloadlinux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz
linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit `objtool` errors such as: vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a: can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd The reason is that in such builds, the Clang invocation that compiles the combined Rust plus helpers bitcode emits LLVM bitcode (again) -- the final code generation happens in the linker's LTO step, which the `-mllvm` trap options passed to Clang do not reach. This, in turn, means that unreachable traps are missing, and the impossible paths do not merely fallthrough to the next symbol, but past the end of their own section, since LTO builds place each function in its own section. Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always emits machine code directly, with the traps in place. Assisted-by: LLM Cc: Gary Guo <gary@garyguo.net> Cc: Boqun Feng <boqun@kernel.org> Cc: Alice Ryhl <aliceryhl@google.com> Cc: Matthew Maurer <mmaurer@google.com> Cc: Josh Poimboeuf <jpoimboe@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: stable@vger.kernel.org Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust") Acked-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'net/x25/x25_timer.c')
-rw-r--r--net/x25/x25_timer.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/net/x25/x25_timer.c b/net/x25/x25_timer.c
new file mode 100644
index 000000000..7896cd43f
--- /dev/null
+++ b/net/x25/x25_timer.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * X.25 Packet Layer release 002
+ *
+ * This is ALPHA test software. This code may break your machine,
+ * randomly fail to work with new releases, misbehave and/or generally
+ * screw up. It might even work.
+ *
+ * This code REQUIRES 2.1.15 or higher
+ *
+ * History
+ * X.25 001 Jonathan Naylor Started coding.
+ * X.25 002 Jonathan Naylor New timer architecture.
+ * Centralised disconnection processing.
+ */
+
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/x25.h>
+
+static void x25_heartbeat_expiry(struct timer_list *t);
+static void x25_timer_expiry(struct timer_list *t);
+
+void x25_init_timers(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ timer_setup(&x25->timer, x25_timer_expiry, 0);
+
+ /* initialized by sock_init_data */
+ sk->sk_timer.function = x25_heartbeat_expiry;
+}
+
+void x25_start_heartbeat(struct sock *sk)
+{
+ sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ);
+}
+
+void x25_stop_heartbeat(struct sock *sk)
+{
+ sk_stop_timer(sk, &sk->sk_timer);
+}
+
+void x25_start_t2timer(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ sk_reset_timer(sk, &x25->timer, jiffies + x25->t2);
+}
+
+void x25_start_t21timer(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ sk_reset_timer(sk, &x25->timer, jiffies + x25->t21);
+}
+
+void x25_start_t22timer(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ sk_reset_timer(sk, &x25->timer, jiffies + x25->t22);
+}
+
+void x25_start_t23timer(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ sk_reset_timer(sk, &x25->timer, jiffies + x25->t23);
+}
+
+void x25_stop_timer(struct sock *sk)
+{
+ sk_stop_timer(sk, &x25_sk(sk)->timer);
+}
+
+unsigned long x25_display_timer(struct sock *sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ if (!timer_pending(&x25->timer))
+ return 0;
+
+ return x25->timer.expires - jiffies;
+}
+
+static void x25_heartbeat_expiry(struct timer_list *t)
+{
+ struct sock *sk = timer_container_of(sk, t, sk_timer);
+
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */
+ goto restart_heartbeat;
+
+ switch (x25_sk(sk)->state) {
+
+ case X25_STATE_0:
+ /*
+ * Magic here: If we listen() and a new link dies
+ * before it is accepted() it isn't 'dead' so doesn't
+ * get removed.
+ */
+ if (sock_flag(sk, SOCK_DESTROY) ||
+ (sk->sk_state == TCP_LISTEN &&
+ sock_flag(sk, SOCK_DEAD))) {
+ bh_unlock_sock(sk);
+ x25_destroy_socket_from_timer(sk);
+ goto out;
+ }
+ break;
+
+ case X25_STATE_3:
+ /*
+ * Check for the state of the receive buffer.
+ */
+ x25_check_rbuf(sk);
+ break;
+ }
+restart_heartbeat:
+ /* Do not rearm once __x25_destroy_socket() has unlinked the socket:
+ * it is past its cancel point and owns the teardown from there on.
+ */
+ if (sk_hashed(sk))
+ x25_start_heartbeat(sk);
+ bh_unlock_sock(sk);
+out:
+ sock_put(sk);
+}
+
+/*
+ * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
+ * by the state machine state.
+ */
+static inline void x25_do_timer_expiry(struct sock * sk)
+{
+ struct x25_sock *x25 = x25_sk(sk);
+
+ switch (x25->state) {
+
+ case X25_STATE_3: /* T2 */
+ if (x25->condition & X25_COND_ACK_PENDING) {
+ x25->condition &= ~X25_COND_ACK_PENDING;
+ x25_enquiry_response(sk);
+ }
+ break;
+
+ case X25_STATE_1: /* T21 */
+ case X25_STATE_4: /* T22 */
+ x25_write_internal(sk, X25_CLEAR_REQUEST);
+ x25->state = X25_STATE_2;
+ x25_start_t23timer(sk);
+ break;
+
+ case X25_STATE_2: /* T23 */
+ x25_disconnect(sk, ETIMEDOUT, 0, 0);
+ break;
+ }
+}
+
+static void x25_timer_expiry(struct timer_list *t)
+{
+ struct x25_sock *x25 = timer_container_of(x25, t, timer);
+ struct sock *sk = &x25->sk;
+
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */
+ if (x25_sk(sk)->state == X25_STATE_3)
+ x25_start_t2timer(sk);
+ } else
+ x25_do_timer_expiry(sk);
+ bh_unlock_sock(sk);
+ sock_put(sk);
+}