net: add sock_set_rcvbuf
authorChristoph Hellwig <hch@lst.de>
Thu, 28 May 2020 05:12:16 +0000 (07:12 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 28 May 2020 18:11:44 +0000 (11:11 -0700)
Add a helper to directly set the SO_RCVBUFFORCE sockopt from kernel space
without going through a fake uaccess.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
fs/dlm/lowcomms.c
include/net/sock.h
net/core/sock.c

index b6e6dba..2822a43 100644 (file)
@@ -1180,7 +1180,6 @@ static int sctp_listen_for_all(void)
        struct socket *sock = NULL;
        int result = -EINVAL;
        struct connection *con = nodeid2con(0, GFP_NOFS);
-       int bufsize = NEEDED_RMEM;
        int one = 1;
 
        if (!con)
@@ -1195,11 +1194,7 @@ static int sctp_listen_for_all(void)
                goto out;
        }
 
-       result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE,
-                                (char *)&bufsize, sizeof(bufsize));
-       if (result)
-               log_print("Error increasing buffer space on socket %d", result);
-
+       sock_set_rcvbuf(sock->sk, NEEDED_RMEM);
        result = kernel_setsockopt(sock, SOL_SCTP, SCTP_NODELAY, (char *)&one,
                                   sizeof(one));
        if (result < 0)
index dc08c17..c997289 100644 (file)
@@ -2693,6 +2693,7 @@ void sock_enable_timestamps(struct sock *sk);
 void sock_no_linger(struct sock *sk);
 void sock_set_keepalive(struct sock *sk);
 void sock_set_priority(struct sock *sk, u32 priority);
+void sock_set_rcvbuf(struct sock *sk, int val);
 void sock_set_reuseaddr(struct sock *sk);
 void sock_set_sndtimeo(struct sock *sk, s64 secs);
 
index 728f5fb..3c6ebf9 100644 (file)
@@ -789,6 +789,35 @@ void sock_set_keepalive(struct sock *sk)
 }
 EXPORT_SYMBOL(sock_set_keepalive);
 
+static void __sock_set_rcvbuf(struct sock *sk, int val)
+{
+       /* Ensure val * 2 fits into an int, to prevent max_t() from treating it
+        * as a negative value.
+        */
+       val = min_t(int, val, INT_MAX / 2);
+       sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+
+       /* We double it on the way in to account for "struct sk_buff" etc.
+        * overhead.   Applications assume that the SO_RCVBUF setting they make
+        * will allow that much actual data to be received on that socket.
+        *
+        * Applications are unaware that "struct sk_buff" and other overheads
+        * allocate from the receive buffer during socket buffer allocation.
+        *
+        * And after considering the possible alternatives, returning the value
+        * we actually used in getsockopt is the most desirable behavior.
+        */
+       WRITE_ONCE(sk->sk_rcvbuf, max_t(int, val * 2, SOCK_MIN_RCVBUF));
+}
+
+void sock_set_rcvbuf(struct sock *sk, int val)
+{
+       lock_sock(sk);
+       __sock_set_rcvbuf(sk, val);
+       release_sock(sk);
+}
+EXPORT_SYMBOL(sock_set_rcvbuf);
+
 /*
  *     This is meant for all protocols to use and covers goings on
  *     at the socket level. Everything here is generic.
@@ -885,30 +914,7 @@ set_sndbuf:
                 * play 'guess the biggest size' games. RCVBUF/SNDBUF
                 * are treated in BSD as hints
                 */
-               val = min_t(u32, val, sysctl_rmem_max);
-set_rcvbuf:
-               /* Ensure val * 2 fits into an int, to prevent max_t()
-                * from treating it as a negative value.
-                */
-               val = min_t(int, val, INT_MAX / 2);
-               sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-               /*
-                * We double it on the way in to account for
-                * "struct sk_buff" etc. overhead.   Applications
-                * assume that the SO_RCVBUF setting they make will
-                * allow that much actual data to be received on that
-                * socket.
-                *
-                * Applications are unaware that "struct sk_buff" and
-                * other overheads allocate from the receive buffer
-                * during socket buffer allocation.
-                *
-                * And after considering the possible alternatives,
-                * returning the value we actually used in getsockopt
-                * is the most desirable behavior.
-                */
-               WRITE_ONCE(sk->sk_rcvbuf,
-                          max_t(int, val * 2, SOCK_MIN_RCVBUF));
+               __sock_set_rcvbuf(sk, min_t(u32, val, sysctl_rmem_max));
                break;
 
        case SO_RCVBUFFORCE:
@@ -920,9 +926,8 @@ set_rcvbuf:
                /* No negative values (to prevent underflow, as val will be
                 * multiplied by 2).
                 */
-               if (val < 0)
-                       val = 0;
-               goto set_rcvbuf;
+               __sock_set_rcvbuf(sk, max(val, 0));
+               break;
 
        case SO_KEEPALIVE:
                if (sk->sk_prot->keepalive)