forked from mirrors/linux
		
	net: add support for ->poll_mask in proto_ops
The socket file operations still implement ->poll until all protocols are switched over. Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
		
							parent
							
								
									3cafb37633
								
							
						
					
					
						commit
						1525242310
					
				
					 2 changed files with 44 additions and 5 deletions
				
			
		|  | @ -147,6 +147,7 @@ struct proto_ops { | ||||||
| 	int		(*getname)   (struct socket *sock, | 	int		(*getname)   (struct socket *sock, | ||||||
| 				      struct sockaddr *addr, | 				      struct sockaddr *addr, | ||||||
| 				      int peer); | 				      int peer); | ||||||
|  | 	__poll_t	(*poll_mask) (struct socket *sock, __poll_t events); | ||||||
| 	__poll_t	(*poll)	     (struct file *file, struct socket *sock, | 	__poll_t	(*poll)	     (struct file *file, struct socket *sock, | ||||||
| 				      struct poll_table_struct *wait); | 				      struct poll_table_struct *wait); | ||||||
| 	int		(*ioctl)     (struct socket *sock, unsigned int cmd, | 	int		(*ioctl)     (struct socket *sock, unsigned int cmd, | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								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_mmap(struct file *file, struct vm_area_struct *vma); | ||||||
| 
 | 
 | ||||||
| static int sock_close(struct inode *inode, struct file *file); | static int sock_close(struct inode *inode, struct file *file); | ||||||
| static __poll_t sock_poll(struct file *file, | static struct wait_queue_head *sock_get_poll_head(struct file *file, | ||||||
| 			      struct poll_table_struct *wait); | 		__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); | static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | ||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
| static long compat_sock_ioctl(struct file *file, | static long compat_sock_ioctl(struct file *file, | ||||||
|  | @ -141,6 +143,8 @@ static const struct file_operations socket_file_ops = { | ||||||
| 	.llseek =	no_llseek, | 	.llseek =	no_llseek, | ||||||
| 	.read_iter =	sock_read_iter, | 	.read_iter =	sock_read_iter, | ||||||
| 	.write_iter =	sock_write_iter, | 	.write_iter =	sock_write_iter, | ||||||
|  | 	.get_poll_head = sock_get_poll_head, | ||||||
|  | 	.poll_mask =	sock_poll_mask, | ||||||
| 	.poll =		sock_poll, | 	.poll =		sock_poll, | ||||||
| 	.unlocked_ioctl = sock_ioctl, | 	.unlocked_ioctl = sock_ioctl, | ||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
|  | @ -1114,14 +1118,48 @@ int sock_create_lite(int family, int type, int protocol, struct socket **res) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(sock_create_lite); | EXPORT_SYMBOL(sock_create_lite); | ||||||
| 
 | 
 | ||||||
|  | static struct wait_queue_head *sock_get_poll_head(struct file *file, | ||||||
|  | 		__poll_t events) | ||||||
|  | { | ||||||
|  | 	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 need to be sure we are in sync with the socket flags modification. | ||||||
|  | 	 * | ||||||
|  | 	 * This memory barrier is paired in the wq_has_sleeper. | ||||||
|  | 	 */ | ||||||
|  | 	smp_mb(); | ||||||
|  | 
 | ||||||
|  | 	/* 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 */ | /* No kernel lock held - perfect */ | ||||||
| static __poll_t sock_poll(struct file *file, poll_table *wait) | static __poll_t sock_poll(struct file *file, poll_table *wait) | ||||||
| { | { | ||||||
| 	struct socket *sock = file->private_data; | 	struct socket *sock = file->private_data; | ||||||
| 	__poll_t events = poll_requested_events(wait); | 	__poll_t events = poll_requested_events(wait), mask = 0; | ||||||
| 
 | 
 | ||||||
|  | 	if (sock->ops->poll) { | ||||||
| 		sock_poll_busy_loop(sock, events); | 		sock_poll_busy_loop(sock, events); | ||||||
| 	return sock->ops->poll(file, sock, wait) | sock_poll_busy_flag(sock); | 		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 mask | sock_poll_busy_flag(sock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int sock_mmap(struct file *file, struct vm_area_struct *vma) | static int sock_mmap(struct file *file, struct vm_area_struct *vma) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Christoph Hellwig
						Christoph Hellwig