AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/14 19:52 flow patch-triage
4m Args:
null

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "AFS_FS",
    "RXGK",
    "RXPERF"
  ],
  "FocusSymbols": [
    "rxrpc_do_sendmsg",
    "rxrpc_kernel_send_data",
    "rxrpc_notify_socket",
    "rxrpc_recvmsg",
    "rxrpc_poke_conn",
    "afs_make_call",
    "afs_wait_for_operation",
    "afs_send_empty_reply",
    "afs_send_simple_reply"
  ],
  "KMSANReasoning": "The patch series touches AF_RXRPC and AFS subsystems with several distinct fixes and refactorings:\n\n1. In Documentation/networking/rxrpc.rst, include/net/af_rxrpc.h, fs/afs/rxrpc.c, net/rxrpc/rxperf.c, and net/rxrpc/sendmsg.c: The `len` parameter is removed from `rxrpc_kernel_send_data()`, deriving length directly from the message iterator via `msg_data_left()`. The data transmission loop, error rewind logic, and lock handling (`user_mutex`) are adjusted. Data copied into `txb-\u003edata` comes directly from `copy_from_iter_full()`, with lengths strictly bounded by iterator count and remaining buffer space.\n2. In fs/afs/cm_security.c: `toksize` calculation in `afs_create_yfs_cm_token()` is adjusted by adding 4 bytes for the token level field. The underlying buffer `appdata` is allocated using `kzalloc()`, and all fields are explicitly initialized.\n3. In net/rxrpc/key.c: Added `#ifdef CONFIG_RXGK` guards and enctype validation in `rxrpc_preparse_xdr_yfs_rxgk()`. All parsed token allocations use `kzalloc()` and initialized buffers.\n4. In fs/afs/internal.h and fs/afs/fs_operation.c: Fixed server reference pinning (`afs_use_server()`) and cleared dangling `op-\u003ecall` pointer (`op-\u003ecall = NULL`) after call release. These prevent use-after-free conditions, which are detected by KASAN.\n5. In net/rxrpc/conn_object.c, call_state.c, and recvmsg.c: Handled connection reference count races (`rxrpc_get_connection_maybe()`) and separated notification paths when calls are completed or requeued. All variables in updated functions (e.g. `remote_abort = 0`) are explicitly initialized.\n\nNone of the changes introduce uninitialized memory allocations, leak uninitialized data or padding to user space, or add branches dependent on uninitialized data. Risks in these changes (locking, reference counting, and buffer bounds) fall squarely under KASAN and LOCKDEP rather than KMSAN. Therefore, a dedicated KMSAN session is not warranted.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch modifies data transmission and state handling across AF_RXRPC sockets and the AFS network filesystem. Specifically, it alters packet queuing, locking, and rewind/error recovery in rxrpc_send_data/rxrpc_kernel_send_data, notification logic in rxrpc_notify_socket, socket requeueing in rxrpc_recvmsg, connection reference handling in rxrpc_poke_conn, and abort/cleanup logic in fs/afs (afs_make_call, afs_wait_for_operation). These modified paths are fully reachable via user-space AF_RXRPC socket syscalls and AFS operations.",
  "WorthFuzzing": true
}

1/1 2026/09/14 19:52 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 829d37230fc7b5291fafb191d4a2371d77c68b51\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Mon Sep 14 19:52:39 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst\nindex 8926dab8e2e60..9b7eeae841485 100644\n--- a/Documentation/networking/rxrpc.rst\n+++ b/Documentation/networking/rxrpc.rst\n@@ -870,7 +870,6 @@ The kernel interface functions are as follows:\n \tint rxrpc_kernel_send_data(struct socket *sock,\n \t\t\t\t   struct rxrpc_call *call,\n \t\t\t\t   struct msghdr *msg,\n-\t\t\t\t   size_t len,\n \t\t\t\t   rxrpc_notify_end_tx_t notify_end_rx);\n \n      This is used to supply either the request part of a client call or the\n@@ -879,14 +878,19 @@ The kernel interface functions are as follows:\n      exclusively to in-kernel virtual addresses.  msg.msg_flags may be given\n      MSG_MORE if there will be subsequent data sends for this call.\n \n-     The msg must not specify a destination address, control data or any flags\n-     other than MSG_MORE.  len is the total amount of data to transmit.\n+     msg must not specify a destination address, control data or any flags\n+     other than MSG_MORE.  The last-packet flag will only be set on the\n+     outgoing packet if MSG_MORE is not set and all the data in the iterator is\n+     buffered.\n \n      notify_end_rx can be NULL or it can be used to specify a function to be\n      called when the call changes state to end the Tx phase.  This function is\n      called with a spinlock held to prevent the last DATA packet from being\n      transmitted until the function returns.\n \n+     It returns 0 if all the data is queued and a negative error code on\n+     failure.\n+\n  (#) Receive data from a call::\n \n \tint rxrpc_kernel_recv_data(struct socket *sock,\ndiff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c\nindex 103168c70dd4d..5eeeef761cf31 100644\n--- a/fs/afs/cm_security.c\n+++ b/fs/afs/cm_security.c\n@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n \t *\tstruct RXGK_AuthName\tidentities\u003c\u003e;\n \t * };\n \t */\n-\ttoksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n+\ttoksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n \n \toffset = 0;\n \tencsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, \u0026offset);\ndiff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c\nindex 20801b29521d1..94fa65548d712 100644\n--- a/fs/afs/fs_operation.c\n+++ b/fs/afs/fs_operation.c\n@@ -297,6 +297,7 @@ void afs_wait_for_operation(struct afs_operation *op)\n \t\t\top-\u003ecall_error = op-\u003ecall-\u003eerror;\n \t\t\top-\u003ecall_responded = op-\u003ecall-\u003eresponded;\n \t\t\tafs_put_call(op-\u003ecall);\n+\t\t\top-\u003ecall = NULL;\n \t\t}\n \t}\n \ndiff --git a/fs/afs/internal.h b/fs/afs/internal.h\nindex 290873bac89b3..65a0866cd8b85 100644\n--- a/fs/afs/internal.h\n+++ b/fs/afs/internal.h\n@@ -1416,22 +1416,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)\n \t\t       __builtin_return_address(0));\n }\n \n-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n-\t\t\t\t    gfp_t gfp)\n-{\n-\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n-\n-\top-\u003ecall\t= afs_get_call(call, afs_call_trace_get);\n-\top-\u003etype\t= call-\u003etype;\n-\tcall-\u003eop\t= op;\n-\tcall-\u003ekey\t= op-\u003ekey;\n-\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n-\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n-\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n-\tafs_make_call(call, gfp);\n-\tafs_put_call(call);\n-}\n-\n static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)\n {\n \tcall-\u003eiov_len = size;\n@@ -1763,6 +1747,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)\n \treturn \u0026vnode-\u003enetfs.inode;\n }\n \n+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\n+\t\t\t\t    gfp_t gfp)\n+{\n+\tstruct afs_addr_list *alist = op-\u003eestate-\u003eaddresses;\n+\n+\top-\u003ecall\t= afs_get_call(call, afs_call_trace_get);\n+\top-\u003etype\t= call-\u003etype;\n+\tcall-\u003eop\t= op;\n+\tcall-\u003eserver\t= afs_use_server(op-\u003eserver, false, afs_server_trace_use_call);\n+\tcall-\u003ekey\t= op-\u003ekey;\n+\tcall-\u003eintr\t= !(op-\u003eflags \u0026 AFS_OPERATION_UNINTR);\n+\tcall-\u003epeer\t= rxrpc_kernel_get_peer(alist-\u003eaddrs[op-\u003eaddr_index].peer);\n+\tcall-\u003eservice_id = op-\u003eserver-\u003eservice_id;\n+\tafs_make_call(call, gfp);\n+\tafs_put_call(call);\n+}\n+\n /*\n  * Note that a dentry got changed.  We need to set d_fsdata to the data version\n  * number derived from the result of the operation.  It doesn't matter if\ndiff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c\nindex d82916657a3dd..4694a6fca9b4c 100644\n--- a/fs/afs/rxrpc.c\n+++ b/fs/afs/rxrpc.c\n@@ -412,8 +412,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= MSG_WAITALL | (call-\u003ewrite_iter ? MSG_MORE : 0);\n \n-\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall,\n-\t\t\t\t     \u0026msg, call-\u003erequest_size,\n+\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall, \u0026msg,\n \t\t\t\t     afs_notify_end_request_tx);\n \tif (ret \u003c 0)\n \t\tgoto error_do_abort;\n@@ -425,7 +424,6 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \n \t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket,\n \t\t\t\t\t     call-\u003erxcall, \u0026msg,\n-\t\t\t\t\t     iov_iter_count(\u0026msg.msg_iter),\n \t\t\t\t\t     afs_notify_end_request_tx);\n \t\t*call-\u003ewrite_iter = msg.msg_iter;\n \n@@ -443,22 +441,21 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)\n \treturn;\n \n error_do_abort:\n-\tif (ret != -ECONNABORTED)\n-\t\trxrpc_kernel_abort_call(call-\u003enet-\u003esocket, rxcall,\n-\t\t\t\t\tRX_USER_ABORT, ret,\n-\t\t\t\t\tafs_abort_send_data_error);\n+\trxrpc_kernel_abort_call(call-\u003enet-\u003esocket, rxcall,\n+\t\t\t\tRX_USER_ABORT, ret, afs_abort_send_data_error);\n \tif (call-\u003easync) {\n \t\tafs_see_call(call, afs_call_trace_async_abort);\n \t\treturn;\n \t}\n \n-\tif (ret == -ECONNABORTED) {\n+\tif (ret == -ESHUTDOWN) {\n \t\tlen = 0;\n \t\tiov_iter_kvec(\u0026msg.msg_iter, ITER_DEST, NULL, 0, 0);\n-\t\trxrpc_kernel_recv_data(call-\u003enet-\u003esocket, rxcall,\n-\t\t\t\t       \u0026msg.msg_iter, \u0026len, false,\n-\t\t\t\t       \u0026call-\u003eabort_code, \u0026call-\u003eservice_id);\n-\t\tcall-\u003eresponded = true;\n+\t\tret = rxrpc_kernel_recv_data(call-\u003enet-\u003esocket, rxcall,\n+\t\t\t\t\t     \u0026msg.msg_iter, \u0026len, false,\n+\t\t\t\t\t     \u0026call-\u003eabort_code, \u0026call-\u003eservice_id);\n+\t\tif (ret == -ECONNABORTED)\n+\t\t\tcall-\u003eresponded = true;\n \t}\n \tcall-\u003eerror = ret;\n \ttrace_afs_call_done(call);\n@@ -859,6 +856,7 @@ void afs_send_empty_reply(struct afs_call *call)\n {\n \tstruct afs_net *net = call-\u003enet;\n \tstruct msghdr msg;\n+\tint ret;\n \n \t_enter(\"\");\n \n@@ -871,22 +869,12 @@ void afs_send_empty_reply(struct afs_call *call)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= 0;\n \n-\tswitch (rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg, 0,\n-\t\t\t\t       afs_notify_end_reply_tx)) {\n-\tcase 0:\n-\t\t_leave(\" [replied]\");\n-\t\treturn;\n-\n-\tcase -ENOMEM:\n-\t\t_debug(\"oom\");\n+\tret = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg,\n+\t\t\t\t     afs_notify_end_reply_tx);\n+\tif (ret \u003c 0)\n \t\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\tafs_abort_oom);\n-\t\tfallthrough;\n-\tdefault:\n-\t\t_leave(\" [error]\");\n-\t\treturn;\n-\t}\n+\t\t\t\t\tRXGEN_SS_MARSHAL, ret,\n+\t\t\t\t\tafs_abort_send_error);\n }\n \n /*\n@@ -912,21 +900,14 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)\n \tmsg.msg_controllen\t= 0;\n \tmsg.msg_flags\t\t= 0;\n \n-\tn = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg, len,\n+\tn = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg,\n \t\t\t\t   afs_notify_end_reply_tx);\n-\tif (n \u003e= 0) {\n-\t\t/* Success */\n-\t\t_leave(\" [replied]\");\n-\t\treturn;\n-\t}\n-\n-\tif (n == -ENOMEM) {\n-\t\t_debug(\"oom\");\n+\tif (n \u003c 0) {\n \t\trxrpc_kernel_abort_call(net-\u003esocket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\tafs_abort_oom);\n+\t\t\t\t\tRXGEN_SS_MARSHAL, n,\n+\t\t\t\t\tafs_abort_send_error);\n+\t\t_leave(\" [error]\");\n \t}\n-\t_leave(\" [error]\");\n }\n \n /*\ndiff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h\nindex 0fb4c41c9bbf5..f3980348ed343 100644\n--- a/include/net/af_rxrpc.h\n+++ b/include/net/af_rxrpc.h\n@@ -64,9 +64,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,\n \t\t\t\t\t   bool upgrade,\n \t\t\t\t\t   enum rxrpc_interruptibility interruptibility,\n \t\t\t\t\t   unsigned int debug_id);\n-int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,\n-\t\t\t   struct msghdr *, size_t,\n-\t\t\t   rxrpc_notify_end_tx_t);\n+int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n+\t\t\t   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);\n int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,\n \t\t\t   struct iov_iter *, size_t *, bool, u32 *, u16 *);\n bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,\ndiff --git a/include/trace/events/afs.h b/include/trace/events/afs.h\nindex 1b3c48b5591df..04b0bb682b810 100644\n--- a/include/trace/events/afs.h\n+++ b/include/trace/events/afs.h\n@@ -148,6 +148,7 @@ enum yfs_cm_operation {\n \tEM(afs_server_trace_unuse_slist_isort,\t\"UNU isort\") \\\n \tEM(afs_server_trace_update,\t\t\"UPDATE   \") \\\n \tEM(afs_server_trace_use_by_uuid,\t\"USE uuid \") \\\n+\tEM(afs_server_trace_use_call,\t\t\"USE call \") \\\n \tEM(afs_server_trace_use_cm_call,\t\"USE cm-cl\") \\\n \tEM(afs_server_trace_use_get_caps,\t\"USE gcaps\") \\\n \tEM(afs_server_trace_use_give_up_cb,\t\"USE gvupc\") \\\ndiff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h\nindex 704a10de66700..52f8718cf7250 100644\n--- a/include/trace/events/rxrpc.h\n+++ b/include/trace/events/rxrpc.h\n@@ -20,16 +20,16 @@\n \t/* AFS errors */\t\t\t\t\t\t\\\n \tEM(afs_abort_general_error,\t\t\"afs-error\")\t\t\\\n \tEM(afs_abort_interrupted,\t\t\"afs-intr\")\t\t\\\n-\tEM(afs_abort_oom,\t\t\t\"afs-oom\")\t\t\\\n \tEM(afs_abort_op_not_supported,\t\t\"afs-op-notsupp\")\t\\\n \tEM(afs_abort_probeuuid_negative,\t\"afs-probeuuid-neg\")\t\\\n \tEM(afs_abort_send_data_error,\t\t\"afs-send-data\")\t\\\n+\tEM(afs_abort_send_error,\t\t\"afs-send-error\")\t\\\n \tEM(afs_abort_unmarshal_error,\t\t\"afs-unmarshal\")\t\\\n \tEM(afs_abort_unsupported_sec_class,\t\"afs-unsup-sec-class\")\t\\\n \t/* rxperf errors */\t\t\t\t\t\t\\\n \tEM(rxperf_abort_general_error,\t\t\"rxperf-error\")\t\t\\\n-\tEM(rxperf_abort_oom,\t\t\t\"rxperf-oom\")\t\t\\\n \tEM(rxperf_abort_op_not_supported,\t\"rxperf-op-notsupp\")\t\\\n+\tEM(rxperf_abort_send_error,\t\t\"rxperf-send-error\")\t\\\n \tEM(rxperf_abort_unmarshal_error,\t\"rxperf-unmarshal\")\t\\\n \t/* RxKAD security errors */\t\t\t\t\t\\\n \tEM(rxkad_abort_1_short_check,\t\t\"rxkad1-short-check\")\t\\\n@@ -148,6 +148,7 @@\n \tEM(rxrpc_eproto_wrong_security,\t\t\"wrong-sec\")\t\t\\\n \tEM(rxrpc_recvmsg_excess_data,\t\t\"recvmsg-excess\")\t\\\n \tEM(rxrpc_recvmsg_short_data,\t\t\"recvmsg-short\")\t\\\n+\tEM(rxrpc_sendmsg_tx_error,\t\t\"tx-error\")\t\t\\\n \tE_(rxrpc_sendmsg_late_send,\t\t\"sendmsg-late\")\n \n #define rxrpc_call_poke_traces \\\n@@ -342,6 +343,7 @@\n \tEM(rxrpc_call_see_distribute_error,\t\"SEE dist-err\") \\\n \tEM(rxrpc_call_see_input,\t\t\"SEE input   \") \\\n \tEM(rxrpc_call_see_notify_released,\t\"SEE nfy-rlsd\") \\\n+\tEM(rxrpc_call_see_notify_skipped,\t\"SEE nfy-skip\") \\\n \tEM(rxrpc_call_see_recvmsg,\t\t\"SEE recvmsg \") \\\n \tEM(rxrpc_call_see_recvmsg_requeue,\t\"SEE recv-rqu\") \\\n \tEM(rxrpc_call_see_recvmsg_requeue_first, \"SEE recv-rqF\") \\\ndiff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h\nindex 865f05fe37ab9..cb36a709f540e 100644\n--- a/net/rxrpc/ar-internal.h\n+++ b/net/rxrpc/ar-internal.h\n@@ -642,6 +642,7 @@ enum rxrpc_call_flag {\n \tRXRPC_CALL_TX_LAST,\t\t/* Last packet in Tx buffer (at rxtx_top) */\n \tRXRPC_CALL_TX_ALL_ACKED,\t/* Last packet has been hard-acked */\n \tRXRPC_CALL_TX_NO_MORE,\t\t/* No more data to transmit (MSG_MORE deasserted) */\n+\tRXRPC_CALL_TX_ERROR,\t\t/* Terminal error; call needs abort */\n \tRXRPC_CALL_SEND_PING,\t\t/* A ping will need to be sent */\n \tRXRPC_CALL_RETRANS_TIMEOUT,\t/* Retransmission due to timeout occurred */\n \tRXRPC_CALL_BEGAN_RX_TIMER,\t/* We began the expect_rx_by timer */\n@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)\n /*\n  * call_state.c\n  */\n+void rxrpc_notify_socket(struct rxrpc_call *call);\n bool rxrpc_set_call_completion(struct rxrpc_call *call,\n \t\t\t       enum rxrpc_call_completion compl,\n \t\t\t       u32 abort_code,\n@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;\n /*\n  * recvmsg.c\n  */\n-void rxrpc_notify_socket(struct rxrpc_call *);\n int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);\n \n /*\ndiff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c\nindex 6afb54373ebbf..52465e88a0440 100644\n--- a/net/rxrpc/call_state.c\n+++ b/net/rxrpc/call_state.c\n@@ -7,6 +7,61 @@\n \n #include \"ar-internal.h\"\n \n+/*\n+ * Post a call for attention by the socket or kernel service.\n+ */\n+static void __rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tstruct rxrpc_sock *rx;\n+\tstruct sock *sk;\n+\tunsigned long flags;\n+\n+\tif (test_bit(RXRPC_CALL_RELEASED, \u0026call-\u003eflags)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_released);\n+\t\treturn;\n+\t}\n+\n+\trcu_read_lock();\n+\n+\trx = rcu_dereference(call-\u003esocket);\n+\tsk = \u0026rx-\u003esk;\n+\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n+\t\tif (call-\u003enotify_rx) {\n+\t\t\tspin_lock_irqsave(\u0026call-\u003enotify_lock, flags);\n+\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n+\t\t\tspin_unlock_irqrestore(\u0026call-\u003enotify_lock, flags);\n+\t\t} else {\n+\t\t\tspin_lock_irqsave(\u0026rx-\u003erecvmsg_lock, flags);\n+\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t\t\t}\n+\t\t\tspin_unlock_irqrestore(\u0026rx-\u003erecvmsg_lock, flags);\n+\n+\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\t\t\tsk-\u003esk_data_ready(sk);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\trcu_read_unlock();\n+}\n+\n+/*\n+ * Post a call for attention by the socket or kernel service if the call isn't\n+ * already complete.\n+ */\n+void rxrpc_notify_socket(struct rxrpc_call *call)\n+{\n+\tif (rxrpc_call_is_complete(call)) {\n+\t\trxrpc_see_call(call, rxrpc_call_see_notify_skipped);\n+\t\treturn;\n+\t}\n+\n+\t__rxrpc_notify_socket(call);\n+}\n+\n /*\n  * Transition a call to the complete state.\n  */\n@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,\n \trxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);\n \ttrace_rxrpc_call_complete(call);\n \twake_up(\u0026call-\u003ewaitq);\n-\trxrpc_notify_socket(call);\n+\t__rxrpc_notify_socket(call);\n \treturn true;\n }\n \ndiff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c\nindex 0ece717db0f85..1be50e0c9cee5 100644\n--- a/net/rxrpc/conn_object.c\n+++ b/net/rxrpc/conn_object.c\n@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)\n \tspin_lock_irq(\u0026local-\u003elock);\n \tbusy = !list_empty(\u0026conn-\u003eattend_link);\n \tif (!busy) {\n-\t\trxrpc_get_connection(conn, why);\n+\t\tif (!rxrpc_get_connection_maybe(conn, why)) {\n+\t\t\tspin_unlock_irq(\u0026local-\u003elock);\n+\t\t\treturn;\n+\t\t}\n \t\tlist_add_tail(\u0026conn-\u003eattend_link, \u0026local-\u003econn_attend_q);\n \t}\n \tspin_unlock_irq(\u0026local-\u003elock);\ndiff --git a/net/rxrpc/key.c b/net/rxrpc/key.c\nindex a0aa78d892897..dc1b3aa51bf32 100644\n--- a/net/rxrpc/key.c\n+++ b/net/rxrpc/key.c\n@@ -129,6 +129,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,\n \treturn 0;\n }\n \n+#ifdef CONFIG_RXGK\n static u64 xdr_dec64(const __be32 *xdr)\n {\n \treturn (u64)ntohl(xdr[0]) \u003c\u003c 32 | (u64)ntohl(xdr[1]);\n@@ -166,12 +167,14 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \t\t\t\t       size_t datalen,\n \t\t\t\t       const __be32 *xdr, unsigned int toklen)\n {\n+\tconst struct krb5_enctype *enc;\n \tstruct rxrpc_key_token *token, **pptoken;\n \ttime64_t expiry;\n \tsize_t plen;\n \tconst __be32 *ticket, *key;\n \ts64 tmp;\n \tsize_t raw_keylen, raw_tktlen, keylen, tktlen;\n+\tint ret = -EKEYREJECTED;\n \n \t_enter(\",{%x,%x,%x,%x},%x\",\n \t       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),\n@@ -229,6 +232,17 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \ttoken-\u003erxgk-\u003ekey.data\t= token-\u003erxgk-\u003e_key;\n \ttoken-\u003erxgk-\u003eticket.len = raw_tktlen;\n \n+\t/* Check the enctype is supported. */\n+\tenc = crypto_krb5_find_enctype(token-\u003erxgk-\u003eenctype);\n+\tif (!enc) {\n+\t\tret = -ENOPKG;\n+\t\tgoto reject_token;\n+\t}\n+\tif (raw_keylen != enc-\u003ekey_len) {\n+\t\tret = -EKEYREJECTED;\n+\t\tgoto reject_token;\n+\t}\n+\n \tif (token-\u003erxgk-\u003eendtime != 0) {\n \t\texpiry = rxrpc_s64_to_time64(token-\u003erxgk-\u003eendtime);\n \t\tif (expiry \u003c 0)\n@@ -280,12 +294,13 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\n \tkfree(token-\u003erxgk);\n \tkfree(token);\n reject:\n-\treturn -EKEYREJECTED;\n+\treturn ret;\n expired:\n \tkfree(token-\u003erxgk);\n \tkfree(token);\n \treturn -EKEYEXPIRED;\n }\n+#endif /* CONFIG_RXGK */\n \n /*\n  * attempt to parse the data as the XDR format\n@@ -386,9 +401,11 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)\n \t\tcase RXRPC_SECURITY_RXKAD:\n \t\t\tret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);\n \t\t\tbreak;\n+#ifdef CONFIG_RXGK\n \t\tcase RXRPC_SECURITY_YFS_RXGK:\n \t\t\tret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);\n \t\t\tbreak;\n+#endif\n \t\tdefault:\n \t\t\tret2 = -EPROTONOSUPPORT;\n \t\t\tbreak;\n@@ -556,10 +573,12 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)\n \t\tcase RXRPC_SECURITY_RXKAD:\n \t\t\tkfree(token-\u003ekad);\n \t\t\tbreak;\n+#ifdef CONFIG_RXGK\n \t\tcase RXRPC_SECURITY_YFS_RXGK:\n \t\t\tkfree(token-\u003erxgk-\u003eticket.data);\n \t\t\tkfree(token-\u003erxgk);\n \t\t\tbreak;\n+#endif\n \t\tdefault:\n \t\t\tpr_err(\"Unknown token type %x on rxrpc key\\n\",\n \t\t\t       token-\u003esecurity_index);\n@@ -603,9 +622,11 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)\n \t\tcase RXRPC_SECURITY_RXKAD:\n \t\t\tseq_puts(m, \"ka\");\n \t\t\tbreak;\n+#ifdef CONFIG_RXGK\n \t\tcase RXRPC_SECURITY_YFS_RXGK:\n \t\t\tseq_puts(m, \"ygk\");\n \t\t\tbreak;\n+#endif\n \t\tdefault: /* we have a ticket we can't encode */\n \t\t\tseq_printf(m, \"%u\", token-\u003esecurity_index);\n \t\t\tbreak;\n@@ -770,12 +791,14 @@ static long rxrpc_read(const struct key *key,\n \t\t\t\ttoksize += RND(token-\u003ekad-\u003eticket_len);\n \t\t\tbreak;\n \n+#ifdef CONFIG_RXGK\n \t\tcase RXRPC_SECURITY_YFS_RXGK:\n \t\t\ttoksize += 6 * 8 + 2 * 4;\n \t\t\tif (!token-\u003eno_leak_key)\n \t\t\t\ttoksize += RND(token-\u003erxgk-\u003ekey.len);\n \t\t\ttoksize += RND(token-\u003erxgk-\u003eticket.len);\n \t\t\tbreak;\n+#endif\n \n \t\tdefault: /* we have a ticket we can't encode */\n \t\t\tpr_err(\"Unsupported key token type (%u)\\n\",\n@@ -856,6 +879,7 @@ static long rxrpc_read(const struct key *key,\n \t\t\t\tENCODE_DATA(token-\u003ekad-\u003eticket_len, token-\u003ekad-\u003eticket);\n \t\t\tbreak;\n \n+#ifdef CONFIG_RXGK\n \t\tcase RXRPC_SECURITY_YFS_RXGK:\n \t\t\tENCODE64(token-\u003erxgk-\u003ebegintime);\n \t\t\tENCODE64(token-\u003erxgk-\u003eendtime);\n@@ -869,6 +893,7 @@ static long rxrpc_read(const struct key *key,\n \t\t\t\tENCODE_DATA(token-\u003erxgk-\u003ekey.len, token-\u003erxgk-\u003ekey.data);\n \t\t\tENCODE_DATA(token-\u003erxgk-\u003eticket.len, token-\u003erxgk-\u003eticket.data);\n \t\t\tbreak;\n+#endif\n \n \t\tdefault:\n \t\t\tpr_err(\"Unsupported key token type (%u)\\n\",\ndiff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c\nindex efcba4b2e74f0..22afc71ea474f 100644\n--- a/net/rxrpc/recvmsg.c\n+++ b/net/rxrpc/recvmsg.c\n@@ -17,13 +17,14 @@\n #include \"ar-internal.h\"\n \n /*\n- * Post a call for attention by the socket or kernel service.  Further\n- * notifications are suppressed by putting recvmsg_link on a dummy queue.\n+ * Requeue a call for recvmsg() to pick up.  We ignore RXRPC_CLOSE, allowing\n+ * recvmsg() to continue picking up calls that are already on the queue if it\n+ * wants to, but no new calls will get added.\n  */\n-void rxrpc_notify_socket(struct rxrpc_call *call)\n+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)\n {\n-\tstruct rxrpc_sock *rx;\n-\tstruct sock *sk;\n+\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n+\tstruct sock *sk = \u0026rx-\u003esk;\n \n \t_enter(\"%d\", call-\u003edebug_id);\n \n@@ -32,31 +33,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)\n \t\treturn;\n \t}\n \n-\trcu_read_lock();\n-\n-\trx = rcu_dereference(call-\u003esocket);\n-\tsk = \u0026rx-\u003esk;\n-\tif (rx \u0026\u0026 sk-\u003esk_state \u003c RXRPC_CLOSE) {\n-\t\tif (call-\u003enotify_rx) {\n-\t\t\tspin_lock_irq(\u0026call-\u003enotify_lock);\n-\t\t\tcall-\u003enotify_rx(sk, call, call-\u003euser_call_ID);\n-\t\t\tspin_unlock_irq(\u0026call-\u003enotify_lock);\n-\t\t} else {\n-\t\t\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n-\t\t\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n-\t\t\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n-\t\t\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n-\t\t\t}\n-\t\t\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tspin_lock_irq(\u0026rx-\u003erecvmsg_lock);\n+\tif (list_empty(\u0026call-\u003erecvmsg_link)) {\n+\t\trxrpc_get_call(call, rxrpc_call_get_notify_socket);\n+\t\tlist_add_tail(\u0026call-\u003erecvmsg_link, \u0026rx-\u003erecvmsg_q);\n+\t}\n+\tspin_unlock_irq(\u0026rx-\u003erecvmsg_lock);\n \n-\t\t\tif (!sock_flag(sk, SOCK_DEAD)) {\n-\t\t\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n-\t\t\t\tsk-\u003esk_data_ready(sk);\n-\t\t\t}\n-\t\t}\n+\tif (!sock_flag(sk, SOCK_DEAD)) {\n+\t\t_debug(\"call %ps\", sk-\u003esk_data_ready);\n+\t\tsk-\u003esk_data_ready(sk);\n \t}\n \n-\trcu_read_unlock();\n \t_leave(\"\");\n }\n \n@@ -561,7 +549,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n \n \tif (!(flags \u0026 MSG_PEEK) \u0026\u0026\n \t    !skb_queue_empty(\u0026call-\u003erecvmsg_queue))\n-\t\trxrpc_notify_socket(call);\n+\t\trxrpc_requeue_call(sock, call);\n \tgoto not_yet_complete;\n \n call_failed:\ndiff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c\nindex b8df6d22314d6..83016830e6965 100644\n--- a/net/rxrpc/rxperf.c\n+++ b/net/rxrpc/rxperf.c\n@@ -74,7 +74,7 @@ static struct workqueue_struct *rxperf_workqueue;\n static void rxperf_deliver_to_call(struct work_struct *work);\n static int rxperf_deliver_param_block(struct rxperf_call *call);\n static int rxperf_deliver_request(struct rxperf_call *call);\n-static int rxperf_process_call(struct rxperf_call *call);\n+static void rxperf_process_call(struct rxperf_call *call);\n static void rxperf_charge_preallocation(struct work_struct *work);\n \n static DECLARE_WORK(rxperf_charge_preallocation_work,\n@@ -293,18 +293,28 @@ static void rxperf_deliver_to_call(struct work_struct *work)\n \t       state == RXPERF_CALL_SV_AWAIT_ACK\n \t       ) {\n \t\tif (state == RXPERF_CALL_SV_AWAIT_ACK) {\n-\t\t\tif (!rxrpc_kernel_check_life(rxperf_socket, call-\u003erxcall))\n+\t\t\tsize_t len = 0;\n+\t\t\tiov_iter_kvec(\u0026call-\u003eiter, ITER_DEST, NULL, 0, 0);\n+\t\t\tret = rxrpc_kernel_recv_data(rxperf_socket,\n+\t\t\t\t\t\t     call-\u003erxcall, \u0026call-\u003eiter,\n+\t\t\t\t\t\t     \u0026len, false, \u0026remote_abort,\n+\t\t\t\t\t\t     \u0026call-\u003eservice_id);\n+\n+\t\t\tif (ret == -EINPROGRESS || ret == -EAGAIN)\n+\t\t\t\treturn;\n+\t\t\tif (ret \u003c 0 || ret == 1) {\n+\t\t\t\tif (ret == 1)\n+\t\t\t\t\tret = 0;\n \t\t\t\tgoto call_complete;\n+\t\t\t}\n \t\t\treturn;\n \t\t}\n \n \t\tret = call-\u003edeliver(call);\n-\t\tif (ret == 0)\n-\t\t\tret = rxperf_process_call(call);\n-\n \t\tswitch (ret) {\n \t\tcase 0:\n-\t\t\tcontinue;\n+\t\t\trxperf_process_call(call);\n+\t\t\treturn;\n \t\tcase -EINPROGRESS:\n \t\tcase -EAGAIN:\n \t\t\treturn;\n@@ -508,7 +518,7 @@ static int rxperf_deliver_request(struct rxperf_call *call)\n /*\n  * Process a call for which we've received the request.\n  */\n-static int rxperf_process_call(struct rxperf_call *call)\n+static void rxperf_process_call(struct rxperf_call *call)\n {\n \tstruct msghdr msg = {};\n \tstruct bio_vec bv;\n@@ -525,12 +535,10 @@ static int rxperf_process_call(struct rxperf_call *call)\n \t\tiov_iter_bvec(\u0026msg.msg_iter, WRITE, \u0026bv, 1, len);\n \t\tmsg.msg_flags = MSG_MORE;\n \t\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg,\n-\t\t\t\t\t   len, rxperf_notify_end_reply_tx);\n+\t\t\t\t\t   rxperf_notify_end_reply_tx);\n \t\tif (n \u003c 0)\n-\t\t\treturn n;\n-\t\tif (n == 0)\n-\t\t\treturn -EIO;\n-\t\treply_len -= n;\n+\t\t\tgoto send_error;\n+\t\treply_len -= len;\n \t}\n \n \tlen = sizeof(rxperf_magic_cookie);\n@@ -538,16 +546,16 @@ static int rxperf_process_call(struct rxperf_call *call)\n \tiov[0].iov_len\t= len;\n \tiov_iter_kvec(\u0026msg.msg_iter, WRITE, iov, 1, len);\n \tmsg.msg_flags = 0;\n-\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg, len,\n+\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg,\n \t\t\t\t   rxperf_notify_end_reply_tx);\n-\tif (n \u003e= 0)\n-\t\treturn 0; /* Success */\n-\n-\tif (n == -ENOMEM)\n-\t\trxrpc_kernel_abort_call(rxperf_socket, call-\u003erxcall,\n-\t\t\t\t\tRXGEN_SS_MARSHAL, -ENOMEM,\n-\t\t\t\t\trxperf_abort_oom);\n-\treturn n;\n+\tif (n \u003c 0)\n+\t\tgoto send_error;\n+\treturn;\n+\n+send_error:\n+\trxrpc_kernel_abort_call(rxperf_socket, call-\u003erxcall,\n+\t\t\t\tRXGEN_SS_MARSHAL, n,\n+\t\t\t\trxperf_abort_send_error);\n }\n \n /*\n@@ -700,4 +708,3 @@ static void __exit rxperf_exit(void)\n \trcu_barrier();\n }\n module_exit(rxperf_exit);\n-\ndiff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c\nindex ed2c9a51005ad..ed7ff32da1847 100644\n--- a/net/rxrpc/sendmsg.c\n+++ b/net/rxrpc/sendmsg.c\n@@ -320,51 +320,53 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)\n static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t   struct rxrpc_call *call,\n \t\t\t   struct msghdr *msg, size_t len,\n-\t\t\t   rxrpc_notify_end_tx_t notify_end_tx,\n-\t\t\t   bool *_dropped_lock)\n+\t\t\t   rxrpc_notify_end_tx_t notify_end_tx)\n+\t__releases(\u0026call-\u003euser_mutex)\n {\n-\tstruct rxrpc_txbuf *txb;\n \tstruct sock *sk = \u0026rx-\u003esk;\n \tenum rxrpc_call_state state;\n+\tunsigned int rewind_by = 0;\n \tlong timeo;\n \tbool more = msg-\u003emsg_flags \u0026 MSG_MORE;\n \tint ret, copied = 0;\n \n-\tif (test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags)) {\n-\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n-\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n-\t\t\t\t  0, -EPROTO);\n-\t\treturn -EPROTO;\n-\t}\n-\n \ttimeo = sock_sndtimeo(sk, msg-\u003emsg_flags \u0026 MSG_DONTWAIT);\n \n \tret = rxrpc_wait_to_be_connected(call, \u0026timeo);\n \tif (ret \u003c 0)\n-\t\treturn ret;\n+\t\tgoto out_unlock;\n \n \tif (call-\u003econn-\u003estate == RXRPC_CONN_CLIENT_UNSECURED) {\n \t\tret = rxrpc_init_client_conn_security(call-\u003econn);\n \t\tif (ret \u003c 0)\n-\t\t\treturn ret;\n+\t\t\tgoto out_unlock;\n \t}\n \n \t/* this should be in poll */\n \tsk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);\n \n reload:\n-\ttxb = call-\u003etx_pending;\n-\tcall-\u003etx_pending = NULL;\n-\tif (txb)\n-\t\trxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags))) {\n+\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n+\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n+\t\t\t\t  0, -EPROTO);\n+\t\tret = -EPROTO;\n+\t\tgoto out_unlock;\n+\t}\n+\tif (unlikely(test_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags))) {\n+\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_tx_error,\n+\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n+\t\t\t\t  0, -EIO);\n+\t\tret = -EIO;\n+\t\tgoto out_unlock;\n+\t}\n \n \tret = -EPIPE;\n \tif (sk-\u003esk_shutdown \u0026 SEND_SHUTDOWN)\n-\t\tgoto maybe_error;\n+\t\tgoto out_unlock;\n \tstate = rxrpc_call_state(call);\n-\tret = -ESHUTDOWN;\n \tif (state \u003e= RXRPC_CALL_COMPLETE)\n-\t\tgoto maybe_error;\n+\t\tgoto call_terminated;\n \tret = -EPROTO;\n \tif (state != RXRPC_CALL_CLIENT_PRE_SEND \u0026\u0026\n \t    state != RXRPC_CALL_CLIENT_SEND_REQUEST \u0026\u0026\n@@ -374,18 +376,20 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_sendmsg_late_send,\n \t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n \t\t\t\t  0, -EPROTO);\n-\t\tgoto maybe_error;\n+\t\tgoto out_unlock;\n \t}\n \n \tret = -EMSGSIZE;\n \tif (call-\u003etx_total_len != -1) {\n-\t\tif (len - copied \u003e call-\u003etx_total_len)\n+\t\tif (len \u003e call-\u003etx_total_len)\n \t\t\tgoto maybe_error;\n-\t\tif (!more \u0026\u0026 len - copied != call-\u003etx_total_len)\n+\t\tif (!more \u0026\u0026 len != call-\u003etx_total_len)\n \t\t\tgoto maybe_error;\n \t}\n \n \tdo {\n+\t\tstruct rxrpc_txbuf *txb = call-\u003etx_pending;\n+\n \t\tif (!txb) {\n \t\t\tsize_t remain;\n \n@@ -405,29 +409,34 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t * the security header is going to be in the padded\n \t\t\t * region (enc blocksize), but the trailer is not.\n \t\t\t */\n-\t\t\tremain = more ? INT_MAX : msg_data_left(msg);\n+\t\t\tremain = more ? INT_MAX : len;\n \t\t\ttxb = call-\u003econn-\u003esecurity-\u003ealloc_txbuf(call, remain, sk-\u003esk_allocation);\n \t\t\tif (!txb) {\n \t\t\t\tret = -ENOMEM;\n \t\t\t\tgoto maybe_error;\n \t\t\t}\n+\t\t\tcall-\u003etx_pending = txb;\n+\t\t} else {\n+\t\t\trxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);\n \t\t}\n \n \t\t_debug(\"append\");\n \n \t\t/* append next segment of data to the current buffer */\n-\t\tif (msg_data_left(msg) \u003e 0) {\n-\t\t\tsize_t copy = umin(txb-\u003espace, msg_data_left(msg));\n+\t\tif (len \u003e 0) {\n+\t\t\tsize_t copy = min3(txb-\u003espace, len, msg_data_left(msg));\n \n \t\t\t_debug(\"add %zu\", copy);\n \t\t\tif (!copy_from_iter_full(txb-\u003edata + txb-\u003eoffset,\n \t\t\t\t\t\t copy, \u0026msg-\u003emsg_iter))\n \t\t\t\tgoto efault;\n \t\t\t_debug(\"added\");\n+\t\t\trewind_by = copy;\n \t\t\ttxb-\u003espace -= copy;\n \t\t\ttxb-\u003elen += copy;\n \t\t\ttxb-\u003eoffset += copy;\n \t\t\tcopied += copy;\n+\t\t\tlen -= copy;\n \t\t\tif (call-\u003etx_total_len != -1)\n \t\t\t\tcall-\u003etx_total_len -= copy;\n \t\t}\n@@ -439,62 +448,141 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \n \t\t/* add the packet to the send queue if it's now full */\n \t\tif (!txb-\u003espace ||\n-\t\t    (msg_data_left(msg) == 0 \u0026\u0026 !more)) {\n-\t\t\tif (msg_data_left(msg) == 0 \u0026\u0026 !more)\n-\t\t\t\ttxb-\u003eflags |= RXRPC_LAST_PACKET;\n-\n+\t\t    (len == 0 \u0026\u0026 !more)) {\n+\t\t\t/* Do any required crypto.  If this fails, it could\n+\t\t\t * have corrupted the txbuf content with a partial\n+\t\t\t * encrypt.  Assume that ENOMEM is retryable, but\n+\t\t\t * everything else is terminal.\n+\t\t\t */\n \t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n-\t\t\tif (ret \u003c 0)\n+\t\t\tif (ret \u003c 0) {\n+\t\t\t\t/* Assume that ENOMEM here means that the\n+\t\t\t\t * encryption hasn't happened yet.  The data is\n+\t\t\t\t * aligned to avoid the need for slow buffering\n+\t\t\t\t * in the crypto walk.\n+\t\t\t\t */\n+\t\t\t\tif (ret == -ENOMEM)\n+\t\t\t\t\tgoto maybe_error_rewind;\n+\t\t\t\tset_bit(RXRPC_CALL_TX_ERROR, \u0026call-\u003eflags);\n \t\t\t\tgoto out;\n+\t\t\t}\n+\n+\t\t\tif (len == 0 \u0026\u0026 !more)\n+\t\t\t\ttxb-\u003eflags |= RXRPC_LAST_PACKET;\n \t\t\trxrpc_queue_packet(rx, call, txb, notify_end_tx);\n-\t\t\ttxb = NULL;\n+\t\t\tcall-\u003etx_pending = NULL;\n+\t\t\trewind_by = 0;\n+\n+\t\t\t/* At this point, if that was the last packet, it may\n+\t\t\t * have been transmitted and the reply (client call) or\n+\t\t\t * final ACK (service call) may have been received,\n+\t\t\t * completing the call.\n+\t\t\t */\n \t\t}\n-\t} while (msg_data_left(msg) \u003e 0);\n+\t} while (len \u003e 0 \u0026\u0026 msg_data_left(msg) \u003e 0);\n \n-success:\n+\t/* Don't check for call completeness here, but leave that to recvmsg or\n+\t * a further call to sendmsg().\n+\t */\n \tret = copied;\n-\tif (rxrpc_call_is_complete(call) \u0026\u0026\n-\t    call-\u003eerror \u003c 0)\n-\t\tret = call-\u003eerror;\n+out_unlock:\n+\tmutex_unlock(\u0026call-\u003euser_mutex);\n out:\n-\tcall-\u003etx_pending = txb;\n+\n+\t/* The return value is a bit complicated as we want to avoid returning\n+\t * an error if we have queued the final packet.  In descending order of\n+\t * preference:\n+\t *\n+\t * (1) If we queue the last packet: the amount copied (which may be\n+\t *     zero).  recvmsg() should be used to collect the result.\n+\t *\n+\t * (2) If another sendmsg() has already queued the last packet: -EPROTO.\n+\t *\n+\t * (3) If an error caused it to be impossible to continue with the\n+\t *     call: -EIO.\n+\t *\n+\t * (4) If the send side of the socket is shut down, -EPIPE.\n+\t *\n+\t * (5) If the call is in the wrong state to transmit: -EPROTO.\n+\t *\n+\t * (6) If the call has terminated early, likely due to an external\n+\t *     event such as being remotely aborted: -ESHUTDOWN.\n+\t *\n+\t * (7) If some data has been copied by this call: the amount copied\n+\t *     (which will be greater than zero).\n+\t *\n+\t * (8) Any other error.\n+\t *\n+\t * For (2)-(6), there's no point in continuing with the sendmsg().  The\n+\t * app should abort the call (just in case the error came from\n+\t * somewhere else) and then use recvmsg() to collect the final result\n+\t * of the call.\n+\t */\n \t_leave(\" = %d\", ret);\n \treturn ret;\n \n call_terminated:\n-\trxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);\n-\t_leave(\" = %d\", call-\u003eerror);\n-\treturn call-\u003eerror;\n-\n+\tret = -ESHUTDOWN;\n+\tgoto out_unlock;\n+\n+maybe_error_rewind:\n+\t/* If we got a retryable error after copying all the supplied data into\n+\t * the last packet, we need to rewind as much as we can so the caller\n+\t * knows they need to retry the sendmsg.\n+\t */\n+\tif (rewind_by \u0026\u0026 !more \u0026\u0026 !len) {\n+\t\tstruct rxrpc_txbuf *txb = call-\u003etx_pending;\n+\n+\t\ttxb-\u003espace  += rewind_by;\n+\t\ttxb-\u003elen    -= rewind_by;\n+\t\ttxb-\u003eoffset -= rewind_by;\n+\t\tcopied      -= rewind_by;\n+\t\tif (call-\u003etx_total_len != -1)\n+\t\t\tcall-\u003etx_total_len += rewind_by;\n+\t\tiov_iter_revert(\u0026msg-\u003emsg_iter, rewind_by);\n+\t}\n maybe_error:\n-\tif (copied)\n-\t\tgoto success;\n-\tgoto out;\n+\tif (copied) {\n+\t\tif (test_bit(RXRPC_CALL_TX_NO_MORE, \u0026call-\u003eflags)) {\n+\t\t\t/* If we've get here, we must have slept waiting for space and .\n+\t\t\t */\n+\t\t\tret = copied;\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\t\tif (rxrpc_call_is_complete(call))\n+\t\t\tgoto call_terminated;\n+\t\tret = copied;\n+\t}\n+\tgoto out_unlock;\n \n efault:\n \tret = -EFAULT;\n-\tgoto out;\n+\tgoto maybe_error;\n \n wait_for_space:\n \tret = -EAGAIN;\n \tif (msg-\u003emsg_flags \u0026 MSG_DONTWAIT)\n \t\tgoto maybe_error;\n \tmutex_unlock(\u0026call-\u003euser_mutex);\n-\t*_dropped_lock = true;\n+\n \tret = rxrpc_wait_for_tx_window(rx, call, \u0026timeo,\n \t\t\t\t       msg-\u003emsg_flags \u0026 MSG_WAITALL);\n \tif (ret \u003c 0)\n-\t\tgoto maybe_error;\n+\t\tgoto out_nolock;\n \tif (call-\u003einterruptibility == RXRPC_INTERRUPTIBLE) {\n \t\tif (mutex_lock_interruptible(\u0026call-\u003euser_mutex) \u003c 0) {\n \t\t\tret = sock_intr_errno(timeo);\n-\t\t\tgoto maybe_error;\n+\t\t\tgoto out_nolock;\n \t\t}\n \t} else {\n \t\tmutex_lock(\u0026call-\u003euser_mutex);\n \t}\n-\t*_dropped_lock = false;\n \tgoto reload;\n+out_nolock:\n+\t_leave(\" = %d [intr]\", ret);\n+\tif (copied)\n+\t\tret = copied;\n+\tgoto out;\n }\n \n /*\n@@ -660,7 +748,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,\n int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n {\n \tstruct rxrpc_call *call;\n-\tbool dropped_lock = false;\n \tint ret;\n \n \tstruct rxrpc_send_params p = {\n@@ -769,16 +856,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n \t\tret = 0;\n \t\tbreak;\n \tcase RXRPC_CMD_SEND_DATA:\n-\t\tret = rxrpc_send_data(rx, call, msg, len, NULL, \u0026dropped_lock);\n-\t\tbreak;\n+\t\tret = rxrpc_send_data(rx, call, msg, len, NULL);\n+\t\tgoto error_put;\n \tdefault:\n \t\tret = -EINVAL;\n \t\tbreak;\n \t}\n \n out_put_unlock:\n-\tif (!dropped_lock)\n-\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n+\tmutex_unlock(\u0026call-\u003euser_mutex);\n error_put:\n \trxrpc_put_call(call, rxrpc_call_put_sendmsg);\n \t_leave(\" = %d\", ret);\n@@ -794,7 +880,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n  * @sock: The socket the call is on\n  * @call: The call to send data through\n  * @msg: The data to send\n- * @len: The amount of data to send\n  * @notify_end_tx: Notification that the last packet is queued.\n  *\n  * Allow a kernel service to send data on a call.  The call must be in an state\n@@ -805,10 +890,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n  * Return: %0 if successful and a negative error code otherwise.\n  */\n int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n-\t\t\t   struct msghdr *msg, size_t len,\n-\t\t\t   rxrpc_notify_end_tx_t notify_end_tx)\n+\t\t\t   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)\n {\n-\tbool dropped_lock = false;\n \tint ret;\n \n \t_enter(\"{%d},\", call-\u003edebug_id);\n@@ -816,15 +899,23 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n \tASSERTCMP(msg-\u003emsg_name, ==, NULL);\n \tASSERTCMP(msg-\u003emsg_control, ==, NULL);\n \n-\tmutex_lock(\u0026call-\u003euser_mutex);\n+\tfor (;;) {\n+\t\tmutex_lock(\u0026call-\u003euser_mutex);\n \n-\tret = rxrpc_send_data(rxrpc_sk(sock-\u003esk), call, msg, len,\n-\t\t\t      notify_end_tx, \u0026dropped_lock);\n-\tif (ret == -ESHUTDOWN)\n-\t\tret = call-\u003eerror;\n+\t\tret = rxrpc_send_data(rxrpc_sk(sock-\u003esk), call, msg,\n+\t\t\t\t      msg_data_left(msg), notify_end_tx);\n+\t\tif (ret \u003c 0)\n+\t\t\tbreak;\n+\t\tif (msg_data_left(msg) == 0) {\n+\t\t\tret = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (ret == 0) {\n+\t\t\tret = -EIO;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n \n-\tif (!dropped_lock)\n-\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n \t_leave(\" = %d\", ret);\n \treturn ret;\n }\n"
}

