[I/OAT]: Make sk_eat_skb I/OAT aware.
[deliverable/linux.git] / net / ipv4 / tcp.c
index 00aa80e9324323305fb72b365f75f96243390d1c..4e067d25a63cd1b03694c7c22a44885c80fe3328 100644 (file)
 #include <linux/fs.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
+#include <linux/cache.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -275,9 +276,9 @@ atomic_t tcp_orphan_count = ATOMIC_INIT(0);
 
 EXPORT_SYMBOL_GPL(tcp_orphan_count);
 
-int sysctl_tcp_mem[3];
-int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
-int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
+int sysctl_tcp_mem[3] __read_mostly;
+int sysctl_tcp_wmem[3] __read_mostly;
+int sysctl_tcp_rmem[3] __read_mostly;
 
 EXPORT_SYMBOL(sysctl_tcp_mem);
 EXPORT_SYMBOL(sysctl_tcp_rmem);
@@ -365,7 +366,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
                mask |= POLLHUP;
        if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM | POLLRDHUP;
 
        /* Connected? */
        if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) {
@@ -936,7 +937,7 @@ static int tcp_recv_urg(struct sock *sk, long timeo,
  * calculation of whether or not we must ACK for the sake of
  * a window update.
  */
-static void cleanup_rbuf(struct sock *sk, int copied)
+void tcp_cleanup_rbuf(struct sock *sk, int copied)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int time_to_ack = 0;
@@ -1071,11 +1072,11 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                break;
                }
                if (skb->h.th->fin) {
-                       sk_eat_skb(sk, skb);
+                       sk_eat_skb(sk, skb, 0);
                        ++seq;
                        break;
                }
-               sk_eat_skb(sk, skb);
+               sk_eat_skb(sk, skb, 0);
                if (!desc->count)
                        break;
        }
@@ -1085,7 +1086,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 
        /* Clean up data we have read: This will do ACK frames. */
        if (copied)
-               cleanup_rbuf(sk, copied);
+               tcp_cleanup_rbuf(sk, copied);
        return copied;
 }
 
@@ -1219,7 +1220,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        }
                }
 
-               cleanup_rbuf(sk, copied);
+               tcp_cleanup_rbuf(sk, copied);
 
                if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) {
                        /* Install new reader */
@@ -1355,14 +1356,14 @@ skip_copy:
                if (skb->h.th->fin)
                        goto found_fin_ok;
                if (!(flags & MSG_PEEK))
-                       sk_eat_skb(sk, skb);
+                       sk_eat_skb(sk, skb, 0);
                continue;
 
        found_fin_ok:
                /* Process the FIN. */
                ++*seq;
                if (!(flags & MSG_PEEK))
-                       sk_eat_skb(sk, skb);
+                       sk_eat_skb(sk, skb, 0);
                break;
        } while (len > 0);
 
@@ -1390,7 +1391,7 @@ skip_copy:
         */
 
        /* Clean up data we have read: This will do ACK frames. */
-       cleanup_rbuf(sk, copied);
+       tcp_cleanup_rbuf(sk, copied);
 
        TCP_CHECK_TIMER(sk);
        release_sock(sk);
@@ -1467,6 +1468,7 @@ void tcp_close(struct sock *sk, long timeout)
 {
        struct sk_buff *skb;
        int data_was_unread = 0;
+       int state;
 
        lock_sock(sk);
        sk->sk_shutdown = SHUTDOWN_MASK;
@@ -1543,6 +1545,11 @@ void tcp_close(struct sock *sk, long timeout)
        sk_stream_wait_close(sk, timeout);
 
 adjudge_to_death:
+       state = sk->sk_state;
+       sock_hold(sk);
+       sock_orphan(sk);
+       atomic_inc(sk->sk_prot->orphan_count);
+
        /* It is the last release_sock in its life. It will remove backlog. */
        release_sock(sk);
 
@@ -1554,8 +1561,9 @@ adjudge_to_death:
        bh_lock_sock(sk);
        BUG_TRAP(!sock_owned_by_user(sk));
 
-       sock_hold(sk);
-       sock_orphan(sk);
+       /* Have we already been destroyed by a softirq or backlog? */
+       if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
+               goto out;
 
        /*      This is a (useful) BSD violating of the RFC. There is a
         *      problem with TCP as specified in that the other end could
@@ -1583,7 +1591,6 @@ adjudge_to_death:
                        if (tmo > TCP_TIMEWAIT_LEN) {
                                inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk));
                        } else {
-                               atomic_inc(sk->sk_prot->orphan_count);
                                tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
                                goto out;
                        }
@@ -1602,7 +1609,6 @@ adjudge_to_death:
                        NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY);
                }
        }
-       atomic_inc(sk->sk_prot->orphan_count);
 
        if (sk->sk_state == TCP_CLOSE)
                inet_csk_destroy_sock(sk);
@@ -1687,18 +1693,14 @@ int tcp_disconnect(struct sock *sk, int flags)
 /*
  *     Socket option code for TCP.
  */
-int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
-                  int optlen)
+static int do_tcp_setsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int optlen)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        int val;
        int err = 0;
 
