mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +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; | 	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 */ | /* Initialize the poll safe wake up structure */ | ||||||
| static void ep_nested_calls_init(struct nested_calls *ncalls) | 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); | 	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 error; | ||||||
| 	int full_check = 0; | 	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 | 	 * deep wakeup paths from forming in parallel through multiple | ||||||
| 	 * EPOLL_CTL_ADD operations. | 	 * 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 (op == EPOLL_CTL_ADD) { | ||||||
| 		if (!list_empty(&f.file->f_ep_links) || | 		if (!list_empty(&f.file->f_ep_links) || | ||||||
| 						is_file_epoll(tf.file)) { | 						is_file_epoll(tf.file)) { | ||||||
| 			full_check = 1; |  | ||||||
| 			mutex_unlock(&ep->mtx); | 			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)) { | 			if (is_file_epoll(tf.file)) { | ||||||
| 				error = -ELOOP; | 				error = -ELOOP; | ||||||
| 				if (ep_loop_check(ep, tf.file) != 0) { | 				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 | 			} else | ||||||
| 				list_add(&tf.file->f_tfile_llink, | 				list_add(&tf.file->f_tfile_llink, | ||||||
| 							&tfile_check_list); | 							&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)) { | 			if (is_file_epoll(tf.file)) { | ||||||
| 				tep = tf.file->private_data; | 				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))) | 	    copy_from_user(&epds, event, sizeof(struct epoll_event))) | ||||||
| 		return -EFAULT; | 		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); | 	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 | #else | ||||||
| 
 | 
 | ||||||
| static inline void eventpoll_init_file(struct file *file) {} | static inline void eventpoll_init_file(struct file *file) {} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jens Axboe
						Jens Axboe