2/1 2026/09/14 19:52 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "AFS_FS",
    "RXGK",
    "RXPERF"
  ],
  "FocusSymbols": [
    "rxrpc_do_sendmsg",
    "rxrpc_kernel_send_data",
    "rxrpc_notify_socket",
    "rxrpc_recvmsg",
    "rxrpc_poke_conn",
    "afs_make_call",
    "afs_wait_for_operation",
    "afs_send_empty_reply",
    "afs_send_simple_reply"
  ],
  "Reasoning": "The patch modifies data transmission and state handling across AF_RXRPC sockets and the AFS network filesystem. Specifically, it alters packet queuing, locking, and rewind/error recovery in rxrpc_send_data/rxrpc_kernel_send_data, notification logic in rxrpc_notify_socket, socket requeueing in rxrpc_recvmsg, connection reference handling in rxrpc_poke_conn, and abort/cleanup logic in fs/afs (afs_make_call, afs_wait_for_operation). These modified paths are fully reachable via user-space AF_RXRPC socket syscalls and AFS operations.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 829d37230fc7b5291fafb191d4a2371d77c68b51
Author: syz-cluster <triage@syzkaller.com>
Date:   Mon Sep 14 19:52:39 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 8926dab8e2e60..9b7eeae841485 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -870,7 +870,6 @@ The kernel interface functions are as follows:
 	int rxrpc_kernel_send_data(struct socket *sock,
 				   struct rxrpc_call *call,
 				   struct msghdr *msg,
-				   size_t len,
 				   rxrpc_notify_end_tx_t notify_end_rx);
 
      This is used to supply either the request part of a client call or the
@@ -879,14 +878,19 @@ The kernel interface functions are as follows:
      exclusively to in-kernel virtual addresses.  msg.msg_flags may be given
      MSG_MORE if there will be subsequent data sends for this call.
 
-     The msg must not specify a destination address, control data or any flags
-     other than MSG_MORE.  len is the total amount of data to transmit.
+     msg must not specify a destination address, control data or any flags
+     other than MSG_MORE.  The last-packet flag will only be set on the
+     outgoing packet if MSG_MORE is not set and all the data in the iterator is
+     buffered.
 
      notify_end_rx can be NULL or it can be used to specify a function to be
      called when the call changes state to end the Tx phase.  This function is
      called with a spinlock held to prevent the last DATA packet from being
      transmitted until the function returns.
 
+     It returns 0 if all the data is queued and a negative error code on
+     failure.
+
  (#) Receive data from a call::
 
 	int rxrpc_kernel_recv_data(struct socket *sock,
diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4d..5eeeef761cf31 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
 	 *	struct RXGK_AuthName	identities<>;
 	 * };
 	 */
-	toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+	toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
 
 	offset = 0;
 	encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c
index 20801b29521d1..94fa65548d712 100644
--- a/fs/afs/fs_operation.c
+++ b/fs/afs/fs_operation.c
@@ -297,6 +297,7 @@ void afs_wait_for_operation(struct afs_operation *op)
 			op->call_error = op->call->error;
 			op->call_responded = op->call->responded;
 			afs_put_call(op->call);
+			op->call = NULL;
 		}
 	}
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 290873bac89b3..65a0866cd8b85 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1416,22 +1416,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
 		       __builtin_return_address(0));
 }
 
-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
-				    gfp_t gfp)
-{
-	struct afs_addr_list *alist = op->estate->addresses;
-
-	op->call	= afs_get_call(call, afs_call_trace_get);
-	op->type	= call->type;
-	call->op	= op;
-	call->key	= op->key;
-	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
-	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
-	call->service_id = op->server->service_id;
-	afs_make_call(call, gfp);
-	afs_put_call(call);
-}
-
 static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
 {
 	call->iov_len = size;
@@ -1763,6 +1747,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
 	return &vnode->netfs.inode;
 }
 
+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
+				    gfp_t gfp)
+{
+	struct afs_addr_list *alist = op->estate->addresses;
+
+	op->call	= afs_get_call(call, afs_call_trace_get);
+	op->type	= call->type;
+	call->op	= op;
+	call->server	= afs_use_server(op->server, false, afs_server_trace_use_call);
+	call->key	= op->key;
+	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
+	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
+	call->service_id = op->server->service_id;
+	afs_make_call(call, gfp);
+	afs_put_call(call);
+}
+
 /*
  * Note that a dentry got changed.  We need to set d_fsdata to the data version
  * number derived from the result of the operation.  It doesn't matter if
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index d82916657a3dd..4694a6fca9b4c 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -412,8 +412,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
 
-	ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
-				     &msg, call->request_size,
+	ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg,
 				     afs_notify_end_request_tx);
 	if (ret < 0)
 		goto error_do_abort;
@@ -425,7 +424,6 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 
 		ret = rxrpc_kernel_send_data(call->net->socket,
 					     call->rxcall, &msg,
-					     iov_iter_count(&msg.msg_iter),
 					     afs_notify_end_request_tx);
 		*call->write_iter = msg.msg_iter;
 
@@ -443,22 +441,21 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	return;
 
 error_do_abort:
-	if (ret != -ECONNABORTED)
-		rxrpc_kernel_abort_call(call->net->socket, rxcall,
-					RX_USER_ABORT, ret,
-					afs_abort_send_data_error);
+	rxrpc_kernel_abort_call(call->net->socket, rxcall,
+				RX_USER_ABORT, ret, afs_abort_send_data_error);
 	if (call->async) {
 		afs_see_call(call, afs_call_trace_async_abort);
 		return;
 	}
 
-	if (ret == -ECONNABORTED) {
+	if (ret == -ESHUTDOWN) {
 		len = 0;
 		iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
-		rxrpc_kernel_recv_data(call->net->socket, rxcall,
-				       &msg.msg_iter, &len, false,
-				       &call->abort_code, &call->service_id);
-		call->responded = true;
+		ret = rxrpc_kernel_recv_data(call->net->socket, rxcall,
+					     &msg.msg_iter, &len, false,
+					     &call->abort_code, &call->service_id);
+		if (ret == -ECONNABORTED)
+			call->responded = true;
 	}
 	call->error = ret;
 	trace_afs_call_done(call);
@@ -859,6 +856,7 @@ void afs_send_empty_reply(struct afs_call *call)
 {
 	struct afs_net *net = call->net;
 	struct msghdr msg;
+	int ret;
 
 	_enter("");
 
@@ -871,22 +869,12 @@ void afs_send_empty_reply(struct afs_call *call)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= 0;
 
-	switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
-				       afs_notify_end_reply_tx)) {
-	case 0:
-		_leave(" [replied]");
-		return;
-
-	case -ENOMEM:
-		_debug("oom");
+	ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
+				     afs_notify_end_reply_tx);
+	if (ret < 0)
 		rxrpc_kernel_abort_call(net->socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					afs_abort_oom);
-		fallthrough;
-	default:
-		_leave(" [error]");
-		return;
-	}
+					RXGEN_SS_MARSHAL, ret,
+					afs_abort_send_error);
 }
 
 /*
@@ -912,21 +900,14 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= 0;
 
-	n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
+	n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
 				   afs_notify_end_reply_tx);
-	if (n >= 0) {
-		/* Success */
-		_leave(" [replied]");
-		return;
-	}
-
-	if (n == -ENOMEM) {
-		_debug("oom");
+	if (n < 0) {
 		rxrpc_kernel_abort_call(net->socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					afs_abort_oom);
+					RXGEN_SS_MARSHAL, n,
+					afs_abort_send_error);
+		_leave(" [error]");
 	}
-	_leave(" [error]");
 }
 
 /*
diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
index 0fb4c41c9bbf5..f3980348ed343 100644
--- a/include/net/af_rxrpc.h
+++ b/include/net/af_rxrpc.h
@@ -64,9 +64,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 					   bool upgrade,
 					   enum rxrpc_interruptibility interruptibility,
 					   unsigned int debug_id);
-int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
-			   struct msghdr *, size_t,
-			   rxrpc_notify_end_tx_t);
+int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
+			   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);
 int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
 			   struct iov_iter *, size_t *, bool, u32 *, u16 *);
 bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591df..04b0bb682b810 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -148,6 +148,7 @@ enum yfs_cm_operation {
 	EM(afs_server_trace_unuse_slist_isort,	"UNU isort") \
 	EM(afs_server_trace_update,		"UPDATE   ") \
 	EM(afs_server_trace_use_by_uuid,	"USE uuid ") \
+	EM(afs_server_trace_use_call,		"USE call ") \
 	EM(afs_server_trace_use_cm_call,	"USE cm-cl") \
 	EM(afs_server_trace_use_get_caps,	"USE gcaps") \
 	EM(afs_server_trace_use_give_up_cb,	"USE gvupc") \
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de66700..52f8718cf7250 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,16 +20,16 @@
 	/* AFS errors */						\
 	EM(afs_abort_general_error,		"afs-error")		\
 	EM(afs_abort_interrupted,		"afs-intr")		\
-	EM(afs_abort_oom,			"afs-oom")		\
 	EM(afs_abort_op_not_supported,		"afs-op-notsupp")	\
 	EM(afs_abort_probeuuid_negative,	"afs-probeuuid-neg")	\
 	EM(afs_abort_send_data_error,		"afs-send-data")	\
+	EM(afs_abort_send_error,		"afs-send-error")	\
 	EM(afs_abort_unmarshal_error,		"afs-unmarshal")	\
 	EM(afs_abort_unsupported_sec_class,	"afs-unsup-sec-class")	\
 	/* rxperf errors */						\
 	EM(rxperf_abort_general_error,		"rxperf-error")		\
-	EM(rxperf_abort_oom,			"rxperf-oom")		\
 	EM(rxperf_abort_op_not_supported,	"rxperf-op-notsupp")	\
+	EM(rxperf_abort_send_error,		"rxperf-send-error")	\
 	EM(rxperf_abort_unmarshal_error,	"rxperf-unmarshal")	\
 	/* RxKAD security errors */					\
 	EM(rxkad_abort_1_short_check,		"rxkad1-short-check")	\
@@ -148,6 +148,7 @@
 	EM(rxrpc_eproto_wrong_security,		"wrong-sec")		\
 	EM(rxrpc_recvmsg_excess_data,		"recvmsg-excess")	\
 	EM(rxrpc_recvmsg_short_data,		"recvmsg-short")	\
+	EM(rxrpc_sendmsg_tx_error,		"tx-error")		\
 	E_(rxrpc_sendmsg_late_send,		"sendmsg-late")
 
 #define rxrpc_call_poke_traces \
@@ -342,6 +343,7 @@
 	EM(rxrpc_call_see_distribute_error,	"SEE dist-err") \
 	EM(rxrpc_call_see_input,		"SEE input   ") \
 	EM(rxrpc_call_see_notify_released,	"SEE nfy-rlsd") \
+	EM(rxrpc_call_see_notify_skipped,	"SEE nfy-skip") \
 	EM(rxrpc_call_see_recvmsg,		"SEE recvmsg ") \
 	EM(rxrpc_call_see_recvmsg_requeue,	"SEE recv-rqu") \
 	EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab9..cb36a709f540e 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -642,6 +642,7 @@ enum rxrpc_call_flag {
 	RXRPC_CALL_TX_LAST,		/* Last packet in Tx buffer (at rxtx_top) */
 	RXRPC_CALL_TX_ALL_ACKED,	/* Last packet has been hard-acked */
 	RXRPC_CALL_TX_NO_MORE,		/* No more data to transmit (MSG_MORE deasserted) */
+	RXRPC_CALL_TX_ERROR,		/* Terminal error; call needs abort */
 	RXRPC_CALL_SEND_PING,		/* A ping will need to be sent */
 	RXRPC_CALL_RETRANS_TIMEOUT,	/* Retransmission due to timeout occurred */
 	RXRPC_CALL_BEGAN_RX_TIMER,	/* We began the expect_rx_by timer */
@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
 /*
  * call_state.c
  */
+void rxrpc_notify_socket(struct rxrpc_call *call);
 bool rxrpc_set_call_completion(struct rxrpc_call *call,
 			       enum rxrpc_call_completion compl,
 			       u32 abort_code,
@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;
 /*
  * recvmsg.c
  */
-void rxrpc_notify_socket(struct rxrpc_call *);
 int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
 
 /*
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebbf..52465e88a0440 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,61 @@
 
 #include "ar-internal.h"
 
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	struct rxrpc_sock *rx;
+	struct sock *sk;
+	unsigned long flags;
+
+	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_released);
+		return;
+	}
+
+	rcu_read_lock();
+
+	rx = rcu_dereference(call->socket);
+	sk = &rx->sk;
+	if (rx && sk->sk_state < RXRPC_CLOSE) {
+		if (call->notify_rx) {
+			spin_lock_irqsave(&call->notify_lock, flags);
+			call->notify_rx(sk, call, call->user_call_ID);
+			spin_unlock_irqrestore(&call->notify_lock, flags);
+		} else {
+			spin_lock_irqsave(&rx->recvmsg_lock, flags);
+			if (list_empty(&call->recvmsg_link)) {
+				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+			}
+			spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+
+			if (!sock_flag(sk, SOCK_DEAD)) {
+				_debug("call %ps", sk->sk_data_ready);
+				sk->sk_data_ready(sk);
+			}
+		}
+	}
+
+	rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service if the call isn't
+ * already complete.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	if (rxrpc_call_is_complete(call)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+		return;
+	}
+
+	__rxrpc_notify_socket(call);
+}
+
 /*
  * Transition a call to the complete state.
  */
@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
 	rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
 	trace_rxrpc_call_complete(call);
 	wake_up(&call->waitq);
-	rxrpc_notify_socket(call);
+	__rxrpc_notify_socket(call);
 	return true;
 }
 
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f85..1be50e0c9cee5 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
 	spin_lock_irq(&local->lock);
 	busy = !list_empty(&conn->attend_link);
 	if (!busy) {
-		rxrpc_get_connection(conn, why);
+		if (!rxrpc_get_connection_maybe(conn, why)) {
+			spin_unlock_irq(&local->lock);
+			return;
+		}
 		list_add_tail(&conn->attend_link, &local->conn_attend_q);
 	}
 	spin_unlock_irq(&local->lock);
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d892897..dc1b3aa51bf32 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -129,6 +129,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
 	return 0;
 }
 
+#ifdef CONFIG_RXGK
 static u64 xdr_dec64(const __be32 *xdr)
 {
 	return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]);
