diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2018-06-22 22:20:35 +0300 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2018-06-22 22:20:35 +0300 | 
| commit | 7731b8bc94e599c9a79e428f3359ff2c34b7576a (patch) | |
| tree | 879f18ccbe274122f2d4f095b43cbc7f953e0ada /net/socket.c | |
| parent | 48e315618dc4dc8904182cd221e3d395d5d97005 (diff) | |
| parent | 9ffc59d57228d74809700be6f7ecb1db10292f05 (diff) | |
| download | linux-7731b8bc94e599c9a79e428f3359ff2c34b7576a.tar.xz | |
Merge branch 'linus' into x86/urgent
Required to queue a dependent fix.
Diffstat (limited to 'net/socket.c')
| -rw-r--r-- | net/socket.c | 80 | 
1 files changed, 62 insertions, 18 deletions
diff --git a/net/socket.c b/net/socket.c index f10f1d947c78..8a109012608a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -117,8 +117,10 @@ static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);  static int sock_mmap(struct file *file, struct vm_area_struct *vma);  static int sock_close(struct inode *inode, struct file *file); -static __poll_t sock_poll(struct file *file, -			      struct poll_table_struct *wait); +static struct wait_queue_head *sock_get_poll_head(struct file *file, +		__poll_t events); +static __poll_t sock_poll_mask(struct file *file, __poll_t); +static __poll_t sock_poll(struct file *file, struct poll_table_struct *wait);  static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg);  #ifdef CONFIG_COMPAT  static long compat_sock_ioctl(struct file *file, @@ -141,6 +143,8 @@ static const struct file_operations socket_file_ops = {  	.llseek =	no_llseek,  	.read_iter =	sock_read_iter,  	.write_iter =	sock_write_iter, +	.get_poll_head = sock_get_poll_head, +	.poll_mask =	sock_poll_mask,  	.poll =		sock_poll,  	.unlocked_ioctl = sock_ioctl,  #ifdef CONFIG_COMPAT @@ -537,7 +541,10 @@ static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)  	if (!err && (iattr->ia_valid & ATTR_UID)) {  		struct socket *sock = SOCKET_I(d_inode(dentry)); -		sock->sk->sk_uid = iattr->ia_uid; +		if (sock->sk) +			sock->sk->sk_uid = iattr->ia_uid; +		else +			err = -ENOENT;  	}  	return err; @@ -586,12 +593,16 @@ EXPORT_SYMBOL(sock_alloc);   *	an inode not a file.   */ -void sock_release(struct socket *sock) +static void __sock_release(struct socket *sock, struct inode *inode)  {  	if (sock->ops) {  		struct module *owner = sock->ops->owner; +		if (inode) +			inode_lock(inode);  		sock->ops->release(sock); +		if (inode) +			inode_unlock(inode);  		sock->ops = NULL;  		module_put(owner);  	} @@ -605,6 +616,11 @@ void sock_release(struct socket *sock)  	}  	sock->file = NULL;  } + +void sock_release(struct socket *sock) +{ +	__sock_release(sock, NULL); +}  EXPORT_SYMBOL(sock_release);  void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags) @@ -1114,27 +1130,48 @@ out_release:  }  EXPORT_SYMBOL(sock_create_lite); -/* No kernel lock held - perfect */ -static __poll_t sock_poll(struct file *file, poll_table *wait) +static struct wait_queue_head *sock_get_poll_head(struct file *file, +		__poll_t events)  { -	__poll_t busy_flag = 0; -	struct socket *sock; +	struct socket *sock = file->private_data; + +	if (!sock->ops->poll_mask) +		return NULL; +	sock_poll_busy_loop(sock, events); +	return sk_sleep(sock->sk); +} + +static __poll_t sock_poll_mask(struct file *file, __poll_t events) +{ +	struct socket *sock = file->private_data;  	/* -	 *      We can't return errors to poll, so it's either yes or no. +	 * We need to be sure we are in sync with the socket flags modification. +	 * +	 * This memory barrier is paired in the wq_has_sleeper.  	 */ -	sock = file->private_data; +	smp_mb(); -	if (sk_can_busy_loop(sock->sk)) { -		/* this socket can poll_ll so tell the system call */ -		busy_flag = POLL_BUSY_LOOP; +	/* this socket can poll_ll so tell the system call */ +	return sock->ops->poll_mask(sock, events) | +		(sk_can_busy_loop(sock->sk) ? POLL_BUSY_LOOP : 0); +} + +/* No kernel lock held - perfect */ +static __poll_t sock_poll(struct file *file, poll_table *wait) +{ +	struct socket *sock = file->private_data; +	__poll_t events = poll_requested_events(wait), mask = 0; -		/* once, only if requested by syscall */ -		if (wait && (wait->_key & POLL_BUSY_LOOP)) -			sk_busy_loop(sock->sk, 1); +	if (sock->ops->poll) { +		sock_poll_busy_loop(sock, events); +		mask = sock->ops->poll(file, sock, wait); +	} else if (sock->ops->poll_mask) { +		sock_poll_wait(file, sock_get_poll_head(file, events), wait); +		mask = sock->ops->poll_mask(sock, events);  	} -	return busy_flag | sock->ops->poll(file, sock, wait); +	return mask | sock_poll_busy_flag(sock);  }  static int sock_mmap(struct file *file, struct vm_area_struct *vma) @@ -1146,7 +1183,7 @@ static int sock_mmap(struct file *file, struct vm_area_struct *vma)  static int sock_close(struct inode *inode, struct file *filp)  { -	sock_release(SOCKET_I(inode)); +	__sock_release(SOCKET_I(inode), inode);  	return 0;  } @@ -1420,6 +1457,13 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec)  		goto out;  	} +	err = security_socket_socketpair(sock1, sock2); +	if (unlikely(err)) { +		sock_release(sock2); +		sock_release(sock1); +		goto out; +	} +  	err = sock1->ops->socketpair(sock1, sock2);  	if (unlikely(err < 0)) {  		sock_release(sock2);  | 
