Merge tag 'v3.10.81' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / unix / af_unix.c
index 123c16419cbe91581fb5435ce39c9436d3c5a2e6..8ccc661efa5304978a559f8b9b7c5c7e4a302dba 100644 (file)
 #include <linux/mount.h>
 #include <net/checksum.h>
 #include <linux/security.h>
+#include <linux/freezer.h>
+
+
+#include <linux/uio.h>
+#include <linux/blkdev.h>
+#include <linux/compat.h>
+#include <linux/rtc.h>
+#include <asm/kmap_types.h>
+#include <linux/device.h>
+
 
 struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
 EXPORT_SYMBOL_GPL(unix_socket_table);
@@ -134,6 +144,17 @@ static struct hlist_head *unix_sockets_unbound(void *addr)
 
 #define UNIX_ABSTRACT(sk)      (unix_sk(sk)->addr->hash < UNIX_HASH_SIZE)
 
+
+//for aee interface start
+#define __UNIX_SOCKET_OUTPUT_BUF_SIZE__   3500
+static struct proc_dir_entry *gunix_socket_track_aee_entry = NULL;
+#define UNIX_SOCK_TRACK_AEE_PROCNAME "driver/usktrk_aee"
+#define UNIX_SOCK_TRACK_PROC_AEE_SIZE 3072
+
+static volatile unsigned int unix_sock_track_stop_flag = 0;
+#define unix_peer(sk) (unix_sk(sk)->peer)
+
+
 #ifdef CONFIG_SECURITY_NETWORK
 static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 {
@@ -166,7 +187,7 @@ static inline unsigned int unix_hash_fold(__wsum n)
        return hash&(UNIX_HASH_SIZE-1);
 }
 
-#define unix_peer(sk) (unix_sk(sk)->peer)
+
 
 static inline int unix_our_peer(struct sock *sk, struct sock *osk)
 {
@@ -313,6 +334,118 @@ found:
        return s;
 }
 
+/* Support code for asymmetrically connected dgram sockets
+ *
+ * If a datagram socket is connected to a socket not itself connected
+ * to the first socket (eg, /dev/log), clients may only enqueue more
+ * messages if the present receive queue of the server socket is not
+ * "too large". This means there's a second writeability condition
+ * poll and sendmsg need to test. The dgram recv code will do a wake
+ * up on the peer_wait wait queue of a socket upon reception of a
+ * datagram which needs to be propagated to sleeping would-be writers
+ * since these might not have sent anything so far. This can't be
+ * accomplished via poll_wait because the lifetime of the server
+ * socket might be less than that of its clients if these break their
+ * association with it or if the server socket is closed while clients
+ * are still connected to it and there's no way to inform "a polling
+ * implementation" that it should let go of a certain wait queue
+ *
+ * In order to propagate a wake up, a wait_queue_t of the client
+ * socket is enqueued on the peer_wait queue of the server socket
+ * whose wake function does a wake_up on the ordinary client socket
+ * wait queue. This connection is established whenever a write (or
+ * poll for write) hit the flow control condition and broken when the
+ * association to the server socket is dissolved or after a wake up
+ * was relayed.
+ */
+
+static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
+                                     void *key)
+{
+       struct unix_sock *u;
+       wait_queue_head_t *u_sleep;
+
+       u = container_of(q, struct unix_sock, peer_wake);
+
+       __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
+                           q);
+       u->peer_wake.private = NULL;
+
+       /* relaying can only happen while the wq still exists */
+       u_sleep = sk_sleep(&u->sk);
+       if (u_sleep)
+               wake_up_interruptible_poll(u_sleep, key);
+
+       return 0;
+}
+
+static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
+{
+       struct unix_sock *u, *u_other;
+       int rc;
+
+       u = unix_sk(sk);
+       u_other = unix_sk(other);
+       rc = 0;
+       spin_lock(&u_other->peer_wait.lock);
+
+       if (!u->peer_wake.private) {
+               u->peer_wake.private = other;
+               __add_wait_queue(&u_other->peer_wait, &u->peer_wake);
+
+               rc = 1;
+       }
+
+       spin_unlock(&u_other->peer_wait.lock);
+       return rc;
+}
+
+static void unix_dgram_peer_wake_disconnect(struct sock *sk,
+                                           struct sock *other)
+{
+       struct unix_sock *u, *u_other;
+
+       u = unix_sk(sk);
+       u_other = unix_sk(other);
+       spin_lock(&u_other->peer_wait.lock);
+
+       if (u->peer_wake.private == other) {
+               __remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
+               u->peer_wake.private = NULL;
+       }
+
+       spin_unlock(&u_other->peer_wait.lock);
+}
+
+static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
+                                                  struct sock *other)
+{
+       unix_dgram_peer_wake_disconnect(sk, other);
+       wake_up_interruptible_poll(sk_sleep(sk),
+                                  POLLOUT |
+                                  POLLWRNORM |
+                                  POLLWRBAND);
+}
+
+/* preconditions:
+ *     - unix_peer(sk) == other
+ *     - association is stable
+ */
+static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
+{
+       int connected;
+
+       connected = unix_dgram_peer_wake_connect(sk, other);
+
+       if (unix_recvq_full(other))
+               return 1;
+
+       if (connected)
+               unix_dgram_peer_wake_disconnect(sk, other);
+
+       return 0;
+}
+
 static inline int unix_writable(struct sock *sk)
 {
        return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
@@ -364,7 +497,9 @@ static void unix_sock_destructor(struct sock *sk)
        WARN_ON(!sk_unhashed(sk));
        WARN_ON(sk->sk_socket);
        if (!sock_flag(sk, SOCK_DEAD)) {
-               printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk);
+               #ifdef CONFIG_MTK_NET_LOGGING 
+               printk(KERN_INFO "[mtk_net][unix]Attempt to release alive unix socket: %p\n", sk);
+               #endif
                return;
        }
 