@@ -166,12 +167,14 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 				       size_t datalen,
 				       const __be32 *xdr, unsigned int toklen)
 {
+	const struct krb5_enctype *enc;
 	struct rxrpc_key_token *token, **pptoken;
 	time64_t expiry;
 	size_t plen;
 	const __be32 *ticket, *key;
 	s64 tmp;
 	size_t raw_keylen, raw_tktlen, keylen, tktlen;
+	int ret = -EKEYREJECTED;
 
 	_enter(",{%x,%x,%x,%x},%x",
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -229,6 +232,17 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	token->rxgk->key.data	= token->rxgk->_key;
 	token->rxgk->ticket.len = raw_tktlen;
 
+	/* Check the enctype is supported. */
+	enc = crypto_krb5_find_enctype(token->rxgk->enctype);
+	if (!enc) {
+		ret = -ENOPKG;
+		goto reject_token;
+	}
+	if (raw_keylen != enc->key_len) {
+		ret = -EKEYREJECTED;
+		goto reject_token;
+	}
+
 	if (token->rxgk->endtime != 0) {
 		expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
 		if (expiry < 0)
@@ -280,12 +294,13 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	kfree(token->rxgk);
 	kfree(token);
 reject:
-	return -EKEYREJECTED;
+	return ret;
 expired:
 	kfree(token->rxgk);
 	kfree(token);
 	return -EKEYEXPIRED;
 }
+#endif /* CONFIG_RXGK */
 
 /*
  * attempt to parse the data as the XDR format
@@ -386,9 +401,11 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
 		case RXRPC_SECURITY_RXKAD:
 			ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
 			break;
+#endif
 		default:
 			ret2 = -EPROTONOSUPPORT;
 			break;
@@ -556,10 +573,12 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
 		case RXRPC_SECURITY_RXKAD:
 			kfree(token->kad);
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			kfree(token->rxgk->ticket.data);
 			kfree(token->rxgk);
 			break;
+#endif
 		default:
 			pr_err("Unknown token type %x on rxrpc key\n",
 			       token->security_index);
@@ -603,9 +622,11 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
 		case RXRPC_SECURITY_RXKAD:
 			seq_puts(m, "ka");
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			seq_puts(m, "ygk");
 			break;
+#endif
 		default: /* we have a ticket we can't encode */
 			seq_printf(m, "%u", token->security_index);
 			break;
@@ -770,12 +791,14 @@ static long rxrpc_read(const struct key *key,
 				toksize += RND(token->kad->ticket_len);
 			break;
 
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			toksize += 6 * 8 + 2 * 4;
 			if (!token->no_leak_key)
 				toksize += RND(token->rxgk->key.len);
 			toksize += RND(token->rxgk->ticket.len);
 			break;
+#endif
 
 		default: /* we have a ticket we can't encode */
 			pr_err("Unsupported key token type (%u)\n",
@@ -856,6 +879,7 @@ static long rxrpc_read(const struct key *key,
 				ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
 			break;
 
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			ENCODE64(token->rxgk->begintime);
 			ENCODE64(token->rxgk->endtime);
@@ -869,6 +893,7 @@ static long rxrpc_read(const struct key *key,
 				ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data);
 			ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data);
 			break;
+#endif
 
 		default:
 			pr_err("Unsupported key token type (%u)\n",
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f0..22afc71ea474f 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,13 +17,14 @@
 #include "ar-internal.h"
 
 /*
- * Post a call for attention by the socket or kernel service.  Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up.  We ignore RXRPC_CLOSE, allowing
+ * recvmsg() to continue picking up calls that are already on the queue if it
+ * wants to, but no new calls will get added.
  */
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
 {
-	struct rxrpc_sock *rx;
-	struct sock *sk;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	struct sock *sk = &rx->sk;
 
 	_enter("%d", call->debug_id);
 
@@ -32,31 +33,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
 		return;
 	}
 
-	rcu_read_lock();
-
-	rx = rcu_dereference(call->socket);
-	sk = &rx->sk;
-	if (rx && sk->sk_state < RXRPC_CLOSE) {
-		if (call->notify_rx) {
-			spin_lock_irq(&call->notify_lock);
-			call->notify_rx(sk, call, call->user_call_ID);
-			spin_unlock_irq(&call->notify_lock);
-		} else {
-			spin_lock_irq(&rx->recvmsg_lock);
-			if (list_empty(&call->recvmsg_link)) {
-				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
-				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
-			}
-			spin_unlock_irq(&rx->recvmsg_lock);
+	spin_lock_irq(&rx->recvmsg_lock);
+	if (list_empty(&call->recvmsg_link)) {
+		rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+		list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+	}
+	spin_unlock_irq(&rx->recvmsg_lock);
 
-			if (!sock_flag(sk, SOCK_DEAD)) {
-				_debug("call %ps", sk->sk_data_ready);
-				sk->sk_data_ready(sk);
-			}
-		}
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		_debug("call %ps", sk->sk_data_ready);
+		sk->sk_data_ready(sk);
 	}
 
-	rcu_read_unlock();
 	_leave("");
 }
 
@@ -561,7 +549,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 	if (!(flags & MSG_PEEK) &&
 	    !skb_queue_empty(&call->recvmsg_queue))
-		rxrpc_notify_socket(call);
+		rxrpc_requeue_call(sock, call);
 	goto not_yet_complete;
 
 call_failed:
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index b8df6d22314d6..83016830e6965 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -74,7 +74,7 @@ static struct workqueue_struct *rxperf_workqueue;
 static void rxperf_deliver_to_call(struct work_struct *work);
 static int rxperf_deliver_param_block(struct rxperf_call *call);
 static int rxperf_deliver_request(struct rxperf_call *call);
-static int rxperf_process_call(struct rxperf_call *call);
+static void rxperf_process_call(struct rxperf_call *call);
 static void rxperf_charge_preallocation(struct work_struct *work);
 
 static DECLARE_WORK(rxperf_charge_preallocation_work,
@@ -293,18 +293,28 @@ static void rxperf_deliver_to_call(struct work_struct *work)
 	       state == RXPERF_CALL_SV_AWAIT_ACK
 	       ) {
 		if (state == RXPERF_CALL_SV_AWAIT_ACK) {
-			if (!rxrpc_kernel_check_life(rxperf_socket, call->rxcall))
+			size_t len = 0;
+			iov_iter_kvec(&call->iter, ITER_DEST, NULL, 0, 0);
+			ret = rxrpc_kernel_recv_data(rxperf_socket,
+						     call->rxcall, &call->iter,
+						     &len, false, &remote_abort,
+						     &call->service_id);
+
+			if (ret == -EINPROGRESS || ret == -EAGAIN)
+				return;
+			if (ret < 0 || ret == 1) {
+				if (ret == 1)
+					ret = 0;
 				goto call_complete;
+			}
 			return;
 		}
 
 		ret = call->deliver(call);
-		if (ret == 0)
-			ret = rxperf_process_call(call);
-
 		switch (ret) {
 		case 0:
-			continue;
+			rxperf_process_call(call);
+			return;
 		case -EINPROGRESS:
 		case -EAGAIN:
 			return;
@@ -508,7 +518,7 @@ static int rxperf_deliver_request(struct rxperf_call *call)
 /*
  * Process a call for which we've received the request.
  */
-static int rxperf_process_call(struct rxperf_call *call)
+static void rxperf_process_call(struct rxperf_call *call)
 {
 	struct msghdr msg = {};
 	struct bio_vec bv;
@@ -525,12 +535,10 @@ static int rxperf_process_call(struct rxperf_call *call)
 		iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, len);
 		msg.msg_flags = MSG_MORE;
 		n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
-					   len, rxperf_notify_end_reply_tx);
+					   rxperf_notify_end_reply_tx);
 		if (n < 0)
-			return n;
-		if (n == 0)
-			return -EIO;
-		reply_len -= n;
+			goto send_error;
+		reply_len -= len;
 	}
 
 	len = sizeof(rxperf_magic_cookie);
@@ -538,16 +546,16 @@ static int rxperf_process_call(struct rxperf_call *call)
 	iov[0].iov_len	= len;
 	iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
 	msg.msg_flags = 0;
-	n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg, len,
+	n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
 				   rxperf_notify_end_reply_tx);
-	if (n >= 0)
-		return 0; /* Success */
-
-	if (n == -ENOMEM)
-		rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					rxperf_abort_oom);
-	return n;
+	if (n < 0)
+		goto send_error;
+	return;
+
+send_error:
+	rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
+				RXGEN_SS_MARSHAL, n,
+				rxperf_abort_send_error);
 }
 
 /*
@@ -700,4 +708,3 @@ static void __exit rxperf_exit(void)
 	rcu_barrier();
 }
 module_exit(rxperf_exit);
-
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005ad..ed7ff32da1847 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,51 +320,53 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
 static int rxrpc_send_data(struct rxrpc_sock *rx,
 			   struct rxrpc_call *call,
 			   struct msghdr *msg, size_t len,
-			   rxrpc_notify_end_tx_t notify_end_tx,
-			   bool *_dropped_lock)
+			   rxrpc_notify_end_tx_t notify_end_tx)
+	__releases(&call->user_mutex)
 {
-	struct rxrpc_txbuf *txb;
 	struct sock *sk = &rx->sk;
 	enum rxrpc_call_state state;
+	unsigned int rewind_by = 0;
 	long timeo;
 	bool more = msg->msg_flags & MSG_MORE;
 	int ret, copied = 0;
 
-	if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
-		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
-				  call->cid, call->call_id, call->rx_consumed,
-				  0, -EPROTO);
-		return -EPROTO;
-	}
-
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
 	ret = rxrpc_wait_to_be_connected(call, &timeo);
 	if (ret < 0)
-		return ret;
+		goto out_unlock;
 
 	if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
 		ret = rxrpc_init_client_conn_security(call->conn);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 	}
 
 	/* this should be in poll */
 	sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
 reload:
-	txb = call->tx_pending;
-	call->tx_pending = NULL;
-	if (txb)
-		rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
+	if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
+		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+				  call->cid, call->call_id, call->rx_consumed,
+				  0, -EPROTO);
+		ret = -EPROTO;
+		goto out_unlock;
+	}
+	if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+				  call->cid, call->call_id, call->rx_consumed,
+				  0, -EIO);
+		ret = -EIO;
+		goto out_unlock;
+	}
 
 	ret = -EPIPE;
 	if (sk->sk_shutdown & SEND_SHUTDOWN)
-		goto maybe_error;
+		goto out_unlock;
 	state = rxrpc_call_state(call);
-	ret = -ESHUTDOWN;
 	if (state >= RXRPC_CALL_COMPLETE)
-		goto maybe_error;
+		goto call_terminated;
 	ret = -EPROTO;
 	if (state != RXRPC_CALL_CLIENT_PRE_SEND &&
 	    state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
@@ -374,18 +376,20 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
 				  call->cid, call->call_id, call->rx_consumed,
 				  0, -EPROTO);
-		goto maybe_error;
+		goto out_unlock;
 	}
 
 	ret = -EMSGSIZE;
 	if (call->tx_total_len != -1) {
-		if (len - copied > call->tx_total_len)
+		if (len > call->tx_total_len)
 			goto maybe_error;
-		if (!more && len - copied != call->tx_total_len)
+		if (!more && len != call->tx_total_len)
 			goto maybe_error;
 	}
 
 	do {
+		struct rxrpc_txbuf *txb = call->tx_pending;
+
 		if (!txb) {
 			size_t remain;
 
@@ -405,29 +409,34 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 			 * the security header is going to be in the padded
 			 * region (enc blocksize), but the trailer is not.
 			 */
-			remain = more ? INT_MAX : msg_data_left(msg);
+			remain = more ? INT_MAX : len;
 			txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
 			if (!txb) {
 				ret = -ENOMEM;
 				goto maybe_error;
 			}
+			call->tx_pending = txb;
+		} else {
+			rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
 		}
 
 		_debug("append");
 
 		/* append next segment of data to the current buffer */
-		if (msg_data_left(msg) > 0) {
-			size_t copy = umin(txb->space, msg_data_left(msg));
+		if (len > 0) {
+			size_t copy = min3(txb->space, len, msg_data_left(msg));
 
 			_debug("add %zu", copy);
 			if (!copy_from_iter_full(txb->data + txb->offset,
 						 copy, &msg->msg_iter))
 				goto efault;
 			_debug("added");
+			rewind_by = copy;
 			txb->space -= copy;
 			txb->len += copy;
 			txb->offset += copy;
 			copied += copy;
+			len -= copy;
 			if (call->tx_total_len != -1)
 				call->tx_total_len -= copy;
 		}
@@ -439,62 +448,141 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
 		/* add the packet to the send queue if it's now full */
 		if (!txb->space ||
-		    (msg_data_left(msg) == 0 && !more)) {
-			if (msg_data_left(msg) == 0 && !more)
-				txb->flags |= RXRPC_LAST_PACKET;
-
+		    (len == 0 && !more)) {
+			/* Do any required crypto.  If this fails, it could
+			 * have corrupted the txbuf content with a partial
+			 * encrypt.  Assume that ENOMEM is retryable, but
+			 * everything else is terminal.
+			 */
 			ret = call->security->secure_packet(call, txb);
-			if (ret < 0)
+			if (ret < 0) {
+				/* Assume that ENOMEM here means that the
+				 * encryption hasn't happened yet.  The data is
+				 * aligned to avoid the need for slow buffering
+				 * in the crypto walk.
+				 */
+				if (ret == -ENOMEM)
+					goto maybe_error_rewind;
+				set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
 				goto out;
+			}
+
+			if (len == 0 && !more)
+				txb->flags |= RXRPC_LAST_PACKET;
 			rxrpc_queue_packet(rx, call, txb, notify_end_tx);
-			txb = NULL;
+			call->tx_pending = NULL;
+			rewind_by = 0;
+
+			/* At this point, if that was the last packet, it may
+			 * have been transmitted and the reply (client call) or
+			 * final ACK (service call) may have been received,
+			 * completing the call.
+			 */
 		}
-	} while (msg_data_left(msg) > 0);
+	} while (len > 0 && msg_data_left(msg) > 0);
 
-success:
+	/* Don't check for call completeness here, but leave that to recvmsg or
+	 * a further call to sendmsg().
+	 */
 	ret = copied;
-	if (rxrpc_call_is_complete(call) &&
-	    call->error < 0)
-		ret = call->error;
+out_unlock:
+	mutex_unlock(&call->user_mutex);
 out:
-	call->tx_pending = txb;
+
+	/* The return value is a bit complicated as we want to avoid returning
+	 * an error if we have queued the final packet.  In descending order of
+	 * preference:
+	 *
+	 * (1) If we queue the last packet: the amount copied (which may be
+	 *     zero).  recvmsg() should be used to collect the result.
+	 *
+	 * (2) If another sendmsg() has already queued the last packet: -EPROTO.
+	 *
+	 * (3) If an error caused it to be impossible to continue with the
+	 *     call: -EIO.
+	 *
+	 * (4) If the send side of the socket is shut down, -EPIPE.
+	 *
+	 * (5) If the call is in the wrong state to transmit: -EPROTO.
+	 *
+	 * (6) If the call has terminated early, likely due to an external
+	 *     event such as being remotely aborted: -ESHUTDOWN.
+	 *
+	 * (7) If some data has been copied by this call: the amount copied
+	 *     (which will be greater than zero).
+	 *
+	 * (8) Any other error.
+	 *
+	 * For (2)-(6), there's no point in continuing with the sendmsg().  The
+	 * app should abort the call (just in case the error came from
+	 * somewhere else) and then use recvmsg() to collect the final result
+	 * of the call.
+	 */
 	_leave(" = %d", ret);
 	return ret;
 
 call_terminated:
-	rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
-	_leave(" = %d", call->error);
-	return call->error;
-
+	ret = -ESHUTDOWN;
+	goto out_unlock;
+
+maybe_error_rewind:
+	/* If we got a retryable error after copying all the supplied data into
+	 * the last packet, we need to rewind as much as we can so the caller
+	 * knows they need to retry the sendmsg.
+	 */
+	if (rewind_by && !more && !len) {
+		struct rxrpc_txbuf *txb = call->tx_pending;
+
+		txb->space  += rewind_by;
+		txb->len    -= rewind_by;
+		txb->offset -= rewind_by;
+		copied      -= rewind_by;
+		if (call->tx_total_len != -1)
+			call->tx_total_len += rewind_by;
+		iov_iter_revert(&msg->msg_iter, rewind_by);
+	}
 maybe_error:
-	if (copied)
-		goto success;
-	goto out;
+	if (copied) {
+		if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
+			/* If we've get here, we must have slept waiting for space and .
+			 */
+			ret = copied;
+			goto out_unlock;
+		}
+		if (rxrpc_call_is_complete(call))
+			goto call_terminated;
+		ret = copied;
+	}
+	goto out_unlock;
 
 efault:
 	ret = -EFAULT;
-	goto out;
+	goto maybe_error;
 
 wait_for_space:
 	ret = -EAGAIN;
 	if (msg->msg_flags & MSG_DONTWAIT)
 		goto maybe_error;
 	mutex_unlock(&call->user_mutex);
-	*_dropped_lock = true;
+
 	ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
 				       msg->msg_flags & MSG_WAITALL);
 	if (ret < 0)
-		goto maybe_error;
+		goto out_nolock;
 	if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
 		if (mutex_lock_interruptible(&call->user_mutex) < 0) {
 			ret = sock_intr_errno(timeo);
-			goto maybe_error;
+			goto out_nolock;
 		}
 	} else {
 		mutex_lock(&call->user_mutex);
 	}
-	*_dropped_lock = false;
 	goto reload;
+out_nolock:
+	_leave(" = %d [intr]", ret);
+	if (copied)
+		ret = copied;
+	goto out;
 }
 
 /*
@@ -660,7 +748,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 {
 	struct rxrpc_call *call;
-	bool dropped_lock = false;
 	int ret;
 
 	struct rxrpc_send_params p = {
@@ -769,16 +856,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 		ret = 0;
 		break;
 	case RXRPC_CMD_SEND_DATA:
-		ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
-		break;
+		ret = rxrpc_send_data(rx, call, msg, len, NULL);
+		goto error_put;
 	default:
 		ret = -EINVAL;
 		break;
 	}
 
 out_put_unlock:
-	if (!dropped_lock)
-		mutex_unlock(&call->user_mutex);
+	mutex_unlock(&call->user_mutex);
 error_put:
 	rxrpc_put_call(call, rxrpc_call_put_sendmsg);
 	_leave(" = %d", ret);
@@ -794,7 +880,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
  * @sock: The socket the call is on
  * @call: The call to send data through
  * @msg: The data to send
- * @len: The amount of data to send
  * @notify_end_tx: Notification that the last packet is queued.
  *
  * Allow a kernel service to send data on a call.  The call must be in an state
@@ -805,10 +890,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
  * Return: %0 if successful and a negative error code otherwise.
  */
 int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
-			   struct msghdr *msg, size_t len,
-			   rxrpc_notify_end_tx_t notify_end_tx)
+			   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)
 {
-	bool dropped_lock = false;
 	int ret;
 
 	_enter("{%d},", call->debug_id);
@@ -816,15 +899,23 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
 	ASSERTCMP(msg->msg_name, ==, NULL);
 	ASSERTCMP(msg->msg_control, ==, NULL);
 
-	mutex_lock(&call->user_mutex);
+	for (;;) {
+		mutex_lock(&call->user_mutex);
 
-	ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
-			      notify_end_tx, &dropped_lock);
-	if (ret == -ESHUTDOWN)
-		ret = call->error;
+		ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg,
+				      msg_data_left(msg), notify_end_tx);
+		if (ret < 0)
+			break;
+		if (msg_data_left(msg) == 0) {
+			ret = 0;
+			break;
+		}
+		if (ret == 0) {
+			ret = -EIO;
+			break;
+		}
+	}
 
-	if (!dropped_lock)
-		mutex_unlock(&call->user_mutex);
 	_leave(" = %d", ret);
 	return ret;
 }

3/2 2026/09/14 19:52 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 17398
							output: 30
							thoughts: 892
						

Thoughts:
**Patch Analysis: Worth Fuzzing?**

Okay, let's dive into this patch. My immediate thought is, "Is this fuzz-worthy?" Given my experience, I need to evaluate the potential for new bugs, especially within the context of the existing fuzzing infrastructure. The instructions are clear: reachability is paramount, and refactorings aren't automatically exempt from scrutiny. New or modified assertions in reachable code? Definitely fuzzable.

Looking at the file list, I see a clear pattern: this patch touches both `AF_RXRPC` (the Reliable X-platform Remote Procedure Call) and the AFS (Andrew File System) components. From a fuzzing perspective, this is interesting. I know syzkaller heavily targets socket syscalls, and `AF_RXRPC` is accessed through standard `socket()` calls, offering a direct avenue for fuzzing. The fact that AFS is also touched adds another dimension, potentially involving filesystem interactions.

The `net/rxrpc/` directory changes are the most interesting, altering key functions like `rxrpc_send_data`, `rxrpc_do_sendmsg`, `rxrpc_kernel_send_data`, `rxrpc_notify_socket`, and key parsing functions. I'm seeing changes related to mutex unlocking, error handling, packet queueing, and connection management. Specific changes include significant alterations to mutex unlocking and error handling, new logic for packet queueing, loop handling in `rxrpc_kernel_send_data`, and rewind logic. The refactoring of `rxrpc_notify_socket` into `__rxrpc_notify_socket` and `rxrpc_notify_socket` in `net/rxrpc/call_state.c` is also a red flag. These are classic areas where race conditions, memory corruption, and other vulnerabilities can lurk. The use of `rxrpc_get_connection_maybe(conn, why)` in `rxrpc_poke_conn` looks like an area ripe for potential null pointer dereferences or other subtle issues.

Since these changes are directly accessible via standard networking APIs and filesystem calls within QEMU/syzkaller, I have to conclude: **WorthFuzzing = True**.

Now, I need to dig deeper. I'll need to identify relevant focus symbols, avoiding ubiquitous hot paths and targeting specific feature logic and entry points. I should also check for non-static callers calling static inline helpers, and I'll need to determine which `CONFIG_` options are required to enable and reach this modified code. Time to break out `grepper` and start inspecting the Kconfig files for dependencies on `rxrpc` and `afs`.



4/2 2026/09/14 19:53 tool grepper
0m Args:
{
  "Expression": "config AF_RXRPC",
  "PathPrefix": "net/rxrpc"
}

Results:
{
  "Output": "net/rxrpc/Kconfig-5-\nnet/rxrpc/Kconfig:6:config AF_RXRPC\nnet/rxrpc/Kconfig-7-\ttristate \"RxRPC session sockets\"\n--\nnet/rxrpc/Kconfig=25=if AF_RXRPC\nnet/rxrpc/Kconfig-26-\nnet/rxrpc/Kconfig:27:config AF_RXRPC_IPV6\nnet/rxrpc/Kconfig-28-\tbool \"IPv6 support for RxRPC\"\n--\nnet/rxrpc/Kconfig-33-\nnet/rxrpc/Kconfig:34:config AF_RXRPC_INJECT_LOSS\nnet/rxrpc/Kconfig-35-\tbool \"Inject packet loss into RxRPC packet stream\"\n--\nnet/rxrpc/Kconfig-39-\nnet/rxrpc/Kconfig:40:config AF_RXRPC_INJECT_RX_DELAY\nnet/rxrpc/Kconfig-41-\tbool \"Inject delay into packet reception\"\n--\nnet/rxrpc/Kconfig-49-\nnet/rxrpc/Kconfig:50:config AF_RXRPC_DEBUG\nnet/rxrpc/Kconfig-51-\tbool \"RxRPC dynamic debugging\"\n--\nnet/rxrpc/Kconfig=89=config RXPERF\n--\nnet/rxrpc/Kconfig-95-\nnet/rxrpc/Kconfig:96:config AF_RXRPC_KUNIT_TEST\nnet/rxrpc/Kconfig-97-\ttristate \"RxRPC crypto KUnit test\" if !KUNIT_ALL_TESTS\n"
}

5/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19278
							output: 34
							thoughts: 32
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating the RxRPC Configuration Landscape**

Alright, time to dive into the `net/rxrpc/Kconfig` file. I need to get a clear picture of the build-time configuration options for RxRPC. Specifically, I want to immediately check the dependencies and what's guarded by the various feature flags, just to get a lay of the land. I'm especially interested in the core features, so I'll be looking for `CONFIG_RXGK` and anything related to performance tuning, like `CONFIG_RXPERF`. Understanding these key flags will help me quickly grasp the architectural choices and conditionally compiled components in play. This gives me a good entry point to understand the broader configuration options and their interactions.



6/2 2026/09/14 19:53 tool read-file
0m Args:
{
  "File": "net/rxrpc/Kconfig",
  "FirstLine": 1,
  "LineCount": 100
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\t#\n   3:\t# RxRPC session sockets\n   4:\t#\n   5:\t\n   6:\tconfig AF_RXRPC\n   7:\t\ttristate \"RxRPC session sockets\"\n   8:\t\tdepends on INET\n   9:\t\tselect CRYPTO\n  10:\t\tselect CRYPTO_LIB_DES if RXKAD\n  11:\t\tselect KEYS\n  12:\t\tselect NET_UDP_TUNNEL\n  13:\t\thelp\n  14:\t\t  Say Y or M here to include support for RxRPC session sockets (just\n  15:\t\t  the transport part, not the presentation part: (un)marshalling is\n  16:\t\t  left to the application).\n  17:\t\n  18:\t\t  These are used for AFS kernel filesystem and userspace utilities.\n  19:\t\n  20:\t\t  This module at the moment only supports client operations and is\n  21:\t\t  currently incomplete.\n  22:\t\n  23:\t\t  See Documentation/networking/rxrpc.rst.\n  24:\t\n  25:\tif AF_RXRPC\n  26:\t\n  27:\tconfig AF_RXRPC_IPV6\n  28:\t\tbool \"IPv6 support for RxRPC\"\n  29:\t\tdepends on IPV6\n  30:\t\thelp\n  31:\t\t  Say Y here to allow AF_RXRPC to use IPV6 UDP as well as IPV4 UDP as\n  32:\t\t  its network transport.\n  33:\t\n  34:\tconfig AF_RXRPC_INJECT_LOSS\n  35:\t\tbool \"Inject packet loss into RxRPC packet stream\"\n  36:\t\thelp\n  37:\t\t  Say Y here to inject packet loss by discarding some received and some\n  38:\t\t  transmitted packets.\n  39:\t\n  40:\tconfig AF_RXRPC_INJECT_RX_DELAY\n  41:\t\tbool \"Inject delay into packet reception\"\n  42:\t\tdepends on SYSCTL\n  43:\t\thelp\n  44:\t\t  Say Y here to inject a delay into packet reception, allowing an\n  45:\t\t  extended RTT time to be modelled.  The delay can be configured using\n  46:\t\t  /proc/sys/net/rxrpc/rxrpc_inject_rx_delay, setting a number of\n  47:\t\t  milliseconds up to 0.5s (note that the granularity is actually in\n  48:\t\t  jiffies).\n  49:\t\n  50:\tconfig AF_RXRPC_DEBUG\n  51:\t\tbool \"RxRPC dynamic debugging\"\n  52:\t\thelp\n  53:\t\t  Say Y here to make runtime controllable debugging messages appear.\n  54:\t\n  55:\t\t  See Documentation/networking/rxrpc.rst.\n  56:\t\n  57:\t\n  58:\tconfig RXKAD\n  59:\t\tbool \"RxRPC Kerberos security\"\n  60:\t\thelp\n  61:\t\t  Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC\n  62:\t\t  through the use of the key retention service.\n  63:\t\n  64:\t\t  See Documentation/networking/rxrpc.rst.\n  65:\t\n  66:\tconfig RXGK\n  67:\t\tbool \"RxRPC GSSAPI security\"\n  68:\t\tselect CRYPTO_KRB5\n  69:\t\tselect CRYPTO_MANAGER\n  70:\t\tselect CRYPTO_KRB5ENC\n  71:\t\tselect CRYPTO_AUTHENC\n  72:\t\tselect CRYPTO_SKCIPHER\n  73:\t\tselect CRYPTO_HASH_INFO\n  74:\t\tselect CRYPTO_HMAC\n  75:\t\tselect CRYPTO_CMAC\n  76:\t\tselect CRYPTO_SHA1\n  77:\t\tselect CRYPTO_SHA256\n  78:\t\tselect CRYPTO_SHA512\n  79:\t\tselect CRYPTO_CBC\n  80:\t\tselect CRYPTO_CTS\n  81:\t\tselect CRYPTO_AES\n  82:\t\tselect CRYPTO_CAMELLIA\n  83:\t\thelp\n  84:\t\t  Provide the GSSAPI-based RxGK security class for AFS.  Keys are added\n  85:\t\t  with add_key().\n  86:\t\n  87:\t\t  See Documentation/networking/rxrpc.rst.\n  88:\t\n  89:\tconfig RXPERF\n  90:\t\ttristate \"RxRPC test service\"\n  91:\t\thelp\n  92:\t\t  Provide an rxperf service tester.  This listens on UDP port 7009 for\n  93:\t\t  incoming calls from the rxperf program (an example of which can be\n  94:\t\t  found in OpenAFS).\n  95:\t\n  96:\tconfig AF_RXRPC_KUNIT_TEST\n  97:\t\ttristate \"RxRPC crypto KUnit test\" if !KUNIT_ALL_TESTS\n  98:\t\tdepends on KUNIT \u0026\u0026 RXKAD\n  99:\t\tdefault KUNIT_ALL_TESTS\n 100:\t\thelp\n"
}

7/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 20807
							output: 32
							thoughts: 72
						

Thoughts:
Here's my summary, as I see it:

**Digging into RXRPC Configuration Options**

Okay, time to dive in and understand the configuration flags related to RXRPC. The first thing I'm noticing is the use of `CONFIG_RXGK`.  Right away, I see it's being used in `net/rxrpc/key.c` – specifically in an `#ifdef` context. This suggests that the feature or functionality governed by `CONFIG_RXGK` is conditionally compiled based on whether that configuration option is enabled. That's good to know, and I'll keep that in mind as I trace through the code.

Then, there's `CONFIG_RXPERF` – and immediately my expert brain tells me that's associated with performance-related aspects, and it’s being used to compile parts of `net/rxrpc/rxperf.c`.  I’ll make a mental note to track down what performance measurements or optimizations are behind that particular Kconfig option.

Finally, just to be thorough and cover all bases, I need to check `fs/afs/Kconfig` to see if there's any cross-dependency or interactions between the AFS filesystem and RXRPC configuration options. Understanding how these components are configured in relation to each other is vital.



8/2 2026/09/14 19:53 tool read-file
0m Args:
{
  "File": "fs/afs/Kconfig",
  "FirstLine": 1,
  "LineCount": 50
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\tconfig AFS_FS\n   3:\t\ttristate \"Andrew File System support (AFS)\"\n   4:\t\tdepends on INET\n   5:\t\tselect AF_RXRPC\n   6:\t\tselect DNS_RESOLVER\n   7:\t\tselect NETFS_SUPPORT\n   8:\t\tselect CRYPTO_KRB5\n   9:\t\thelp\n  10:\t\t  If you say Y here, you will get an experimental Andrew File System\n  11:\t\t  driver. It currently only supports unsecured read-only AFS access.\n  12:\t\n  13:\t\t  See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n  14:\t\n  15:\t\t  If unsure, say N.\n  16:\t\n  17:\tconfig AFS_DEBUG\n  18:\t\tbool \"AFS dynamic debugging\"\n  19:\t\tdepends on AFS_FS\n  20:\t\thelp\n  21:\t\t  Say Y here to make runtime controllable debugging messages appear.\n  22:\t\n  23:\t\t  See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n  24:\t\n  25:\t\t  If unsure, say N.\n  26:\t\n  27:\tconfig AFS_FSCACHE\n  28:\t\tbool \"Provide AFS client caching support\"\n  29:\t\tdepends on AFS_FS=m \u0026\u0026 FSCACHE || AFS_FS=y \u0026\u0026 FSCACHE=y\n  30:\t\thelp\n  31:\t\t  Say Y here if you want AFS data to be cached locally on disk through\n  32:\t\t  the generic filesystem cache manager\n  33:\t\n  34:\tconfig AFS_DEBUG_CURSOR\n  35:\t\tbool \"AFS server cursor debugging\"\n  36:\t\tdepends on AFS_FS\n  37:\t\thelp\n  38:\t\t  Say Y here to cause the contents of a server cursor to be dumped to\n  39:\t\t  the dmesg log if the server rotation algorithm fails to successfully\n  40:\t\t  contact a server.\n  41:\t\n  42:\t\t  See \u003cfile:Documentation/filesystems/afs.rst\u003e for more information.\n  43:\t\n  44:\t\t  If unsure, say N.\n"
}

9/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 21763
							output: 31
							thoughts: 38
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach that query, as if it were my thought process:

**Diving into the Build Process of Key Files**

Right, so I need to understand how these core components are compiled – `cm_security.c`, `fs_operation.c`, and `rxrpc.c`. Given their potential integration with the AFS filesytem, a good place to start is the `fs/afs/Makefile`. It's highly likely that this Makefile orchestrates the build process for AFS-related code, and my target files are very likely involved. By examining the dependencies and build rules there, I can get a clear picture of how these individual C files are compiled, linked, and incorporated into the overall system. This will provide some necessary context for understanding these parts and how they might fit together.



10/2 2026/09/14 19:53 tool read-file
0m Args:
{
  "File": "fs/afs/Makefile",
  "FirstLine": 1,
  "LineCount": 50
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\t#\n   3:\t# Makefile for Red Hat Linux AFS client.\n   4:\t#\n   5:\t\n   6:\tkafs-y := \\\n   7:\t\taddr_list.o \\\n   8:\t\taddr_prefs.o \\\n   9:\t\tcallback.o \\\n  10:\t\tcell.o \\\n  11:\t\tcm_security.o \\\n  12:\t\tcmservice.o \\\n  13:\t\tdir.o \\\n  14:\t\tdir_edit.o \\\n  15:\t\tdir_search.o \\\n  16:\t\tdir_silly.o \\\n  17:\t\tdynroot.o \\\n  18:\t\tfile.o \\\n  19:\t\tflock.o \\\n  20:\t\tfsclient.o \\\n  21:\t\tfs_operation.o \\\n  22:\t\tfs_probe.o \\\n  23:\t\tinode.o \\\n  24:\t\tmain.o \\\n  25:\t\tmisc.o \\\n  26:\t\tmntpt.o \\\n  27:\t\trotate.o \\\n  28:\t\trxrpc.o \\\n  29:\t\tsecurity.o \\\n  30:\t\tserver.o \\\n  31:\t\tserver_list.o \\\n  32:\t\tsuper.o \\\n  33:\t\tsymlink.o \\\n  34:\t\tvalidation.o \\\n  35:\t\tvlclient.o \\\n  36:\t\tvl_alias.o \\\n  37:\t\tvl_list.o \\\n  38:\t\tvl_probe.o \\\n  39:\t\tvl_rotate.o \\\n  40:\t\tvolume.o \\\n  41:\t\twrite.o \\\n  42:\t\txattr.o \\\n  43:\t\tyfsclient.o\n  44:\t\n  45:\tkafs-$(CONFIG_PROC_FS) += proc.o\n  46:\tobj-$(CONFIG_AFS_FS)  := kafs.o\n"
}

