diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2010-12-22 18:57:02 +0100 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2010-12-22 18:57:02 +0100 | 
| commit | 4b7bd364700d9ac8372eff48832062b936d0793b (patch) | |
| tree | 0dbf78c95456a0b02d07fcd473281f04a87e266d /net/unix | |
| parent | c0d8768af260e2cbb4bf659ae6094a262c86b085 (diff) | |
| parent | 90a8a73c06cc32b609a880d48449d7083327e11a (diff) | |
| download | olio-linux-3.10-4b7bd364700d9ac8372eff48832062b936d0793b.tar.xz olio-linux-3.10-4b7bd364700d9ac8372eff48832062b936d0793b.zip  | |
Merge branch 'master' into for-next
Conflicts:
	MAINTAINERS
	arch/arm/mach-omap2/pm24xx.c
	drivers/scsi/bfa/bfa_fcpim.c
Needed to update to apply fixes for which the old branch was too
outdated.
Diffstat (limited to 'net/unix')
| -rw-r--r-- | net/unix/af_unix.c | 37 | ||||
| -rw-r--r-- | net/unix/garbage.c | 9 | 
2 files changed, 40 insertions, 6 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3c95304a081..2268e679812 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1343,9 +1343,25 @@ static void unix_destruct_scm(struct sk_buff *skb)  	sock_wfree(skb);  } +#define MAX_RECURSION_LEVEL 4 +  static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)  {  	int i; +	unsigned char max_level = 0; +	int unix_sock_count = 0; + +	for (i = scm->fp->count - 1; i >= 0; i--) { +		struct sock *sk = unix_get_socket(scm->fp->fp[i]); + +		if (sk) { +			unix_sock_count++; +			max_level = max(max_level, +					unix_sk(sk)->recursion_level); +		} +	} +	if (unlikely(max_level > MAX_RECURSION_LEVEL)) +		return -ETOOMANYREFS;  	/*  	 * Need to duplicate file references for the sake of garbage @@ -1356,9 +1372,11 @@ 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]); -	return 0; +	if (unix_sock_count) { +		for (i = scm->fp->count - 1; i >= 0; i--) +			unix_inflight(scm->fp->fp[i]); +	} +	return max_level;  }  static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) @@ -1393,6 +1411,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,  	struct sk_buff *skb;  	long timeo;  	struct scm_cookie tmp_scm; +	int max_level;  	if (NULL == siocb->scm)  		siocb->scm = &tmp_scm; @@ -1431,8 +1450,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,  		goto out;  	err = unix_scm_to_skb(siocb->scm, skb, true); -	if (err) +	if (err < 0)  		goto out_free; +	max_level = err + 1;  	unix_get_secdata(siocb->scm, skb);  	skb_reset_transport_header(skb); @@ -1514,6 +1534,8 @@ restart:  	if (sock_flag(other, SOCK_RCVTSTAMP))  		__net_timestamp(skb);  	skb_queue_tail(&other->sk_receive_queue, skb); +	if (max_level > unix_sk(other)->recursion_level) +		unix_sk(other)->recursion_level = max_level;  	unix_state_unlock(other);  	other->sk_data_ready(other, len);  	sock_put(other); @@ -1544,6 +1566,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,  	int sent = 0;  	struct scm_cookie tmp_scm;  	bool fds_sent = false; +	int max_level;  	if (NULL == siocb->scm)  		siocb->scm = &tmp_scm; @@ -1607,10 +1630,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,  		/* Only send the fds in the first buffer */  		err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); -		if (err) { +		if (err < 0) {  			kfree_skb(skb);  			goto out_err;  		} +		max_level = err + 1;  		fds_sent = true;  		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); @@ -1626,6 +1650,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,  			goto pipe_err_free;  		skb_queue_tail(&other->sk_receive_queue, skb); +		if (max_level > unix_sk(other)->recursion_level) +			unix_sk(other)->recursion_level = max_level;  		unix_state_unlock(other);  		other->sk_data_ready(other, size);  		sent += size; @@ -1845,6 +1871,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,  		unix_state_lock(sk);  		skb = skb_dequeue(&sk->sk_receive_queue);  		if (skb == NULL) { +			unix_sk(sk)->recursion_level = 0;  			if (copied >= target)  				goto unlock; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index c8df6fda0b1..f89f83bf828 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);  unsigned int unix_tot_inflight; -static struct sock *unix_get_socket(struct file *filp) +struct sock *unix_get_socket(struct file *filp)  {  	struct sock *u_sock = NULL;  	struct inode *inode = filp->f_path.dentry->d_inode; @@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u)  }  static bool gc_in_progress = false; +#define UNIX_INFLIGHT_TRIGGER_GC 16000  void wait_for_unix_gc(void)  { +	/* +	 * If number of inflight sockets is insane, +	 * force a garbage collect right now. +	 */ +	if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) +		unix_gc();  	wait_event(unix_gc_wait, gc_in_progress == false);  }  |