net: fix sk_mem_reclaim_partial()
[pandora-kernel.git] / net / core / sock.c
index 4ed7b1d..b8f4f35 100644 (file)
@@ -281,27 +281,18 @@ static void sock_disable_timestamp(struct sock *sk, int flag)
 }
 
 
-int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-       int err;
        int skb_len;
        unsigned long flags;
        struct sk_buff_head *list = &sk->sk_receive_queue;
 
-       /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
-          number of warnings when compiling with -W --ANK
-        */
-       if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
-           (unsigned)sk->sk_rcvbuf) {
+       if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) {
                atomic_inc(&sk->sk_drops);
                trace_sock_rcvqueue_full(sk, skb);
                return -ENOMEM;
        }
 
-       err = sk_filter(sk, skb);
-       if (err)
-               return err;
-
        if (!sk_rmem_schedule(sk, skb->truesize)) {
                atomic_inc(&sk->sk_drops);
                return -ENOBUFS;
@@ -331,13 +322,26 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                sk->sk_data_ready(sk, skb_len);
        return 0;
 }
+EXPORT_SYMBOL(__sock_queue_rcv_skb);
+
+int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       int err;
+
+       err = sk_filter(sk, skb);
+       if (err)
+               return err;
+
+       return __sock_queue_rcv_skb(sk, skb);
+}
 EXPORT_SYMBOL(sock_queue_rcv_skb);
 
-int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
+int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
+                    const int nested, unsigned int trim_cap)
 {
        int rc = NET_RX_SUCCESS;
 
-       if (sk_filter(sk, skb))
+       if (sk_filter_trim_cap(sk, skb, trim_cap))
                goto discard_and_relse;
 
        skb->dev = NULL;
@@ -373,7 +377,7 @@ discard_and_relse:
        kfree_skb(skb);
        goto out;
 }
-EXPORT_SYMBOL(sk_receive_skb);
+EXPORT_SYMBOL(__sk_receive_skb);
 
 void sk_reset_txq(struct sock *sk)
 {
@@ -530,23 +534,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                break;
        case SO_SNDBUF:
                /* Don't error on this BSD doesn't and if you think
-                  about it this is right. Otherwise apps have to
-                  play 'guess the biggest size' games. RCVBUF/SNDBUF
-                  are treated in BSD as hints */
-
-               if (val > sysctl_wmem_max)
-                       val = sysctl_wmem_max;
+                * about it this is right. Otherwise apps have to
+                * play 'guess the biggest size' games. RCVBUF/SNDBUF
+                * are treated in BSD as hints
+                */
+               val = min_t(u32, val, sysctl_wmem_max);
 set_sndbuf:
                sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-               if ((val * 2) < SOCK_MIN_SNDBUF)
-                       sk->sk_sndbuf = SOCK_MIN_SNDBUF;
-               else
-                       sk->sk_sndbuf = val * 2;
-
-               /*
-                *      Wake up sending tasks if we
-                *      upped the value.
-                */
+               sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF);
+               /* Wake up sending tasks if we upped the value. */
                sk->sk_write_space(sk);
                break;
 
@@ -559,12 +555,11 @@ set_sndbuf:
 
        case SO_RCVBUF:
                /* Don't error on this BSD doesn't and if you think
-                  about it this is right. Otherwise apps have to
-                  play 'guess the biggest size' games. RCVBUF/SNDBUF
-                  are treated in BSD as hints */
-
-               if (val > sysctl_rmem_max)
-                       val = sysctl_rmem_max;
+                * about it this is right. Otherwise apps have to
+                * play 'guess the biggest size' games. RCVBUF/SNDBUF
+                * are treated in BSD as hints
+                */
+               val = min_t(u32, val, sysctl_rmem_max);
 set_rcvbuf:
                sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
                /*
@@ -582,10 +577,7 @@ set_rcvbuf:
                 * returning the value we actually used in getsockopt
                 * is the most desirable behavior.
                 */
