вот так выглядит более правильно diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 3c8af63..7ca2e4f 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -6,7 +6,7 @@ #include <linux/mutex.h> #include <net/sock.h> -extern void unix_inflight(struct file *fp); +extern int unix_inflight(struct file *fp); extern void unix_notinflight(struct file *fp); extern void unix_gc(void); extern void wait_for_unix_gc(void); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index cb552e2..673ea9c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -572,11 +572,17 @@ static struct proto unix_proto = { */ static struct lock_class_key af_unix_sk_receive_queue_lock_key; +#define UNIX_INFLIGHT_TRIGGER_GC 128 +extern bool gc_in_progress; + static struct sock * unix_create1(struct socket *sock) { struct sock *sk = NULL; struct unix_sock *u; + if (atomic_read(&unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) + unix_gc(); + if (atomic_read(&unix_nr_socks) >= 2*get_max_files()) goto out; @@ -1268,6 +1274,7 @@ EXPORT_SYMBOL_GPL(unix_destruct_fds); static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; + int rc = 0; /* * Need to duplicate file references for the sake of garbage @@ -1278,10 +1285,13 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) if (!UNIXCB(skb).fp) return -ENOMEM; - for (i=scm->fp->count-1; i>=0; i--) - unix_inflight(scm->fp->fp[i]); + for (i=scm->fp->count-1; i>=0; i--) { + rc = unix_inflight(scm->fp->fp[i]); + if (rc) + break; + } skb->destructor = unix_destruct_fds; - return 0; + return rc; } /* diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 5f96cea..4042e9a 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -124,21 +124,25 @@ static struct sock *unix_get_socket(struct file *filp) * descriptor if it is for an AF_UNIX socket. */ -void unix_inflight(struct file *fp) +int unix_inflight(struct file *fp) { + int ret = 0; struct sock *s = unix_get_socket(fp); if(s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); - if (atomic_inc_return(&u->inflight) == 1) { + ret = atomic_inc_return(&u->inflight); + if (ret == 1) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); } else { BUG_ON(list_empty(&u->link)); } atomic_inc(&unix_tot_inflight); + ret = ret > get_max_files(); spin_unlock(&unix_gc_lock); } + return ret; } EXPORT_SYMBOL_GPL(unix_notinflight); @@ -270,7 +274,7 @@ static void inc_inflight_move_tail(struct unix_sock *u) list_move_tail(&u->link, &gc_candidates); } -static bool gc_in_progress = false; +bool gc_in_progress = false; void wait_for_unix_gc(void) { ну и для параноиков sysctl -w fs.files-max=1000
|