diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
commit | 78c388aed2b7184182c08428db1de6c872d815f5 (patch) | |
tree | 4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /net/unix | |
parent | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (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.c | 10 | ||||
-rw-r--r-- | net/unix/garbage.c | 115 |
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); } |