@@ -375,10 +510,10 @@ static void unix_sock_destructor(struct sock *sk)
        local_bh_disable();
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        local_bh_enable();
-#ifdef UNIX_REFCNT_DEBUG
-       printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk,
+    #ifdef UNIX_REFCNT_DEBUG
+       printk(KERN_DEBUG "[mtk_net][unix]UNIX %p is destroyed, %ld are still alive.\n", sk,
                atomic_long_read(&unix_nr_socks));
-#endif
+    #endif
 }
 
 static void unix_release_sock(struct sock *sk, int embrion)
@@ -417,6 +552,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
                        skpair->sk_state_change(skpair);
                        sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
                }
+
+               unix_dgram_peer_wake_disconnect(sk, skpair);
                sock_put(skpair); /* It may now die */
                unix_peer(sk) = NULL;
        }
@@ -498,6 +635,7 @@ out_unlock:
        unix_state_unlock(sk);
        put_pid(old_pid);
 out:
+   
        return err;
 }
 
@@ -650,6 +788,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
        INIT_LIST_HEAD(&u->link);
        mutex_init(&u->readlock); /* single task reading lock */
        init_waitqueue_head(&u->peer_wait);
+       init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
        unix_insert_socket(unix_sockets_unbound(sk), sk);
 out:
        if (sk == NULL)
@@ -896,7 +1035,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        atomic_set(&addr->refcnt, 1);
 
        if (sun_path[0]) {
-               struct path path;
+               struct path path;      
+
                umode_t mode = S_IFSOCK |
                       (SOCK_INODE(sock)->i_mode & ~current_umask());
                err = unix_mknod(sun_path, mode, &path);
@@ -933,6 +1073,7 @@ out_unlock:
 out_up:
        mutex_unlock(&u->readlock);
 out:
        return err;
 }
 
