patch-2.3.15 linux/net/unix/garbage.c

Next file: linux/net/unix/sysctl_net_unix.c
Previous file: linux/net/unix/af_unix.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/net/unix/garbage.c linux/net/unix/garbage.c
@@ -84,9 +84,14 @@
 
 /* Internal data structures and random procedures: */
 
-#define GC_HEAD ((unix_socket *)(-1))
+#define GC_HEAD		((unix_socket *)(-1))
+#define GC_ORPHAN	((unix_socket *)(-3))
+
 static unix_socket *gc_current=GC_HEAD;	/* stack of objects to mark */
 
+atomic_t unix_tot_inflight = ATOMIC_INIT(0);
+
+
 extern inline unix_socket *unix_get_socket(struct file *filp)
 {
 	unix_socket * u_sock = NULL;
@@ -116,15 +121,19 @@
 void unix_inflight(struct file *fp)
 {
 	unix_socket *s=unix_get_socket(fp);
-	if(s)
-		s->protinfo.af_unix.inflight++;
+	if(s) {
+		atomic_inc(&s->protinfo.af_unix.inflight);
+		atomic_inc(&unix_tot_inflight);
+	}
 }
 
 void unix_notinflight(struct file *fp)
 {
 	unix_socket *s=unix_get_socket(fp);
-	if(s)
-		s->protinfo.af_unix.inflight--;
+	if(s) {
+		atomic_dec(&s->protinfo.af_unix.inflight);
+		atomic_dec(&unix_tot_inflight);
+	}
 }
 
 
@@ -146,8 +155,9 @@
 
 extern inline void maybe_unmark_and_push(unix_socket *x)
 {
-	if (x->protinfo.af_unix.gc_tree)
+	if (x->protinfo.af_unix.gc_tree != GC_ORPHAN)
 		return;
+	sock_hold(x);
 	x->protinfo.af_unix.gc_tree = gc_current;
 	gc_current = x;
 }
@@ -157,23 +167,24 @@
 
 void unix_gc(void)
 {
-	static int in_unix_gc=0;
+	static DECLARE_MUTEX(unix_gc_sem);
 	int i;
 	unix_socket *s;
 	struct sk_buff_head hitlist;
 	struct sk_buff *skb;
-	
+
 	/*
 	 *	Avoid a recursive GC.
 	 */
 
-	if(in_unix_gc)
+	if(!down_trylock(&unix_gc_sem))
 		return;
-	in_unix_gc=1;
-	
+
+	read_lock(&unix_table_lock);
+
 	forall_unix_sockets(i, s)
 	{
-		s->protinfo.af_unix.gc_tree=NULL;
+		s->protinfo.af_unix.gc_tree=GC_ORPHAN;
 	}
 	/*
 	 *	Everything is now marked 
@@ -199,7 +210,7 @@
 		 *	in flight we are in use.
 		 */
 		if(s->socket && s->socket->file &&
-		   file_count(s->socket->file) > s->protinfo.af_unix.inflight)
+		   file_count(s->socket->file) > atomic_read(&s->protinfo.af_unix.inflight))
 			maybe_unmark_and_push(s);
 	}
 
@@ -210,8 +221,9 @@
 	while (!empty_stack())
 	{
 		unix_socket *x = pop_stack();
-		unix_socket *f=NULL,*sk;
-tail:		
+		unix_socket *sk;
+
+		spin_lock(&x->receive_queue.lock);
 		skb=skb_peek(&x->receive_queue);
 		
 		/*
@@ -238,49 +250,28 @@
 					 */
 					if((sk=unix_get_socket(*fp++))!=NULL)
 					{
-						/*
-						 *	Remember the first,
-						 *	unmark the rest.
-						 */
-						if(f==NULL)
-							f=sk;
-						else
-							maybe_unmark_and_push(sk);
+						maybe_unmark_and_push(sk);
 					}
 				}
 			}
 			/* We have to scan not-yet-accepted ones too */
-			if ((UNIXCB(skb).attr & MSG_SYN) && !skb->sk->dead) {
-				if (f==NULL)
-					f=skb->sk;
-				else
-					maybe_unmark_and_push(skb->sk);
+			if (x->state == TCP_LISTEN) {
+				maybe_unmark_and_push(skb->sk);
 			}
 			skb=skb->next;
 		}
-		/*
-		 *	Handle first born specially 
-		 */
-
-		if (f) 
-		{
-			if (!f->protinfo.af_unix.gc_tree)
-			{
-				f->protinfo.af_unix.gc_tree=GC_HEAD;
-				x=f;
-				f=NULL;
-				goto tail;
-			}
-		}
+		spin_unlock(&x->receive_queue.lock);
+		sock_put(x);
 	}
 
 	skb_queue_head_init(&hitlist);
 
 	forall_unix_sockets(i, s)
 	{
-		if (!s->protinfo.af_unix.gc_tree)
+		if (s->protinfo.af_unix.gc_tree == GC_ORPHAN)
 		{
 			struct sk_buff *nextsk;
+			spin_lock(&s->receive_queue.lock);
 			skb=skb_peek(&s->receive_queue);
 			while(skb && skb != (struct sk_buff *)&s->receive_queue)
 			{
@@ -290,21 +281,24 @@
 				 */
 				if(UNIXCB(skb).fp)
 				{
-					skb_unlink(skb);
-					skb_queue_tail(&hitlist,skb);
+					__skb_unlink(skb, skb->list);
+					__skb_queue_tail(&hitlist,skb);
 				}
 				skb=nextsk;
 			}
+			spin_unlock(&s->receive_queue.lock);
 		}
+		s->protinfo.af_unix.gc_tree = GC_ORPHAN;
 	}
+	read_unlock(&unix_table_lock);
 
 	/*
 	 *	Here we are. Hitlist is filled. Die.
 	 */
 
-	while ((skb=skb_dequeue(&hitlist))!=NULL) {
+	while ((skb=__skb_dequeue(&hitlist))!=NULL) {
 		kfree_skb(skb);
 	}
 
-	in_unix_gc=0;
+	up(&unix_gc_sem);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)