diff options
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 111 | 
1 files changed, 49 insertions, 62 deletions
| diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f1dffe84f0d5..8309687a56b0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -661,11 +661,11 @@ static int unix_set_peek_off(struct sock *sk, int val)  {  	struct unix_sock *u = unix_sk(sk); -	if (mutex_lock_interruptible(&u->readlock)) +	if (mutex_lock_interruptible(&u->iolock))  		return -EINTR;  	sk->sk_peek_off = val; -	mutex_unlock(&u->readlock); +	mutex_unlock(&u->iolock);  	return 0;  } @@ -779,7 +779,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)  	spin_lock_init(&u->lock);  	atomic_long_set(&u->inflight, 0);  	INIT_LIST_HEAD(&u->link); -	mutex_init(&u->readlock); /* single task reading lock */ +	mutex_init(&u->iolock); /* single task reading lock */ +	mutex_init(&u->bindlock); /* single task binding lock */  	init_waitqueue_head(&u->peer_wait);  	init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);  	unix_insert_socket(unix_sockets_unbound(sk), sk); @@ -848,7 +849,7 @@ static int unix_autobind(struct socket *sock)  	int err;  	unsigned int retries = 0; -	err = mutex_lock_interruptible(&u->readlock); +	err = mutex_lock_interruptible(&u->bindlock);  	if (err)  		return err; @@ -895,7 +896,7 @@ retry:  	spin_unlock(&unix_table_lock);  	err = 0; -out:	mutex_unlock(&u->readlock); +out:	mutex_unlock(&u->bindlock);  	return err;  } @@ -954,20 +955,32 @@ fail:  	return NULL;  } -static int unix_mknod(struct dentry *dentry, const struct path *path, umode_t mode, -		      struct path *res) +static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)  { -	int err; +	struct dentry *dentry; +	struct path path; +	int err = 0; +	/* +	 * Get the parent directory, calculate the hash for last +	 * component. +	 */ +	dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); +	err = PTR_ERR(dentry); +	if (IS_ERR(dentry)) +		return err; -	err = security_path_mknod(path, dentry, mode, 0); +	/* +	 * All right, let's create it. +	 */ +	err = security_path_mknod(&path, dentry, mode, 0);  	if (!err) { -		err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0); +		err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);  		if (!err) { -			res->mnt = mntget(path->mnt); +			res->mnt = mntget(path.mnt);  			res->dentry = dget(dentry);  		}  	} - +	done_path_create(&path, dentry);  	return err;  } @@ -978,12 +991,10 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  	struct unix_sock *u = unix_sk(sk);  	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;  	char *sun_path = sunaddr->sun_path; -	int err, name_err; +	int err;  	unsigned int hash;  	struct unix_address *addr;  	struct hlist_head *list; -	struct path path; -	struct dentry *dentry;  	err = -EINVAL;  	if (sunaddr->sun_family != AF_UNIX) @@ -999,34 +1010,14 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  		goto out;  	addr_len = err; -	name_err = 0; -	dentry = NULL; -	if (sun_path[0]) { -		/* Get the parent directory, calculate the hash for last -		 * component. -		 */ -		dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); - -		if (IS_ERR(dentry)) { -			/* delay report until after 'already bound' check */ -			name_err = PTR_ERR(dentry); -			dentry = NULL; -		} -	} - -	err = mutex_lock_interruptible(&u->readlock); +	err = mutex_lock_interruptible(&u->bindlock);  	if (err) -		goto out_path; +		goto out;  	err = -EINVAL;  	if (u->addr)  		goto out_up; -	if (name_err) { -		err = name_err == -EEXIST ? -EADDRINUSE : name_err; -		goto out_up; -	} -  	err = -ENOMEM;  	addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);  	if (!addr) @@ -1037,11 +1028,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  	addr->hash = hash ^ sk->sk_type;  	atomic_set(&addr->refcnt, 1); -	if (dentry) { -		struct path u_path; +	if (sun_path[0]) { +		struct path path;  		umode_t mode = S_IFSOCK |  		       (SOCK_INODE(sock)->i_mode & ~current_umask()); -		err = unix_mknod(dentry, &path, mode, &u_path); +		err = unix_mknod(sun_path, mode, &path);  		if (err) {  			if (err == -EEXIST)  				err = -EADDRINUSE; @@ -1049,9 +1040,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  			goto out_up;  		}  		addr->hash = UNIX_HASH_SIZE; -		hash = d_real_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1); +		hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);  		spin_lock(&unix_table_lock); -		u->path = u_path; +		u->path = path;  		list = &unix_socket_table[hash];  	} else {  		spin_lock(&unix_table_lock); @@ -1073,11 +1064,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)  out_unlock:  	spin_unlock(&unix_table_lock);  out_up: -	mutex_unlock(&u->readlock); -out_path: -	if (dentry) -		done_path_create(&path, dentry); - +	mutex_unlock(&u->bindlock);  out:  	return err;  } @@ -1969,17 +1956,17 @@ static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,  	if (false) {  alloc_skb:  		unix_state_unlock(other); -		mutex_unlock(&unix_sk(other)->readlock); +		mutex_unlock(&unix_sk(other)->iolock);  		newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT,  					      &err, 0);  		if (!newskb)  			goto err;  	} -	/* we must acquire readlock as we modify already present +	/* we must acquire iolock as we modify already present  	 * skbs in the sk_receive_queue and mess with skb->len  	 */ -	err = mutex_lock_interruptible(&unix_sk(other)->readlock); +	err = mutex_lock_interruptible(&unix_sk(other)->iolock);  	if (err) {  		err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS;  		goto err; @@ -2046,7 +2033,7 @@ alloc_skb:  	}  	unix_state_unlock(other); -	mutex_unlock(&unix_sk(other)->readlock); +	mutex_unlock(&unix_sk(other)->iolock);  	other->sk_data_ready(other);  	scm_destroy(&scm); @@ -2055,7 +2042,7 @@ alloc_skb:  err_state_unlock:  	unix_state_unlock(other);  err_unlock: -	mutex_unlock(&unix_sk(other)->readlock); +	mutex_unlock(&unix_sk(other)->iolock);  err:  	kfree_skb(newskb);  	if (send_sigpipe && !(flags & MSG_NOSIGNAL)) @@ -2123,7 +2110,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,  	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);  	do { -		mutex_lock(&u->readlock); +		mutex_lock(&u->iolock);  		skip = sk_peek_offset(sk, flags);  		skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err, @@ -2131,14 +2118,14 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,  		if (skb)  			break; -		mutex_unlock(&u->readlock); +		mutex_unlock(&u->iolock);  		if (err != -EAGAIN)  			break;  	} while (timeo &&  		 !__skb_wait_for_more_packets(sk, &err, &timeo, last)); -	if (!skb) { /* implies readlock unlocked */ +	if (!skb) { /* implies iolock unlocked */  		unix_state_lock(sk);  		/* Signal EOF on disconnected non-blocking SEQPACKET socket. */  		if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN && @@ -2203,7 +2190,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,  out_free:  	skb_free_datagram(sk, skb); -	mutex_unlock(&u->readlock); +	mutex_unlock(&u->iolock);  out:  	return err;  } @@ -2298,7 +2285,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)  	/* Lock the socket to prevent queue disordering  	 * while sleeps in memcpy_tomsg  	 */ -	mutex_lock(&u->readlock); +	mutex_lock(&u->iolock);  	if (flags & MSG_PEEK)  		skip = sk_peek_offset(sk, flags); @@ -2340,7 +2327,7 @@ again:  				break;  			} -			mutex_unlock(&u->readlock); +			mutex_unlock(&u->iolock);  			timeo = unix_stream_data_wait(sk, timeo, last,  						      last_len); @@ -2351,7 +2338,7 @@ again:  				goto out;  			} -			mutex_lock(&u->readlock); +			mutex_lock(&u->iolock);  			goto redo;  unlock:  			unix_state_unlock(sk); @@ -2454,7 +2441,7 @@ unlock:  		}  	} while (size); -	mutex_unlock(&u->readlock); +	mutex_unlock(&u->iolock);  	if (state->msg)  		scm_recv(sock, state->msg, &scm, flags);  	else @@ -2495,9 +2482,9 @@ static ssize_t skb_unix_socket_splice(struct sock *sk,  	int ret;  	struct unix_sock *u = unix_sk(sk); -	mutex_unlock(&u->readlock); +	mutex_unlock(&u->iolock);  	ret = splice_to_pipe(pipe, spd); -	mutex_lock(&u->readlock); +	mutex_lock(&u->iolock);  	return ret;  } | 
