Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

af_unix: Use cached value for SOCK_STREAM in unix_inq_len().

Compared to TCP, ioctl(SIOCINQ) for AF_UNIX SOCK_STREAM socket is more
expensive, as unix_inq_len() requires iterating through the receive queue
and accumulating skb->len.

Let's cache the value for SOCK_STREAM to a new field during sendmsg()
and recvmsg().

The field is protected by the receive queue lock.

Note that ioctl(SIOCINQ) for SOCK_DGRAM returns the length of the first
skb in the queue.

SOCK_SEQPACKET still requires iterating through the queue because we do
not touch functions shared with unix_dgram_ops. But, if really needed,
we can support it by switching __skb_try_recv_datagram() to a custom
version.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20250702223606.1054680-5-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
f4e1fb04 d0aac854

+29 -10
+1
include/net/af_unix.h
··· 47 47 #define peer_wait peer_wq.wait 48 48 wait_queue_entry_t peer_wake; 49 49 struct scm_stat scm_stat; 50 + int inq_len; 50 51 #if IS_ENABLED(CONFIG_AF_UNIX_OOB) 51 52 struct sk_buff *oob_skb; 52 53 #endif
+28 -10
net/unix/af_unix.c
··· 2297 2297 2298 2298 spin_lock(&other->sk_receive_queue.lock); 2299 2299 WRITE_ONCE(ousk->oob_skb, skb); 2300 + WRITE_ONCE(ousk->inq_len, ousk->inq_len + 1); 2300 2301 __skb_queue_tail(&other->sk_receive_queue, skb); 2301 2302 spin_unlock(&other->sk_receive_queue.lock); 2302 2303 ··· 2320 2319 struct sock *sk = sock->sk; 2321 2320 struct sk_buff *skb = NULL; 2322 2321 struct sock *other = NULL; 2322 + struct unix_sock *otheru; 2323 2323 struct scm_cookie scm; 2324 2324 bool fds_sent = false; 2325 2325 int err, sent = 0; ··· 2344 2342 if (msg->msg_namelen) { 2345 2343 err = READ_ONCE(sk->sk_state) == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; 2346 2344 goto out_err; 2347 - } else { 2348 - other = unix_peer(sk); 2349 - if (!other) { 2350 - err = -ENOTCONN; 2351 - goto out_err; 2352 - } 2353 2345 } 2346 + 2347 + other = unix_peer(sk); 2348 + if (!other) { 2349 + err = -ENOTCONN; 2350 + goto out_err; 2351 + } 2352 + 2353 + otheru = unix_sk(other); 2354 2354 2355 2355 if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) 2356 2356 goto out_pipe; ··· 2421 2417 2422 2418 unix_maybe_add_creds(skb, sk, other); 2423 2419 scm_stat_add(other, skb); 2424 - skb_queue_tail(&other->sk_receive_queue, skb); 2420 + 2421 + spin_lock(&other->sk_receive_queue.lock); 2422 + WRITE_ONCE(otheru->inq_len, otheru->inq_len + skb->len); 2423 + __skb_queue_tail(&other->sk_receive_queue, skb); 2424 + spin_unlock(&other->sk_receive_queue.lock); 2425 + 2425 2426 unix_state_unlock(other); 2426 2427 other->sk_data_ready(other); 2427 2428 sent += size; ··· 2713 2704 2714 2705 if (!(state->flags & MSG_PEEK)) { 2715 2706 WRITE_ONCE(u->oob_skb, NULL); 2707 + WRITE_ONCE(u->inq_len, u->inq_len - 1); 2716 2708 2717 2709 if (oob_skb->prev != (struct sk_buff *)&sk->sk_receive_queue && 2718 2710 !unix_skb_len(oob_skb->prev)) { ··· 2817 2807 mutex_unlock(&u->iolock); 2818 2808 return -EAGAIN; 2819 2809 } 2810 + 2811 + WRITE_ONCE(u->inq_len, u->inq_len - skb->len); 2820 2812 2821 2813 #if IS_ENABLED(CONFIG_AF_UNIX_OOB) 2822 2814 if (skb == u->oob_skb) { ··· 3000 2988 if (unix_skb_len(skb)) 3001 2989 break; 3002 2990 3003 - skb_unlink(skb, &sk->sk_receive_queue); 2991 + spin_lock(&sk->sk_receive_queue.lock); 2992 + WRITE_ONCE(u->inq_len, u->inq_len - skb->len); 2993 + __skb_unlink(skb, &sk->sk_receive_queue); 2994 + spin_unlock(&sk->sk_receive_queue.lock); 2995 + 3004 2996 consume_skb(skb); 3005 2997 3006 2998 if (scm.fp) ··· 3175 3159 if (READ_ONCE(sk->sk_state) == TCP_LISTEN) 3176 3160 return -EINVAL; 3177 3161 3162 + if (sk->sk_type == SOCK_STREAM) 3163 + return READ_ONCE(unix_sk(sk)->inq_len); 3164 + 3178 3165 spin_lock(&sk->sk_receive_queue.lock); 3179 - if (sk->sk_type == SOCK_STREAM || 3180 - sk->sk_type == SOCK_SEQPACKET) { 3166 + if (sk->sk_type == SOCK_SEQPACKET) { 3181 3167 skb_queue_walk(&sk->sk_receive_queue, skb) 3182 3168 amount += unix_skb_len(skb); 3183 3169 } else {