-               if ((val * 2) < SOCK_MIN_RCVBUF)
-                       sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
-               else
-                       sk->sk_rcvbuf = val * 2;
+               sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF);
                break;
 
        case SO_RCVBUFFORCE:
@@ -597,7 +589,8 @@ set_rcvbuf:
 
        case SO_KEEPALIVE:
 #ifdef CONFIG_INET
-               if (sk->sk_protocol == IPPROTO_TCP)
+               if (sk->sk_protocol == IPPROTO_TCP &&
+                   sk->sk_type == SOCK_STREAM)
                        tcp_set_keepalive(sk, valbool);
 #endif
                sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
@@ -764,6 +757,20 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred,
 }
 EXPORT_SYMBOL_GPL(cred_to_ucred);
 
+void cred_real_to_ucred(struct pid *pid, const struct cred *cred,
+                       struct ucred *ucred)
+{
+       ucred->pid = pid_vnr(pid);
+       ucred->uid = ucred->gid = -1;
+       if (cred) {
+               struct user_namespace *current_ns = current_user_ns();
+
+               ucred->uid = user_ns_map_uid(current_ns, cred, cred->uid);
+               ucred->gid = user_ns_map_gid(current_ns, cred, cred->gid);
+       }
+}
+EXPORT_SYMBOL_GPL(cred_real_to_ucred);
+
 int sock_getsockopt(struct socket *sock, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
@@ -912,7 +919,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_PASSCRED:
-               v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
+               v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
                break;
 
        case SO_PEERCRED:
@@ -947,7 +954,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_PASSSEC:
-               v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+               v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
                break;
 
        case SO_PEERSEC:
@@ -1010,18 +1017,6 @@ static void sock_copy(struct sock *nsk, const struct sock *osk)
 #endif
 }
 
-/*
- * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes
- * un-modified. Special care is taken when initializing object to zero.
- */
-static inline void sk_prot_clear_nulls(struct sock *sk, int size)
-{
-       if (offsetof(struct sock, sk_node.next) != 0)
-               memset(sk, 0, offsetof(struct sock, sk_node.next));
-       memset(&sk->sk_node.pprev, 0,
-              size - offsetof(struct sock, sk_node.pprev));
-}
-
 void sk_prot_clear_portaddr_nulls(struct sock *sk, int size)
 {
        unsigned long nulls1, nulls2;
@@ -1374,6 +1369,11 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+void sock_efree(struct sk_buff *skb)
+{
+       sock_put(skb->sk);
+}
+EXPORT_SYMBOL(sock_efree);
 
 int sock_i_uid(struct sock *sk)
 {
@@ -1501,6 +1501,11 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
        gfp_t gfp_mask;
        long timeo;
        int err;
+       int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+       err = -EMSGSIZE;
+       if (npages > MAX_SKB_FRAGS)
+               goto failure;
 
        gfp_mask = sk->sk_allocation;
        if (gfp_mask & __GFP_WAIT)
@@ -1519,14 +1524,12 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
                        skb = alloc_skb(header_len, gfp_mask);
                        if (skb) {
-                               int npages;
                                int i;
 
                                /* No pages, we're done... */
                                if (!data_len)
                                        break;
 
-                               npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
                                skb->truesize += data_len;
                                skb_shinfo(skb)->nr_frags = npages;
                                for (i = 0; i < npages; i++) {
@@ -1747,14 +1750,15 @@ EXPORT_SYMBOL(__sk_mem_schedule);
 /**
  *     __sk_reclaim - reclaim memory_allocated
  *     @sk: socket
+ *     @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple)
  */
-void __sk_mem_reclaim(struct sock *sk)
+void __sk_mem_reclaim(struct sock *sk, int amount)
 {
        struct proto *prot = sk->sk_prot;
 
-       atomic_long_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT,
-                  prot->memory_allocated);
-       sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1;
+       amount >>= SK_MEM_QUANTUM_SHIFT;
+       atomic_long_sub(amount, prot->memory_allocated);
+       sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT;
 
        if (prot->memory_pressure && *prot->memory_pressure &&
            (atomic_long_read(prot->memory_allocated) < prot->sysctl_mem[0]))