11/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 22538
							output: 32
							thoughts: 71
						

Thoughts:
**Analyzing KAFS and Dependencies**

Okay, so here's what I'm thinking. I've got these three object files: `cm_security.o`, `fs_operation.o`, and `rxrpc.o`. They're all bundled within `kafs-y`, and that whole module is conditionally compiled based on the `CONFIG_AFS_FS` configuration option. Makes sense, that's pretty standard practice. Then I remembered that `AF_RXRPC` is a dependency for `AFS_FS`, which is good to keep in mind, and a normal expectation given the naming. Just to be thorough, I should really take a look at the `net/rxrpc/Makefile`, because that's where the heart of the RXRPC protocol logic should be. I'll need to check how it's all wired together.



12/2 2026/09/14 19:53 tool read-file
0m Args:
{
  "File": "net/rxrpc/Makefile",
  "FirstLine": 1,
  "LineCount": 50
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\t#\n   3:\t# Makefile for Linux kernel RxRPC\n   4:\t#\n   5:\t\n   6:\tobj-$(CONFIG_AF_RXRPC) += rxrpc.o\n   7:\t\n   8:\trxrpc-y := \\\n   9:\t\taf_rxrpc.o \\\n  10:\t\tcall_accept.o \\\n  11:\t\tcall_event.o \\\n  12:\t\tcall_object.o \\\n  13:\t\tcall_state.o \\\n  14:\t\tconn_client.o \\\n  15:\t\tconn_event.o \\\n  16:\t\tconn_object.o \\\n  17:\t\tconn_service.o \\\n  18:\t\tinput.o \\\n  19:\t\tinput_rack.o \\\n  20:\t\tinsecure.o \\\n  21:\t\tio_thread.o \\\n  22:\t\tkey.o \\\n  23:\t\tlocal_event.o \\\n  24:\t\tlocal_object.o \\\n  25:\t\tmisc.o \\\n  26:\t\tnet_ns.o \\\n  27:\t\toob.o \\\n  28:\t\toutput.o \\\n  29:\t\tpeer_event.o \\\n  30:\t\tpeer_object.o \\\n  31:\t\trecvmsg.o \\\n  32:\t\trtt.o \\\n  33:\t\tsecurity.o \\\n  34:\t\tsendmsg.o \\\n  35:\t\tserver_key.o \\\n  36:\t\tskbuff.o \\\n  37:\t\ttxbuf.o \\\n  38:\t\tutils.o\n  39:\t\n  40:\trxrpc-$(CONFIG_PROC_FS) += proc.o\n  41:\trxrpc-$(CONFIG_RXKAD) += rxkad.o fcrypt.o\n  42:\trxrpc-$(CONFIG_SYSCTL) += sysctl.o\n  43:\trxrpc-$(CONFIG_RXGK) += \\\n  44:\t\trxgk.o \\\n  45:\t\trxgk_app.o \\\n  46:\t\trxgk_kdf.o\n  47:\t\n  48:\tobj-$(CONFIG_RXPERF) += rxperf.o\n  49:\tobj-$(CONFIG_KUNIT) += tests/\n"
}

13/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 23428
							output: 31
							thoughts: 988
						

Thoughts:
**Fuzzing Target Identification: RXRPC Core Logic**

Okay, let's break this down systematically. My initial assessment is that `AF_RXRPC` is definitely worth fuzzing. It's a network protocol, accessible through sockets and AFS mounting, making it directly reachable. The patch touches core data transmission, connection management, and error handling – those are classic hotspots for bugs. The modules that are compiled (`net/rxrpc/`, `fs/afs/`, `net/rxrpc/key.c`, and `net/rxrpc/rxperf.o`) tell the story: this isn't just a minor tweak; it's deep in the critical path.

Specifically, I'm noting the following key areas that are modified, and which are therefore primary points of concern:

*   The rewrite of `rxrpc_send_data` is significant. The changes to packet buffering, locking, error handling, encryption checks, and mutex unlocking are all low-level areas and ripe for subtle concurrency bugs or buffer overflows.
*   `rxrpc_kernel_send_data` and its new signature, along with its integration with `afs_make_call` and `rxperf_process_call`, imply that in-kernel services are being directly impacted by these changes. This means we must consider a variety of kernel entry points to get at this code.
*   The logic around socket notification (`rxrpc_notify_socket`, `rxrpc_requeue_call`) always raises my eyebrows; any kind of call state management is an important vector to evaluate. Replacing `rxrpc_notify_socket` with a split between two functions, including the new `__rxrpc_notify_socket` must be examined.
*   Changes to connection probing (`rxrpc_poke_conn`) with `rxrpc_get_connection_maybe` are interesting, too. Early exits and connection handling deserve a close look.
*   `rxrpc_preparse_xdr_yfs_rxgk` (and the broader `rxrpc_preparse_xdr`) – key validation is always a target for attack. Input validation flaws are some of the most common issues to find.
*   Error handling updates within `afs_make_call`, `afs_send_empty_reply`, and `afs_send_simple_reply` might seem minor, but subtle error paths can be easily missed.
*   The modification of `afs_wait_for_operation` indicates that the patch influences crucial interactions between AFS operations and the `rxrpc` core.

Now, let's hone in on the most *focused* targets within that landscape. I need to identify the most critical functions that are changed *and* are likely to be used frequently. From the listed functions, I'm seeing:

1.  `rxrpc_send_data` (in `net/rxrpc/sendmsg.c`): This is a good starting point, as it's the core of sending data. It's also likely called in many paths.
2.  `rxrpc_kernel_send_data` (in `net/rxrpc/sendmsg.c`): In-kernel services like AFS and rxperf will be impacted.
3.  `rxrpc_do_sendmsg` (in `net/rxrpc/sendmsg.c`): This is the *userspace* entry point to `rxrpc`.
4.  `rxrpc_notify_socket` (in `net/rxrpc/call_state.c`)
5.  `rxrpc_requeue_call` (called by `rxrpc_recvmsg` in `net/rxrpc/recvmsg.c`): This needs examination. We might want to look at `rxrpc_recvmsg` instead.
6.  `rxrpc_poke_conn` (in `net/rxrpc/conn_object.c`)
7.  `rxrpc_preparse_xdr_yfs_rxgk` (in `net/rxrpc/key.c`)
8.  `afs_make_call` (in `fs/afs/rxrpc.c`)
9.  `afs_wait_for_operation` (in `fs/afs/fs_operation.c`)
10. `afs_send_empty_reply` / `afs_send_simple_reply` (in `fs/afs/rxrpc.c`)
11. `rxperf_process_call` (in `net/rxrpc/rxperf.c`)

My next step will be to verify whether `rxrpc_do_sendmsg` is exported. That's a crucial piece of information – a non-static symbol is a much easier target from userspace. Let's check


14/2 2026/09/14 19:53 tool grepper
0m Args:
{
  "Expression": "rxrpc_do_sendmsg",
  "PathPrefix": "net/rxrpc"
}

Results:
{
  "Output": "net/rxrpc/af_rxrpc.c=538=static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)\n--\nnet/rxrpc/af_rxrpc.c-600-\t\telse\nnet/rxrpc/af_rxrpc.c:601:\t\t\tret = rxrpc_do_sendmsg(rx, m, len);\nnet/rxrpc/af_rxrpc.c-602-\t\t/* The socket has been unlocked */\n--\nnet/rxrpc/ar-internal.h=1500=bool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error,\nnet/rxrpc/ar-internal.h-1501-\t\t\t enum rxrpc_abort_reason why);\nnet/rxrpc/ar-internal.h:1502:int rxrpc_do_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t);\nnet/rxrpc/ar-internal.h-1503-\n--\nnet/rxrpc/sendmsg.c=697=rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,\n--\nnet/rxrpc/sendmsg.c-747- */\nnet/rxrpc/sendmsg.c:748:int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\nnet/rxrpc/sendmsg.c-749-{\n"
}

15/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 25860
							output: 36
							thoughts: 88
						

Thoughts:
Here's my thought process, summarized as if I were considering this code:

**Analyzing `rxrpc_do_sendmsg` and `rxrpc_kernel_send_data`**

Okay, so `rxrpc_do_sendmsg` isn't declared `static`, which is immediately interesting. That implies it's intended to be called from outside the module it's defined in. Let's see how that ties into the broader architecture. What about `rxrpc_kernel_send_data`? My spidey-sense is tingling – is this one potentially also accessible externally?

A quick scan of `include/net/af_rxrpc.h` seems like a good place to start. Aha! I see `int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call, ...)` declared. And, yes, it’s *also* non-static and exported. Let me just confirm that with a quick check for `EXPORT_SYMBOL`. Yep, it looks like it's explicitly intended for external use. Interesting – it must have a well-defined and important role in the system. I'll need to dig deeper into its purpose and how it's being used to understand the rationale behind this design.



16/2 2026/09/14 19:53 tool grepper
0m Args:
{
  "Expression": "EXPORT_SYMBOL.*rxrpc_kernel_send_data",
  "PathPrefix": "net/rxrpc"
}

Results:
{
  "Output": "net/rxrpc/sendmsg.c=892=int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\n--\nnet/rxrpc/sendmsg.c-921-}\nnet/rxrpc/sendmsg.c:922:EXPORT_SYMBOL(rxrpc_kernel_send_data);\nnet/rxrpc/sendmsg.c-923-\n"
}

17/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 26363
							output: 30
							thoughts: 443
						

Thoughts:
**Analyzing RXRPC Symbol Visibility**

Okay, yes! Let's dive in. I need to understand the visibility of these RXRPC symbols, especially for potential instrumentation points. First up, I was wondering about `rxrpc_sendmsg`. Ah, that's static within `af_rxrpc.c`, but `rxrpc_do_sendmsg` is non-static and in `sendmsg.c`. That's good.

What about `rxrpc_send_data`? It's static in `sendmsg.c`, which is what I thought, but it *might* be inlined. That's the key question. Since both `rxrpc_do_sendmsg` and `rxrpc_kernel_send_data` call it, it's great that we have distinct symbols for `rxrpc_do_sendmsg`, `rxrpc_kernel_send_data`, *and* potentially `rxrpc_send_data` (if not inlined).

Wait, I should confirm whether `rxrpc_send_data` is marked as `static` or `static noinline`. Let me check `sendmsg.c`. Okay, it's `static int rxrpc_send_data(struct rxrpc_sock *rx, ...)` - so yes, it *is* static. But it might still be inlined...However, even if inlined, the compiler is not going to remove the distinct symbols `rxrpc_do_sendmsg` and `rxrpc_kernel_send_data`.

Now, let's look at `rxrpc_notify_socket`. I'll go to `net/rxrpc/call_state.c`... ah, `void rxrpc_notify_socket(struct rxrpc_call *call)` - it's *non-static*. Confirmed by `ar-internal.h` as well. That's good. I need to make sure I'm catching all relevant function calls.

Next, `rxrpc_recvmsg`. That's in `net/rxrpc/recvmsg.c`, and it's `int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags)` - and *non-static*! Excellent.

Finally, `rxrpc_poke_conn`. That's in `net/rxrpc/conn_object.c`... It's `void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)`. Let's see if that's non-static.



18/2 2026/09/14 19:53 tool grepper
0m Args:
{
  "Expression": "rxrpc_poke_conn",
  "PathPrefix": "net/rxrpc"
}

Results:
{
  "Output": "net/rxrpc/ar-internal.h=1198=extern unsigned int rxrpc_closed_conn_expiry;\nnet/rxrpc/ar-internal.h-1199-\nnet/rxrpc/ar-internal.h:1200:void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why);\nnet/rxrpc/ar-internal.h-1201-struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *, gfp_t);\n--\nnet/rxrpc/conn_event.c=49=int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,\n--\nnet/rxrpc/conn_event.c-65-\t\ttrace_rxrpc_abort(0, why, cid, call, seq, abort_code, err);\nnet/rxrpc/conn_event.c:66:\t\trxrpc_poke_conn(conn, rxrpc_conn_get_poke_abort);\nnet/rxrpc/conn_event.c-67-\t}\n--\nnet/rxrpc/conn_event.c=576=void rxrpc_post_response(struct rxrpc_connection *conn, struct sk_buff *skb)\n--\nnet/rxrpc/conn_event.c-597-\tspin_unlock_irq(\u0026local-\u003elock);\nnet/rxrpc/conn_event.c:598:\trxrpc_poke_conn(conn, rxrpc_conn_get_poke_response);\nnet/rxrpc/conn_event.c-599-\trxrpc_free_skb(old, rxrpc_skb_put_old_response);\n--\nnet/rxrpc/conn_object.c=23=static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,\n--\nnet/rxrpc/conn_object.c-25-\nnet/rxrpc/conn_object.c:26:void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)\nnet/rxrpc/conn_object.c-27-{\n--\nnet/rxrpc/conn_object.c=47=static void rxrpc_connection_timer(struct timer_list *timer)\n--\nnet/rxrpc/conn_object.c-51-\nnet/rxrpc/conn_object.c:52:\trxrpc_poke_conn(conn, rxrpc_conn_get_poke_timer);\nnet/rxrpc/conn_object.c-53-}\n"
}

19/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28030
							output: 30
							thoughts: 148
						

Thoughts:
**Non-Static Function Audit: AFS Module**

Okay, so `rxrpc_poke_conn` wasn't static, which immediately flags a potential area for review. Now, I need to methodically check the AFS functions within the `fs/afs/` directory, specifically focusing on their static declaration. This is a common practice when auditing for potential vulnerabilities or unintended external access.

Let's see... looking at the function definitions, it appears that `afs_make_call` (in `fs/afs/rxrpc.c`), `afs_wait_for_operation` (in `fs/afs/fs_operation.c`), `afs_send_empty_reply` and `afs_send_simple_reply` (both in `fs/afs/rxrpc.c`) are *also* non-static. This requires further investigation, as non-static functions within the kernel could be exposed more broadly than intended. Time to dig deeper and understand the rationale behind their non-static nature, and whether it introduces any potential risks or conflicts. I need to understand how these functions are used and if they truly require external linkage.



20/2 2026/09/14 19:53 tool grepper
0m Args:
{
  "Expression": "void afs_make_call",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/internal.h=1384=void afs_deferred_put_call(struct afs_call *call);\nfs/afs/internal.h:1385:void afs_make_call(struct afs_call *call, gfp_t gfp);\nfs/afs/internal.h-1386-void afs_deliver_to_call(struct afs_call *call);\n--\nfs/afs/rxrpc.c=332=static void afs_notify_end_request_tx(struct sock *sock,\n--\nfs/afs/rxrpc.c-344- */\nfs/afs/rxrpc.c:345:void afs_make_call(struct afs_call *call, gfp_t gfp)\nfs/afs/rxrpc.c-346-{\n"
}

21/2 2026/09/14 19:53 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28664
							output: 33
							thoughts: 106
						

Thoughts:
**Analyzing AFS Code and Token Creation**

Okay, so I'm digging into this AFS code, specifically looking at some function definitions. I've noted that `afs_make_call`, `afs_wait_for_operation`, `afs_send_empty_reply`, and `afs_send_simple_reply` are all *non-static*, which is useful. But my attention is now on `afs_create_yfs_cm_token`. I need to figure out how this function is used.

I see it's defined in `fs/afs/cm_security.c` and is marked as `static`: `static int afs_create_yfs_cm_token(struct sk_buff *challenge, ...)`. The "static" qualifier here is significant, limiting its scope. This means it *should* only be callable within that particular C file.

Now, the important question: where is it actually *called*? I'm going to track down the callers, cross-reference this function, and see where it’s being invoked within the module. This should help me understand the context of this token creation function.



22/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "afs_create_yfs_cm_token",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/cm_security.c-21-#ifdef CONFIG_RXGK\nfs/afs/cm_security.c:22:static int afs_create_yfs_cm_token(struct sk_buff *challenge,\nfs/afs/cm_security.c-23-\t\t\t\t   struct afs_server *server);\n--\nfs/afs/cm_security.c=29=static int afs_respond_to_challenge(struct sk_buff *challenge)\n--\nfs/afs/cm_security.c-78-\t\t\t\tif (!server-\u003ecm_rxgk_appdata.data)\nfs/afs/cm_security.c:79:\t\t\t\t\tafs_create_yfs_cm_token(challenge, server);\nfs/afs/cm_security.c-80-\t\t\t\tmutex_unlock(\u0026server-\u003ecm_token_lock);\n--\nfs/afs/cm_security.c=121=int afs_create_token_key(struct afs_net *net, struct socket *socket)\n--\nfs/afs/cm_security.c-179- */\nfs/afs/cm_security.c:180:static int afs_create_yfs_cm_token(struct sk_buff *challenge,\nfs/afs/cm_security.c-181-\t\t\t\t   struct afs_server *server)\n"
}

23/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 29380
							output: 36
							thoughts: 60
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own:

**Investigating a Conditional Compilation in AFS Security**

Alright, that's interesting. I just spotted that `afs_create_yfs_cm_token` is *also* nested within an `#ifdef CONFIG_RXGK` preprocessor directive, and it's hanging out in `fs/afs/cm_security.c`. I need to drill down into the context here. I'm going to quickly glance at lines 20-30 of that file to get a sense of the surrounding code and the broader conditional compilation strategy at play. That will help me understand why this function is being conditionally compiled in the first place, and what the implications are for systems either *with* or *without* RXGK support. Is it a feature flag, or something more fundamental to the AFS security model? Let's take a look.



24/2 2026/09/14 19:54 tool read-file
0m Args:
{
  "File": "fs/afs/cm_security.c",
  "FirstLine": 15,
  "LineCount": 40
}

Results:
{
  "Contents": "  15:\t#include \u003ctrace/events/rxrpc.h\u003e\n  16:\t\n  17:\t#define RXGK_SERVER_ENC_TOKEN 1036U // 0x40c\n  18:\t#define xdr_round_up(x) (round_up((x), sizeof(__be32)))\n  19:\t#define xdr_len_object(x) (4 + round_up((x), sizeof(__be32)))\n  20:\t\n  21:\t#ifdef CONFIG_RXGK\n  22:\tstatic int afs_create_yfs_cm_token(struct sk_buff *challenge,\n  23:\t\t\t\t\t   struct afs_server *server);\n  24:\t#endif\n  25:\t\n  26:\t/*\n  27:\t * Respond to an RxGK challenge, adding appdata.\n  28:\t */\n  29:\tstatic int afs_respond_to_challenge(struct sk_buff *challenge)\n  30:\t{\n  31:\t#ifdef CONFIG_RXGK\n  32:\t\tstruct krb5_buffer appdata = {};\n  33:\t\tstruct afs_server *server;\n  34:\t#endif\n  35:\t\tstruct rxrpc_peer *peer;\n  36:\t\tunsigned long peer_data;\n  37:\t\tu16 service_id;\n  38:\t\tu8 security_index;\n  39:\t\n  40:\t\trxrpc_kernel_query_challenge(challenge, \u0026peer, \u0026peer_data,\n  41:\t\t\t\t\t     \u0026service_id, \u0026security_index);\n  42:\t\n  43:\t\t_enter(\"%u,%u\", service_id, security_index);\n  44:\t\n  45:\t\tswitch (service_id) {\n  46:\t\t\t/* We don't send CM_SERVICE RPCs, so don't expect a challenge\n  47:\t\t\t * therefrom.\n  48:\t\t\t */\n  49:\t\tcase FS_SERVICE:\n  50:\t\tcase VL_SERVICE:\n  51:\t\tcase YFS_FS_SERVICE:\n  52:\t\tcase YFS_VL_SERVICE:\n  53:\t\t\tbreak;\n  54:\t\tdefault:\n"
}

25/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30237
							output: 30
							thoughts: 34
						

Thoughts:
Okay, let's break this down.

**Locating the Function's Context**

Right, so I need to understand what's happening with `afs_respond_to_challenge`. The first step, as always, is to figure out where the heck it lives. Aha, `fs/afs/cm_security.c`. That gives me the file – excellent! Now, just knowing the file doesn't tell me much. I need to know the bigger picture. I need to trace its flow. Is this a top-level entry point? Is it being called by some core function or an interrupt handler? I need to understand its relationship with other functions or data structures. I need to see where it's registered or where something else calls it. Time to start digging through the code, searching for references to the function name.



26/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "afs_respond_to_challenge",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/cm_security.c=22=static int afs_create_yfs_cm_token(struct sk_buff *challenge,\n--\nfs/afs/cm_security.c-28- */\nfs/afs/cm_security.c:29:static int afs_respond_to_challenge(struct sk_buff *challenge)\nfs/afs/cm_security.c-30-{\n--\nfs/afs/cm_security.c=98=void afs_process_oob_queue(struct work_struct *work)\n--\nfs/afs/cm_security.c-107-\t\tcase RXRPC_OOB_CHALLENGE:\nfs/afs/cm_security.c:108:\t\t\tafs_respond_to_challenge(oob);\nfs/afs/cm_security.c-109-\t\t\tbreak;\n"
}

27/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30694
							output: 30
							thoughts: 109
						

Thoughts:
**Investigating Potential Concurrency Issues**

Okay, so I'm looking at some code and immediately I've spotted a few points of interest. `afs_process_oob_queue` from `fs/afs/cm_security.c` is a work queue handler – that's something that often touches concurrency concerns, so that's flagged. Then, I've got `rxperf_process_call` in `net/rxrpc/rxperf.c`, which is called from `rxperf_deliver_to_call`. Again, this smacks of potentially asynchronous operation, which always needs a closer look in my line of work.

But then, the interesting one: `afs_make_op_call`. I just remembered it's a static inline, defined in `fs/afs/internal.h`. Static inlines can be tricky with locking, as they get expanded. Now I need to check every single call site of that thing. Need to understand exactly *where* that inline function is getting used, and in what context, to properly understand the impact on concurrency. Let's see...



28/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "afs_make_op_call",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/fsclient.c=272=void afs_fs_fetch_status(struct afs_operation *op)\n--\nfs/afs/fsclient.c-294-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:295:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-296-}\n--\nfs/afs/fsclient.c=429=static void afs_fs_fetch_data64(struct afs_operation *op)\n--\nfs/afs/fsclient.c-457-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:458:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-459-}\n--\nfs/afs/fsclient.c=464=void afs_fs_fetch_data(struct afs_operation *op)\n--\nfs/afs/fsclient.c-493-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:494:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-495-}\n--\nfs/afs/fsclient.c=537=void afs_fs_create_file(struct afs_operation *op)\n--\nfs/afs/fsclient.c-577-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/fsclient.c:578:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-579-}\n--\nfs/afs/fsclient.c=591=void afs_fs_make_dir(struct afs_operation *op)\n--\nfs/afs/fsclient.c-631-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/fsclient.c:632:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-633-}\n--\nfs/afs/fsclient.c=671=void afs_fs_remove_file(struct afs_operation *op)\n--\nfs/afs/fsclient.c-705-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/fsclient.c:706:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-707-}\n--\nfs/afs/fsclient.c=719=void afs_fs_remove_dir(struct afs_operation *op)\n--\nfs/afs/fsclient.c-753-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/fsclient.c:754:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-755-}\n--\nfs/afs/fsclient.c=797=void afs_fs_link(struct afs_operation *op)\n--\nfs/afs/fsclient.c-834-\ttrace_afs_make_fs_call1(call, \u0026vp-\u003efid, name);\nfs/afs/fsclient.c:835:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-836-}\n--\nfs/afs/fsclient.c=879=void afs_fs_symlink(struct afs_operation *op)\n--\nfs/afs/fsclient.c-930-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/fsclient.c:931:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-932-}\n--\nfs/afs/fsclient.c=974=void afs_fs_rename(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1027-\ttrace_afs_make_fs_call2(call, \u0026orig_dvp-\u003efid, orig_name, new_name);\nfs/afs/fsclient.c:1028:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1029-}\n--\nfs/afs/fsclient.c=1076=static void afs_fs_store_data64(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1115-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1116:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1117-}\n--\nfs/afs/fsclient.c=1122=void afs_fs_store_data(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1166-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1167:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1168-}\n--\nfs/afs/fsclient.c=1198=static void afs_fs_setattr_size64(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1233-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1234:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1235-}\n--\nfs/afs/fsclient.c=1241=static void afs_fs_setattr_size(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1275-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1276:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1277-}\n--\nfs/afs/fsclient.c=1283=void afs_fs_setattr(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1312-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1313:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1314-}\n--\nfs/afs/fsclient.c=1457=void afs_fs_get_volume_status(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1476-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1477:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1478-}\n--\nfs/afs/fsclient.c=1538=void afs_fs_set_lock(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1559-\ttrace_afs_make_fs_calli(call, \u0026vp-\u003efid, op-\u003elock.type);\nfs/afs/fsclient.c:1560:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1561-}\n--\nfs/afs/fsclient.c=1566=void afs_fs_extend_lock(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1586-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1587:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1588-}\n--\nfs/afs/fsclient.c=1593=void afs_fs_release_lock(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1613-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1614:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1615-}\n--\nfs/afs/fsclient.c=1944=void afs_fs_inline_bulk_status(struct afs_operation *op)\n--\nfs/afs/fsclient.c-1983-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:1984:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/fsclient.c-1985-}\n--\nfs/afs/fsclient.c=2068=void afs_fs_fetch_acl(struct afs_operation *op)\n--\nfs/afs/fsclient.c-2089-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:2090:\tafs_make_op_call(op, call, GFP_KERNEL);\nfs/afs/fsclient.c-2091-}\n--\nfs/afs/fsclient.c=2106=void afs_fs_store_acl(struct afs_operation *op)\n--\nfs/afs/fsclient.c-2135-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/fsclient.c:2136:\tafs_make_op_call(op, call, GFP_KERNEL);\nfs/afs/fsclient.c-2137-}\n--\nfs/afs/internal.h=1745=static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)\n--\nfs/afs/internal.h-1749-\nfs/afs/internal.h:1750:static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,\nfs/afs/internal.h-1751-\t\t\t\t    gfp_t gfp)\n--\nfs/afs/yfsclient.c=468=void yfs_fs_fetch_data(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-503-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:504:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-505-}\n--\nfs/afs/yfsclient.c=549=void yfs_fs_create_file(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-586-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:587:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-588-}\n--\nfs/afs/yfsclient.c=600=void yfs_fs_make_dir(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-635-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:636:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-637-}\n--\nfs/afs/yfsclient.c=691=void yfs_fs_remove_file2(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-721-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:722:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-723-}\n--\nfs/afs/yfsclient.c=760=void yfs_fs_remove_file(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-791-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:792:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-793-}\n--\nfs/afs/yfsclient.c=805=void yfs_fs_remove_dir(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-833-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:834:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-835-}\n--\nfs/afs/yfsclient.c=875=void yfs_fs_link(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-907-\ttrace_afs_make_fs_call1(call, \u0026vp-\u003efid, name);\nfs/afs/yfsclient.c:908:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-909-}\n--\nfs/afs/yfsclient.c=952=void yfs_fs_symlink(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-989-\ttrace_afs_make_fs_call1(call, \u0026dvp-\u003efid, name);\nfs/afs/yfsclient.c:990:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-991-}\n--\nfs/afs/yfsclient.c=1034=void yfs_fs_rename(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1072-\ttrace_afs_make_fs_call2(call, \u0026orig_dvp-\u003efid, orig_name, new_name);\nfs/afs/yfsclient.c:1073:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1074-}\n--\nfs/afs/yfsclient.c=1189=void yfs_fs_rename_replace(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1228-\ttrace_afs_make_fs_call2(call, \u0026orig_dvp-\u003efid, orig_name, new_name);\nfs/afs/yfsclient.c:1229:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1230-}\n--\nfs/afs/yfsclient.c=1235=void yfs_fs_rename_noreplace(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1272-\ttrace_afs_make_fs_call2(call, \u0026orig_dvp-\u003efid, orig_name, new_name);\nfs/afs/yfsclient.c:1273:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1274-}\n--\nfs/afs/yfsclient.c=1279=void yfs_fs_rename_exchange(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1318-\ttrace_afs_make_fs_call2(call, \u0026orig_dvp-\u003efid, orig_name, new_name);\nfs/afs/yfsclient.c:1319:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1320-}\n--\nfs/afs/yfsclient.c=1335=void yfs_fs_store_data(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1374-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1375:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1376-}\n--\nfs/afs/yfsclient.c=1399=static void yfs_fs_setattr_size(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1431-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1432:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1433-}\n--\nfs/afs/yfsclient.c=1439=void yfs_fs_setattr(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1470-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1471:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1472-}\n--\nfs/afs/yfsclient.c=1615=void yfs_fs_get_volume_status(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1641-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1642:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1643-}\n--\nfs/afs/yfsclient.c=1680=void yfs_fs_set_lock(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1706-\ttrace_afs_make_fs_calli(call, \u0026vp-\u003efid, op-\u003elock.type);\nfs/afs/yfsclient.c:1707:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1708-}\n--\nfs/afs/yfsclient.c=1713=void yfs_fs_extend_lock(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1737-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1738:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1739-}\n--\nfs/afs/yfsclient.c=1744=void yfs_fs_release_lock(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1768-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1769:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1770-}\n--\nfs/afs/yfsclient.c=1809=void yfs_fs_fetch_status(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-1835-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:1836:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-1837-}\n--\nfs/afs/yfsclient.c=1984=void yfs_fs_inline_bulk_status(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-2016-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:2017:\tafs_make_op_call(op, call, GFP_NOFS);\nfs/afs/yfsclient.c-2018-}\n--\nfs/afs/yfsclient.c=2153=void yfs_fs_fetch_opaque_acl(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-2179-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:2180:\tafs_make_op_call(op, call, GFP_KERNEL);\nfs/afs/yfsclient.c-2181-}\n--\nfs/afs/yfsclient.c=2196=void yfs_fs_store_opaque_acl2(struct afs_operation *op)\n--\nfs/afs/yfsclient.c-2230-\ttrace_afs_make_fs_call(call, \u0026vp-\u003efid);\nfs/afs/yfsclient.c:2231:\tafs_make_op_call(op, call, GFP_KERNEL);\nfs/afs/yfsclient.c-2232-}\n"
}

29/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36669
							output: 29
							thoughts: 419
						

Thoughts:
**Analyzing the AFS/RxRPC Code Flow**

Okay, so I'm looking at this code and trying to get a handle on the changes. It looks like `afs_make_op_call` is the starting point, calling `afs_make_call`, which in turn sets up the server connection using `afs_use_server`.  Crucially, `afs_make_call` then uses `rxrpc_kernel_send_data` to actually transmit the data and also handles the completion or abortion of the call. That's the core flow I need to understand.

Now, let's break down these modified files. First, `rxrpc_do_sendmsg` – that's the main function for sending messages on an `AF_RXRPC` socket, so it's a critical entry point. Then, `rxrpc_kernel_send_data` is the kernel's way of sending data on an RxRPC call, which I saw before. `rxrpc_notify_socket` is the socket notification function; it looks like it's now checking `rxrpc_call_is_complete`.  That suggests some kind of state change tracking.

Next, `rxrpc_recvmsg` handles incoming messages, and specifically calls `rxrpc_requeue_call` which is interesting. `rxrpc_poke_conn` seems to be modified to use `rxrpc_get_connection_maybe`, so a connection is possibly looked up here. And there's `rxrpc_preparse_xdr_yfs_rxgk` in `key.c`, which is parsing a YFS token.  I'll want to dig into that, especially if we're dealing with keys.

Of course, the key AFS-specific functions are `afs_make_call`, which is what I started with, and `afs_wait_for_operation`.  `afs_make_call` is sending data with `rxrpc_kernel_send_data` and managing the response, and `afs_wait_for_operation` is waiting for an AFS call to finish and cleaning it up. That's a good summary of the main flow.

One more thing: Let me make sure that `rxrpc_preparse_xdr_yfs_rxgk` is properly scoped. Okay, checking `net/rxrpc/key.c`, yep, it's static.  Its caller is `rxrpc_preparse_xdr`, which is itself called by `rxrpc_preparse`. That's important for understanding the context of the token parsing and what dependencies it might have.



30/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "rxrpc_preparse",
  "PathPrefix": "net/rxrpc"
}

