patch-2.0.36 linux/net/unix/garbage.c
Next file: linux/scripts/checkconfig.pl
Previous file: linux/net/socket.c
Back to the patch index
Back to the overall index
- Lines: 216
- Date:
Sun Nov 15 10:33:23 1998
- Orig file:
v2.0.35/linux/net/unix/garbage.c
- Orig date:
Tue Mar 10 13:19:10 1998
diff -u --recursive --new-file v2.0.35/linux/net/unix/garbage.c linux/net/unix/garbage.c
@@ -39,6 +39,25 @@
* 2 of the License, or (at your option) any later version.
*
* Fixes:
+ * Al Viro 11 Oct 1998
+ * Graph may have cycles. That is, we can send the descriptor
+ * of foo to bar and vice versa. Current code chokes on that.
+ * Fix: move SCM_RIGHTS ones into the separate list and then
+ * kfree_skb() them all instead of doing explicit fput's.
+ * Another problem: since fput() may block somebody may
+ * create a new unix_socket when we are in the middle of sweep
+ * phase. Fix: revert the logic wrt MARKED. Mark everything
+ * upon the beginning and unmark non-junk ones.
+ *
+ * [12 Oct 1998] AAARGH! New code purges all SCM_RIGHTS
+ * sent to connect()'ed but still not accept()'ed sockets.
+ * Fixed. Old code had slightly different problem here:
+ * extra fput() in situation when we passed the descriptor via
+ * such socket and closed it (descriptor). That would happen on
+ * each unix_gc() until the accept(). Since the struct file in
+ * question would go to the free list and might be reused...
+ * That might be the reason of random oopses on close_fp() in
+ * unrelated processes.
*
*/
@@ -136,11 +155,11 @@
return in_stack == 0;
}
-extern inline void maybe_mark_and_push(unix_socket *x)
+extern inline void maybe_unmark_and_push(unix_socket *x)
{
- if (x->protinfo.af_unix.marksweep&MARKED)
+ if (!(x->protinfo.af_unix.marksweep&MARKED))
return;
- x->protinfo.af_unix.marksweep|=MARKED;
+ x->protinfo.af_unix.marksweep&=~MARKED;
push_stack(x);
}
@@ -151,8 +170,9 @@
{
static int in_unix_gc=0;
unix_socket *s;
- unix_socket *next;
-
+ struct sk_buff *skb;
+ struct sk_buff_head hitlist;
+
/*
* Avoid a recursive GC.
*/
@@ -170,16 +190,21 @@
}
/*
- * Assume everything is now unmarked
+ * Everything is now marked
*/
+ for(s=unix_socket_list;s!=NULL;s=s->next)
+ {
+ s->protinfo.af_unix.marksweep|=MARKED;
+ }
+
/* Invariant to be maintained:
- - everything marked is either:
+ - everything unmarked is either:
-- (a) on the stack, or
- -- (b) has all of its children marked
- - everything on the stack is always marked
+ -- (b) has all of its children unmarked
+ - everything on the stack is always unmarked
- nothing is ever pushed onto the stack twice, because:
- -- nothing previously marked is ever pushed on the stack
+ -- nothing previously unmarked is ever pushed on the stack
*/
/*
@@ -192,19 +217,19 @@
* If all instances of the descriptor are not
* in flight we are in use.
*/
- if(s->socket && s->socket->file && s->socket->file->f_count > s->protinfo.af_unix.inflight)
- maybe_mark_and_push(s);
+ if(s->socket && s->socket->file &&
+ s->socket->file->f_count > s->protinfo.af_unix.inflight)
+ maybe_unmark_and_push(s);
}
/*
- * Mark phase
+ * Mark phase
*/
while (!empty_stack())
{
unix_socket *x = pop_stack();
unix_socket *f=NULL,*sk;
- struct sk_buff *skb;
tail:
skb=skb_peek(&x->receive_queue);
@@ -233,27 +258,38 @@
if((sk=unix_get_socket(*fp++))!=NULL)
{
/*
- * Remember the first, mark the
+ * Remember the first, unmark the
* rest.
*/
if(f==NULL)
f=sk;
else
- maybe_mark_and_push(sk);
+ maybe_unmark_and_push(sk);
}
}
}
+ /*
+ * If we are connecting we need to handle this too
+ */
+ if(x->state == TCP_LISTEN)
+ {
+ if(f==NULL)
+ f=skb->sk;
+ else
+ maybe_unmark_and_push(skb->sk);
+ }
skb=skb->next;
}
+
/*
* Handle first born specially
*/
if (f)
{
- if (!(f->protinfo.af_unix.marksweep&MARKED))
+ if (f->protinfo.af_unix.marksweep&MARKED)
{
- f->protinfo.af_unix.marksweep|=MARKED;
+ f->protinfo.af_unix.marksweep&=~MARKED;
x=f;
f=NULL;
goto tail;
@@ -261,35 +297,44 @@
}
}
- /*
- * Sweep phase. NOTE: this part dominates the time complexity
- */
+ skb_queue_head_init(&hitlist);
- for(s=unix_socket_list;s!=NULL;s=next)
+ for(s=unix_socket_list;s!=NULL;s=s->next)
{
- next=s->next;
- if (!(s->protinfo.af_unix.marksweep&MARKED))
+ if (s->protinfo.af_unix.marksweep&MARKED)
{
- /*
- * We exist only in the passing tree of sockets
- * that is no longer connected to active descriptors
- * Time to die..
- *
- * Subtle item: We will correctly sweep out the
- * socket that has just been closed by the user.
- * We must not close this as we are in the middle
- * of its close at this moment. Skip that file
- * using f_count==0 to spot it.
- */
-
- if(s->socket && s->socket->file && s->socket->file->f_count)
- close_fp(s->socket->file);
+ struct sk_buff *nextsk;
+ skb=skb_peek(&s->receive_queue);
+ while(skb && skb != (struct sk_buff *)&s->receive_queue)
+ {
+ nextsk=skb->next;
+ /*
+ * Do we have file descriptors ?
+ */
+ if(*(int *)(skb->h.filp))
+ {
+ /*
+ * Pull these buffers out of line
+ * so they will each be freed once
+ * at the end.
+ */
+ skb_unlink(skb);
+ skb_queue_tail(&hitlist,skb);
+ }
+ skb=nextsk;
+ }
}
- else
- s->protinfo.af_unix.marksweep&=~MARKED; /* unmark everything for next collection */
}
-
+
+ /*
+ * Here we are. Hitlist is filled. Die.
+ */
+
+ while ((skb=skb_dequeue(&hitlist))!=NULL)
+ {
+ kfree_skb(skb, FREE_READ);
+ }
+
in_unix_gc=0;
-
vfree(stack);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov