mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +02:00 
			
		
		
		
	eventpoll: support non-blocking do_epoll_ctl() calls
Also make it available outside of epoll, along with the helper that decides if we need to copy the passed in epoll_event. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									58e41a44c4
								
							
						
					
					
						commit
						39220e8d4a
					
				
					 2 changed files with 42 additions and 13 deletions
				
			
		|  | @ -354,12 +354,6 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p) | |||
| 	return container_of(p, struct ep_pqueue, pt)->epi; | ||||
| } | ||||
| 
 | ||||
| /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | ||||
| static inline int ep_op_has_event(int op) | ||||
| { | ||||
| 	return op != EPOLL_CTL_DEL; | ||||
| } | ||||
| 
 | ||||
| /* Initialize the poll safe wake up structure */ | ||||
| static void ep_nested_calls_init(struct nested_calls *ncalls) | ||||
| { | ||||
|  | @ -2074,7 +2068,20 @@ SYSCALL_DEFINE1(epoll_create, int, size) | |||
| 	return do_epoll_create(0); | ||||
| } | ||||
| 
 | ||||
| static int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds) | ||||
| static inline int epoll_mutex_lock(struct mutex *mutex, int depth, | ||||
| 				   bool nonblock) | ||||
| { | ||||
| 	if (!nonblock) { | ||||
| 		mutex_lock_nested(mutex, depth); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (mutex_trylock(mutex)) | ||||
| 		return 0; | ||||
| 	return -EAGAIN; | ||||
| } | ||||
| 
 | ||||
| int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, | ||||
| 		 bool nonblock) | ||||
| { | ||||
| 	int error; | ||||
| 	int full_check = 0; | ||||
|  | @ -2145,13 +2152,17 @@ static int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds) | |||
| 	 * deep wakeup paths from forming in parallel through multiple | ||||
| 	 * EPOLL_CTL_ADD operations. | ||||
| 	 */ | ||||
| 	mutex_lock_nested(&ep->mtx, 0); | ||||
| 	error = epoll_mutex_lock(&ep->mtx, 0, nonblock); | ||||
| 	if (error) | ||||
| 		goto error_tgt_fput; | ||||
| 	if (op == EPOLL_CTL_ADD) { | ||||
| 		if (!list_empty(&f.file->f_ep_links) || | ||||
| 						is_file_epoll(tf.file)) { | ||||
| 			full_check = 1; | ||||
| 			mutex_unlock(&ep->mtx); | ||||
| 			mutex_lock(&epmutex); | ||||
| 			error = epoll_mutex_lock(&epmutex, 0, nonblock); | ||||
| 			if (error) | ||||
| 				goto error_tgt_fput; | ||||
| 			full_check = 1; | ||||
| 			if (is_file_epoll(tf.file)) { | ||||
| 				error = -ELOOP; | ||||
| 				if (ep_loop_check(ep, tf.file) != 0) { | ||||
|  | @ -2161,10 +2172,19 @@ static int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds) | |||
| 			} else | ||||
| 				list_add(&tf.file->f_tfile_llink, | ||||
| 							&tfile_check_list); | ||||
| 			mutex_lock_nested(&ep->mtx, 0); | ||||
| 			error = epoll_mutex_lock(&ep->mtx, 0, nonblock); | ||||
| 			if (error) { | ||||
| out_del: | ||||
| 				list_del(&tf.file->f_tfile_llink); | ||||
| 				goto error_tgt_fput; | ||||
| 			} | ||||
| 			if (is_file_epoll(tf.file)) { | ||||
| 				tep = tf.file->private_data; | ||||
| 				mutex_lock_nested(&tep->mtx, 1); | ||||
| 				error = epoll_mutex_lock(&tep->mtx, 1, nonblock); | ||||
| 				if (error) { | ||||
| 					mutex_unlock(&ep->mtx); | ||||
| 					goto out_del; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -2233,7 +2253,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, | |||
| 	    copy_from_user(&epds, event, sizeof(struct epoll_event))) | ||||
| 		return -EFAULT; | ||||
| 
 | ||||
| 	return do_epoll_ctl(epfd, op, fd, &epds); | ||||
| 	return do_epoll_ctl(epfd, op, fd, &epds, false); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -61,6 +61,15 @@ static inline void eventpoll_release(struct file *file) | |||
| 	eventpoll_release_file(file); | ||||
| } | ||||
| 
 | ||||
| int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, | ||||
| 		 bool nonblock); | ||||
| 
 | ||||
| /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | ||||
| static inline int ep_op_has_event(int op) | ||||
| { | ||||
| 	return op != EPOLL_CTL_DEL; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static inline void eventpoll_init_file(struct file *file) {} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jens Axboe
						Jens Axboe