@@ -972,6 +1113,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
        int err;
 
        if (addr->sa_family != AF_UNSPEC) {
+     
                err = unix_mkname(sunaddr, alen, &hash);
                if (err < 0)
                        goto out;
@@ -1017,6 +1159,8 @@ restart:
        if (unix_peer(sk)) {
                struct sock *old_peer = unix_peer(sk);
                unix_peer(sk) = other;
+               unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
+
                unix_state_double_unlock(sk, other);
 
                if (other != old_peer)
@@ -1026,12 +1170,21 @@ restart:
                unix_peer(sk) = other;
                unix_state_double_unlock(sk, other);
        }
+       
+#ifdef CONFIG_MTK_NET_LOGGING 
+    if((SOCK_INODE(sock)!= NULL) && (sunaddr != NULL) && (other->sk_socket != NULL) && (SOCK_INODE(other->sk_socket) != NULL))
+    {
+              printk(KERN_INFO "[mtk_net][socket]unix_dgram_connect[%lu]:connect [%s] other[%lu]\n",SOCK_INODE(sock)->i_ino,sunaddr->sun_path,SOCK_INODE(other->sk_socket)->i_ino);
+         }
+#endif 
+            
        return 0;
 
 out_unlock:
        unix_state_double_unlock(sk, other);
        sock_put(other);
 out:
+     
        return err;
 }
 
@@ -1214,8 +1367,17 @@ restart:
        __skb_queue_tail(&other->sk_receive_queue, skb);
        spin_unlock(&other->sk_receive_queue.lock);
        unix_state_unlock(other);
+       
+       #ifdef CONFIG_MTK_NET_LOGGING 
+       if((SOCK_INODE(sock)!= NULL) && (sunaddr != NULL) && (other->sk_socket != NULL) && (SOCK_INODE(other->sk_socket) != NULL))
+  {
+         printk(KERN_INFO "[mtk_net][socket]unix_stream_connect[%lu ]: connect [%s] other[%lu] \n",SOCK_INODE(sock)->i_ino,sunaddr->sun_path,SOCK_INODE(other->sk_socket)->i_ino);
+       }
+  #endif 
+
        other->sk_data_ready(other, 0);
        sock_put(other);
+       
        return 0;
 
 out_unlock:
@@ -1228,6 +1390,7 @@ out:
                unix_release_sock(newsk, 0);
        if (other)
                sock_put(other);
+    
        return err;
 }
 
@@ -1279,7 +1442,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
        /* If socket state is TCP_LISTEN it cannot change (for now...),
         * so that no locks are necessary.
         */
-
+    
        skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err);
        if (!skb) {
                /* This means receive shutdown. */
@@ -1298,9 +1461,11 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
        unix_sock_inherit_flags(sock, newsock);
        sock_graft(tsk, newsock);
        unix_state_unlock(tsk);
+    
        return 0;
 
 out:
+    
        return err;
 }
 
@@ -1456,7 +1621,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        struct scm_cookie tmp_scm;
        int max_level;
        int data_len = 0;
-
+       int sk_locked;
+        
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
        wait_for_unix_gc();
@@ -1532,12 +1698,14 @@ restart:
                goto out_free;
        }
 
+       sk_locked = 0;
        unix_state_lock(other);
+restart_locked:
        err = -EPERM;
        if (!unix_may_send(sk, other))
                goto out_unlock;
 
