summaryrefslogtreecommitdiffstats
path: root/net/unix
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /net/unix
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c10
-rw-r--r--net/unix/garbage.c115
2 files changed, 79 insertions, 46 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 8e0110b18..bdd15f744 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -8,7 +8,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: af_unix.c,v 1.68 1998/08/26 13:18:35 davem Exp $
+ * Version: $Id: af_unix.c,v 1.71 1998/10/03 09:39:05 davem Exp $
*
* Fixes:
* Linus Torvalds : Assorted bug cures.
@@ -463,7 +463,7 @@ static int unix_autobind(struct socket *sock)
addr = kmalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL);
if (!addr)
- return -ENOBUFS;
+ return -ENOMEM;
if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.dentry)
{
kfree(addr);
@@ -548,7 +548,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
if (!addr)
- return -ENOBUFS;
+ return -ENOMEM;
/* We slept; recheck ... */
@@ -786,7 +786,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
struct sk_buff *skb;
if (sock->state != SS_UNCONNECTED)
- return(-EINVAL);
+ return(-EINVAL);
if (!(sock->flags & SO_ACCEPTCON))
return(-EINVAL);
@@ -1332,7 +1332,7 @@ static int unix_shutdown(struct socket *sock, int mode)
peer_mode |= SEND_SHUTDOWN;
if (mode&SEND_SHUTDOWN)
peer_mode |= RCV_SHUTDOWN;
- other->shutdown |= mode;
+ other->shutdown |= peer_mode;
other->state_change(other);
}
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 4f85caa73..3dcc2cada 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -31,6 +31,25 @@
* Fixes:
* Alan Cox 07 Sept 1997 Vmalloc internal stack as needed.
* Cope with changing max_files.
+ * 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
+ * skb_free() 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.
*
*/
@@ -123,11 +142,11 @@ extern inline int empty_stack(void)
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);
}
@@ -139,7 +158,8 @@ void unix_gc(void)
static int in_unix_gc=0;
int i;
unix_socket *s;
- unix_socket *next;
+ struct sk_buff_head hitlist;
+ struct sk_buff *skb;
/*
* Avoid a recursive GC.
@@ -163,17 +183,21 @@ void unix_gc(void)
max_stack=max_files;
}
+ forall_unix_sockets(i, s)
+ {
+ s->protinfo.af_unix.marksweep|=MARKED;
+ }
/*
- * Assume everything is now unmarked
+ * Everything is now 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
*/
/*
@@ -186,8 +210,9 @@ void unix_gc(void)
* 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);
}
/*
@@ -198,7 +223,6 @@ void unix_gc(void)
{
unix_socket *x = pop_stack();
unix_socket *f=NULL,*sk;
- struct sk_buff *skb;
tail:
skb=skb_peek(&x->receive_queue);
@@ -227,16 +251,23 @@ tail:
if((sk=unix_get_socket(*fp++))!=NULL)
{
/*
- * Remember the first, mark the
- * rest.
+ * Remember the first,
+ * unmark the rest.
*/
if(f==NULL)
f=sk;
else
- maybe_mark_and_push(sk);
+ maybe_unmark_and_push(sk);
}
}
}
+ /* We have to scan not-yet-accepted ones too */
+ if (UNIXCB(skb).attr & MSG_SYN) {
+ if (f==NULL)
+ f=skb->sk;
+ else
+ maybe_unmark_and_push(skb->sk);
+ }
skb=skb->next;
}
/*
@@ -245,9 +276,9 @@ tail:
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;
@@ -255,35 +286,37 @@ tail:
}
}
- /*
- * Sweep phase. NOTE: this part dominates the time complexity
- */
+ skb_queue_head_init(&hitlist);
forall_unix_sockets(i, s)
{
- 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)
- fput(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(UNIXCB(skb).fp)
+ {
+ 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);
+ }
+
in_unix_gc=0;
-
- free_page((long)stack);
}