void unix_notinflight(struct file *fp) { struct sock *s = unix_get_socket(fp); if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); BUG_ON(list_empty(&u->link)); if (atomic_long_dec_and_test(&u->inflight)) list_del_init(&u->link); unix_tot_inflight--; spin_unlock(&unix_gc_lock); } }
void unix_inflight(struct file *fp) { struct sock *s = unix_get_socket(fp); if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); if (atomic_long_inc_return(&u->inflight) == 1) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); } else { BUG_ON(list_empty(&u->link)); } unix_tot_inflight++; spin_unlock(&unix_gc_lock); } }
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { struct sk_buff *skb; struct sk_buff *next; spin_lock(&x->sk_receive_queue.lock); receive_queue_for_each_skb(x, next, skb) { /* * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { bool hit = false; /* * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { /* * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); if (sk) { struct unix_sock *u = unix_sk(sk); /* * Ignore non-candidates, they could * have been added to the queues after * starting the garbage collection */ if (u->gc_candidate) { hit = true; func(u); } } } if (hit && hitlist != NULL) { __skb_unlink(skb, &x->sk_receive_queue); __skb_queue_tail(hitlist, skb); } } } spin_unlock(&x->sk_receive_queue.lock); }
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { struct sk_buff *skb; struct sk_buff *next; spin_lock(&x->sk_receive_queue.lock); receive_queue_for_each_skb(x, next, skb) { /* * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { bool hit = false; /* * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { /* * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); if (sk) { hit = true; func(unix_sk(sk)); } } if (hit && hitlist != NULL) { __skb_unlink(skb, &x->sk_receive_queue); __skb_queue_tail(hitlist, skb); } } } spin_unlock(&x->sk_receive_queue.lock); }
void unix_notinflight(struct file *fp) { unix_socket *s=unix_get_socket(fp); if(s) s->protinfo.af_unix.inflight--; }
void unix_gc(void) { static int in_unix_gc=0; unix_socket *s; unix_socket *next; /* * Avoid a recursive GC. */ if(in_unix_gc) return; in_unix_gc=1; stack=(unix_socket **)get_free_page(GFP_KERNEL); /* * Assume everything is now unmarked */ /* Invariant to be maintained: - everything marked is either: -- (a) on the stack, or -- (b) has all of its children marked - everything on the stack is always marked - nothing is ever pushed onto the stack twice, because: -- nothing previously marked is ever pushed on the stack */ /* * Push root set */ for(s=unix_socket_list;s!=NULL;s=s->next) { /* * 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); } /* * 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); /* * Loop through all but first born */ while(skb && skb != (struct sk_buff *)&x->receive_queue) { /* * Do we have file descriptors ? */ if(skb->h.filp) { /* * Process the descriptors of this socket */ int nfd=*(int *)skb->h.filp; struct file **fp=(struct file **)(skb->h.filp+sizeof(int)); while(nfd--) { /* * Get the socket the fd matches if * it indeed does so */ if((sk=unix_get_socket(*fp++))!=NULL) { /* * Remember the first, mark the * rest. */ if(f==NULL) f=sk; else maybe_mark_and_push(sk); } } } skb=skb->next; } /* * Handle first born specially */ if (f) { if (!(f->protinfo.af_unix.marksweep&MARKED)) { f->protinfo.af_unix.marksweep|=MARKED; x=f; f=NULL; goto tail; } } } /* * Sweep phase. NOTE: this part dominates the time complexity */ for(s=unix_socket_list;s!=NULL;s=next) { next=s->next; 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); } else s->protinfo.af_unix.marksweep&=~MARKED; /* unmark everything for next collection */ } in_unix_gc=0; free_page((long)stack); }