Results:
{
  "Output": "net/rxrpc/key.c-25-\nnet/rxrpc/key.c:26:static int rxrpc_preparse(struct key_preparsed_payload *);\nnet/rxrpc/key.c-27-static void rxrpc_free_preparse(struct key_preparsed_payload *);\n--\nnet/rxrpc/key.c=36=struct key_type key_type_rxrpc = {\n--\nnet/rxrpc/key.c-38-\t.flags\t\t= KEY_TYPE_NET_DOMAIN,\nnet/rxrpc/key.c:39:\t.preparse\t= rxrpc_preparse,\nnet/rxrpc/key.c-40-\t.free_preparse\t= rxrpc_free_preparse,\n--\nnet/rxrpc/key.c=46=EXPORT_SYMBOL(key_type_rxrpc);\n--\nnet/rxrpc/key.c-51- */\nnet/rxrpc/key.c:52:static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,\nnet/rxrpc/key.c-53-\t\t\t\t    size_t datalen,\n--\nnet/rxrpc/key.c=138=static time64_t rxrpc_s64_to_time64(s64 time_in_100ns)\n--\nnet/rxrpc/key.c-165- */\nnet/rxrpc/key.c:166:static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,\nnet/rxrpc/key.c-167-\t\t\t\t       size_t datalen,\n--\nnet/rxrpc/key.c-308- */\nnet/rxrpc/key.c:309:static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)\nnet/rxrpc/key.c-310-{\n--\nnet/rxrpc/key.c-401-\t\tcase RXRPC_SECURITY_RXKAD:\nnet/rxrpc/key.c:402:\t\t\tret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);\nnet/rxrpc/key.c-403-\t\t\tbreak;\n--\nnet/rxrpc/key.c-405-\t\tcase RXRPC_SECURITY_YFS_RXGK:\nnet/rxrpc/key.c:406:\t\t\tret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);\nnet/rxrpc/key.c-407-\t\t\tbreak;\n--\nnet/rxrpc/key.c-454- */\nnet/rxrpc/key.c:455:static int rxrpc_preparse(struct key_preparsed_payload *prep)\nnet/rxrpc/key.c-456-{\n--\nnet/rxrpc/key.c-471-\tif (prep-\u003edatalen \u003e 7 * 4) {\nnet/rxrpc/key.c:472:\t\tret = rxrpc_preparse_xdr(prep);\nnet/rxrpc/key.c-473-\t\tif (ret != -EPROTO)\n--\nnet/rxrpc/server_key.c=25=static int rxrpc_vet_description_s(const char *);\nnet/rxrpc/server_key.c:26:static int rxrpc_preparse_s(struct key_preparsed_payload *);\nnet/rxrpc/server_key.c-27-static void rxrpc_free_preparse_s(struct key_preparsed_payload *);\n--\nnet/rxrpc/server_key.c=35=struct key_type key_type_rxrpc_s = {\n--\nnet/rxrpc/server_key.c-38-\t.vet_description = rxrpc_vet_description_s,\nnet/rxrpc/server_key.c:39:\t.preparse\t= rxrpc_preparse_s,\nnet/rxrpc/server_key.c-40-\t.free_preparse\t= rxrpc_free_preparse_s,\n--\nnet/rxrpc/server_key.c=49=static int rxrpc_vet_description_s(const char *desc)\n--\nnet/rxrpc/server_key.c-65- */\nnet/rxrpc/server_key.c:66:static int rxrpc_preparse_s(struct key_preparsed_payload *prep)\nnet/rxrpc/server_key.c-67-{\n"
}

31/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38811
							output: 32
							thoughts: 1095
						

Thoughts:
**Focusing on RXRPC and AFS Integration**

Okay, let's break this down. My goal is to pinpoint the critical components and configurations related to the `key_type_rxrpc` functionality, particularly how it interacts with AFS and the `RXGK` feature.

First, I see the `key_type_rxrpc` itself hinges on `rxrpc_preparse`, which calls `rxrpc_preparse_xdr`, and ultimately `rxrpc_preparse_xdr_yfs_rxgk` when the right config is set.  `key_type_rxrpc.read` is `rxrpc_read`, `key_type_rxrpc.describe` is `rxrpc_describe`, and `key_type_rxrpc.destroy` is `rxrpc_destroy`. These are the key functions.

Now, the configuration aspects are key. We have:

*   `AF_RXRPC`:  This is *fundamental* and required for the core `net/rxrpc` code.
*   `AFS_FS`:  Also *fundamental*, required for the `fs/afs/` code.
*   `RXGK`:  This is *specifically* needed for that `rxrpc_preparse_xdr_yfs_rxgk` function, as well as YFS RXGK support within `net/rxrpc/key.c` and `fs/afs/cm_security.c`.
*   `RXPERF`:  For the performance-related code in `net/rxrpc/rxperf.c`.

I need to confirm these are the only required ones, and check for dependencies within the Kconfig files.

Looking at `net/rxrpc/Kconfig`: `AF_RXRPC` depends on `INET` and selects `CRYPTO`, `KEYS`, and `NET_UDP_TUNNEL`. `RXGK` (under `if AF_RXRPC`) selects `CRYPTO_KRB5` and potentially other options. `RXPERF` is also conditional on `AF_RXRPC`. So, `AF_RXRPC` is a parent config.

In `fs/afs/Kconfig`: `AFS_FS` depends on `INET` and *selects* `AF_RXRPC`, `DNS_RESOLVER`, `NETFS_SUPPORT`, `CRYPTO_KRB5`. That means the two essential configs are interlinked in their dependencies.

Thus, the core configs to enable are clearly `AF_RXRPC`, `AFS_FS`, `RXGK`, and `RXPERF`.

Are there others that are relevant? `INET` is standard, but good to note. `KEYS` is selected by `AF_RXRPC`.  I'm confident the significant configurations are `AF_RXRPC`, `AFS_FS`, `RXGK`, and `RXPERF`.

Now, I need to choose the *FocusSymbols* – the functions that directly implement the added or modified logic. They should be non-ubiquitous. I want functions implementing the logic.

I initially thought of:

*   `rxrpc_do_sendmsg`
*   `rxrpc_kernel_send_data`
*   `rxrpc_notify_socket`
*   `rxrpc_recvmsg`
*   `rxrpc_poke_conn`
*   `afs_make_call`
*   `afs_wait_for_operation`
*   `afs_send_empty_reply`
*   `afs_send_simple_reply`

I had considered including `rxrpc_send_data` but it is static. However, it looks like it's a large static function, so the compiler may not inline it, and it has callers! `rxrpc_do_sendmsg` and `rxrpc_kernel_send_data` are the key non-static wrappers and are a good choice to represent the logic. Thus, I *should* include it.

So, after this careful analysis, the focus symbol list is:

*   `rxrpc_do_sendmsg`
*   `rxrpc_kernel_send_data`
*   `rxrpc_send_data`
*   `rxrpc_notify_socket`
*   `rxrpc_recvmsg`
*   `rxrpc_poke_conn`
*   `afs_make_call`
*   `afs_wait_for_operation`
*   `afs_send_empty_reply`
*   `afs_send_simple_reply`

Just need to double-check that `afs_wait_for_operation` is non-static.



32/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "void afs_wait_for_operation",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/fs_operation.c=259=void afs_end_vnode_operation(struct afs_operation *op)\n--\nfs/afs/fs_operation.c-277- */\nfs/afs/fs_operation.c:278:void afs_wait_for_operation(struct afs_operation *op)\nfs/afs/fs_operation.c-279-{\n--\nfs/afs/internal.h=1218=extern void afs_end_vnode_operation(struct afs_operation *op);\nfs/afs/internal.h:1219:extern void afs_wait_for_operation(struct afs_operation *);\nfs/afs/internal.h-1220-extern int afs_do_sync_operation(struct afs_operation *);\n"
}

33/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41158
							output: 32
							thoughts: 60
						

Thoughts:
**Internal Function Review**

Okay, so `afs_wait_for_operation` is confirmed as non-static and exported internally, which is as expected. Now, I need to verify a couple of related functions. I'm wondering about the scope and accessibility of `afs_send_empty_reply` and `afs_send_simple_reply`. Given my understanding of the AFS file system architecture, I think the best place to find their definitions is in `fs/afs/rxrpc.c`. Let's take a look there.



34/2 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "void afs_send_empty_reply",
  "PathPrefix": "fs/afs"
}

Results:
{
  "Output": "fs/afs/internal.h=1391=extern void afs_flat_call_destructor(struct afs_call *);\nfs/afs/internal.h:1392:extern void afs_send_empty_reply(struct afs_call *);\nfs/afs/internal.h-1393-extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);\n--\nfs/afs/rxrpc.c=843=static void afs_notify_end_reply_tx(struct sock *sock,\n--\nfs/afs/rxrpc.c-854- */\nfs/afs/rxrpc.c:855:void afs_send_empty_reply(struct afs_call *call)\nfs/afs/rxrpc.c-856-{\n"
}

35/2 2026/09/14 19:54 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41575
							output: 273
							thoughts: 477
						

Thoughts:
**My Assessment of the Patch's Scope and Impact**

Okay, so I'm looking at this patch and confirming my initial understanding. Yes, it's definitely dealing with non-static elements, specifically. I need to make sure I'm not missing anything; is `rxperf_process_call` relevant here? Hmm, it's static in `rxperf.c`. And it's called by `rxperf_deliver_to_call`, which is a work item callback: `static void rxperf_deliver_to_call(struct work_struct *work);`. However, is the `rxperf` target as crucial here, or is this primarily about the core RxRPC and AFS components? It feels like the latter is the primary focus.

Let's review the reasoning behind this, it seems to be centered around the following points:

*   The patch is touching AF\_RXRPC network socket tx/rx state logic and related connection/AFS client call management.
*   The primary changes focus on optimizing the packet queue and handling error conditions in `rxrpc_send_data` and `rxrpc_kernel_send_data`.
*   Further adjustments are evident in `rxrpc_notify_socket`, socket requeuing within `rxrpc_recvmsg`, connection reference counting in `rxrpc_poke_conn`, and updates to the AFS call abort processes through `afs_make_call` and `afs_wait_for_operation`.
*   All of these modified paths can be reached through the standard network socket interactions, along with AFS filesystem operations.

The `EnableConfigs` list confirms my suspicion: AF\_RXRPC, AFS\_FS, RXGK, and RXPERF. These are further reinforced by the `FocusSymbols` list, which includes: `rxrpc_do_sendmsg`, `rxrpc_kernel_send_data`, `rxrpc_notify_socket`, `rxrpc_recvmsg`, `rxrpc_poke_conn`, `afs_make_call`, `afs_wait_for_operation`, `afs_send_empty_reply`, and `afs_send_simple_reply`.

Let's double-check the configuration options. Those configurations are confirmed: `CONFIG_AF_RXRPC`, `CONFIG_AFS_FS`, `CONFIG_RXGK`, and `CONFIG_RXPERF`, which are equivalent without the `CONFIG_` prefix.

And, of course, yes, `Is WorthFuzzing` is set to true. Everything checks out. I'm satisfied that this is an accurate representation of the patch's scope and implications. I'll initiate the `set-results` procedure now.



36/2 2026/09/14 19:54 tool set-results
0m Args:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "AFS_FS",
    "RXGK",
    "RXPERF"
  ],
  "FocusSymbols": [
    "rxrpc_do_sendmsg",
    "rxrpc_kernel_send_data",
    "rxrpc_notify_socket",
    "rxrpc_recvmsg",
    "rxrpc_poke_conn",
    "afs_make_call",
    "afs_wait_for_operation",
    "afs_send_empty_reply",
    "afs_send_simple_reply"
  ],
  "Reasoning": "The patch modifies data transmission and state handling across AF_RXRPC sockets and the AFS network filesystem. Specifically, it alters packet queuing, locking, and rewind/error recovery in rxrpc_send_data/rxrpc_kernel_send_data, notification logic in rxrpc_notify_socket, socket requeueing in rxrpc_recvmsg, connection reference handling in rxrpc_poke_conn, and abort/cleanup logic in fs/afs (afs_make_call, afs_wait_for_operation). These modified paths are fully reachable via user-space AF_RXRPC socket syscalls and AFS operations.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "AF_RXRPC",
    "AFS_FS",
    "RXGK",
    "RXPERF"
  ],
  "FocusSymbols": [
    "rxrpc_do_sendmsg",
    "rxrpc_kernel_send_data",
    "rxrpc_notify_socket",
    "rxrpc_recvmsg",
    "rxrpc_poke_conn",
    "afs_make_call",
    "afs_wait_for_operation",
    "afs_send_empty_reply",
    "afs_send_simple_reply"
  ],
  "Reasoning": "The patch modifies data transmission and state handling across AF_RXRPC sockets and the AFS network filesystem. Specifically, it alters packet queuing, locking, and rewind/error recovery in rxrpc_send_data/rxrpc_kernel_send_data, notification logic in rxrpc_notify_socket, socket requeueing in rxrpc_recvmsg, connection reference handling in rxrpc_poke_conn, and abort/cleanup logic in fs/afs (afs_make_call, afs_wait_for_operation). These modified paths are fully reachable via user-space AF_RXRPC socket syscalls and AFS operations.",
  "WorthFuzzing": true
}

37/1 2026/09/14 19:54 action If
2m Args:
{
  "WorthFuzzing": true
}

Results:
null

38/2 2026/09/14 19:54 agent kmsan-evaluator
2m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch series touches AF_RXRPC and AFS subsystems with several distinct fixes and refactorings:\n\n1. In Documentation/networking/rxrpc.rst, include/net/af_rxrpc.h, fs/afs/rxrpc.c, net/rxrpc/rxperf.c, and net/rxrpc/sendmsg.c: The `len` parameter is removed from `rxrpc_kernel_send_data()`, deriving length directly from the message iterator via `msg_data_left()`. The data transmission loop, error rewind logic, and lock handling (`user_mutex`) are adjusted. Data copied into `txb-\u003edata` comes directly from `copy_from_iter_full()`, with lengths strictly bounded by iterator count and remaining buffer space.\n2. In fs/afs/cm_security.c: `toksize` calculation in `afs_create_yfs_cm_token()` is adjusted by adding 4 bytes for the token level field. The underlying buffer `appdata` is allocated using `kzalloc()`, and all fields are explicitly initialized.\n3. In net/rxrpc/key.c: Added `#ifdef CONFIG_RXGK` guards and enctype validation in `rxrpc_preparse_xdr_yfs_rxgk()`. All parsed token allocations use `kzalloc()` and initialized buffers.\n4. In fs/afs/internal.h and fs/afs/fs_operation.c: Fixed server reference pinning (`afs_use_server()`) and cleared dangling `op-\u003ecall` pointer (`op-\u003ecall = NULL`) after call release. These prevent use-after-free conditions, which are detected by KASAN.\n5. In net/rxrpc/conn_object.c, call_state.c, and recvmsg.c: Handled connection reference count races (`rxrpc_get_connection_maybe()`) and separated notification paths when calls are completed or requeued. All variables in updated functions (e.g. `remote_abort = 0`) are explicitly initialized.\n\nNone of the changes introduce uninitialized memory allocations, leak uninitialized data or padding to user space, or add branches dependent on uninitialized data. Risks in these changes (locking, reference counting, and buffer bounds) fall squarely under KASAN and LOCKDEP rather than KMSAN. Therefore, a dedicated KMSAN session is not warranted.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 829d37230fc7b5291fafb191d4a2371d77c68b51
Author: syz-cluster <triage@syzkaller.com>
Date:   Mon Sep 14 19:52:39 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/networking/rxrpc.rst b/Documentation/networking/rxrpc.rst
index 8926dab8e2e60..9b7eeae841485 100644
--- a/Documentation/networking/rxrpc.rst
+++ b/Documentation/networking/rxrpc.rst
@@ -870,7 +870,6 @@ The kernel interface functions are as follows:
 	int rxrpc_kernel_send_data(struct socket *sock,
 				   struct rxrpc_call *call,
 				   struct msghdr *msg,
-				   size_t len,
 				   rxrpc_notify_end_tx_t notify_end_rx);
 
      This is used to supply either the request part of a client call or the
@@ -879,14 +878,19 @@ The kernel interface functions are as follows:
      exclusively to in-kernel virtual addresses.  msg.msg_flags may be given
      MSG_MORE if there will be subsequent data sends for this call.
 
-     The msg must not specify a destination address, control data or any flags
-     other than MSG_MORE.  len is the total amount of data to transmit.
+     msg must not specify a destination address, control data or any flags
+     other than MSG_MORE.  The last-packet flag will only be set on the
+     outgoing packet if MSG_MORE is not set and all the data in the iterator is
+     buffered.
 
      notify_end_rx can be NULL or it can be used to specify a function to be
      called when the call changes state to end the Tx phase.  This function is
      called with a spinlock held to prevent the last DATA packet from being
      transmitted until the function returns.
 
+     It returns 0 if all the data is queued and a negative error code on
+     failure.
+
  (#) Receive data from a call::
 
 	int rxrpc_kernel_recv_data(struct socket *sock,
diff --git a/fs/afs/cm_security.c b/fs/afs/cm_security.c
index 103168c70dd4d..5eeeef761cf31 100644
--- a/fs/afs/cm_security.c
+++ b/fs/afs/cm_security.c
@@ -235,7 +235,7 @@ static int afs_create_yfs_cm_token(struct sk_buff *challenge,
 	 *	struct RXGK_AuthName	identities<>;
 	 * };
 	 */
-	toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+	toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
 
 	offset = 0;
 	encsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, &offset);
diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c
index 20801b29521d1..94fa65548d712 100644
--- a/fs/afs/fs_operation.c
+++ b/fs/afs/fs_operation.c
@@ -297,6 +297,7 @@ void afs_wait_for_operation(struct afs_operation *op)
 			op->call_error = op->call->error;
 			op->call_responded = op->call->responded;
 			afs_put_call(op->call);
+			op->call = NULL;
 		}
 	}
 
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 290873bac89b3..65a0866cd8b85 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1416,22 +1416,6 @@ static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
 		       __builtin_return_address(0));
 }
 
-static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
-				    gfp_t gfp)
-{
-	struct afs_addr_list *alist = op->estate->addresses;
-
-	op->call	= afs_get_call(call, afs_call_trace_get);
-	op->type	= call->type;
-	call->op	= op;
-	call->key	= op->key;
-	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
-	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
-	call->service_id = op->server->service_id;
-	afs_make_call(call, gfp);
-	afs_put_call(call);
-}
-
 static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size)
 {
 	call->iov_len = size;
@@ -1763,6 +1747,23 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
 	return &vnode->netfs.inode;
 }
 
+static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
+				    gfp_t gfp)
+{
+	struct afs_addr_list *alist = op->estate->addresses;
+
+	op->call	= afs_get_call(call, afs_call_trace_get);
+	op->type	= call->type;
+	call->op	= op;
+	call->server	= afs_use_server(op->server, false, afs_server_trace_use_call);
+	call->key	= op->key;
+	call->intr	= !(op->flags & AFS_OPERATION_UNINTR);
+	call->peer	= rxrpc_kernel_get_peer(alist->addrs[op->addr_index].peer);
+	call->service_id = op->server->service_id;
+	afs_make_call(call, gfp);
+	afs_put_call(call);
+}
+
 /*
  * Note that a dentry got changed.  We need to set d_fsdata to the data version
  * number derived from the result of the operation.  It doesn't matter if
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index d82916657a3dd..4694a6fca9b4c 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -412,8 +412,7 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
 
-	ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
-				     &msg, call->request_size,
+	ret = rxrpc_kernel_send_data(call->net->socket, rxcall, &msg,
 				     afs_notify_end_request_tx);
 	if (ret < 0)
 		goto error_do_abort;
@@ -425,7 +424,6 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 
 		ret = rxrpc_kernel_send_data(call->net->socket,
 					     call->rxcall, &msg,
-					     iov_iter_count(&msg.msg_iter),
 					     afs_notify_end_request_tx);
 		*call->write_iter = msg.msg_iter;
 
@@ -443,22 +441,21 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
 	return;
 
 error_do_abort:
-	if (ret != -ECONNABORTED)
-		rxrpc_kernel_abort_call(call->net->socket, rxcall,
-					RX_USER_ABORT, ret,
-					afs_abort_send_data_error);
+	rxrpc_kernel_abort_call(call->net->socket, rxcall,
+				RX_USER_ABORT, ret, afs_abort_send_data_error);
 	if (call->async) {
 		afs_see_call(call, afs_call_trace_async_abort);
 		return;
 	}
 
-	if (ret == -ECONNABORTED) {
+	if (ret == -ESHUTDOWN) {
 		len = 0;
 		iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
-		rxrpc_kernel_recv_data(call->net->socket, rxcall,
-				       &msg.msg_iter, &len, false,
-				       &call->abort_code, &call->service_id);
-		call->responded = true;
+		ret = rxrpc_kernel_recv_data(call->net->socket, rxcall,
+					     &msg.msg_iter, &len, false,
+					     &call->abort_code, &call->service_id);
+		if (ret == -ECONNABORTED)
+			call->responded = true;
 	}
 	call->error = ret;
 	trace_afs_call_done(call);
@@ -859,6 +856,7 @@ void afs_send_empty_reply(struct afs_call *call)
 {
 	struct afs_net *net = call->net;
 	struct msghdr msg;
+	int ret;
 
 	_enter("");
 
@@ -871,22 +869,12 @@ void afs_send_empty_reply(struct afs_call *call)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= 0;
 
-	switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
-				       afs_notify_end_reply_tx)) {
-	case 0:
-		_leave(" [replied]");
-		return;
-
-	case -ENOMEM:
-		_debug("oom");
+	ret = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
+				     afs_notify_end_reply_tx);
+	if (ret < 0)
 		rxrpc_kernel_abort_call(net->socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					afs_abort_oom);
-		fallthrough;
-	default:
-		_leave(" [error]");
-		return;
-	}
+					RXGEN_SS_MARSHAL, ret,
+					afs_abort_send_error);
 }
 
 /*
@@ -912,21 +900,14 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
 	msg.msg_controllen	= 0;
 	msg.msg_flags		= 0;
 
-	n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
+	n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg,
 				   afs_notify_end_reply_tx);
-	if (n >= 0) {
-		/* Success */
-		_leave(" [replied]");
-		return;
-	}
-
-	if (n == -ENOMEM) {
-		_debug("oom");
+	if (n < 0) {
 		rxrpc_kernel_abort_call(net->socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					afs_abort_oom);
+					RXGEN_SS_MARSHAL, n,
+					afs_abort_send_error);
+		_leave(" [error]");
 	}
-	_leave(" [error]");
 }
 
 /*
diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
index 0fb4c41c9bbf5..f3980348ed343 100644
--- a/include/net/af_rxrpc.h
+++ b/include/net/af_rxrpc.h
@@ -64,9 +64,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 					   bool upgrade,
 					   enum rxrpc_interruptibility interruptibility,
 					   unsigned int debug_id);
-int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
-			   struct msghdr *, size_t,
-			   rxrpc_notify_end_tx_t);
+int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
+			   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);
 int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
 			   struct iov_iter *, size_t *, bool, u32 *, u16 *);
 bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 1b3c48b5591df..04b0bb682b810 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -148,6 +148,7 @@ enum yfs_cm_operation {
 	EM(afs_server_trace_unuse_slist_isort,	"UNU isort") \
 	EM(afs_server_trace_update,		"UPDATE   ") \
 	EM(afs_server_trace_use_by_uuid,	"USE uuid ") \
+	EM(afs_server_trace_use_call,		"USE call ") \
 	EM(afs_server_trace_use_cm_call,	"USE cm-cl") \
 	EM(afs_server_trace_use_get_caps,	"USE gcaps") \
 	EM(afs_server_trace_use_give_up_cb,	"USE gvupc") \
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 704a10de66700..52f8718cf7250 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -20,16 +20,16 @@
 	/* AFS errors */						\
 	EM(afs_abort_general_error,		"afs-error")		\
 	EM(afs_abort_interrupted,		"afs-intr")		\
-	EM(afs_abort_oom,			"afs-oom")		\
 	EM(afs_abort_op_not_supported,		"afs-op-notsupp")	\
 	EM(afs_abort_probeuuid_negative,	"afs-probeuuid-neg")	\
 	EM(afs_abort_send_data_error,		"afs-send-data")	\
+	EM(afs_abort_send_error,		"afs-send-error")	\
 	EM(afs_abort_unmarshal_error,		"afs-unmarshal")	\
 	EM(afs_abort_unsupported_sec_class,	"afs-unsup-sec-class")	\
 	/* rxperf errors */						\
 	EM(rxperf_abort_general_error,		"rxperf-error")		\
-	EM(rxperf_abort_oom,			"rxperf-oom")		\
 	EM(rxperf_abort_op_not_supported,	"rxperf-op-notsupp")	\
+	EM(rxperf_abort_send_error,		"rxperf-send-error")	\
 	EM(rxperf_abort_unmarshal_error,	"rxperf-unmarshal")	\
 	/* RxKAD security errors */					\
 	EM(rxkad_abort_1_short_check,		"rxkad1-short-check")	\
@@ -148,6 +148,7 @@
 	EM(rxrpc_eproto_wrong_security,		"wrong-sec")		\
 	EM(rxrpc_recvmsg_excess_data,		"recvmsg-excess")	\
 	EM(rxrpc_recvmsg_short_data,		"recvmsg-short")	\
+	EM(rxrpc_sendmsg_tx_error,		"tx-error")		\
 	E_(rxrpc_sendmsg_late_send,		"sendmsg-late")
 
 #define rxrpc_call_poke_traces \
@@ -342,6 +343,7 @@
 	EM(rxrpc_call_see_distribute_error,	"SEE dist-err") \
 	EM(rxrpc_call_see_input,		"SEE input   ") \
 	EM(rxrpc_call_see_notify_released,	"SEE nfy-rlsd") \
+	EM(rxrpc_call_see_notify_skipped,	"SEE nfy-skip") \
 	EM(rxrpc_call_see_recvmsg,		"SEE recvmsg ") \
 	EM(rxrpc_call_see_recvmsg_requeue,	"SEE recv-rqu") \
 	EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab9..cb36a709f540e 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -642,6 +642,7 @@ enum rxrpc_call_flag {
 	RXRPC_CALL_TX_LAST,		/* Last packet in Tx buffer (at rxtx_top) */
 	RXRPC_CALL_TX_ALL_ACKED,	/* Last packet has been hard-acked */
 	RXRPC_CALL_TX_NO_MORE,		/* No more data to transmit (MSG_MORE deasserted) */
+	RXRPC_CALL_TX_ERROR,		/* Terminal error; call needs abort */
 	RXRPC_CALL_SEND_PING,		/* A ping will need to be sent */
 	RXRPC_CALL_RETRANS_TIMEOUT,	/* Retransmission due to timeout occurred */
 	RXRPC_CALL_BEGAN_RX_TIMER,	/* We began the expect_rx_by timer */
@@ -1109,6 +1110,7 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
 /*
  * call_state.c
  */
+void rxrpc_notify_socket(struct rxrpc_call *call);
 bool rxrpc_set_call_completion(struct rxrpc_call *call,
 			       enum rxrpc_call_completion compl,
 			       u32 abort_code,
@@ -1441,7 +1443,6 @@ extern const struct seq_operations rxrpc_local_seq_ops;
 /*
  * recvmsg.c
  */
-void rxrpc_notify_socket(struct rxrpc_call *);
 int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
 
 /*
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
index 6afb54373ebbf..52465e88a0440 100644
--- a/net/rxrpc/call_state.c
+++ b/net/rxrpc/call_state.c
@@ -7,6 +7,61 @@
 
 #include "ar-internal.h"
 
+/*
+ * Post a call for attention by the socket or kernel service.
+ */
+static void __rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	struct rxrpc_sock *rx;
+	struct sock *sk;
+	unsigned long flags;
+
+	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_released);
+		return;
+	}
+
+	rcu_read_lock();
+
+	rx = rcu_dereference(call->socket);
+	sk = &rx->sk;
+	if (rx && sk->sk_state < RXRPC_CLOSE) {
+		if (call->notify_rx) {
+			spin_lock_irqsave(&call->notify_lock, flags);
+			call->notify_rx(sk, call, call->user_call_ID);
+			spin_unlock_irqrestore(&call->notify_lock, flags);
+		} else {
+			spin_lock_irqsave(&rx->recvmsg_lock, flags);
+			if (list_empty(&call->recvmsg_link)) {
+				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+			}
+			spin_unlock_irqrestore(&rx->recvmsg_lock, flags);
+
+			if (!sock_flag(sk, SOCK_DEAD)) {
+				_debug("call %ps", sk->sk_data_ready);
+				sk->sk_data_ready(sk);
+			}
+		}
+	}
+
+	rcu_read_unlock();
+}
+
+/*
+ * Post a call for attention by the socket or kernel service if the call isn't
+ * already complete.
+ */
+void rxrpc_notify_socket(struct rxrpc_call *call)
+{
+	if (rxrpc_call_is_complete(call)) {
+		rxrpc_see_call(call, rxrpc_call_see_notify_skipped);
+		return;
+	}
+
+	__rxrpc_notify_socket(call);
+}
+
 /*
  * Transition a call to the complete state.
  */
@@ -25,7 +80,7 @@ bool rxrpc_set_call_completion(struct rxrpc_call *call,
 	rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
 	trace_rxrpc_call_complete(call);
 	wake_up(&call->waitq);
-	rxrpc_notify_socket(call);
+	__rxrpc_notify_socket(call);
 	return true;
 }
 
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 0ece717db0f85..1be50e0c9cee5 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -34,7 +34,10 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
 	spin_lock_irq(&local->lock);
 	busy = !list_empty(&conn->attend_link);
 	if (!busy) {
-		rxrpc_get_connection(conn, why);
+		if (!rxrpc_get_connection_maybe(conn, why)) {
+			spin_unlock_irq(&local->lock);
+			return;
+		}
 		list_add_tail(&conn->attend_link, &local->conn_attend_q);
 	}
 	spin_unlock_irq(&local->lock);
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index a0aa78d892897..dc1b3aa51bf32 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -129,6 +129,7 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
 	return 0;
 }
 
+#ifdef CONFIG_RXGK
 static u64 xdr_dec64(const __be32 *xdr)
 {
 	return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]);