-       if (sock_flag(other, SOCK_DEAD)) {
+       if (unlikely(sock_flag(other, SOCK_DEAD))) {
                /*
                 *      Check with 1003.1g - what should
                 *      datagram error
@@ -1545,10 +1713,12 @@ restart:
                unix_state_unlock(other);
                sock_put(other);
 
-               err = 0;
+               if (!sk_locked)
                unix_state_lock(sk);
                if (unix_peer(sk) == other) {
                        unix_peer(sk) = NULL;
+                       unix_dgram_peer_wake_disconnect_wakeup(sk, other);
+
                        unix_state_unlock(sk);
 
                        unix_dgram_disconnected(sk, other);
@@ -1574,21 +1744,43 @@ restart:
                        goto out_unlock;
        }
 
-       if (unix_peer(other) != sk && unix_recvq_full(other)) {
-               if (!timeo) {
-                       err = -EAGAIN;
-                       goto out_unlock;
+       /* other == sk && unix_peer(other) != sk if
+        * - unix_peer(sk) == NULL, destination address bound to sk
+        * - unix_peer(sk) == sk by time of get but disconnected before lock
+        */
+       if (other != sk &&
+           unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+               if (timeo) {
+                       timeo = unix_wait_for_peer(other, timeo);
+
+                       err = sock_intr_errno(timeo);
+                       if (signal_pending(current))
+                               goto out_free;
+
+                       goto restart;
                }
 
-               timeo = unix_wait_for_peer(other, timeo);
+               if (!sk_locked) {
+                       unix_state_unlock(other);
+                       unix_state_double_lock(sk, other);
+               }
 
-               err = sock_intr_errno(timeo);
-               if (signal_pending(current))
-                       goto out_free;
+               if (unix_peer(sk) != other ||
+                   unix_dgram_peer_wake_me(sk, other)) {
+                       err = -EAGAIN;
+                       sk_locked = 1;
+                       goto out_unlock;
+               }
 
-               goto restart;
+               if (!sk_locked) {
+                       sk_locked = 1;
+                       goto restart_locked;
+               }
        }
 
+       if (unlikely(sk_locked))
+               unix_state_unlock(sk);
+
        if (sock_flag(other, SOCK_RCVTSTAMP))
                __net_timestamp(skb);
        maybe_add_creds(skb, sock, other);
@@ -1599,9 +1791,12 @@ restart:
        other->sk_data_ready(other, len);
        sock_put(other);
        scm_destroy(siocb->scm);
+    
        return len;
 
 out_unlock:
+       if (sk_locked)
+               unix_state_unlock(sk);
        unix_state_unlock(other);
 out_free:
        kfree_skb(skb);
@@ -1609,6 +1804,7 @@ out:
        if (other)
                sock_put(other);
        scm_destroy(siocb->scm);
+      
        return err;
 }
 
@@ -1628,6 +1824,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
+               
        wait_for_unix_gc();
        err = scm_send(sock, msg, siocb->scm, false);
        if (err < 0)
@@ -1671,6 +1868,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 
                skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT,
                                          &err);
+               
 
                if (skb == NULL)
                        goto out_err;
@@ -1704,7 +1902,33 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 
                if (sock_flag(other, SOCK_DEAD) ||
                    (other->sk_shutdown & RCV_SHUTDOWN))
+               {
+                    if( other->sk_socket )
+                    {
+                        if(sk->sk_socket)
+                        {
+                
+                         #ifdef CONFIG_MTK_NET_LOGGING 
+                         printk(KERN_INFO " [mtk_net][unix]: sendmsg[%lu:%lu]:peer close\n" ,SOCK_INODE(sk->sk_socket)->i_ino,SOCK_INODE(other->sk_socket)->i_ino);
+                                        #endif
+                        }
+                        else{
+                                           #ifdef CONFIG_MTK_NET_LOGGING 
+                                       printk(KERN_INFO " [mtk_net][unix]: sendmsg[null:%lu]:peer close\n" ,SOCK_INODE(other->sk_socket)->i_ino);
+                                       #endif
+                        }        
+
+                   }
+                   else        
+                                       {
+                                               #ifdef CONFIG_MTK_NET_LOGGING   
+                                       printk(KERN_INFO " [mtk_net][unix]: sendmsg:peer close \n" );
+                                       #endif
+                               }
+                               
+          
                        goto pipe_err_free;
+               }
 
                maybe_add_creds(skb, sock, other);
                skb_queue_tail(&other->sk_receive_queue, skb);
@@ -1730,6 +1954,7 @@ pipe_err:
 out_err:
        scm_destroy(siocb->scm);
        siocb->scm = NULL;
+        
        return sent ? : err;
 }
 
@@ -1871,6 +2096,7 @@ out_free:
 out_unlock:
        mutex_unlock(&u->readlock);
 out:
+      
        return err;
 }
 
@@ -1896,7 +2122,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
 
                set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
                unix_state_unlock(sk);
-               timeo = schedule_timeout(timeo);
+               timeo = freezable_schedule_timeout(timeo);
                unix_state_lock(sk);
 
                if (sock_flag(sk, SOCK_DEAD))
@@ -1926,6 +2152,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
        int err = 0;
        long timeo;
        int skip;