-       if (level != SOL_TCP)
-               return icsk->icsk_af_ops->setsockopt(sk, level, optname,
-                                                    optval, optlen);
-
        /* This is a string value all the others are int's */
        if (optname == TCP_CONGESTION) {
                char name[TCP_CA_NAME_MAX];
@@ -1856,7 +1858,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                            (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) &&
                            inet_csk_ack_scheduled(sk)) {
                                icsk->icsk_ack.pending |= ICSK_ACK_PUSHED;
-                               cleanup_rbuf(sk, 1);
+                               tcp_cleanup_rbuf(sk, 1);
                                if (!(val & 1))
                                        icsk->icsk_ack.pingpong = 1;
                        }
@@ -1871,6 +1873,30 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
        return err;
 }
 
+int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
+                  int optlen)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (level != SOL_TCP)
+               return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+                                                    optval, optlen);
+       return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_setsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int optlen)
+{
+       if (level != SOL_TCP)
+               return inet_csk_compat_setsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_tcp_setsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_setsockopt);
+#endif
+
 /* Return information about state of tcp endpoint in API format. */
 void tcp_get_info(struct sock *sk, struct tcp_info *info)
 {
@@ -1931,17 +1957,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
 
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
-int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
-                  int __user *optlen)
+static int do_tcp_getsockopt(struct sock *sk, int level,
+               int optname, char __user *optval, int __user *optlen)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        int val, len;
 
-       if (level != SOL_TCP)
-               return icsk->icsk_af_ops->getsockopt(sk, level, optname,
-                                                    optval, optlen);
-
        if (get_user(len, optlen))
                return -EFAULT;
 
@@ -2025,6 +2047,29 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
        return 0;
 }
 
+int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
+                  int __user *optlen)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (level != SOL_TCP)
+               return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+                                                    optval, optlen);
+       return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+#ifdef CONFIG_COMPAT
+int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       if (level != SOL_TCP)
+               return inet_csk_compat_getsockopt(sk, level, optname,
+                                                 optval, optlen);
+       return do_tcp_getsockopt(sk, level, optname, optval, optlen);
+}
+
+EXPORT_SYMBOL(compat_tcp_getsockopt);
+#endif
 
 extern void __skb_cb_too_small_for_tcp(int, int);
 extern struct tcp_congestion_ops tcp_reno;
@@ -2042,7 +2087,8 @@ __setup("thash_entries=", set_thash_entries);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
-       int order, i;
+       unsigned long limit;
+       int order, i, max_share;
 
        if (sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
                __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -2116,12 +2162,16 @@ void __init tcp_init(void)
        sysctl_tcp_mem[1] = 1024 << order;
        sysctl_tcp_mem[2] = 1536 << order;
 
-       if (order < 3) {
-               sysctl_tcp_wmem[2] = 64 * 1024;
-               sysctl_tcp_rmem[0] = PAGE_SIZE;
-               sysctl_tcp_rmem[1] = 43689;
-               sysctl_tcp_rmem[2] = 2 * 43689;
-       }
+       limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
+       max_share = min(4UL*1024*1024, limit);
+
+       sysctl_tcp_wmem[0] = SK_STREAM_MEM_QUANTUM;
+       sysctl_tcp_wmem[1] = 16*1024;
+       sysctl_tcp_wmem[2] = max(64*1024, max_share);
+
+       sysctl_tcp_rmem[0] = SK_STREAM_MEM_QUANTUM;
+       sysctl_tcp_rmem[1] = 87380;
+       sysctl_tcp_rmem[2] = max(87380, max_share);
 
        printk(KERN_INFO "TCP: Hash tables configured "
               "(established %d bind %d)\n",
This page took 0.053179 seconds and 5 git commands to generate.