Loading net/unix/garbage.c +28 −42 Original line number Original line Diff line number Diff line Loading @@ -95,39 +95,36 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); unsigned int unix_tot_inflight; unsigned int unix_tot_inflight; struct sock *unix_get_socket(struct file *filp) struct sock *unix_get_socket(struct file *filp) { { struct sock *u_sock = NULL; struct sock *u_sock = NULL; struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp); /* /* Socket ? */ * Socket ? */ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { struct socket *sock = SOCKET_I(inode); struct socket *sock = SOCKET_I(inode); struct sock *s = sock->sk; struct sock *s = sock->sk; /* /* PF_UNIX ? */ * PF_UNIX ? */ if (s && sock->ops && sock->ops->family == PF_UNIX) if (s && sock->ops && sock->ops->family == PF_UNIX) u_sock = s; u_sock = s; } } return u_sock; return u_sock; } } /* /* Keep the number of times in flight count for the file * Keep the number of times in flight count for the file * descriptor if it is for an AF_UNIX socket. * descriptor if it is for an AF_UNIX socket. */ */ void unix_inflight(struct file *fp) void unix_inflight(struct file *fp) { { struct sock *s = unix_get_socket(fp); struct sock *s = unix_get_socket(fp); if (s) { if (s) { struct unix_sock *u = unix_sk(s); struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); spin_lock(&unix_gc_lock); if (atomic_long_inc_return(&u->inflight) == 1) { if (atomic_long_inc_return(&u->inflight) == 1) { BUG_ON(!list_empty(&u->link)); BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); list_add_tail(&u->link, &gc_inflight_list); Loading @@ -142,10 +139,13 @@ void unix_inflight(struct file *fp) void unix_notinflight(struct file *fp) void unix_notinflight(struct file *fp) { { struct sock *s = unix_get_socket(fp); struct sock *s = unix_get_socket(fp); if (s) { if (s) { struct unix_sock *u = unix_sk(s); struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); spin_lock(&unix_gc_lock); BUG_ON(list_empty(&u->link)); BUG_ON(list_empty(&u->link)); if (atomic_long_dec_and_test(&u->inflight)) if (atomic_long_dec_and_test(&u->inflight)) list_del_init(&u->link); list_del_init(&u->link); unix_tot_inflight--; unix_tot_inflight--; Loading @@ -161,32 +161,27 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), spin_lock(&x->sk_receive_queue.lock); spin_lock(&x->sk_receive_queue.lock); skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { /* /* Do we have file descriptors ? */ * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { if (UNIXCB(skb).fp) { bool hit = false; bool hit = false; /* /* Process the descriptors of this socket */ * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { while (nfd--) { /* /* Get the socket the fd matches if it indeed does so */ * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); struct sock *sk = unix_get_socket(*fp++); if (sk) { if (sk) { struct unix_sock *u = unix_sk(sk); struct unix_sock *u = unix_sk(sk); /* /* Ignore non-candidates, they could * Ignore non-candidates, they could * have been added to the queues after * have been added to the queues after * starting the garbage collection * starting the garbage collection */ */ if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { hit = true; hit = true; func(u); func(u); } } } } Loading @@ -203,24 +198,22 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), static void scan_children(struct sock *x, void (*func)(struct unix_sock *), static void scan_children(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) struct sk_buff_head *hitlist) { { if (x->sk_state != TCP_LISTEN) if (x->sk_state != TCP_LISTEN) { scan_inflight(x, func, hitlist); scan_inflight(x, func, hitlist); else { } else { struct sk_buff *skb; struct sk_buff *skb; struct sk_buff *next; struct sk_buff *next; struct unix_sock *u; struct unix_sock *u; LIST_HEAD(embryos); LIST_HEAD(embryos); /* /* For a listening socket collect the queued embryos * For a listening socket collect the queued embryos * and perform a scan on them as well. * and perform a scan on them as well. */ */ spin_lock(&x->sk_receive_queue.lock); spin_lock(&x->sk_receive_queue.lock); skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { u = unix_sk(skb->sk); u = unix_sk(skb->sk); /* /* An embryo cannot be in-flight, so it's safe * An embryo cannot be in-flight, so it's safe * to use the list link. * to use the list link. */ */ BUG_ON(!list_empty(&u->link)); BUG_ON(!list_empty(&u->link)); Loading Loading @@ -249,8 +242,7 @@ static void inc_inflight(struct unix_sock *usk) static void inc_inflight_move_tail(struct unix_sock *u) static void inc_inflight_move_tail(struct unix_sock *u) { { atomic_long_inc(&u->inflight); atomic_long_inc(&u->inflight); /* /* If this still might be part of a cycle, move it to the end * If this still might be part of a cycle, move it to the end * of the list, so that it's checked even if it was already * of the list, so that it's checked even if it was already * passed over * passed over */ */ Loading @@ -263,8 +255,7 @@ static bool gc_in_progress; void wait_for_unix_gc(void) void wait_for_unix_gc(void) { { /* /* If number of inflight sockets is insane, * If number of inflight sockets is insane, * force a garbage collect right now. * force a garbage collect right now. */ */ if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) Loading @@ -288,8 +279,7 @@ void unix_gc(void) goto out; goto out; gc_in_progress = true; gc_in_progress = true; /* /* First, select candidates for garbage collection. Only * First, select candidates for garbage collection. Only * in-flight sockets are considered, and from those only ones * in-flight sockets are considered, and from those only ones * which don't have any external reference. * which don't have any external reference. * * Loading Loading @@ -320,15 +310,13 @@ void unix_gc(void) } } } } /* /* Now remove all internal in-flight reference to children of * Now remove all internal in-flight reference to children of * the candidates. * the candidates. */ */ list_for_each_entry(u, &gc_candidates, link) list_for_each_entry(u, &gc_candidates, link) scan_children(&u->sk, dec_inflight, NULL); scan_children(&u->sk, dec_inflight, NULL); /* /* Restore the references for children of all candidates, * Restore the references for children of all candidates, * which have remaining references. Do this recursively, so * which have remaining references. Do this recursively, so * only those remain, which form cyclic references. * only those remain, which form cyclic references. * * Loading @@ -350,8 +338,7 @@ void unix_gc(void) } } list_del(&cursor); list_del(&cursor); /* /* not_cycle_list contains those sockets which do not make up a * not_cycle_list contains those sockets which do not make up a * cycle. Restore these to the inflight list. * cycle. Restore these to the inflight list. */ */ while (!list_empty(¬_cycle_list)) { while (!list_empty(¬_cycle_list)) { Loading @@ -360,8 +347,7 @@ void unix_gc(void) list_move_tail(&u->link, &gc_inflight_list); list_move_tail(&u->link, &gc_inflight_list); } } /* /* Now gc_candidates contains only garbage. Restore original * Now gc_candidates contains only garbage. Restore original * inflight counters for these as well, and remove the skbuffs * inflight counters for these as well, and remove the skbuffs * which are creating the cycle(s). * which are creating the cycle(s). */ */ Loading Loading
net/unix/garbage.c +28 −42 Original line number Original line Diff line number Diff line Loading @@ -95,39 +95,36 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); unsigned int unix_tot_inflight; unsigned int unix_tot_inflight; struct sock *unix_get_socket(struct file *filp) struct sock *unix_get_socket(struct file *filp) { { struct sock *u_sock = NULL; struct sock *u_sock = NULL; struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp); /* /* Socket ? */ * Socket ? */ if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { struct socket *sock = SOCKET_I(inode); struct socket *sock = SOCKET_I(inode); struct sock *s = sock->sk; struct sock *s = sock->sk; /* /* PF_UNIX ? */ * PF_UNIX ? */ if (s && sock->ops && sock->ops->family == PF_UNIX) if (s && sock->ops && sock->ops->family == PF_UNIX) u_sock = s; u_sock = s; } } return u_sock; return u_sock; } } /* /* Keep the number of times in flight count for the file * Keep the number of times in flight count for the file * descriptor if it is for an AF_UNIX socket. * descriptor if it is for an AF_UNIX socket. */ */ void unix_inflight(struct file *fp) void unix_inflight(struct file *fp) { { struct sock *s = unix_get_socket(fp); struct sock *s = unix_get_socket(fp); if (s) { if (s) { struct unix_sock *u = unix_sk(s); struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); spin_lock(&unix_gc_lock); if (atomic_long_inc_return(&u->inflight) == 1) { if (atomic_long_inc_return(&u->inflight) == 1) { BUG_ON(!list_empty(&u->link)); BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); list_add_tail(&u->link, &gc_inflight_list); Loading @@ -142,10 +139,13 @@ void unix_inflight(struct file *fp) void unix_notinflight(struct file *fp) void unix_notinflight(struct file *fp) { { struct sock *s = unix_get_socket(fp); struct sock *s = unix_get_socket(fp); if (s) { if (s) { struct unix_sock *u = unix_sk(s); struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); spin_lock(&unix_gc_lock); BUG_ON(list_empty(&u->link)); BUG_ON(list_empty(&u->link)); if (atomic_long_dec_and_test(&u->inflight)) if (atomic_long_dec_and_test(&u->inflight)) list_del_init(&u->link); list_del_init(&u->link); unix_tot_inflight--; unix_tot_inflight--; Loading @@ -161,32 +161,27 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), spin_lock(&x->sk_receive_queue.lock); spin_lock(&x->sk_receive_queue.lock); skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { /* /* Do we have file descriptors ? */ * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { if (UNIXCB(skb).fp) { bool hit = false; bool hit = false; /* /* Process the descriptors of this socket */ * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { while (nfd--) { /* /* Get the socket the fd matches if it indeed does so */ * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); struct sock *sk = unix_get_socket(*fp++); if (sk) { if (sk) { struct unix_sock *u = unix_sk(sk); struct unix_sock *u = unix_sk(sk); /* /* Ignore non-candidates, they could * Ignore non-candidates, they could * have been added to the queues after * have been added to the queues after * starting the garbage collection * starting the garbage collection */ */ if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) { hit = true; hit = true; func(u); func(u); } } } } Loading @@ -203,24 +198,22 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), static void scan_children(struct sock *x, void (*func)(struct unix_sock *), static void scan_children(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) struct sk_buff_head *hitlist) { { if (x->sk_state != TCP_LISTEN) if (x->sk_state != TCP_LISTEN) { scan_inflight(x, func, hitlist); scan_inflight(x, func, hitlist); else { } else { struct sk_buff *skb; struct sk_buff *skb; struct sk_buff *next; struct sk_buff *next; struct unix_sock *u; struct unix_sock *u; LIST_HEAD(embryos); LIST_HEAD(embryos); /* /* For a listening socket collect the queued embryos * For a listening socket collect the queued embryos * and perform a scan on them as well. * and perform a scan on them as well. */ */ spin_lock(&x->sk_receive_queue.lock); spin_lock(&x->sk_receive_queue.lock); skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { skb_queue_walk_safe(&x->sk_receive_queue, skb, next) { u = unix_sk(skb->sk); u = unix_sk(skb->sk); /* /* An embryo cannot be in-flight, so it's safe * An embryo cannot be in-flight, so it's safe * to use the list link. * to use the list link. */ */ BUG_ON(!list_empty(&u->link)); BUG_ON(!list_empty(&u->link)); Loading Loading @@ -249,8 +242,7 @@ static void inc_inflight(struct unix_sock *usk) static void inc_inflight_move_tail(struct unix_sock *u) static void inc_inflight_move_tail(struct unix_sock *u) { { atomic_long_inc(&u->inflight); atomic_long_inc(&u->inflight); /* /* If this still might be part of a cycle, move it to the end * If this still might be part of a cycle, move it to the end * of the list, so that it's checked even if it was already * of the list, so that it's checked even if it was already * passed over * passed over */ */ Loading @@ -263,8 +255,7 @@ static bool gc_in_progress; void wait_for_unix_gc(void) void wait_for_unix_gc(void) { { /* /* If number of inflight sockets is insane, * If number of inflight sockets is insane, * force a garbage collect right now. * force a garbage collect right now. */ */ if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) Loading @@ -288,8 +279,7 @@ void unix_gc(void) goto out; goto out; gc_in_progress = true; gc_in_progress = true; /* /* First, select candidates for garbage collection. Only * First, select candidates for garbage collection. Only * in-flight sockets are considered, and from those only ones * in-flight sockets are considered, and from those only ones * which don't have any external reference. * which don't have any external reference. * * Loading Loading @@ -320,15 +310,13 @@ void unix_gc(void) } } } } /* /* Now remove all internal in-flight reference to children of * Now remove all internal in-flight reference to children of * the candidates. * the candidates. */ */ list_for_each_entry(u, &gc_candidates, link) list_for_each_entry(u, &gc_candidates, link) scan_children(&u->sk, dec_inflight, NULL); scan_children(&u->sk, dec_inflight, NULL); /* /* Restore the references for children of all candidates, * Restore the references for children of all candidates, * which have remaining references. Do this recursively, so * which have remaining references. Do this recursively, so * only those remain, which form cyclic references. * only those remain, which form cyclic references. * * Loading @@ -350,8 +338,7 @@ void unix_gc(void) } } list_del(&cursor); list_del(&cursor); /* /* not_cycle_list contains those sockets which do not make up a * not_cycle_list contains those sockets which do not make up a * cycle. Restore these to the inflight list. * cycle. Restore these to the inflight list. */ */ while (!list_empty(¬_cycle_list)) { while (!list_empty(¬_cycle_list)) { Loading @@ -360,8 +347,7 @@ void unix_gc(void) list_move_tail(&u->link, &gc_inflight_list); list_move_tail(&u->link, &gc_inflight_list); } } /* /* Now gc_candidates contains only garbage. Restore original * Now gc_candidates contains only garbage. Restore original * inflight counters for these as well, and remove the skbuffs * inflight counters for these as well, and remove the skbuffs * which are creating the cycle(s). * which are creating the cycle(s). */ */ Loading