+       struct sock * other = unix_peer(sk);
 
        err = -EINVAL;
        if (sk->sk_state != TCP_ESTABLISHED)
@@ -1980,8 +2207,27 @@ again:
                        if (err)
                                goto unlock;
                        if (sk->sk_shutdown & RCV_SHUTDOWN)
+                       {
+                            if(sk && sk->sk_socket )
+                            {
+                                  if(other && other->sk_socket ){
+                                       #ifdef CONFIG_MTK_NET_LOGGING 
+                                       
+                     printk(KERN_INFO " [mtk_net][unix]: recvmsg[%lu:%lu]:exit read due to peer shutdown  \n" ,SOCK_INODE(sk->sk_socket)->i_ino,SOCK_INODE(other->sk_socket)->i_ino);
+                                  #endif
+                                  }else{                                  
+                                       #ifdef CONFIG_MTK_NET_LOGGING                              
+                     printk(KERN_INFO "[mtk_net][unix]: recvmsg[%lu:null]:exit read due to peer shutdown  \n" ,SOCK_INODE(sk->sk_socket)->i_ino);
+                     #endif
+                                  }
+                                }
+                           else{       
+                                       #ifdef CONFIG_MTK_NET_LOGGING 
+                                  printk(KERN_INFO " [mtk_net][unix]: recvmsg: exit read due to peer shutdown \n" );
+                                  #endif
+                           }
                                goto unlock;
-
+                       }
                        unix_state_unlock(sk);
                        err = -EAGAIN;
                        if (!timeo)
@@ -1989,6 +2235,28 @@ again:
                        mutex_unlock(&u->readlock);
 
                        timeo = unix_stream_data_wait(sk, timeo, last);
+                        if (!timeo)
+                        {
+                            if(sk && sk->sk_socket )
+                            {
+                                if(other && other->sk_socket ){
+                                       #ifdef CONFIG_MTK_NET_LOGGING 
+                     printk(KERN_INFO " [mtk_net][unix]: recvmsg[%lu:%lu]:exit read due to timeout  \n" ,SOCK_INODE(sk->sk_socket)->i_ino,SOCK_INODE(other->sk_socket)->i_ino);
+                                  #endif
+                                  }else{                                  
+                                       #ifdef CONFIG_MTK_NET_LOGGING                              
+                     printk(KERN_INFO " [mtk_net][unix]: recvmsg[%lu:null]:exit read due to timeout  \n" ,SOCK_INODE(sk->sk_socket)->i_ino);
+                     #endif
+                                   }                     
+                          }
+                          else 
+                                       {
+                                               #ifdef CONFIG_MTK_NET_LOGGING   
+                                 printk(KERN_INFO " [mtk_net][unix]: recvmsg:exit read due to timeout \n" );
+                                 #endif
+                               }
+                                 
+                        }
 
                        if (signal_pending(current)
                            ||  mutex_lock_interruptible(&u->readlock)) {
@@ -2072,6 +2340,7 @@ again:
        mutex_unlock(&u->readlock);
        scm_recv(sock, msg, siocb->scm, flags);
 out:
+  
        return copied ? : err;
 }
 
@@ -2240,22 +2509,29 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
                        mask |= POLLHUP;
                /* connection hasn't started yet? */
                if (sk->sk_state == TCP_SYN_SENT)
+    {
+        
                        return mask;
-       }
+         }
+  }
 
        /* No write status requested, avoid expensive OUT tests. */
        if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT)))
+  {     
                return mask;
+  }
 
        writable = unix_writable(sk);
-       other = unix_peer_get(sk);
-       if (other) {
-               if (unix_peer(other) != sk) {
-                       sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
-                       if (unix_recvq_full(other))
-                               writable = 0;
-               }
-               sock_put(other);
+       if (writable) {
+               unix_state_lock(sk);
+
+               other = unix_peer(sk);
+               if (other && unix_peer(other) != sk &&
+                   unix_recvq_full(other) &&
+                   unix_dgram_peer_wake_me(sk, other))
+                       writable = 0;
+
+               unix_state_unlock(sk);
        }
 
        if (writable)