]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
tcp: pass back data left in socket after receive
authorJens Axboe <axboe@kernel.dk>
Fri, 29 Apr 2022 00:45:06 +0000 (18:45 -0600)
committerJakub Kicinski <kuba@kernel.org>
Sat, 30 Apr 2022 01:55:27 +0000 (18:55 -0700)
This is currently done for CMSG_INQ, add an ability to do so via struct
msghdr as well and have CMSG_INQ use that too. If the caller sets
msghdr->msg_get_inq, then we'll pass back the hint in msghdr->msg_inq.

Rearrange struct msghdr a bit so we can add this member while shrinking
it at the same time. On a 64-bit build, it was 96 bytes before this
change and 88 bytes afterwards.

Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Link: https://lore.kernel.org/r/650c22ca-cffc-0255-9a05-2413a1e20826@kernel.dk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/socket.h
net/ipv4/tcp.c

index 6f85f5d957efea06c7fc19c78181feda9e57aead..12085c9a854492b6819775f40415a1056c2c0125 100644 (file)
@@ -50,6 +50,9 @@ struct linger {
 struct msghdr {
        void            *msg_name;      /* ptr to socket address structure */
        int             msg_namelen;    /* size of socket address structure */
+
+       int             msg_inq;        /* output, data left in socket */
+
        struct iov_iter msg_iter;       /* data */
 
        /*
@@ -62,8 +65,9 @@ struct msghdr {
                void __user     *msg_control_user;
        };
        bool            msg_control_is_user : 1;
-       __kernel_size_t msg_controllen; /* ancillary data buffer length */
+       bool            msg_get_inq : 1;/* return INQ after receive */
        unsigned int    msg_flags;      /* flags on received message */
+       __kernel_size_t msg_controllen; /* ancillary data buffer length */
        struct kiocb    *msg_iocb;      /* ptr to iocb for async requests */
 };
 
index cf18fbcbf123a864608a9603bfe215def9e4b70e..bb7ef45408e1aee88ee043b48d07dcecc4089711 100644 (file)
@@ -2335,8 +2335,10 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len,
        if (sk->sk_state == TCP_LISTEN)
                goto out;
 
-       if (tp->recvmsg_inq)
+       if (tp->recvmsg_inq) {
                *cmsg_flags = TCP_CMSG_INQ;
+               msg->msg_get_inq = 1;
+       }
        timeo = sock_rcvtimeo(sk, nonblock);
 
        /* Urgent data needs to be handled specially. */
@@ -2559,7 +2561,7 @@ recv_sndq:
 int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
                int flags, int *addr_len)
 {
-       int cmsg_flags = 0, ret, inq;
+       int cmsg_flags = 0, ret;
        struct scm_timestamping_internal tss;
 
        if (unlikely(flags & MSG_ERRQUEUE))
@@ -2576,12 +2578,14 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
        release_sock(sk);
        sk_defer_free_flush(sk);
 
-       if (cmsg_flags && ret >= 0) {
+       if ((cmsg_flags || msg->msg_get_inq) && ret >= 0) {
                if (cmsg_flags & TCP_CMSG_TS)
                        tcp_recv_timestamp(msg, sk, &tss);
-               if (cmsg_flags & TCP_CMSG_INQ) {
-                       inq = tcp_inq_hint(sk);
-                       put_cmsg(msg, SOL_TCP, TCP_CM_INQ, sizeof(inq), &inq);
+               if (msg->msg_get_inq) {
+                       msg->msg_inq = tcp_inq_hint(sk);
+                       if (cmsg_flags & TCP_CMSG_INQ)
+                               put_cmsg(msg, SOL_TCP, TCP_CM_INQ,
+                                        sizeof(msg->msg_inq), &msg->msg_inq);
                }
        }
        return ret;