@@ -166,12 +167,14 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 				       size_t datalen,
 				       const __be32 *xdr, unsigned int toklen)
 {
+	const struct krb5_enctype *enc;
 	struct rxrpc_key_token *token, **pptoken;
 	time64_t expiry;
 	size_t plen;
 	const __be32 *ticket, *key;
 	s64 tmp;
 	size_t raw_keylen, raw_tktlen, keylen, tktlen;
+	int ret = -EKEYREJECTED;
 
 	_enter(",{%x,%x,%x,%x},%x",
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -229,6 +232,17 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	token->rxgk->key.data	= token->rxgk->_key;
 	token->rxgk->ticket.len = raw_tktlen;
 
+	/* Check the enctype is supported. */
+	enc = crypto_krb5_find_enctype(token->rxgk->enctype);
+	if (!enc) {
+		ret = -ENOPKG;
+		goto reject_token;
+	}
+	if (raw_keylen != enc->key_len) {
+		ret = -EKEYREJECTED;
+		goto reject_token;
+	}
+
 	if (token->rxgk->endtime != 0) {
 		expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
 		if (expiry < 0)
@@ -280,12 +294,13 @@ static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
 	kfree(token->rxgk);
 	kfree(token);
 reject:
-	return -EKEYREJECTED;
+	return ret;
 expired:
 	kfree(token->rxgk);
 	kfree(token);
 	return -EKEYEXPIRED;
 }
+#endif /* CONFIG_RXGK */
 
 /*
  * attempt to parse the data as the XDR format
@@ -386,9 +401,11 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
 		case RXRPC_SECURITY_RXKAD:
 			ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
 			break;
+#endif
 		default:
 			ret2 = -EPROTONOSUPPORT;
 			break;
@@ -556,10 +573,12 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
 		case RXRPC_SECURITY_RXKAD:
 			kfree(token->kad);
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			kfree(token->rxgk->ticket.data);
 			kfree(token->rxgk);
 			break;
+#endif
 		default:
 			pr_err("Unknown token type %x on rxrpc key\n",
 			       token->security_index);
@@ -603,9 +622,11 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
 		case RXRPC_SECURITY_RXKAD:
 			seq_puts(m, "ka");
 			break;
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			seq_puts(m, "ygk");
 			break;
+#endif
 		default: /* we have a ticket we can't encode */
 			seq_printf(m, "%u", token->security_index);
 			break;
@@ -770,12 +791,14 @@ static long rxrpc_read(const struct key *key,
 				toksize += RND(token->kad->ticket_len);
 			break;
 
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			toksize += 6 * 8 + 2 * 4;
 			if (!token->no_leak_key)
 				toksize += RND(token->rxgk->key.len);
 			toksize += RND(token->rxgk->ticket.len);
 			break;
+#endif
 
 		default: /* we have a ticket we can't encode */
 			pr_err("Unsupported key token type (%u)\n",
@@ -856,6 +879,7 @@ static long rxrpc_read(const struct key *key,
 				ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
 			break;
 
+#ifdef CONFIG_RXGK
 		case RXRPC_SECURITY_YFS_RXGK:
 			ENCODE64(token->rxgk->begintime);
 			ENCODE64(token->rxgk->endtime);
@@ -869,6 +893,7 @@ static long rxrpc_read(const struct key *key,
 				ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data);
 			ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data);
 			break;
+#endif
 
 		default:
 			pr_err("Unsupported key token type (%u)\n",
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index efcba4b2e74f0..22afc71ea474f 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -17,13 +17,14 @@
 #include "ar-internal.h"
 
 /*
- * Post a call for attention by the socket or kernel service.  Further
- * notifications are suppressed by putting recvmsg_link on a dummy queue.
+ * Requeue a call for recvmsg() to pick up.  We ignore RXRPC_CLOSE, allowing
+ * recvmsg() to continue picking up calls that are already on the queue if it
+ * wants to, but no new calls will get added.
  */
-void rxrpc_notify_socket(struct rxrpc_call *call)
+static void rxrpc_requeue_call(struct socket *sock, struct rxrpc_call *call)
 {
-	struct rxrpc_sock *rx;
-	struct sock *sk;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	struct sock *sk = &rx->sk;
 
 	_enter("%d", call->debug_id);
 
@@ -32,31 +33,18 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
 		return;
 	}
 
-	rcu_read_lock();
-
-	rx = rcu_dereference(call->socket);
-	sk = &rx->sk;
-	if (rx && sk->sk_state < RXRPC_CLOSE) {
-		if (call->notify_rx) {
-			spin_lock_irq(&call->notify_lock);
-			call->notify_rx(sk, call, call->user_call_ID);
-			spin_unlock_irq(&call->notify_lock);
-		} else {
-			spin_lock_irq(&rx->recvmsg_lock);
-			if (list_empty(&call->recvmsg_link)) {
-				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
-				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
-			}
-			spin_unlock_irq(&rx->recvmsg_lock);
+	spin_lock_irq(&rx->recvmsg_lock);
+	if (list_empty(&call->recvmsg_link)) {
+		rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+		list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+	}
+	spin_unlock_irq(&rx->recvmsg_lock);
 
-			if (!sock_flag(sk, SOCK_DEAD)) {
-				_debug("call %ps", sk->sk_data_ready);
-				sk->sk_data_ready(sk);
-			}
-		}
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		_debug("call %ps", sk->sk_data_ready);
+		sk->sk_data_ready(sk);
 	}
 
-	rcu_read_unlock();
 	_leave("");
 }
 
@@ -561,7 +549,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 
 	if (!(flags & MSG_PEEK) &&
 	    !skb_queue_empty(&call->recvmsg_queue))
-		rxrpc_notify_socket(call);
+		rxrpc_requeue_call(sock, call);
 	goto not_yet_complete;
 
 call_failed:
diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
index b8df6d22314d6..83016830e6965 100644
--- a/net/rxrpc/rxperf.c
+++ b/net/rxrpc/rxperf.c
@@ -74,7 +74,7 @@ static struct workqueue_struct *rxperf_workqueue;
 static void rxperf_deliver_to_call(struct work_struct *work);
 static int rxperf_deliver_param_block(struct rxperf_call *call);
 static int rxperf_deliver_request(struct rxperf_call *call);
-static int rxperf_process_call(struct rxperf_call *call);
+static void rxperf_process_call(struct rxperf_call *call);
 static void rxperf_charge_preallocation(struct work_struct *work);
 
 static DECLARE_WORK(rxperf_charge_preallocation_work,
@@ -293,18 +293,28 @@ static void rxperf_deliver_to_call(struct work_struct *work)
 	       state == RXPERF_CALL_SV_AWAIT_ACK
 	       ) {
 		if (state == RXPERF_CALL_SV_AWAIT_ACK) {
-			if (!rxrpc_kernel_check_life(rxperf_socket, call->rxcall))
+			size_t len = 0;
+			iov_iter_kvec(&call->iter, ITER_DEST, NULL, 0, 0);
+			ret = rxrpc_kernel_recv_data(rxperf_socket,
+						     call->rxcall, &call->iter,
+						     &len, false, &remote_abort,
+						     &call->service_id);
+
+			if (ret == -EINPROGRESS || ret == -EAGAIN)
+				return;
+			if (ret < 0 || ret == 1) {
+				if (ret == 1)
+					ret = 0;
 				goto call_complete;
+			}
 			return;
 		}
 
 		ret = call->deliver(call);
-		if (ret == 0)
-			ret = rxperf_process_call(call);
-
 		switch (ret) {
 		case 0:
-			continue;
+			rxperf_process_call(call);
+			return;
 		case -EINPROGRESS:
 		case -EAGAIN:
 			return;
@@ -508,7 +518,7 @@ static int rxperf_deliver_request(struct rxperf_call *call)
 /*
  * Process a call for which we've received the request.
  */
-static int rxperf_process_call(struct rxperf_call *call)
+static void rxperf_process_call(struct rxperf_call *call)
 {
 	struct msghdr msg = {};
 	struct bio_vec bv;
@@ -525,12 +535,10 @@ static int rxperf_process_call(struct rxperf_call *call)
 		iov_iter_bvec(&msg.msg_iter, WRITE, &bv, 1, len);
 		msg.msg_flags = MSG_MORE;
 		n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
-					   len, rxperf_notify_end_reply_tx);
+					   rxperf_notify_end_reply_tx);
 		if (n < 0)
-			return n;
-		if (n == 0)
-			return -EIO;
-		reply_len -= n;
+			goto send_error;
+		reply_len -= len;
 	}
 
 	len = sizeof(rxperf_magic_cookie);
@@ -538,16 +546,16 @@ static int rxperf_process_call(struct rxperf_call *call)
 	iov[0].iov_len	= len;
 	iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
 	msg.msg_flags = 0;
-	n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg, len,
+	n = rxrpc_kernel_send_data(rxperf_socket, call->rxcall, &msg,
 				   rxperf_notify_end_reply_tx);
-	if (n >= 0)
-		return 0; /* Success */
-
-	if (n == -ENOMEM)
-		rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-					RXGEN_SS_MARSHAL, -ENOMEM,
-					rxperf_abort_oom);
-	return n;
+	if (n < 0)
+		goto send_error;
+	return;
+
+send_error:
+	rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
+				RXGEN_SS_MARSHAL, n,
+				rxperf_abort_send_error);
 }
 
 /*
@@ -700,4 +708,3 @@ static void __exit rxperf_exit(void)
 	rcu_barrier();
 }
 module_exit(rxperf_exit);
-
diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
index ed2c9a51005ad..ed7ff32da1847 100644
--- a/net/rxrpc/sendmsg.c
+++ b/net/rxrpc/sendmsg.c
@@ -320,51 +320,53 @@ static int rxrpc_alloc_txqueue(struct sock *sk, struct rxrpc_call *call)
 static int rxrpc_send_data(struct rxrpc_sock *rx,
 			   struct rxrpc_call *call,
 			   struct msghdr *msg, size_t len,
-			   rxrpc_notify_end_tx_t notify_end_tx,
-			   bool *_dropped_lock)
+			   rxrpc_notify_end_tx_t notify_end_tx)
+	__releases(&call->user_mutex)
 {
-	struct rxrpc_txbuf *txb;
 	struct sock *sk = &rx->sk;
 	enum rxrpc_call_state state;
+	unsigned int rewind_by = 0;
 	long timeo;
 	bool more = msg->msg_flags & MSG_MORE;
 	int ret, copied = 0;
 
-	if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
-		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
-				  call->cid, call->call_id, call->rx_consumed,
-				  0, -EPROTO);
-		return -EPROTO;
-	}
-
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
 	ret = rxrpc_wait_to_be_connected(call, &timeo);
 	if (ret < 0)
-		return ret;
+		goto out_unlock;
 
 	if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
 		ret = rxrpc_init_client_conn_security(call->conn);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 	}
 
 	/* this should be in poll */
 	sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
 reload:
-	txb = call->tx_pending;
-	call->tx_pending = NULL;
-	if (txb)
-		rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
+	if (unlikely(test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags))) {
+		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+				  call->cid, call->call_id, call->rx_consumed,
+				  0, -EPROTO);
+		ret = -EPROTO;
+		goto out_unlock;
+	}
+	if (unlikely(test_bit(RXRPC_CALL_TX_ERROR, &call->flags))) {
+		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_tx_error,
+				  call->cid, call->call_id, call->rx_consumed,
+				  0, -EIO);
+		ret = -EIO;
+		goto out_unlock;
+	}
 
 	ret = -EPIPE;
 	if (sk->sk_shutdown & SEND_SHUTDOWN)
-		goto maybe_error;
+		goto out_unlock;
 	state = rxrpc_call_state(call);
-	ret = -ESHUTDOWN;
 	if (state >= RXRPC_CALL_COMPLETE)
-		goto maybe_error;
+		goto call_terminated;
 	ret = -EPROTO;
 	if (state != RXRPC_CALL_CLIENT_PRE_SEND &&
 	    state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
@@ -374,18 +376,20 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 		trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
 				  call->cid, call->call_id, call->rx_consumed,
 				  0, -EPROTO);
-		goto maybe_error;
+		goto out_unlock;
 	}
 
 	ret = -EMSGSIZE;
 	if (call->tx_total_len != -1) {
-		if (len - copied > call->tx_total_len)
+		if (len > call->tx_total_len)
 			goto maybe_error;
-		if (!more && len - copied != call->tx_total_len)
+		if (!more && len != call->tx_total_len)
 			goto maybe_error;
 	}
 
 	do {
+		struct rxrpc_txbuf *txb = call->tx_pending;
+
 		if (!txb) {
 			size_t remain;
 
@@ -405,29 +409,34 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 			 * the security header is going to be in the padded
 			 * region (enc blocksize), but the trailer is not.
 			 */
-			remain = more ? INT_MAX : msg_data_left(msg);
+			remain = more ? INT_MAX : len;
 			txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
 			if (!txb) {
 				ret = -ENOMEM;
 				goto maybe_error;
 			}
+			call->tx_pending = txb;
+		} else {
+			rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
 		}
 
 		_debug("append");
 
 		/* append next segment of data to the current buffer */
-		if (msg_data_left(msg) > 0) {
-			size_t copy = umin(txb->space, msg_data_left(msg));
+		if (len > 0) {
+			size_t copy = min3(txb->space, len, msg_data_left(msg));
 
 			_debug("add %zu", copy);
 			if (!copy_from_iter_full(txb->data + txb->offset,
 						 copy, &msg->msg_iter))
 				goto efault;
 			_debug("added");
+			rewind_by = copy;
 			txb->space -= copy;
 			txb->len += copy;
 			txb->offset += copy;
 			copied += copy;
+			len -= copy;
 			if (call->tx_total_len != -1)
 				call->tx_total_len -= copy;
 		}
@@ -439,62 +448,141 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
 		/* add the packet to the send queue if it's now full */
 		if (!txb->space ||
-		    (msg_data_left(msg) == 0 && !more)) {
-			if (msg_data_left(msg) == 0 && !more)
-				txb->flags |= RXRPC_LAST_PACKET;
-
+		    (len == 0 && !more)) {
+			/* Do any required crypto.  If this fails, it could
+			 * have corrupted the txbuf content with a partial
+			 * encrypt.  Assume that ENOMEM is retryable, but
+			 * everything else is terminal.
+			 */
 			ret = call->security->secure_packet(call, txb);
-			if (ret < 0)
+			if (ret < 0) {
+				/* Assume that ENOMEM here means that the
+				 * encryption hasn't happened yet.  The data is
+				 * aligned to avoid the need for slow buffering
+				 * in the crypto walk.
+				 */
+				if (ret == -ENOMEM)
+					goto maybe_error_rewind;
+				set_bit(RXRPC_CALL_TX_ERROR, &call->flags);
 				goto out;
+			}
+
+			if (len == 0 && !more)
+				txb->flags |= RXRPC_LAST_PACKET;
 			rxrpc_queue_packet(rx, call, txb, notify_end_tx);
-			txb = NULL;
+			call->tx_pending = NULL;
+			rewind_by = 0;
+
+			/* At this point, if that was the last packet, it may
+			 * have been transmitted and the reply (client call) or
+			 * final ACK (service call) may have been received,
+			 * completing the call.
+			 */
 		}
-	} while (msg_data_left(msg) > 0);
+	} while (len > 0 && msg_data_left(msg) > 0);
 
-success:
+	/* Don't check for call completeness here, but leave that to recvmsg or
+	 * a further call to sendmsg().
+	 */
 	ret = copied;
-	if (rxrpc_call_is_complete(call) &&
-	    call->error < 0)
-		ret = call->error;
+out_unlock:
+	mutex_unlock(&call->user_mutex);
 out:
-	call->tx_pending = txb;
+
+	/* The return value is a bit complicated as we want to avoid returning
+	 * an error if we have queued the final packet.  In descending order of
+	 * preference:
+	 *
+	 * (1) If we queue the last packet: the amount copied (which may be
+	 *     zero).  recvmsg() should be used to collect the result.
+	 *
+	 * (2) If another sendmsg() has already queued the last packet: -EPROTO.
+	 *
+	 * (3) If an error caused it to be impossible to continue with the
+	 *     call: -EIO.
+	 *
+	 * (4) If the send side of the socket is shut down, -EPIPE.
+	 *
+	 * (5) If the call is in the wrong state to transmit: -EPROTO.
+	 *
+	 * (6) If the call has terminated early, likely due to an external
+	 *     event such as being remotely aborted: -ESHUTDOWN.
+	 *
+	 * (7) If some data has been copied by this call: the amount copied
+	 *     (which will be greater than zero).
+	 *
+	 * (8) Any other error.
+	 *
+	 * For (2)-(6), there's no point in continuing with the sendmsg().  The
+	 * app should abort the call (just in case the error came from
+	 * somewhere else) and then use recvmsg() to collect the final result
+	 * of the call.
+	 */
 	_leave(" = %d", ret);
 	return ret;
 
 call_terminated:
-	rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
-	_leave(" = %d", call->error);
-	return call->error;
-
+	ret = -ESHUTDOWN;
+	goto out_unlock;
+
+maybe_error_rewind:
+	/* If we got a retryable error after copying all the supplied data into
+	 * the last packet, we need to rewind as much as we can so the caller
+	 * knows they need to retry the sendmsg.
+	 */
+	if (rewind_by && !more && !len) {
+		struct rxrpc_txbuf *txb = call->tx_pending;
+
+		txb->space  += rewind_by;
+		txb->len    -= rewind_by;
+		txb->offset -= rewind_by;
+		copied      -= rewind_by;
+		if (call->tx_total_len != -1)
+			call->tx_total_len += rewind_by;
+		iov_iter_revert(&msg->msg_iter, rewind_by);
+	}
 maybe_error:
-	if (copied)
-		goto success;
-	goto out;
+	if (copied) {
+		if (test_bit(RXRPC_CALL_TX_NO_MORE, &call->flags)) {
+			/* If we've get here, we must have slept waiting for space and .
+			 */
+			ret = copied;
+			goto out_unlock;
+		}
+		if (rxrpc_call_is_complete(call))
+			goto call_terminated;
+		ret = copied;
+	}
+	goto out_unlock;
 
 efault:
 	ret = -EFAULT;
-	goto out;
+	goto maybe_error;
 
 wait_for_space:
 	ret = -EAGAIN;
 	if (msg->msg_flags & MSG_DONTWAIT)
 		goto maybe_error;
 	mutex_unlock(&call->user_mutex);
-	*_dropped_lock = true;
+
 	ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
 				       msg->msg_flags & MSG_WAITALL);
 	if (ret < 0)
-		goto maybe_error;
+		goto out_nolock;
 	if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
 		if (mutex_lock_interruptible(&call->user_mutex) < 0) {
 			ret = sock_intr_errno(timeo);
-			goto maybe_error;
+			goto out_nolock;
 		}
 	} else {
 		mutex_lock(&call->user_mutex);
 	}
-	*_dropped_lock = false;
 	goto reload;
+out_nolock:
+	_leave(" = %d [intr]", ret);
+	if (copied)
+		ret = copied;
+	goto out;
 }
 
 /*
@@ -660,7 +748,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 {
 	struct rxrpc_call *call;
-	bool dropped_lock = false;
 	int ret;
 
 	struct rxrpc_send_params p = {
@@ -769,16 +856,15 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
 		ret = 0;
 		break;
 	case RXRPC_CMD_SEND_DATA:
-		ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
-		break;
+		ret = rxrpc_send_data(rx, call, msg, len, NULL);
+		goto error_put;
 	default:
 		ret = -EINVAL;
 		break;
 	}
 
 out_put_unlock:
-	if (!dropped_lock)
-		mutex_unlock(&call->user_mutex);
+	mutex_unlock(&call->user_mutex);
 error_put:
 	rxrpc_put_call(call, rxrpc_call_put_sendmsg);
 	_leave(" = %d", ret);
@@ -794,7 +880,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
  * @sock: The socket the call is on
  * @call: The call to send data through
  * @msg: The data to send
- * @len: The amount of data to send
  * @notify_end_tx: Notification that the last packet is queued.
  *
  * Allow a kernel service to send data on a call.  The call must be in an state
@@ -805,10 +890,8 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
  * Return: %0 if successful and a negative error code otherwise.
  */
 int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
-			   struct msghdr *msg, size_t len,
-			   rxrpc_notify_end_tx_t notify_end_tx)
+			   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)
 {
-	bool dropped_lock = false;
 	int ret;
 
 	_enter("{%d},", call->debug_id);
@@ -816,15 +899,23 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
 	ASSERTCMP(msg->msg_name, ==, NULL);
 	ASSERTCMP(msg->msg_control, ==, NULL);
 
-	mutex_lock(&call->user_mutex);
+	for (;;) {
+		mutex_lock(&call->user_mutex);
 
-	ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
-			      notify_end_tx, &dropped_lock);
-	if (ret == -ESHUTDOWN)
-		ret = call->error;
+		ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg,
+				      msg_data_left(msg), notify_end_tx);
+		if (ret < 0)
+			break;
+		if (msg_data_left(msg) == 0) {
+			ret = 0;
+			break;
+		}
+		if (ret == 0) {
+			ret = -EIO;
+			break;
+		}
+	}
 
-	if (!dropped_lock)
-		mutex_unlock(&call->user_mutex);
 	_leave(" = %d", ret);
 	return ret;
 }

39/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 16610
							output: 34
							thoughts: 1035
						

Thoughts:
**KMSAN Fuzzing Session Justification**

Okay, so the question is, does this patch series warrant firing up a dedicated KMSAN fuzzing session? Let's break it down, line by line, to see if there are any obvious areas of concern.

First, let's look at the changes and what they do:

1.  `Documentation/networking/rxrpc.rst`: Doc updates, removing a `len` parameter in `rxrpc_kernel_send_data()`. Purely documentation, shouldn't be a problem from a security perspective.
2.  `fs/afs/cm_security.c`: A calculation change, modifying `toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);` to `toksize = keysize + 4 + 8 + 4 + 4 + 8`. It seems that the only change is removing the initial `+ 8` value, this might be related to some off-by-one errors? I should probably check line 235 specifically, I wonder what the `afs_create_yfs_cm_token` function does here. I need to run a `read-file` or `grepper` command to see what is going on there.
3.  `fs/afs/fs_operation.c`: Adding `op->call = NULL;` after `afs_put_call(op->call);`. This seems like a potential use-after-free or double-free protection. This is good defensive coding.
4.  `fs/afs/internal.h`: Moving `afs_make_op_call` and adding `call->server = afs_use_server(op->server, false, afs_server_trace_use_call);`. Looks more like refactoring and resource management.
5.  `fs/afs/rxrpc.c`: Changes in `rxrpc_kernel_send_data` calls: no `call->request_size` or `iov_iter_count(&msg.msg_iter)`, handling `-ESHUTDOWN` instead of `-ECONNABORTED`, and removal of `len` from `rxrpc_kernel_send_data` in a few functions. This touches the core data transfer, this definitely needs a closer look and testing.
6.  `include/net/af_rxrpc.h`: Signature change for `rxrpc_kernel_send_data`: removing the `size_t len` argument. This is the definition change. This is the core of the change in 5, and this is where potential issues might be.
7.  `include/trace/events/afs.h` and `rxrpc.h`: Adding trace events. Auditing is always good.
8.  `net/rxrpc/ar-internal.h`, `call_state.c`: Checking `if (rxrpc_call_is_complete(call))`. Looks like more state management.
9.  `net/rxrpc/conn_object.c`: Using `if (!rxrpc_get_connection_maybe(conn, why))` instead of an unconditional `rxrpc_get_connection`. Improved error handling.
10. `net/rxrpc/key.c`: Conditional compilation for `CONFIG_RXGK` and adding checks for encryption type support in `rxrpc_preparse_xdr_yfs_rxgk`. These are key handling changes. Adding encryption support and enforcing key lengths adds security, but bad key/algorithm combinations or implementation bugs are potential areas of concern.
11. `net/rxrpc/recvmsg.c`: Refactoring notification in `rxrpc_requeue_call`. Looks like cleanup and optimization.
12. `net/rxrpc/rxperf.c`: Updates for the new `rxrpc_kernel_send_data` signature and error handling. Handling of received data. This needs more attention.
13. `net/rxrpc/sendmsg.c`: Significant changes in `rxrpc_send_data` and `rxrpc_kernel_send_data`: locking, loop logic with checks for `len` and `msg_data_left(msg)`, rewind logic on error, and `rxrpc_kernel_send_data` looping via `rxrpc_send_data`. This is the *core* of the data transfer logic, this is where a lot of changes are occurring. This is a very high-priority area for scrutiny and testing. The locking change is good.

So, overall, these patches introduce a mix of documentation updates, refactoring, improvements in error handling and defensive coding, and *significant* changes to the core data transfer logic in RXRPC. The removal of the `


40/3 2026/09/14 19:54 tool grepper
0m Args:
{
  "Expression": "afs_create_yfs_cm_token",
  "PathPrefix": "fs/afs/"
}

Results:
{
  "Output": "fs/afs/cm_security.c-21-#ifdef CONFIG_RXGK\nfs/afs/cm_security.c:22:static int afs_create_yfs_cm_token(struct sk_buff *challenge,\nfs/afs/cm_security.c-23-\t\t\t\t   struct afs_server *server);\n--\nfs/afs/cm_security.c=29=static int afs_respond_to_challenge(struct sk_buff *challenge)\n--\nfs/afs/cm_security.c-78-\t\t\t\tif (!server-\u003ecm_rxgk_appdata.data)\nfs/afs/cm_security.c:79:\t\t\t\t\tafs_create_yfs_cm_token(challenge, server);\nfs/afs/cm_security.c-80-\t\t\t\tmutex_unlock(\u0026server-\u003ecm_token_lock);\n--\nfs/afs/cm_security.c=121=int afs_create_token_key(struct afs_net *net, struct socket *socket)\n--\nfs/afs/cm_security.c-179- */\nfs/afs/cm_security.c:180:static int afs_create_yfs_cm_token(struct sk_buff *challenge,\nfs/afs/cm_security.c-181-\t\t\t\t   struct afs_server *server)\n"
}

41/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19036
							output: 37
							thoughts: 26
						

Thoughts:
Here's my summary, as though I'm processing those thoughts:

**Diving into the AFS Security Implementation**

Okay, time to dig into the AFS security code. I'm going to focus on `fs/afs/cm_security.c`, specifically around lines 180 to 270. That section likely deals with a particular security aspect – probably something related to access control, authentication, or perhaps key management within the Cache Manager. Given the filename, I'm anticipating interactions with the underlying file system and how it enforces or verifies security policies. Let's see if it's handling authorization checks for incoming requests, potentially validating credentials, or perhaps managing the communication of security tokens with the AFS server. I'm expecting to see data structures related to principals, protection levels, and how they map onto the specific operations being performed. This should be interesting to see how the implementation translates the AFS security model into the kernel context. I will be looking out for any potential vulnerabilities or efficiencies in the logic.



42/3 2026/09/14 19:54 tool read-file
0m Args:
{
  "File": "fs/afs/cm_security.c",
  "FirstLine": 180,
  "LineCount": 90
}

Results:
{
  "Contents": " 180:\tstatic int afs_create_yfs_cm_token(struct sk_buff *challenge,\n 181:\t\t\t\t\t   struct afs_server *server)\n 182:\t{\n 183:\t\tconst struct krb5_enctype *conn_krb5, *token_krb5;\n 184:\t\tconst struct krb5_buffer *token_key;\n 185:\t\tstruct crypto_aead *aead;\n 186:\t\tstruct scatterlist sg;\n 187:\t\tstruct afs_net *net = server-\u003ecell-\u003enet;\n 188:\t\tconst struct key *key = net-\u003efs_cm_token_key;\n 189:\t\tsize_t keysize, uuidsize, authsize, toksize, encsize, contsize, adatasize, offset;\n 190:\t\t__be32 caps[1] = {\n 191:\t\t\t[0] = htonl(AFS_CAP_ERROR_TRANSLATION),\n 192:\t\t};\n 193:\t\t__be32 *xdr;\n 194:\t\tvoid *appdata, *K0, *encbase;\n 195:\t\tu32 enctype;\n 196:\t\tint ret;\n 197:\t\n 198:\t\tif (!key)\n 199:\t\t\treturn -ENOKEY;\n 200:\t\n 201:\t\t/* Assume that the fileserver is happy to use the same encoding type as\n 202:\t\t * we were told to use by the token obtained by the user.\n 203:\t\t */\n 204:\t\tenctype = rxgk_kernel_query_challenge(challenge);\n 205:\t\n 206:\t\tconn_krb5 = crypto_krb5_find_enctype(enctype);\n 207:\t\tif (!conn_krb5)\n 208:\t\t\treturn -ENOPKG;\n 209:\t\ttoken_krb5 = key-\u003epayload.data[0];\n 210:\t\ttoken_key = (const struct krb5_buffer *)\u0026key-\u003epayload.data[2];\n 211:\t\n 212:\t\t/* struct rxgk_key {\n 213:\t\t *\tafs_uint32\tenctype;\n 214:\t\t *\topaque\t\tkey\u003c\u003e;\n 215:\t\t * };\n 216:\t\t */\n 217:\t\tkeysize = 4 + xdr_len_object(conn_krb5-\u003ekey_len);\n 218:\t\n 219:\t\t/* struct RXGK_AuthName {\n 220:\t\t *\tafs_int32\tkind;\n 221:\t\t *\topaque\t\tdata\u003cAUTHDATAMAX\u003e;\n 222:\t\t *\topaque\t\tdisplay\u003cAUTHPRINTABLEMAX\u003e;\n 223:\t\t * };\n 224:\t\t */\n 225:\t\tuuidsize = sizeof(server-\u003euuid);\n 226:\t\tauthsize = 4 + xdr_len_object(uuidsize) + xdr_len_object(0);\n 227:\t\n 228:\t\t/* struct RXGK_Token {\n 229:\t\t *\trxgk_key\t\tK0;\n 230:\t\t *\tRXGK_Level\t\tlevel;\n 231:\t\t *\trxgkTime\t\tstarttime;\n 232:\t\t *\tafs_int32\t\tlifetime;\n 233:\t\t *\tafs_int32\t\tbytelife;\n 234:\t\t *\trxgkTime\t\texpirationtime;\n 235:\t\t *\tstruct RXGK_AuthName\tidentities\u003c\u003e;\n 236:\t\t * };\n 237:\t\t */\n 238:\t\ttoksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);\n 239:\t\n 240:\t\toffset = 0;\n 241:\t\tencsize = crypto_krb5_how_much_buffer(token_krb5, KRB5_ENCRYPT_MODE, toksize, \u0026offset);\n 242:\t\n 243:\t\t/* struct RXGK_TokenContainer {\n 244:\t\t *\tafs_int32\tkvno;\n 245:\t\t *\tafs_int32\tenctype;\n 246:\t\t *\topaque\t\tencrypted_token\u003c\u003e;\n 247:\t\t * };\n 248:\t\t */\n 249:\t\tcontsize = 4 + 4 + xdr_len_object(encsize);\n 250:\t\n 251:\t\t/* struct YFSAppData {\n 252:\t\t *\topr_uuid\tinitiatorUuid;\n 253:\t\t *\topr_uuid\tacceptorUuid;\n 254:\t\t *\tCapabilities\tcaps;\n 255:\t\t *\tafs_int32\tenctype;\n 256:\t\t *\topaque\t\tcallbackKey\u003c\u003e;\n 257:\t\t *\topaque\t\tcallbackToken\u003c\u003e;\n 258:\t\t * };\n 259:\t\t */\n 260:\t\tadatasize = 16 + 16 +\n 261:\t\t\txdr_len_object(sizeof(caps)) +\n 262:\t\t\t4 +\n 263:\t\t\txdr_len_object(conn_krb5-\u003ekey_len) +\n 264:\t\t\txdr_len_object(contsize);\n 265:\t\n 266:\t\tret = -ENOMEM;\n 267:\t\tappdata = kzalloc(adatasize, GFP_KERNEL);\n 268:\t\tif (!appdata)\n 269:\t\t\tgoto out;\n"
}

43/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 20759
							output: 37
							thoughts: 244
						

Thoughts:
**Analyzing the Token Size Calculation**

Okay, let's break this down. I'm looking at the `toksize` calculation, specifically the struct `RXGK_Token` definition. It's clear from the diff that there's a correction here. Previously, the calculation was off. The line:

```
/* struct RXGK_Token {
 *	rxgk_key		K0;
 *	RXGK_Level		level;
 *	rxgkTime		starttime;
 *	afs_int32		lifetime;
 *	afs_int32		bytelife;
 *	rxgkTime		expirationtime;
 *	struct RXGK_AuthName	identities<>;
 * };
 */
-	toksize = keysize + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
+	toksize = keysize + 4 + 8 + 4 + 4 + 8 + xdr_len_object(authsize);
```

Shows the discrepancy. I see that `RXGK_Level` is an `afs_int32` which means a 4-byte integer. The previous calculation *missed* that! It's a classic oversight, and easy to make, but crucial for ensuring correct memory allocation and token size. So, the old `toksize` calculation was 4 bytes too small. I'll need to double check the context around the `fs/afs/cm_security.c` file, lines 270-330, to ensure this change doesn't introduce any unforeseen issues or dependencies. Let's see if this fixes the problem...



44/3 2026/09/14 19:54 tool read-file
0m Args:
{
  "File": "fs/afs/cm_security.c",
  "FirstLine": 270,
  "LineCount": 80
}

Results:
{
  "Contents": " 270:\t\txdr = appdata;\n 271:\t\n 272:\t\tmemcpy(xdr, \u0026net-\u003euuid, 16);\t\t/* appdata.initiatorUuid */\n 273:\t\txdr += 16 / 4;\n 274:\t\tmemcpy(xdr, \u0026server-\u003euuid, 16);\t\t/* appdata.acceptorUuid */\n 275:\t\txdr += 16 / 4;\n 276:\t\t*xdr++ = htonl(ARRAY_SIZE(caps));\t/* appdata.caps.len */\n 277:\t\tmemcpy(xdr, \u0026caps, sizeof(caps));\t/* appdata.caps */\n 278:\t\txdr += ARRAY_SIZE(caps);\n 279:\t\t*xdr++ = htonl(conn_krb5-\u003eetype);\t/* appdata.enctype */\n 280:\t\n 281:\t\t*xdr++ = htonl(conn_krb5-\u003ekey_len);\t/* appdata.callbackKey.len */\n 282:\t\tK0 = xdr;\n 283:\t\tget_random_bytes(K0, conn_krb5-\u003ekey_len); /* appdata.callbackKey.data */\n 284:\t\txdr += xdr_round_up(conn_krb5-\u003ekey_len) / 4;\n 285:\t\n 286:\t\t*xdr++ = htonl(contsize);\t\t/* appdata.callbackToken.len */\n 287:\t\t*xdr++ = htonl(1);\t\t\t/* cont.kvno */\n 288:\t\t*xdr++ = htonl(token_krb5-\u003eetype);\t/* cont.enctype */\n 289:\t\t*xdr++ = htonl(encsize);\t\t/* cont.encrypted_token.len */\n 290:\t\n 291:\t\tencbase = xdr;\n 292:\t\txdr += offset / 4;\n 293:\t\t*xdr++ = htonl(conn_krb5-\u003eetype);\t/* token.K0.enctype */\n 294:\t\t*xdr++ = htonl(conn_krb5-\u003ekey_len);\t/* token.K0.key.len */\n 295:\t\tmemcpy(xdr, K0, conn_krb5-\u003ekey_len);\t/* token.K0.key.data */\n 296:\t\txdr += xdr_round_up(conn_krb5-\u003ekey_len) / 4;\n 297:\t\n 298:\t\t*xdr++ = htonl(RXRPC_SECURITY_ENCRYPT);\t/* token.level */\n 299:\t\t*xdr++ = htonl(0);\t\t\t/* token.starttime */\n 300:\t\t*xdr++ = htonl(0);\t\t\t/* \" */\n 301:\t\t*xdr++ = htonl(0);\t\t\t/* token.lifetime */\n 302:\t\t*xdr++ = htonl(0);\t\t\t/* token.bytelife */\n 303:\t\t*xdr++ = htonl(0);\t\t\t/* token.expirationtime */\n 304:\t\t*xdr++ = htonl(0);\t\t\t/* \" */\n 305:\t\t*xdr++ = htonl(1);\t\t\t/* token.identities.count */\n 306:\t\t*xdr++ = htonl(0);\t\t\t/* token.identities[0].kind */\n 307:\t\t*xdr++ = htonl(uuidsize);\t\t/* token.identities[0].data.len */\n 308:\t\tmemcpy(xdr, \u0026server-\u003euuid, uuidsize);\n 309:\t\txdr += xdr_round_up(uuidsize) / 4;\n 310:\t\t*xdr++ = htonl(0);\t\t\t/* token.identities[0].display.len */\n 311:\t\n 312:\t\txdr = encbase + xdr_round_up(encsize);\n 313:\t\n 314:\t\tif ((unsigned long)xdr - (unsigned long)appdata != adatasize)\n 315:\t\t\tpr_err(\"Appdata size incorrect %lx != %zx\\n\",\n 316:\t\t\t       (unsigned long)xdr - (unsigned long)appdata, adatasize);\n 317:\t\n 318:\t\taead = crypto_krb5_prepare_encryption(token_krb5, token_key, RXGK_SERVER_ENC_TOKEN,\n 319:\t\t\t\t\t\t      GFP_KERNEL);\n 320:\t\tif (IS_ERR(aead)) {\n 321:\t\t\tret = PTR_ERR(aead);\n 322:\t\t\tgoto out_token;\n 323:\t\t}\n 324:\t\n 325:\t\tsg_init_one(\u0026sg, encbase, encsize);\n 326:\t\tret = crypto_krb5_encrypt(token_krb5, aead, \u0026sg, 1, encsize, offset, toksize, false);\n 327:\t\tif (ret \u003c 0)\n 328:\t\t\tgoto out_aead;\n 329:\t\n 330:\t\tserver-\u003ecm_rxgk_appdata.len  = adatasize;\n 331:\t\tserver-\u003ecm_rxgk_appdata.data = appdata;\n 332:\t\tappdata = NULL;\n 333:\t\n 334:\tout_aead:\n 335:\t\tcrypto_free_aead(aead);\n 336:\tout_token:\n 337:\t\tkfree(appdata);\n 338:\tout:\n 339:\t\treturn ret;\n 340:\t}\n 341:\t#endif /* CONFIG_RXGK */\n"
}

45/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 22835
							output: 36
							thoughts: 436
						

Thoughts:
**Analyzing a Potential Vulnerability**

Okay, so I'm looking at this code and immediately my attention is drawn to `appdata = kzalloc(adatasize, GFP_KERNEL);`. That's good, it's `kzalloc`'d, meaning it's zeroed, which is the crucial point here.  The `contsize` calculation depends on `encsize`, which in turn hinges on `toksize`. Previously, it seems `toksize` might have been smaller, potentially leading to `encsize` being slightly smaller than the written data, or maybe the `crypto_krb5_encrypt` function was expecting a smaller `toksize`. But, again, *the buffer was zeroed by kzalloc*.

The key question is whether `crypto_krb5_encrypt` could be reading uninitialized memory. Given that `appdata` was allocated with `kzalloc(adatasize, GFP_KERNEL)`, I'm fairly certain the answer is no. This suggests any problem here is either an out-of-bounds write or a sizing issue; however, `kzalloc` makes sure that all of the memory is zeroed.

Let's shift focus to the patch itself. I'm going to look at other changes to see if they shed any light.

I'm checking out `net/rxrpc/key.c`. I see they've added a check:

```c
	/* Check the enctype is supported. */
	enc = crypto_krb5_find_enctype(token->rxgk->enctype);
	if (!enc) {
		ret = -ENOPKG;
		goto reject_token;
	}
	if (raw_keylen != enc->key_len) {
		ret = -EKEYREJECTED;
		goto reject_token;
	}
