mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
net: add sk_set_nospace() and sk_clear_nospace()
SOCK_NOSPACE lives in sk->sk_socket->flags and is manipulated from about thirty places in the tree, all of them open coding the sk->sk_socket dereference, some with a NULL check, some without, and some reaching the struct socket by yet another path. Add sk_set_nospace() and sk_clear_nospace() helpers and convert the core networking setters and clearers to them; the following patches convert the remaining subsystem callers so that "git grep _bit(SOCK_NOSPACE" only reports the two helpers and the remaining test_bit() sites. Callers that had no NULL check are all called from user context with a socket attached, so folding the check into the helpers only makes them more robust. No functional change intended. This is a preparation patch: a following one gives TCP a cheaper private copy of this bit, and needs a single choke point to keep it in sync. Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Signed-off-by: Eric Dumazet <edumazet@kernel.org> Link: https://patch.msgid.link/20260929071743.23624-3-edumazet@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
e234d76255
commit
6ba48a271b
|
|
@ -1129,6 +1129,8 @@ static inline void sk_forward_alloc_add(struct sock *sk, int val)
|
|||
}
|
||||
|
||||
void sk_stream_write_space(struct sock *sk);
|
||||
void sk_set_nospace(struct sock *sk);
|
||||
void sk_clear_nospace(struct sock *sk);
|
||||
|
||||
/* OOB backlog add */
|
||||
static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
|
||||
|
|
|
|||
|
|
@ -2957,6 +2957,39 @@ void sock_kzfree_s(struct sock *sk, void *mem, int size)
|
|||
}
|
||||
EXPORT_SYMBOL(sock_kzfree_s);
|
||||
|
||||
/**
|
||||
* sk_set_nospace - tell the transport a writer is waiting for space
|
||||
* @sk: socket
|
||||
*
|
||||
* Must be called before the final check of the available send space,
|
||||
* so that the transport can not miss the request and forget to call
|
||||
* sk->sk_write_space() once space is available again.
|
||||
*/
|
||||
void sk_set_nospace(struct sock *sk)
|
||||
{
|
||||
struct socket *sock = sk->sk_socket;
|
||||
|
||||
if (sock)
|
||||
set_bit(SOCK_NOSPACE, &sock->flags);
|
||||
}
|
||||
EXPORT_SYMBOL(sk_set_nospace);
|
||||
|
||||
/**
|
||||
* sk_clear_nospace - tell the transport no writer is waiting for space
|
||||
* @sk: socket
|
||||
*
|
||||
* Called from ->sk_write_space() handlers, once send space has been
|
||||
* made available to writers.
|
||||
*/
|
||||
void sk_clear_nospace(struct sock *sk)
|
||||
{
|
||||
struct socket *sock = sk->sk_socket;
|
||||
|
||||
if (sock)
|
||||
clear_bit(SOCK_NOSPACE, &sock->flags);
|
||||
}
|
||||
EXPORT_SYMBOL(sk_clear_nospace);
|
||||
|
||||
/* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
|
||||
I think, these locks should be removed for datagram sockets.
|
||||
*/
|
||||
|
|
@ -2970,7 +3003,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
|
|||
break;
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
||||
if (refcount_read(&sk->sk_wmem_alloc) < READ_ONCE(sk->sk_sndbuf))
|
||||
break;
|
||||
|
|
@ -3011,7 +3044,7 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
|
|||
break;
|
||||
|
||||
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
err = -EAGAIN;
|
||||
if (!timeo)
|
||||
goto failure;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ void sk_stream_write_space(struct sock *sk)
|
|||
struct socket_wq *wq;
|
||||
|
||||
if (__sk_stream_is_writeable(sk, 1) && sock) {
|
||||
clear_bit(SOCK_NOSPACE, &sock->flags);
|
||||
sk_clear_nospace(sk);
|
||||
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
|
|
@ -143,7 +143,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
|
|||
if (sk_stream_memory_free(sk) && !vm_wait)
|
||||
break;
|
||||
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
sk->sk_write_pending++;
|
||||
ret = sk_wait_event(sk, ¤t_timeo, READ_ONCE(sk->sk_err) ||
|
||||
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
|
||||
|
|
@ -177,7 +177,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
|
|||
* When TCP receives ACK packets that make room, tcp_check_space()
|
||||
* only calls tcp_new_space() if SOCK_NOSPACE is set.
|
||||
*/
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
do_interrupted:
|
||||
|
|
|
|||
|
|
@ -607,7 +607,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
|||
mask |= EPOLLOUT | EPOLLWRNORM;
|
||||
} else { /* send SIGIO later */
|
||||
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
|
||||
/* Race breaker. If space is freed after
|
||||
* wspace test but before the flags are set,
|
||||
|
|
@ -1397,7 +1397,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
|
|||
continue;
|
||||
|
||||
wait_for_space:
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
tcp_remove_empty_skb(sk);
|
||||
if (copied)
|
||||
tcp_push(sk, flags & ~MSG_MORE, mss_now,
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
|||
goto out_err;
|
||||
continue;
|
||||
wait_for_sndbuf:
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
wait_for_memory:
|
||||
err = sk_stream_wait_memory(sk, &timeo);
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -735,7 +735,7 @@ static void kcm_tx_work(struct work_struct *w)
|
|||
/* Primarily for SOCK_SEQPACKET sockets */
|
||||
if (likely(sk->sk_socket) &&
|
||||
test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
|
||||
clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_clear_nospace(sk);
|
||||
sk->sk_write_space(sk);
|
||||
}
|
||||
|
||||
|
|
@ -779,7 +779,7 @@ static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|||
/* Call the sk_stream functions to manage the sndbuf mem. */
|
||||
if (!sk_stream_memory_free(sk)) {
|
||||
kcm_push(kcm);
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
err = sk_stream_wait_memory(sk, &timeo);
|
||||
if (err)
|
||||
goto out_error;
|
||||
|
|
|
|||
|
|
@ -2106,7 +2106,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|||
continue;
|
||||
|
||||
wait_for_memory:
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
__mptcp_push_pending(sk, msg->msg_flags);
|
||||
ret = sk_stream_wait_memory(sk, &timeo);
|
||||
if (ret)
|
||||
|
|
@ -4471,7 +4471,7 @@ static __poll_t mptcp_check_writeable(struct mptcp_sock *msk)
|
|||
if (__mptcp_stream_is_writeable(sk, 1))
|
||||
return EPOLLOUT | EPOLLWRNORM;
|
||||
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
smp_mb__after_atomic(); /* NOSPACE is changed by mptcp_write_space() */
|
||||
if (__mptcp_stream_is_writeable(sk, 1))
|
||||
return EPOLLOUT | EPOLLWRNORM;
|
||||
|
|
|
|||
|
|
@ -2925,7 +2925,7 @@ __poll_t smc_poll(struct file *file, struct socket *sock,
|
|||
mask |= EPOLLOUT | EPOLLWRNORM;
|
||||
} else {
|
||||
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
|
||||
if (sk->sk_state != SMC_INIT) {
|
||||
/* Race breaker the same way as tcp_poll(). */
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static void smc_tx_write_space(struct sock *sk)
|
|||
if (atomic_read(&smc->conn.sndbuf_space) && sock) {
|
||||
if (test_bit(SOCK_NOSPACE, &sock->flags))
|
||||
SMC_STAT_RMB_TX_FULL(smc, !smc->conn.lnk);
|
||||
clear_bit(SOCK_NOSPACE, &sock->flags);
|
||||
sk_clear_nospace(sk);
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (skwq_has_sleeper(wq))
|
||||
|
|
@ -100,7 +100,7 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
|
|||
}
|
||||
if (!timeo) {
|
||||
/* ensure EPOLLOUT is subsequently generated */
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
|
|||
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
|
||||
if (atomic_read(&conn->sndbuf_space) && !conn->urg_tx_pend)
|
||||
break; /* at least 1 byte of free & no urgent data */
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
sk_wait_event(sk, &timeo,
|
||||
READ_ONCE(sk->sk_err) ||
|
||||
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
|
||||
|
|
|
|||
|
|
@ -966,7 +966,7 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
|
|||
continue;
|
||||
|
||||
wait_for_sndbuf:
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_set_nospace(sk);
|
||||
wait_for_memory:
|
||||
ret = sk_stream_wait_memory(sk, &timeo);
|
||||
if (ret) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user