usb: gadget: phonet: Add Phonet over ACM for RMC
[linux-3.10.git] / net / unix / garbage.c
index 5a0061d..9bc73f8 100644 (file)
 #include <linux/un.h>
 #include <linux/net.h>
 #include <linux/fs.h>
-#include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
+#include <linux/wait.h>
 
 #include <net/sock.h>
 #include <net/af_unix.h>
 static LIST_HEAD(gc_inflight_list);
 static LIST_HEAD(gc_candidates);
 static DEFINE_SPINLOCK(unix_gc_lock);
+static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
 
 unsigned int unix_tot_inflight;
 
 
-static struct sock *unix_get_socket(struct file *filp)
+struct sock *unix_get_socket(struct file *filp)
 {
        struct sock *u_sock = NULL;
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(filp);
 
        /*
         *      Socket ?
         */
-       if (S_ISSOCK(inode->i_mode)) {
+       if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
                struct socket *sock = SOCKET_I(inode);
                struct sock *s = sock->sk;
 
@@ -152,15 +153,6 @@ void unix_notinflight(struct file *fp)
        }
 }
 
-static inline struct sk_buff *sock_queue_head(struct sock *sk)
-{
-       return (struct sk_buff *)&sk->sk_receive_queue;
-}
-
-#define receive_queue_for_each_skb(sk, next, skb) \
-       for (skb = sock_queue_head(sk)->next, next = skb->next; \
-            skb != sock_queue_head(sk); skb = next, next = skb->next)
-
 static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
                          struct sk_buff_head *hitlist)
 {
@@ -168,7 +160,7 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
        struct sk_buff *next;
 
        spin_lock(&x->sk_receive_queue.lock);
-       receive_queue_for_each_skb(x, next, skb) {
+       skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
                /*
                 *      Do we have file descriptors ?
                 */
@@ -193,7 +185,7 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
                                         * have been added to the queues after
                                         * starting the garbage collection
                                         */
-                                       if (u->gc_candidate) {
+                                       if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) {
                                                hit = true;
                                                func(u);
                                        }
@@ -224,7 +216,7 @@ static void scan_children(struct sock *x, void (*func)(struct unix_sock *),
                 * and perform a scan on them as well.
                 */
                spin_lock(&x->sk_receive_queue.lock);
-               receive_queue_for_each_skb(x, next, skb) {
+               skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
                        u = unix_sk(skb->sk);
 
                        /*
@@ -262,16 +254,27 @@ static void inc_inflight_move_tail(struct unix_sock *u)
         * of the list, so that it's checked even if it was already
         * passed over
         */
-       if (u->gc_maybe_cycle)
+       if (test_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags))
                list_move_tail(&u->link, &gc_candidates);
 }
 
-/* The external entry point: unix_gc() */
+static bool gc_in_progress = false;
+#define UNIX_INFLIGHT_TRIGGER_GC 16000
 
-void unix_gc(void)
+void wait_for_unix_gc(void)
 {
-       static bool gc_in_progress = false;
+       /*
+        * If number of inflight sockets is insane,
+        * force a garbage collect right now.
+        */
+       if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
+               unix_gc();
+       wait_event(unix_gc_wait, gc_in_progress == false);
+}
 
+/* The external entry point: unix_gc() */
+void unix_gc(void)
+{
        struct unix_sock *u;
        struct unix_sock *next;
        struct sk_buff_head hitlist;
@@ -312,8 +315,8 @@ void unix_gc(void)
                BUG_ON(total_refs < inflight_refs);
                if (total_refs == inflight_refs) {
                        list_move_tail(&u->link, &gc_candidates);
-                       u->gc_candidate = 1;
-                       u->gc_maybe_cycle = 1;
+                       __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
+                       __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
                }
        }
 
@@ -341,7 +344,7 @@ void unix_gc(void)
 
                if (atomic_long_read(&u->inflight) > 0) {
                        list_move_tail(&u->link, &not_cycle_list);
-                       u->gc_maybe_cycle = 0;
+                       __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
                        scan_children(&u->sk, inc_inflight_move_tail, NULL);
                }
        }
@@ -353,7 +356,7 @@ void unix_gc(void)
         */
        while (!list_empty(&not_cycle_list)) {
                u = list_entry(not_cycle_list.next, struct unix_sock, link);
-               u->gc_candidate = 0;
+               __clear_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
                list_move_tail(&u->link, &gc_inflight_list);
        }
 
@@ -376,6 +379,7 @@ void unix_gc(void)
        /* All candidates should have been detached by now. */
        BUG_ON(!list_empty(&gc_candidates));
        gc_in_progress = false;
+       wake_up(&unix_gc_wait);
 
  out:
        spin_unlock(&unix_gc_lock);