```

Okay, so they're checking the encryption type and key length.  I need to understand what was happening *before* this check was introduced within `rxrpc_preparse_xdr_yfs_rxgk` in the `net/rxrpc/key.c` file. This is where the root cause probably lies.



46/3 2026/09/14 19:54 tool read-file
0m Args:
{
  "File": "net/rxrpc/key.c",
  "FirstLine": 210,
  "LineCount": 60
}

Results:
{
  "Contents": " 210:\t\n 211:\t\tplen -= sizeof(*token);\n 212:\t\ttoken = kzalloc_obj(*token);\n 213:\t\tif (!token)\n 214:\t\t\tgoto nomem;\n 215:\t\n 216:\t\ttoken-\u003erxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);\n 217:\t\tif (!token-\u003erxgk)\n 218:\t\t\tgoto nomem_token;\n 219:\t\n 220:\t\ttoken-\u003esecurity_index\t= RXRPC_SECURITY_YFS_RXGK;\n 221:\t\ttoken-\u003erxgk-\u003ebegintime\t= xdr_dec64(xdr + 0 * 2);\n 222:\t\ttoken-\u003erxgk-\u003eendtime\t= xdr_dec64(xdr + 1 * 2);\n 223:\t\ttoken-\u003erxgk-\u003elevel\t= tmp = xdr_dec64(xdr + 2 * 2);\n 224:\t\tif (tmp \u003c -1LL || tmp \u003e RXRPC_SECURITY_ENCRYPT)\n 225:\t\t\tgoto reject_token;\n 226:\t\ttoken-\u003erxgk-\u003elifetime\t= xdr_dec64(xdr + 3 * 2);\n 227:\t\ttoken-\u003erxgk-\u003ebytelife\t= xdr_dec64(xdr + 4 * 2);\n 228:\t\ttoken-\u003erxgk-\u003eenctype\t= tmp = xdr_dec64(xdr + 5 * 2);\n 229:\t\tif (tmp \u003c 0 || tmp \u003e UINT_MAX)\n 230:\t\t\tgoto reject_token;\n 231:\t\ttoken-\u003erxgk-\u003ekey.len\t= raw_keylen;\n 232:\t\ttoken-\u003erxgk-\u003ekey.data\t= token-\u003erxgk-\u003e_key;\n 233:\t\ttoken-\u003erxgk-\u003eticket.len = raw_tktlen;\n 234:\t\n 235:\t\t/* Check the enctype is supported. */\n 236:\t\tenc = crypto_krb5_find_enctype(token-\u003erxgk-\u003eenctype);\n 237:\t\tif (!enc) {\n 238:\t\t\tret = -ENOPKG;\n 239:\t\t\tgoto reject_token;\n 240:\t\t}\n 241:\t\tif (raw_keylen != enc-\u003ekey_len) {\n 242:\t\t\tret = -EKEYREJECTED;\n 243:\t\t\tgoto reject_token;\n 244:\t\t}\n 245:\t\n 246:\t\tif (token-\u003erxgk-\u003eendtime != 0) {\n 247:\t\t\texpiry = rxrpc_s64_to_time64(token-\u003erxgk-\u003eendtime);\n 248:\t\t\tif (expiry \u003c 0)\n 249:\t\t\t\tgoto expired;\n 250:\t\t\tif (expiry \u003c prep-\u003eexpiry)\n 251:\t\t\t\tprep-\u003eexpiry = expiry;\n 252:\t\t}\n 253:\t\n 254:\t\tmemcpy(token-\u003erxgk-\u003ekey.data, key, token-\u003erxgk-\u003ekey.len);\n 255:\t\n 256:\t\t/* Pad the ticket so that we can use it directly in XDR */\n 257:\t\ttoken-\u003erxgk-\u003eticket.data = kzalloc(tktlen, GFP_KERNEL);\n 258:\t\tif (!token-\u003erxgk-\u003eticket.data)\n 259:\t\t\tgoto nomem_yrxgk;\n 260:\t\tmemcpy(token-\u003erxgk-\u003eticket.data, ticket, token-\u003erxgk-\u003eticket.len);\n 261:\t\n 262:\t\t_debug(\"SCIX: %u\",\ttoken-\u003esecurity_index);\n 263:\t\t_debug(\"EXPY: %llx\",\ttoken-\u003erxgk-\u003eendtime);\n 264:\t\t_debug(\"LIFE: %llx\",\ttoken-\u003erxgk-\u003elifetime);\n 265:\t\t_debug(\"BYTE: %llx\",\ttoken-\u003erxgk-\u003ebytelife);\n 266:\t\t_debug(\"ENC : %u\",\ttoken-\u003erxgk-\u003eenctype);\n 267:\t\t_debug(\"LEVL: %u\",\ttoken-\u003erxgk-\u003elevel);\n 268:\t\t_debug(\"KLEN: %u\",\ttoken-\u003erxgk-\u003ekey.len);\n 269:\t\t_debug(\"TLEN: %u\",\ttoken-\u003erxgk-\u003eticket.len);\n"
}

47/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 24941
							output: 37
							thoughts: 153
						

Thoughts:
**Analyzing the Rationale for Memory Allocation and Key Length Verification**

Okay, so the initial setup is pretty straightforward: `token->rxgk = kzalloc(...)` and `token->rxgk->ticket.data = kzalloc(...)`. Everything is being allocated with `kzalloc`, which makes sense for initialization. The key thing here is the verification step: checking that `enc` is not NULL and that `raw_keylen` matches `enc->key_len`. I can see the potential problems if we *didn't* have this check. Without it, we could end up with `crypto_krb5_find_enctype` returning NULL later on, or we could have a key length mismatch during crypto operations. Either scenario could lead to a nasty NULL dereference or, even worse, an invalid key size, which would probably be caught by KASAN or trigger a `BUG`. That's a classic security and stability vulnerability.

Now, let's switch gears and dig into `net/rxrpc/sendmsg.c`. The core functionality is definitely within that file. I need to figure out *what* specifically changed in `sendmsg.c`. Let's focus on the area around lines 315-530. That's a big chunk of code, so let's start reading there and see what jumps out.



48/3 2026/09/14 19:54 tool read-file
0m Args:
{
  "File": "net/rxrpc/sendmsg.c",
  "FirstLine": 380,
  "LineCount": 80
}

Results:
{
  "Contents": " 380:\t\t}\n 381:\t\n 382:\t\tret = -EMSGSIZE;\n 383:\t\tif (call-\u003etx_total_len != -1) {\n 384:\t\t\tif (len \u003e call-\u003etx_total_len)\n 385:\t\t\t\tgoto maybe_error;\n 386:\t\t\tif (!more \u0026\u0026 len != call-\u003etx_total_len)\n 387:\t\t\t\tgoto maybe_error;\n 388:\t\t}\n 389:\t\n 390:\t\tdo {\n 391:\t\t\tstruct rxrpc_txbuf *txb = call-\u003etx_pending;\n 392:\t\n 393:\t\t\tif (!txb) {\n 394:\t\t\t\tsize_t remain;\n 395:\t\n 396:\t\t\t\t_debug(\"alloc\");\n 397:\t\n 398:\t\t\t\tif (!rxrpc_check_tx_space(call, NULL))\n 399:\t\t\t\t\tgoto wait_for_space;\n 400:\t\n 401:\t\t\t\t/* See if we need to begin/extend the Tx queue. */\n 402:\t\t\t\tif (!call-\u003esend_queue || !((call-\u003esend_top + 1) \u0026 RXRPC_TXQ_MASK)) {\n 403:\t\t\t\t\tret = rxrpc_alloc_txqueue(sk, call);\n 404:\t\t\t\t\tif (ret \u003c 0)\n 405:\t\t\t\t\t\tgoto maybe_error;\n 406:\t\t\t\t}\n 407:\t\n 408:\t\t\t\t/* Work out the maximum size of a packet.  Assume that\n 409:\t\t\t\t * the security header is going to be in the padded\n 410:\t\t\t\t * region (enc blocksize), but the trailer is not.\n 411:\t\t\t\t */\n 412:\t\t\t\tremain = more ? INT_MAX : len;\n 413:\t\t\t\ttxb = call-\u003econn-\u003esecurity-\u003ealloc_txbuf(call, remain, sk-\u003esk_allocation);\n 414:\t\t\t\tif (!txb) {\n 415:\t\t\t\t\tret = -ENOMEM;\n 416:\t\t\t\t\tgoto maybe_error;\n 417:\t\t\t\t}\n 418:\t\t\t\tcall-\u003etx_pending = txb;\n 419:\t\t\t} else {\n 420:\t\t\t\trxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);\n 421:\t\t\t}\n 422:\t\n 423:\t\t\t_debug(\"append\");\n 424:\t\n 425:\t\t\t/* append next segment of data to the current buffer */\n 426:\t\t\tif (len \u003e 0) {\n 427:\t\t\t\tsize_t copy = min3(txb-\u003espace, len, msg_data_left(msg));\n 428:\t\n 429:\t\t\t\t_debug(\"add %zu\", copy);\n 430:\t\t\t\tif (!copy_from_iter_full(txb-\u003edata + txb-\u003eoffset,\n 431:\t\t\t\t\t\t\t copy, \u0026msg-\u003emsg_iter))\n 432:\t\t\t\t\tgoto efault;\n 433:\t\t\t\t_debug(\"added\");\n 434:\t\t\t\trewind_by = copy;\n 435:\t\t\t\ttxb-\u003espace -= copy;\n 436:\t\t\t\ttxb-\u003elen += copy;\n 437:\t\t\t\ttxb-\u003eoffset += copy;\n 438:\t\t\t\tcopied += copy;\n 439:\t\t\t\tlen -= copy;\n 440:\t\t\t\tif (call-\u003etx_total_len != -1)\n 441:\t\t\t\t\tcall-\u003etx_total_len -= copy;\n 442:\t\t\t}\n 443:\t\n 444:\t\t\t/* check for the far side aborting the call or a network error\n 445:\t\t\t * occurring */\n 446:\t\t\tif (rxrpc_call_is_complete(call))\n 447:\t\t\t\tgoto call_terminated;\n 448:\t\n 449:\t\t\t/* add the packet to the send queue if it's now full */\n 450:\t\t\tif (!txb-\u003espace ||\n 451:\t\t\t    (len == 0 \u0026\u0026 !more)) {\n 452:\t\t\t\t/* Do any required crypto.  If this fails, it could\n 453:\t\t\t\t * have corrupted the txbuf content with a partial\n 454:\t\t\t\t * encrypt.  Assume that ENOMEM is retryable, but\n 455:\t\t\t\t * everything else is terminal.\n 456:\t\t\t\t */\n 457:\t\t\t\tret = call-\u003esecurity-\u003esecure_packet(call, txb);\n 458:\t\t\t\tif (ret \u003c 0) {\n 459:\t\t\t\t\t/* Assume that ENOMEM here means that the\n"
}

49/3 2026/09/14 19:54 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 26601
							output: 30
							thoughts: 76
						

Thoughts:
**Analyzing the `sendmsg.c` Code**

Alright, let's dive into the rest of `sendmsg.c`. The critical line here is this call: `txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);`. My expert eye immediately hones in on `alloc_txbuf`. This is where the rubber meets the road, isn't it? How exactly is this function implemented? Specifically, I need to know if `txb->data` is properly initialized *and* if there are adequate bounds checks in place. Buffer overflows are a nightmare, and I need to nip that potential problem in the bud. So, my next step is clear – I'm heading directly to the definition of `alloc_txbuf` to investigate. Let's get cracking!



50/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "\\.alloc_txbuf",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/insecure.c=80=const struct rxrpc_security rxrpc_no_security = {\n--\nnet/rxrpc/insecure.c-86-\t.free_call_crypto\t\t= none_free_call_crypto,\nnet/rxrpc/insecure.c:87:\t.alloc_txbuf\t\t\t= none_alloc_txbuf,\nnet/rxrpc/insecure.c-88-\t.secure_packet\t\t\t= none_secure_packet,\n--\nnet/rxrpc/rxgk.c=1332=const struct rxrpc_security rxgk_yfs = {\n--\nnet/rxrpc/rxgk.c-1342-\t.init_connection_security\t= rxgk_init_connection_security,\nnet/rxrpc/rxgk.c:1343:\t.alloc_txbuf\t\t\t= rxgk_alloc_txbuf,\nnet/rxrpc/rxgk.c-1344-\t.secure_packet\t\t\t= rxgk_secure_packet,\n--\nnet/rxrpc/rxkad.c=1121=const struct rxrpc_security rxkad = {\n--\nnet/rxrpc/rxkad.c-1130-\t.init_connection_security\t= rxkad_init_connection_security,\nnet/rxrpc/rxkad.c:1131:\t.alloc_txbuf\t\t\t= rxkad_alloc_txbuf,\nnet/rxrpc/rxkad.c-1132-\t.secure_packet\t\t\t= rxkad_secure_packet,\n"
}

51/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 27275
							output: 34
							thoughts: 38
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach that memory allocation:

**Investigating `alloc_txbuf` in the RxRPC Data Transmission Buffer**

Right, so I need to understand how the RxRPC stack allocates its data transmission buffers. The first place I'm going to look is in the `net/rxrpc/` directory. Given the function name `rxrpc_alloc_data_txbuf`, I'm betting that the definition I'm after, specifically `alloc_txbuf` (or wherever `rxrpc_alloc_data_txbuf` itself resides), is in `txbuf.c`. That file is the most logical starting point for investigating the buffer allocation strategy for transmitting data. Let's see what that reveals about the low-level memory management and how it interacts with the broader RxRPC data transmission mechanisms. That's where I'll get the real meat of the allocation logic.



52/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxrpc_alloc_data_txbuf",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/ar-internal.h=1544=extern atomic_t rxrpc_nr_txbuf;\nnet/rxrpc/ar-internal.h:1545:struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size,\nnet/rxrpc/ar-internal.h-1546-\t\t\t\t\t   size_t data_align, gfp_t gfp);\n--\nnet/rxrpc/insecure.c=20=static struct rxrpc_txbuf *none_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp)\nnet/rxrpc/insecure.c-21-{\nnet/rxrpc/insecure.c:22:\treturn rxrpc_alloc_data_txbuf(call, umin(remain, RXRPC_JUMBO_DATALEN), 1, gfp);\nnet/rxrpc/insecure.c-23-}\n--\nnet/rxrpc/rxgk.c=283=static struct rxrpc_txbuf *rxgk_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp)\n--\nnet/rxrpc/rxgk.c-292-\t\talloc = umin(remain, RXRPC_JUMBO_DATALEN);\nnet/rxrpc/rxgk.c:293:\t\treturn rxrpc_alloc_data_txbuf(call, alloc, 1, gfp);\nnet/rxrpc/rxgk.c-294-\tcase RXRPC_SECURITY_AUTH:\n--\nnet/rxrpc/rxgk.c-324-\nnet/rxrpc/rxgk.c:325:\ttxb = rxrpc_alloc_data_txbuf(call, alloc, 16, gfp);\nnet/rxrpc/rxgk.c-326-\tif (!txb)\n--\nnet/rxrpc/rxkad.c=139=static struct rxrpc_txbuf *rxkad_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp)\n--\nnet/rxrpc/rxkad.c-148-\t\talloc = umin(remain, RXRPC_JUMBO_DATALEN);\nnet/rxrpc/rxkad.c:149:\t\treturn rxrpc_alloc_data_txbuf(call, alloc, 1, gfp);\nnet/rxrpc/rxkad.c-150-\tcase RXRPC_SECURITY_AUTH:\n--\nnet/rxrpc/rxkad.c-166-\nnet/rxrpc/rxkad.c:167:\ttxb = rxrpc_alloc_data_txbuf(call, alloc, RXKAD_ALIGN, gfp);\nnet/rxrpc/rxkad.c-168-\tif (!txb)\n--\nnet/rxrpc/txbuf.c=14=atomic_t rxrpc_nr_txbuf;\n--\nnet/rxrpc/txbuf.c-18- */\nnet/rxrpc/txbuf.c:19:struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size,\nnet/rxrpc/txbuf.c-20-\t\t\t\t\t   size_t data_align, gfp_t gfp)\n"
}

53/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 28385
							output: 36
							thoughts: 27
						

Thoughts:
Here's my summary, as though I'm thinking through this process:

**Diving into the `rxrpc_alloc_data_txbuf` Function**

Okay, time to dig into the `rxrpc_alloc_data_txbuf` function. I need to refresh my memory on the data transmission buffer allocation within the RxRPC subsystem. Let's start with `net/rxrpc/txbuf.c`. I expect to find the core logic for setting up the transmit buffer structures there. I anticipate this function will handle things like memory allocation (potentially using SLAB or SLUB), buffer initialization, and potentially some accounting for the size and type of data being transmitted. I'm curious to see how it integrates with the rest of the RxRPC transmit path – is it tightly coupled with the connection object, or more loosely tied to the socket? I also want to see if it handles fragmenting data larger than the MTU, or if that is handled higher up in the stack. I bet there are some interesting memory management considerations in this area. Alright, let's get into the code.



54/3 2026/09/14 19:55 tool read-file
0m Args:
{
  "File": "net/rxrpc/txbuf.c",
  "FirstLine": 18,
  "LineCount": 40
}

Results:
{
  "Contents": "  18:\t */\n  19:\tstruct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_size,\n  20:\t\t\t\t\t\t   size_t data_align, gfp_t gfp)\n  21:\t{\n  22:\t\tstruct rxrpc_txbuf *txb;\n  23:\t\tsize_t total, doff, jsize = sizeof(struct rxrpc_jumbo_header);\n  24:\t\tvoid *buf;\n  25:\t\n  26:\t\ttxb = kzalloc_obj(*txb, gfp);\n  27:\t\tif (!txb)\n  28:\t\t\treturn NULL;\n  29:\t\n  30:\t\t/* We put a jumbo header in the buffer, but not a full wire header to\n  31:\t\t * avoid delayed-corruption problems with zerocopy.\n  32:\t\t */\n  33:\t\tdoff = round_up(jsize, data_align);\n  34:\t\ttotal = doff + data_size;\n  35:\t\n  36:\t\tdata_align = umax(data_align, L1_CACHE_BYTES);\n  37:\t\tmutex_lock(\u0026call-\u003econn-\u003etx_data_alloc_lock);\n  38:\t\tbuf = page_frag_alloc_align(\u0026call-\u003econn-\u003etx_data_alloc, total, gfp,\n  39:\t\t\t\t\t    data_align);\n  40:\t\tmutex_unlock(\u0026call-\u003econn-\u003etx_data_alloc_lock);\n  41:\t\tif (!buf) {\n  42:\t\t\tkfree(txb);\n  43:\t\t\treturn NULL;\n  44:\t\t}\n  45:\t\n  46:\t\trefcount_set(\u0026txb-\u003eref, 1);\n  47:\t\ttxb-\u003ecall_debug_id\t= call-\u003edebug_id;\n  48:\t\ttxb-\u003edebug_id\t\t= atomic_inc_return(\u0026rxrpc_txbuf_debug_ids);\n  49:\t\ttxb-\u003ealloc_size\t\t= data_size;\n  50:\t\ttxb-\u003espace\t\t= data_size;\n  51:\t\ttxb-\u003eoffset\t\t= 0;\n  52:\t\ttxb-\u003eflags\t\t= call-\u003econn-\u003eout_clientflag;\n  53:\t\ttxb-\u003eseq\t\t= call-\u003esend_top + 1;\n  54:\t\ttxb-\u003edata\t\t= buf + doff;\n  55:\t\n  56:\t\ttrace_rxrpc_txbuf(txb-\u003edebug_id, txb-\u003ecall_debug_id, txb-\u003eseq, 1,\n  57:\t\t\t\t  rxrpc_txbuf_alloc_data);\n"
}

55/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 29353
							output: 30
							thoughts: 291
						

Thoughts:
**Analyzing the `rxrpc_send_data` Function**

Okay, let's break down how `rxrpc_send_data` interacts with `copy_from_iter_full`. The key here is understanding the data buffer (`txb`) and its associated bookkeeping. We start with `txb->space` initialized to the total `data_size`, `txb->offset` at zero, and `txb->len` initially zero (thanks to `kzalloc`).

The `copy_from_iter_full` function is the core operation. It copies `copy` bytes from user space (or a kernel iterator) into the buffer. Then, we see the updates: `rewind_by`, `txb->space` is reduced by `copy`, `txb->len` (the amount of valid data in the buffer) is *increased* by `copy`, and `txb->offset` increments by `copy` to reflect our position in the buffer. The copied byte count (`copied`) and the remaining length to be copied (`len`) are also adjusted. We have the conditional check of `call->tx_total_len` as well, where we subtract `copy` from it if the total length is defined.

Important: If `copy_from_iter_full` has a failure, it jumps to `efault`. That makes sense. But if it succeeds, then `txb->len` *accurately* reflects the number of bytes that *were* actually copied during this iteration.

Now, the crucial question that comes to mind, especially given the `secure_packet` call: does `secure_packet` *only* encrypt those `txb->len` bytes? We need to be absolutely sure about that. The implications are significant if we have any data integrity or security concerns. I'll need to check the exact implementation details in `rxgk_secure_packet`, `none_secure_packet`, or `rxkad_secure_packet` to confirm. This is where the devil is always in the details!



56/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "secure_packet.*=",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/insecure.c=80=const struct rxrpc_security rxrpc_no_security = {\n--\nnet/rxrpc/insecure.c-87-\t.alloc_txbuf\t\t\t= none_alloc_txbuf,\nnet/rxrpc/insecure.c:88:\t.secure_packet\t\t\t= none_secure_packet,\nnet/rxrpc/insecure.c-89-\t.verify_packet\t\t\t= none_verify_packet,\n--\nnet/rxrpc/rxgk.c=1332=const struct rxrpc_security rxgk_yfs = {\n--\nnet/rxrpc/rxgk.c-1343-\t.alloc_txbuf\t\t\t= rxgk_alloc_txbuf,\nnet/rxrpc/rxgk.c:1344:\t.secure_packet\t\t\t= rxgk_secure_packet,\nnet/rxrpc/rxgk.c-1345-\t.verify_packet\t\t\t= rxgk_verify_packet,\n--\nnet/rxrpc/rxkad.c=1121=const struct rxrpc_security rxkad = {\n--\nnet/rxrpc/rxkad.c-1131-\t.alloc_txbuf\t\t\t= rxkad_alloc_txbuf,\nnet/rxrpc/rxkad.c:1132:\t.secure_packet\t\t\t= rxkad_secure_packet,\nnet/rxrpc/rxkad.c-1133-\t.verify_packet\t\t\t= rxkad_verify_packet,\n"
}

57/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30487
							output: 30
							thoughts: 23
						

Thoughts:
Here's a summary of my immediate thought process:

**Diving into `net/rxrpc/insecure.c`**

Okay, time to dig into this. My first thought is to get right to the heart of the matter. I need to investigate `none_secure_packet` within `net/rxrpc/insecure.c`. This suggests we're dealing with an insecure packet handling scenario within the RxRPC network subsystem, and I need to understand exactly how this function works. I'm expecting this will involve looking at how the function identifies insecure packets, and I will be looking closely at the conditions that determine how these packets are processed. I need to understand any potential vulnerabilities or risks associated with this code path, as well as if there are any subtle bugs or edge cases in this area.



58/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "none_secure_packet",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/insecure.c=20=static struct rxrpc_txbuf *none_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp)\n--\nnet/rxrpc/insecure.c-24-\nnet/rxrpc/insecure.c:25:static int none_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)\nnet/rxrpc/insecure.c-26-{\n--\nnet/rxrpc/insecure.c=80=const struct rxrpc_security rxrpc_no_security = {\n--\nnet/rxrpc/insecure.c-87-\t.alloc_txbuf\t\t\t= none_alloc_txbuf,\nnet/rxrpc/insecure.c:88:\t.secure_packet\t\t\t= none_secure_packet,\nnet/rxrpc/insecure.c-89-\t.verify_packet\t\t\t= none_verify_packet,\n"
}

59/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30955
							output: 36
							thoughts: 23
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into `net/rxrpc/insecure.c`**

Okay, time to get my hands dirty and delve into the `net/rxrpc/insecure.c` file, specifically lines 25 through 40. I know this section likely deals with aspects related to the RPCRX subsystem's handling of potentially insecure communication, so I'm keen to see how they've addressed it. I'm expecting to find details on how they balance security with potentially performance considerations. I'll be looking for things like: the presence (or absence) of explicit checks, any default behaviors that might lean towards less-secure options, and the overall architectural approach to managing insecure transactions within this context. I'll be mentally parsing the code, looking for data structures, function calls, and any comments that illuminate the reasoning behind the design choices. This file is probably a key piece in understanding how the developers tackled the trade-offs inherent in secure remote procedure calls. Let's see what's in store.



60/3 2026/09/14 19:55 tool read-file
0m Args:
{
  "File": "net/rxrpc/insecure.c",
  "FirstLine": 25,
  "LineCount": 20
}

Results:
{
  "Contents": "  25:\tstatic int none_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)\n  26:\t{\n  27:\t\ttxb-\u003epkt_len = txb-\u003elen;\n  28:\t\tif (txb-\u003elen == RXRPC_JUMBO_DATALEN)\n  29:\t\t\ttxb-\u003ejumboable = true;\n  30:\t\treturn 0;\n  31:\t}\n  32:\t\n  33:\tstatic int none_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)\n  34:\t{\n  35:\t\treturn 0;\n  36:\t}\n  37:\t\n  38:\tstatic void none_free_call_crypto(struct rxrpc_call *call)\n  39:\t{\n  40:\t}\n  41:\t\n  42:\tstatic bool none_validate_challenge(struct rxrpc_connection *conn,\n  43:\t\t\t\t\t    struct sk_buff *skb)\n  44:\t{\n"
}

61/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 31522
							output: 32
							thoughts: 40
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm deep in the weeds of network packet handling:

**Analyzing Packet Length Assignment and Security Checks**

Alright, so the first thing I see is the line `txb->pkt_len = txb->len;`. That's a straightforward assignment of the total length of the transmit buffer (`txb->len`) to the packet length field (`txb->pkt_len`). Makes sense; we're essentially saying the entire buffer represents the packet, at least initially. But before I proceed further in this section of code I need to make sure that the `pkt_len` assignment is handled correctly with respect to packet security. Now, let's make a quick mental note to go and cross-reference `rxgk_secure_packet` and `rxkad_secure_packet` functions as well. I need to ensure they handle `pkt_len` appropriately, maybe they do some checks or re-calculation based on security processing. This could involve decryption, authentication, or even integrity checks that might modify the effective packet length. I should see if those functions update `txb->pkt_len`, or make a comparison to ensure the `txb->pkt_len` doesn't exceed security constrictions. Better to be thorough when it comes to security. I don't want any vulnerabilities creeping in because of a mismanaged length value. So, I will be sure to check those functions when I'm done here.



62/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxgk_secure_packet",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/rxgk.c=283=static struct rxrpc_txbuf *rxgk_alloc_txbuf(struct rxrpc_call *call, size_t remain, gfp_t gfp)\n--\nnet/rxrpc/rxgk.c-342- */\nnet/rxrpc/rxgk.c:343:static int rxgk_secure_packet_integrity(const struct rxrpc_call *call,\nnet/rxrpc/rxgk.c-344-\t\t\t\t\tstruct rxgk_context *gk,\n--\nnet/rxrpc/rxgk.c-388- */\nnet/rxrpc/rxgk.c:389:static int rxgk_secure_packet_encrypted(const struct rxrpc_call *call,\nnet/rxrpc/rxgk.c-390-\t\t\t\t\tstruct rxgk_context *gk,\n--\nnet/rxrpc/rxgk.c-429- */\nnet/rxrpc/rxgk.c:430:static int rxgk_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)\nnet/rxrpc/rxgk.c-431-{\n--\nnet/rxrpc/rxgk.c-456-\tcase RXRPC_SECURITY_AUTH:\nnet/rxrpc/rxgk.c:457:\t\treturn rxgk_secure_packet_integrity(call, gk, txb);\nnet/rxrpc/rxgk.c-458-\tcase RXRPC_SECURITY_ENCRYPT:\nnet/rxrpc/rxgk.c:459:\t\treturn rxgk_secure_packet_encrypted(call, gk, txb);\nnet/rxrpc/rxgk.c-460-\tdefault:\n--\nnet/rxrpc/rxgk.c=1332=const struct rxrpc_security rxgk_yfs = {\n--\nnet/rxrpc/rxgk.c-1343-\t.alloc_txbuf\t\t\t= rxgk_alloc_txbuf,\nnet/rxrpc/rxgk.c:1344:\t.secure_packet\t\t\t= rxgk_secure_packet,\nnet/rxrpc/rxgk.c-1345-\t.verify_packet\t\t\t= rxgk_verify_packet,\n"
}

63/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 32489
							output: 31
							thoughts: 24
						

Thoughts:
Here's my take on those thoughts, tailored for an expert audience:

**Diving into the RxRPC Key Exchange**

Okay, so I need to refresh my memory on the specifics of the `rxkad_secure_packet` function. My instinct is that it's in the `net/rxrpc/rxkad.c` file; that seems like the logical place for key exchange and security-related logic within the RxRPC implementation. I want to zero in on how it's handling secure packet construction, the key derivation, any potential HMAC calculations, and, crucially, how it interacts with the Kerberos authentication process. I need to understand this function's role in the end-to-end security model, especially within the context of the newer RxRPC implementations.



64/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxkad_secure_packet",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/rxkad.c=209=static void rxkad_free_call_crypto(struct rxrpc_call *call)\n--\nnet/rxrpc/rxkad.c-215- */\nnet/rxrpc/rxkad.c:216:static void rxkad_secure_packet_auth(const struct rxrpc_call *call,\nnet/rxrpc/rxkad.c-217-\t\t\t\t     struct rxrpc_txbuf *txb)\n--\nnet/rxrpc/rxkad.c-244- */\nnet/rxrpc/rxkad.c:245:static void rxkad_secure_packet_encrypt(const struct rxrpc_call *call,\nnet/rxrpc/rxkad.c-246-\t\t\t\t\tstruct rxrpc_txbuf *txb)\n--\nnet/rxrpc/rxkad.c-277- */\nnet/rxrpc/rxkad.c:278:static int rxkad_secure_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)\nnet/rxrpc/rxkad.c-279-{\n--\nnet/rxrpc/rxkad.c-319-\tcase RXRPC_SECURITY_AUTH:\nnet/rxrpc/rxkad.c:320:\t\trxkad_secure_packet_auth(call, txb);\nnet/rxrpc/rxkad.c-321-\t\tif (txb-\u003ealloc_size == RXRPC_JUMBO_DATALEN)\n--\nnet/rxrpc/rxkad.c-325-\tcase RXRPC_SECURITY_ENCRYPT:\nnet/rxrpc/rxkad.c:326:\t\trxkad_secure_packet_encrypt(call, txb);\nnet/rxrpc/rxkad.c-327-\t\tif (txb-\u003ealloc_size == RXRPC_JUMBO_DATALEN)\n--\nnet/rxrpc/rxkad.c=1121=const struct rxrpc_security rxkad = {\n--\nnet/rxrpc/rxkad.c-1131-\t.alloc_txbuf\t\t\t= rxkad_alloc_txbuf,\nnet/rxrpc/rxkad.c:1132:\t.secure_packet\t\t\t= rxkad_secure_packet,\nnet/rxrpc/rxkad.c-1133-\t.verify_packet\t\t\t= rxkad_verify_packet,\n"
}

65/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 33293
							output: 33
							thoughts: 590
						

Thoughts:
**Analyzing Potential Uninitialized Data in RxRPC**

Okay, let's dive into this. My initial focus is on how `rxrpc_kernel_recv_data` handles specific error scenarios, particularly concerning the initialization or lack thereof of `call->abort_code` and `call->service_id`. I'm seeing a code path in `net/rxrpc/rxperf.c` within the `rxperf_deliver_to_call` function where there's a check for `RXPERF_CALL_SV_AWAIT_ACK`.  It's calling `rxrpc_kernel_recv_data`, and then immediately returning if the return of the call is in progress. The logic seems to imply the code expects the function to potentially set these variables, but the subsequent code doesn't explicitly check for their initialization.

Then, there is an interaction with `afs_make_call`. I see that a check is being made to intercept `-ESHUTDOWN`, which is then translated into a `-ECONNABORTED` and the logic continues. I see that if the return from the call is `-ECONNABORTED`, then the `call->responded` flag is set. That, coupled with the previous logic, brings me to the assumption that setting `call->responded` is the main goal.

My concern is that, in some error conditions, particularly within the contexts of these calls, I want to make sure these variables are either properly set to a defined state or that the code handles their potential uninitialized status correctly. I need to trace this function to see if these variables are initialized on all paths. If these variables are not initialized in all paths, then there might be bugs in the way these values are used.

Therefore, my next step is to examine the implementation of `rxrpc_kernel_recv_data` itself within `net/rxrpc/recvmsg.c` to understand exactly what happens to these variables under different error conditions and if they're always initialized.



66/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxrpc_kernel_recv_data",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/recvmsg.c=395=int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n--\nnet/rxrpc/recvmsg.c-612-/**\nnet/rxrpc/recvmsg.c:613: * rxrpc_kernel_recv_data - Allow a kernel service to receive data/info\nnet/rxrpc/recvmsg.c-614- * @sock: The socket that the call exists on\n--\nnet/rxrpc/recvmsg.c-631- */\nnet/rxrpc/recvmsg.c:632:int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,\nnet/rxrpc/recvmsg.c-633-\t\t\t   struct iov_iter *iter, size_t *_len,\n--\nnet/rxrpc/recvmsg.c-697-}\nnet/rxrpc/recvmsg.c:698:EXPORT_SYMBOL(rxrpc_kernel_recv_data);\n--\nnet/rxrpc/rxperf.c=280=static void rxperf_deliver_to_call(struct work_struct *work)\n--\nnet/rxrpc/rxperf.c-297-\t\t\tiov_iter_kvec(\u0026call-\u003eiter, ITER_DEST, NULL, 0, 0);\nnet/rxrpc/rxperf.c:298:\t\t\tret = rxrpc_kernel_recv_data(rxperf_socket,\nnet/rxrpc/rxperf.c-299-\t\t\t\t\t\t     call-\u003erxcall, \u0026call-\u003eiter,\n--\nnet/rxrpc/rxperf.c=369=static int rxperf_extract_data(struct rxperf_call *call, bool want_more)\n--\nnet/rxrpc/rxperf.c-373-\nnet/rxrpc/rxperf.c:374:\tret = rxrpc_kernel_recv_data(rxperf_socket, call-\u003erxcall, \u0026call-\u003eiter,\nnet/rxrpc/rxperf.c-375-\t\t\t\t     \u0026call-\u003eiov_len, want_more, \u0026remote_abort,\n"
}

67/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 34861
							output: 37
							thoughts: 26
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Diving into rxrpc_kernel_recv_data**

Alright, let's get down to it. Time to dissect `rxrpc_kernel_recv_data` within `net/rxrpc/recvmsg.c`. I need to understand how the RxRPC kernel handles receiving data via the `recvmsg` system call, particularly the core mechanics. I'm assuming this function sits at the heart of the kernel-side data reception process for RxRPC, so a deep understanding here is critical for any serious RxRPC analysis or debugging. I'm expecting to find the logic for handling socket buffers, copying data into user space, managing flow control, and potentially dealing with fragmentation or reassembly if the underlying transport layer requires it. I'll be looking specifically for any nuanced error handling, edge cases, and optimization strategies employed within this crucial data path. Understanding how the kernel interfaces with the user-space `recvmsg` call is key. I'm also curious to see how concurrency is managed, as this function will most likely be handling data from multiple connections simultaneously.



68/3 2026/09/14 19:55 tool read-file
0m Args:
{
  "File": "net/rxrpc/recvmsg.c",
  "FirstLine": 630,
  "LineCount": 60
}

Results:
{
  "Contents": " 630:\t * %-EAGAIN if we need more data.\n 631:\t */\n 632:\tint rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,\n 633:\t\t\t\t   struct iov_iter *iter, size_t *_len,\n 634:\t\t\t\t   bool want_more, u32 *_abort, u16 *_service)\n 635:\t{\n 636:\t\tsize_t offset = 0;\n 637:\t\tint ret;\n 638:\t\n 639:\t\t_enter(\"{%d},%zu,%d\", call-\u003edebug_id, *_len, want_more);\n 640:\t\n 641:\t\tmutex_lock(\u0026call-\u003euser_mutex);\n 642:\t\n 643:\t\tret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, \u0026offset);\n 644:\t\t*_len -= offset;\n 645:\t\tif (ret == -EIO)\n 646:\t\t\tgoto call_failed;\n 647:\t\tif (ret \u003c 0)\n 648:\t\t\tgoto out;\n 649:\t\n 650:\t\t/* We can only reach here with a partially full buffer if we have\n 651:\t\t * reached the end of the data.  We must otherwise have a full buffer\n 652:\t\t * or have been given -EAGAIN.\n 653:\t\t */\n 654:\t\tif (ret == 1) {\n 655:\t\t\tif (iov_iter_count(iter) \u003e 0)\n 656:\t\t\t\tgoto short_data;\n 657:\t\t\tif (!want_more)\n 658:\t\t\t\tgoto read_phase_complete;\n 659:\t\t\tret = 0;\n 660:\t\t\tgoto out;\n 661:\t\t}\n 662:\t\n 663:\t\tif (!want_more)\n 664:\t\t\tgoto excess_data;\n 665:\t\tgoto out;\n 666:\t\n 667:\tread_phase_complete:\n 668:\t\tret = 1;\n 669:\tout:\n 670:\t\tif (_service)\n 671:\t\t\t*_service = call-\u003edest_srx.srx_service;\n 672:\t\tmutex_unlock(\u0026call-\u003euser_mutex);\n 673:\t\t_leave(\" = %d [%zu,%d]\", ret, iov_iter_count(iter), *_abort);\n 674:\t\treturn ret;\n 675:\t\n 676:\tshort_data:\n 677:\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_recvmsg_short_data,\n 678:\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n 679:\t\t\t\t  0, -EBADMSG);\n 680:\t\tret = -EBADMSG;\n 681:\t\tgoto out;\n 682:\texcess_data:\n 683:\t\ttrace_rxrpc_abort(call-\u003edebug_id, rxrpc_recvmsg_excess_data,\n 684:\t\t\t\t  call-\u003ecid, call-\u003ecall_id, call-\u003erx_consumed,\n 685:\t\t\t\t  0, -EMSGSIZE);\n 686:\t\tret = -EMSGSIZE;\n 687:\t\tgoto out;\n 688:\tcall_failed:\n 689:\t\t*_abort = call-\u003eabort_code;\n"
}

69/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36078
							output: 32
							thoughts: 124
						

Thoughts:
**Analyzing a Potential Bug in RxRPC Data Handling**

Okay, so I'm looking at this code and something's bugging me. Specifically, line 673 jumps out: `_leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort);`. It's logging the return value `ret` and other info. But wait a minute... Does the `call_failed` condition *only* trigger when `ret` is exactly `-EIO`? My gut says no, and I need to verify that. What about other negative return codes? What if `ret` is less than zero, but *isn't* `-EIO`? Like, say, `-ECONNABORTED`? That's a possibility, and it could be masking a different issue. The function is definitely logging on an error, but is it the right error?

Okay, time to dig deeper. I need to figure out where `rxrpc_recvmsg_data` might actually return `-ECONNABORTED`. I need to track down all the possible return paths there. Let's trace back.



70/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxrpc_recvmsg_data",
  "PathPrefix": "net/rxrpc/"
}

Results:
{
  "Output": "net/rxrpc/recvmsg.c=221=static int rxrpc_recvmsg_oob(struct socket *sock, struct msghdr *msg,\n--\nnet/rxrpc/recvmsg.c-266- */\nnet/rxrpc/recvmsg.c:267:static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,\nnet/rxrpc/recvmsg.c-268-\t\t\t      struct msghdr *msg, struct iov_iter *iter,\n--\nnet/rxrpc/recvmsg.c-382-done:\nnet/rxrpc/recvmsg.c:383:\ttrace_rxrpc_recvdata(call, rxrpc_recvmsg_data_return, seq,\nnet/rxrpc/recvmsg.c-384-\t\t\t     rx_pkt_offset, rx_pkt_len, ret);\n--\nnet/rxrpc/recvmsg.c=395=int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,\n--\nnet/rxrpc/recvmsg.c-534-\nnet/rxrpc/recvmsg.c:535:\tret = rxrpc_recvmsg_data(sock, call, msg, \u0026msg-\u003emsg_iter, len,\nnet/rxrpc/recvmsg.c-536-\t\t\t\t flags, \u0026copied);\n--\nnet/rxrpc/recvmsg.c=632=int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,\n--\nnet/rxrpc/recvmsg.c-642-\nnet/rxrpc/recvmsg.c:643:\tret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, \u0026offset);\nnet/rxrpc/recvmsg.c-644-\t*_len -= offset;\n"
}

71/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36943
							output: 37
							thoughts: 23
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into `rxrpc_recvmsg_data`**

Okay, time to get to the heart of this. My focus is zeroed in on `rxrpc_recvmsg_data`, specifically lines 265 through 310. That block is where the critical handling is likely occurring. I need to refresh my understanding of what those lines are responsible for; I know this is where the core data reception and possibly message assembly are happening, but I need to pinpoint the exact logic in that section to understand if the issue is originating there. Let's delve in and see what's happening.



72/3 2026/09/14 19:55 tool read-file
0m Args:
{
  "File": "net/rxrpc/recvmsg.c",
  "FirstLine": 265,
  "LineCount": 50
}

Results:
{
  "Contents": " 265:\t * call has failed it returns -EIO.\n 266:\t */\n 267:\tstatic int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,\n 268:\t\t\t\t      struct msghdr *msg, struct iov_iter *iter,\n 269:\t\t\t\t      size_t len, int flags, size_t *_offset)\n 270:\t{\n 271:\t\tstruct rxrpc_skb_priv *sp;\n 272:\t\tstruct rxrpc_sock *rx = rxrpc_sk(sock-\u003esk);\n 273:\t\tstruct sk_buff *skb;\n 274:\t\trxrpc_seq_t seq = 0;\n 275:\t\tsize_t remain;\n 276:\t\tunsigned int rx_pkt_offset, rx_pkt_len;\n 277:\t\tint copy, ret = -EAGAIN, ret2;\n 278:\t\n 279:\t\trx_pkt_offset = call-\u003erx_pkt_offset;\n 280:\t\trx_pkt_len = call-\u003erx_pkt_len;\n 281:\t\n 282:\t\tif (rxrpc_call_has_failed(call)) {\n 283:\t\t\tseq = call-\u003eackr_window - 1;\n 284:\t\t\tret = -EIO;\n 285:\t\t\tgoto done;\n 286:\t\t}\n 287:\t\n 288:\t\tif (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, \u0026call-\u003eflags)) {\n 289:\t\t\tseq = call-\u003eackr_window - 1;\n 290:\t\t\tret = 1;\n 291:\t\t\tgoto done;\n 292:\t\t}\n 293:\t\n 294:\t\t/* No one else can be removing stuff from the queue, so we shouldn't\n 295:\t\t * need the Rx lock to walk it.\n 296:\t\t */\n 297:\t\tskb = skb_peek(\u0026call-\u003erecvmsg_queue);\n 298:\t\twhile (skb) {\n 299:\t\t\trxrpc_see_skb(skb, rxrpc_skb_see_recvmsg);\n 300:\t\t\tsp = rxrpc_skb(skb);\n 301:\t\t\tseq = sp-\u003ehdr.seq;\n 302:\t\n 303:\t\t\tif (!(flags \u0026 MSG_PEEK))\n 304:\t\t\t\ttrace_rxrpc_receive(call, rxrpc_receive_front,\n 305:\t\t\t\t\t\t    sp-\u003ehdr.serial, seq);\n 306:\t\n 307:\t\t\tif (msg)\n 308:\t\t\t\tsock_recv_timestamp(msg, sock-\u003esk, skb);\n 309:\t\n 310:\t\t\tif (call-\u003erx_dec_seq != sp-\u003ehdr.seq ||\n 311:\t\t\t    !call-\u003erx_dec_buffer) {\n 312:\t\t\t\tret2 = rxrpc_verify_data(call, skb);\n 313:\t\t\t\ttrace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,\n 314:\t\t\t\t\t\t     call-\u003erx_dec_offset,\n"
}

73/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 37977
							output: 37
							thoughts: 446
						

Thoughts:
**Analyzing RXRPC Error Handling and Data Delivery**

Okay, let's break this down. I'm looking at how the `rxrpc_kernel_recv_data` function handles errors, specifically focusing on lines 685-695. The code snippet shows that if a call fails (`rxrpc_call_has_failed(call)` is true), the `ret` variable is set to `-EIO`, but then at the `call_failed` label, `*_abort` gets the `call->abort_code`, and `ret` takes the value of `call->error`. So, if the original `ret` was `-ECONNABORTED`, then `*_abort` will be initialized to whatever value `call->abort_code` has. Got it.

Now, I need to understand this in the context of `rxperf_deliver_to_call`. I'm seeing a section within `rxperf_deliver_to_call` where it calls `rxrpc_kernel_recv_data`.  Specifically, I am interested in this portion:

```c
		if (state == RXPERF_CALL_SV_AWAIT_ACK) {
			size_t len = 0;
			iov_iter_kvec(&call->iter, ITER_DEST, NULL, 0, 0);
			ret = rxrpc_kernel_recv_data(rxperf_socket,
						     call->rxcall, &call->iter,
						     &len, false, &remote_abort,
						     &call->service_id);

			if (ret == -EINPROGRESS || ret == -EAGAIN)
				return;
			if (ret < 0 || ret == 1) {
				if (ret == 1)
					ret = 0;
				goto call_complete;
			}
			return;
		}
```
Okay, `rxrpc_kernel_recv_data` is called with `&remote_abort`.  That's interesting. I need to figure out where `remote_abort` is actually *declared* within `rxperf_deliver_to_call`.  Let me quickly check lines 280-320 of `net/rxrpc/rxperf.c` to see if it is declared there. That's the missing piece of the puzzle.



74/3 2026/09/14 19:55 tool read-file
0m Args:
{
  "File": "net/rxrpc/rxperf.c",
  "FirstLine": 280,
  "LineCount": 40
}

Results:
{
  "Contents": " 280:\tstatic void rxperf_deliver_to_call(struct work_struct *work)\n 281:\t{\n 282:\t\tstruct rxperf_call *call = container_of(work, struct rxperf_call, work);\n 283:\t\tenum rxperf_call_state state;\n 284:\t\tu32 abort_code, remote_abort = 0;\n 285:\t\tint ret = 0;\n 286:\t\n 287:\t\tif (call-\u003estate == RXPERF_CALL_COMPLETE)\n 288:\t\t\treturn;\n 289:\t\n 290:\t\twhile (state = call-\u003estate,\n 291:\t\t       state == RXPERF_CALL_SV_AWAIT_PARAMS ||\n 292:\t\t       state == RXPERF_CALL_SV_AWAIT_REQUEST ||\n 293:\t\t       state == RXPERF_CALL_SV_AWAIT_ACK\n 294:\t\t       ) {\n 295:\t\t\tif (state == RXPERF_CALL_SV_AWAIT_ACK) {\n 296:\t\t\t\tsize_t len = 0;\n 297:\t\t\t\tiov_iter_kvec(\u0026call-\u003eiter, ITER_DEST, NULL, 0, 0);\n 298:\t\t\t\tret = rxrpc_kernel_recv_data(rxperf_socket,\n 299:\t\t\t\t\t\t\t     call-\u003erxcall, \u0026call-\u003eiter,\n 300:\t\t\t\t\t\t\t     \u0026len, false, \u0026remote_abort,\n 301:\t\t\t\t\t\t\t     \u0026call-\u003eservice_id);\n 302:\t\n 303:\t\t\t\tif (ret == -EINPROGRESS || ret == -EAGAIN)\n 304:\t\t\t\t\treturn;\n 305:\t\t\t\tif (ret \u003c 0 || ret == 1) {\n 306:\t\t\t\t\tif (ret == 1)\n 307:\t\t\t\t\t\tret = 0;\n 308:\t\t\t\t\tgoto call_complete;\n 309:\t\t\t\t}\n 310:\t\t\t\treturn;\n 311:\t\t\t}\n 312:\t\n 313:\t\t\tret = call-\u003edeliver(call);\n 314:\t\t\tswitch (ret) {\n 315:\t\t\tcase 0:\n 316:\t\t\t\trxperf_process_call(call);\n 317:\t\t\t\treturn;\n 318:\t\t\tcase -EINPROGRESS:\n 319:\t\t\tcase -EAGAIN:\n"
}

75/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 39592
							output: 22
							thoughts: 650
						

Thoughts:
**Analyzing Remote Abort Handling in AFS/RxRPC**

Okay, so I'm looking into how remote aborts are handled within the AFS file system, specifically focusing on the `rxrpc` component. It seems like the core issue revolves around how the abort code is propagated and used. My initial thought is that `remote_abort` is initialized to zero, which is expected.

I started by examining the `afs_make_call` function in `fs/afs/rxrpc.c`. I noticed a change related to error handling. The code now checks for `-ESHUTDOWN` instead of `-ECONNABORTED`, and calls `rxrpc_kernel_recv_data`. The interesting thing is that if `rxrpc_kernel_recv_data` returns `-ECONNABORTED`, then `call->responded` is set to true.

Then I dug into `rxrpc_kernel_send_data`. My initial thought was to see where `call->abort_code` is set. After looking at the `rxrpc_kernel_send_data` loop, I realized it has changed, and the `len` argument is removed! This triggered a flag; I want to see what callers were passing to `rxrpc_kernel_send_data`. It's a key observation, this removal of the `len` argument, and it will likely be crucial in understanding the complete flow. Now, I need to analyze all the callers of this function to understand the implications of this change. I'll need to do a full cross-reference search throughout the kernel source to get the full picture.



76/3 2026/09/14 19:55 tool grepper
0m Args:
{
  "Expression": "rxrpc_kernel_send_data"
}

Results:
{
  "Output": "Documentation/networking/rxrpc.rst=795=The kernel interface functions are as follows:\n--\nDocumentation/networking/rxrpc.rst-869-\nDocumentation/networking/rxrpc.rst:870:\tint rxrpc_kernel_send_data(struct socket *sock,\nDocumentation/networking/rxrpc.rst-871-\t\t\t\t   struct rxrpc_call *call,\n--\nfs/afs/rxrpc.c=345=void afs_make_call(struct afs_call *call, gfp_t gfp)\n--\nfs/afs/rxrpc.c-414-\nfs/afs/rxrpc.c:415:\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall, \u0026msg,\nfs/afs/rxrpc.c-416-\t\t\t\t     afs_notify_end_request_tx);\n--\nfs/afs/rxrpc.c-424-\nfs/afs/rxrpc.c:425:\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket,\nfs/afs/rxrpc.c-426-\t\t\t\t\t     call-\u003erxcall, \u0026msg,\n--\nfs/afs/rxrpc.c=855=void afs_send_empty_reply(struct afs_call *call)\n--\nfs/afs/rxrpc.c-871-\nfs/afs/rxrpc.c:872:\tret = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg,\nfs/afs/rxrpc.c-873-\t\t\t\t     afs_notify_end_reply_tx);\n--\nfs/afs/rxrpc.c=883=void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)\n--\nfs/afs/rxrpc.c-902-\nfs/afs/rxrpc.c:903:\tn = rxrpc_kernel_send_data(net-\u003esocket, call-\u003erxcall, \u0026msg,\nfs/afs/rxrpc.c-904-\t\t\t\t   afs_notify_end_reply_tx);\n--\ninclude/net/af_rxrpc.h=55=struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,\n--\ninclude/net/af_rxrpc.h-66-\t\t\t\t\t   unsigned int debug_id);\ninclude/net/af_rxrpc.h:67:int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\ninclude/net/af_rxrpc.h-68-\t\t\t   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx);\n--\nnet/rxrpc/rxperf.c=521=static void rxperf_process_call(struct rxperf_call *call)\n--\nnet/rxrpc/rxperf.c-536-\t\tmsg.msg_flags = MSG_MORE;\nnet/rxrpc/rxperf.c:537:\t\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg,\nnet/rxrpc/rxperf.c-538-\t\t\t\t\t   rxperf_notify_end_reply_tx);\n--\nnet/rxrpc/rxperf.c-548-\tmsg.msg_flags = 0;\nnet/rxrpc/rxperf.c:549:\tn = rxrpc_kernel_send_data(rxperf_socket, call-\u003erxcall, \u0026msg,\nnet/rxrpc/rxperf.c-550-\t\t\t\t   rxperf_notify_end_reply_tx);\n--\nnet/rxrpc/sendmsg.c=748=int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)\n--\nnet/rxrpc/sendmsg.c-878-/**\nnet/rxrpc/sendmsg.c:879: * rxrpc_kernel_send_data - Allow a kernel service to send data on a call\nnet/rxrpc/sendmsg.c-880- * @sock: The socket the call is on\n--\nnet/rxrpc/sendmsg.c-891- */\nnet/rxrpc/sendmsg.c:892:int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,\nnet/rxrpc/sendmsg.c-893-\t\t\t   struct msghdr *msg, rxrpc_notify_end_tx_t notify_end_tx)\n--\nnet/rxrpc/sendmsg.c-921-}\nnet/rxrpc/sendmsg.c:922:EXPORT_SYMBOL(rxrpc_kernel_send_data);\nnet/rxrpc/sendmsg.c-923-\n"
}

77/3 2026/09/14 19:55 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41780
							output: 36
							thoughts: 691
						

Thoughts:
**Analyzing Reply Path in AFS**

Okay, so this patch claims every caller is updated, which piques my interest. Let's dig into the details. I need to understand how the reply path works, specifically focusing on how data is sent back to the client. I'm going to start by examining `afs_send_empty_reply` and `afs_send_simple_reply` within `fs/afs/rxrpc.c`.

First, `afs_send_empty_reply` is straightforward. It prepares a `msghdr` struct, sets the total transmit length to zero, and then uses `rxrpc_kernel_send_data` to transmit the empty reply.  Critically, `msg` is zeroed out using `memset`. I'm verifying that with an empty reply, `msg_data_left(&msg)` will be zero; `iov_iter_count(&msg.msg_iter)` will also be zero.

Next, I'll look at `afs_send_simple_reply`. Here, we're sending a non-empty reply.  Again, `msghdr msg` is memset to zero, and the data is copied to the msg.  The transmit length is set using `rxrpc_kernel_set_tx_total_len`.  The `iov_iter_kvec` function correctly initializes the `msg.msg_iter` member. I'm satisfied that this path handles the non-empty reply correctly.

Now, I'll transition to the call setup.  I need to understand how these replies are linked to the initial call. Time to scrutinize `afs_make_call` in the same file.



78/3 2026/09/14 19:56 tool read-file
0m Args:
{
  "File": "fs/afs/rxrpc.c",
  "FirstLine": 390,
  "LineCount": 45
}

Results:
{
  "Contents": " 390:\t\t\t\t\t\t call-\u003eservice_id,\n 391:\t\t\t\t\t\t call-\u003eupgrade,\n 392:\t\t\t\t\t\t (call-\u003eintr ? RXRPC_PREINTERRUPTIBLE :\n 393:\t\t\t\t\t\t  RXRPC_UNINTERRUPTIBLE),\n 394:\t\t\t\t\t\t call-\u003edebug_id);\n 395:\t\tif (IS_ERR(rxcall)) {\n 396:\t\t\tret = PTR_ERR(rxcall);\n 397:\t\t\tcall-\u003eerror = ret;\n 398:\t\t\tgoto error_kill_call;\n 399:\t\t}\n 400:\t\n 401:\t\tcall-\u003erxcall = rxcall;\n 402:\t\tcall-\u003eissue_time = ktime_get_real();\n 403:\t\n 404:\t\t/* send the request */\n 405:\t\tiov[0].iov_base\t= call-\u003erequest;\n 406:\t\tiov[0].iov_len\t= call-\u003erequest_size;\n 407:\t\n 408:\t\tmsg.msg_name\t\t= NULL;\n 409:\t\tmsg.msg_namelen\t\t= 0;\n 410:\t\tiov_iter_kvec(\u0026msg.msg_iter, ITER_SOURCE, iov, 1, call-\u003erequest_size);\n 411:\t\tmsg.msg_control\t\t= NULL;\n 412:\t\tmsg.msg_controllen\t= 0;\n 413:\t\tmsg.msg_flags\t\t= MSG_WAITALL | (call-\u003ewrite_iter ? MSG_MORE : 0);\n 414:\t\n 415:\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket, rxcall, \u0026msg,\n 416:\t\t\t\t\t     afs_notify_end_request_tx);\n 417:\t\tif (ret \u003c 0)\n 418:\t\t\tgoto error_do_abort;\n 419:\t\n 420:\t\tif (call-\u003ewrite_iter) {\n 421:\t\t\tmsg.msg_iter = *call-\u003ewrite_iter;\n 422:\t\t\tmsg.msg_flags \u0026= ~MSG_MORE;\n 423:\t\t\ttrace_afs_send_data(call, \u0026msg);\n 424:\t\n 425:\t\t\tret = rxrpc_kernel_send_data(call-\u003enet-\u003esocket,\n 426:\t\t\t\t\t\t     call-\u003erxcall, \u0026msg,\n 427:\t\t\t\t\t\t     afs_notify_end_request_tx);\n 428:\t\t\t*call-\u003ewrite_iter = msg.msg_iter;\n 429:\t\n 430:\t\t\ttrace_afs_sent_data(call, \u0026msg, ret);\n 431:\t\t\tif (ret \u003c 0)\n 432:\t\t\t\tgoto error_do_abort;\n 433:\t\t}\n 434:\t\n"
}

79/3 2026/09/14 19:56 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 43589
							output: 534
							thoughts: 2448
						

Thoughts:
**KMSAN Assessment: No Need for KMSAN in This Patch**

Okay, let's break this down. First, I went through each changed file methodically. `Documentation/networking/rxrpc.rst` just got documentation updates, so no worries there. Then, looking at `net/rxrpc/recvmsg.c`, it seems we have some queuing logic with `rxrpc_requeue_call`, nothing KMSAN-related. `net/rxrpc/conn_object.c` is all about connection refcounting and lifecycle management – classic concurrency stuff, KASAN can handle this. `net/rxrpc/call_state.c` shows state checking and tracing which doesn't seem to be relevant. Jumping into `fs/afs/internal.h` and `fs/afs/fs_operation.c`, I see reference handling and dangling pointer avoidance with `afs_use_server` and `op->call = NULL;`. This is prime KASAN territory, preventing use-after-free, a very important fix!

Now, the critical part. We have to be *absolutely* sure if this warrants KMSAN. Remember, KMSAN detects uninitialized memory *reads*, which can lead to information leaks. But KASAN, LOCKDEP, and the usual suspects are already running and can catch a lot of bugs!  The patch *only* warrants `NeedsKMSAN=true` if it changes code that: 1. sends kernel data structures to userspace without initializing all fields, 2. has conditional logic based on uninitialized stuff, 3. allocates data structures with uninitialized fields, or 4. alters buffer length or bounds calculations allowing uninitialized data to be read.

I dug in. Did any of those cases show up in the patch? Let's check each point:
1.  Kernel structures sent to user space:  The guarded `#ifdef CONFIG_RXGK` in `rxrpc_preparse_xdr_yfs_rxgk` with `kzalloc` is completely initialized!
2. Conditional logic:  Explicit initialization of local variables (such as `remote_abort`, etc) within the various methods.
3. Allocation of uninitialized buffers: Everything uses `kzalloc` or similar zeroing mechanisms (`appdata`, `token`, `txbuf`). No issues.
4. Bounds checks: The change in `fs/afs/cm_security.c` corrected `toksize` to prevent undercalculation, and `txb->len` and `copied` in `sendmsg.c` correctly track copied data, no uninitialized bytes get read.

So it all comes down to, is there uninitialized memory at risk? **No.** The patch primarily touches these areas:
*   Token size correction using `kzalloc`.
*   API simplification/error handling fixes (removing `len` parameter, rewinding and locking).
*   Guards and validation of keys.
*   Reference counting, dangling pointer fixes (all handled by KASAN).
*   Notification and error code propagation, variable initialization.

These are all about synchronization, lifetime, and data correctness – prime areas for KASAN, KCSAN, and LOCKDEP.  KMSAN is unnecessary.

Therefore, after a careful review, the answer is: `NeedsKMSAN = false`. We're good to go!



80/3 2026/09/14 19:56 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch series touches AF_RXRPC and AFS subsystems with several distinct fixes and refactorings:\n\n1. In Documentation/networking/rxrpc.rst, include/net/af_rxrpc.h, fs/afs/rxrpc.c, net/rxrpc/rxperf.c, and net/rxrpc/sendmsg.c: The `len` parameter is removed from `rxrpc_kernel_send_data()`, deriving length directly from the message iterator via `msg_data_left()`. The data transmission loop, error rewind logic, and lock handling (`user_mutex`) are adjusted. Data copied into `txb-\u003edata` comes directly from `copy_from_iter_full()`, with lengths strictly bounded by iterator count and remaining buffer space.\n2. In fs/afs/cm_security.c: `toksize` calculation in `afs_create_yfs_cm_token()` is adjusted by adding 4 bytes for the token level field. The underlying buffer `appdata` is allocated using `kzalloc()`, and all fields are explicitly initialized.\n3. In net/rxrpc/key.c: Added `#ifdef CONFIG_RXGK` guards and enctype validation in `rxrpc_preparse_xdr_yfs_rxgk()`. All parsed token allocations use `kzalloc()` and initialized buffers.\n4. In fs/afs/internal.h and fs/afs/fs_operation.c: Fixed server reference pinning (`afs_use_server()`) and cleared dangling `op-\u003ecall` pointer (`op-\u003ecall = NULL`) after call release. These prevent use-after-free conditions, which are detected by KASAN.\n5. In net/rxrpc/conn_object.c, call_state.c, and recvmsg.c: Handled connection reference count races (`rxrpc_get_connection_maybe()`) and separated notification paths when calls are completed or requeued. All variables in updated functions (e.g. `remote_abort = 0`) are explicitly initialized.\n\nNone of the changes introduce uninitialized memory allocations, leak uninitialized data or padding to user space, or add branches dependent on uninitialized data. Risks in these changes (locking, reference counting, and buffer bounds) fall squarely under KASAN and LOCKDEP rather than KMSAN. Therefore, a dedicated KMSAN session is not warranted.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch series touches AF_RXRPC and AFS subsystems with several distinct fixes and refactorings:\n\n1. In Documentation/networking/rxrpc.rst, include/net/af_rxrpc.h, fs/afs/rxrpc.c, net/rxrpc/rxperf.c, and net/rxrpc/sendmsg.c: The `len` parameter is removed from `rxrpc_kernel_send_data()`, deriving length directly from the message iterator via `msg_data_left()`. The data transmission loop, error rewind logic, and lock handling (`user_mutex`) are adjusted. Data copied into `txb-\u003edata` comes directly from `copy_from_iter_full()`, with lengths strictly bounded by iterator count and remaining buffer space.\n2. In fs/afs/cm_security.c: `toksize` calculation in `afs_create_yfs_cm_token()` is adjusted by adding 4 bytes for the token level field. The underlying buffer `appdata` is allocated using `kzalloc()`, and all fields are explicitly initialized.\n3. In net/rxrpc/key.c: Added `#ifdef CONFIG_RXGK` guards and enctype validation in `rxrpc_preparse_xdr_yfs_rxgk()`. All parsed token allocations use `kzalloc()` and initialized buffers.\n4. In fs/afs/internal.h and fs/afs/fs_operation.c: Fixed server reference pinning (`afs_use_server()`) and cleared dangling `op-\u003ecall` pointer (`op-\u003ecall = NULL`) after call release. These prevent use-after-free conditions, which are detected by KASAN.\n5. In net/rxrpc/conn_object.c, call_state.c, and recvmsg.c: Handled connection reference count races (`rxrpc_get_connection_maybe()`) and separated notification paths when calls are completed or requeued. All variables in updated functions (e.g. `remote_abort = 0`) are explicitly initialized.\n\nNone of the changes introduce uninitialized memory allocations, leak uninitialized data or padding to user space, or add branches dependent on uninitialized data. Risks in these changes (locking, reference counting, and buffer bounds) fall squarely under KASAN and LOCKDEP rather than KMSAN. Therefore, a dedicated KMSAN session is not warranted.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)