diff options
Diffstat (limited to 'fs/eventpoll.c')
| -rw-r--r-- | fs/eventpoll.c | 57 | 
1 files changed, 37 insertions, 20 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 9efb553b2b2b..1ba406615991 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1712,15 +1712,25 @@ static int ep_send_events(struct eventpoll *ep,  	return res;  } -static inline struct timespec64 ep_set_mstimeout(long ms) +static struct timespec64 *ep_timeout_to_timespec(struct timespec64 *to, long ms)  { -	struct timespec64 now, ts = { -		.tv_sec = ms / MSEC_PER_SEC, -		.tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC), -	}; +	struct timespec64 now; + +	if (ms < 0) +		return NULL; + +	if (!ms) { +		to->tv_sec = 0; +		to->tv_nsec = 0; +		return to; +	} + +	to->tv_sec = ms / MSEC_PER_SEC; +	to->tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC);  	ktime_get_ts64(&now); -	return timespec64_add_safe(now, ts); +	*to = timespec64_add_safe(now, *to); +	return to;  }  /** @@ -1732,8 +1742,8 @@ static inline struct timespec64 ep_set_mstimeout(long ms)   *          stored.   * @maxevents: Size (in terms of number of events) of the caller event buffer.   * @timeout: Maximum timeout for the ready events fetch operation, in - *           milliseconds. If the @timeout is zero, the function will not block, - *           while if the @timeout is less than zero, the function will block + *           timespec. If the timeout is zero, the function will not block, + *           while if the @timeout ptr is NULL, the function will block   *           until at least one event has been retrieved (or an error   *           occurred).   * @@ -1741,7 +1751,7 @@ static inline struct timespec64 ep_set_mstimeout(long ms)   *          error code, in case of error.   */  static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, -		   int maxevents, long timeout) +		   int maxevents, struct timespec64 *timeout)  {  	int res, eavail, timed_out = 0;  	u64 slack = 0; @@ -1750,13 +1760,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,  	lockdep_assert_irqs_enabled(); -	if (timeout > 0) { -		struct timespec64 end_time = ep_set_mstimeout(timeout); - -		slack = select_estimate_accuracy(&end_time); +	if (timeout && (timeout->tv_sec | timeout->tv_nsec)) { +		slack = select_estimate_accuracy(timeout);  		to = &expires; -		*to = timespec64_to_ktime(end_time); -	} else if (timeout == 0) { +		*to = timespec64_to_ktime(*timeout); +	} else if (timeout) {  		/*  		 * Avoid the unnecessary trip to the wait queue loop, if the  		 * caller specified a non blocking operation. @@ -2175,7 +2183,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,   * part of the user space epoll_wait(2).   */  static int do_epoll_wait(int epfd, struct epoll_event __user *events, -			 int maxevents, int timeout) +			 int maxevents, struct timespec64 *to)  {  	int error;  	struct fd f; @@ -2209,7 +2217,7 @@ static int do_epoll_wait(int epfd, struct epoll_event __user *events,  	ep = f.file->private_data;  	/* Time to fish for events ... */ -	error = ep_poll(ep, events, maxevents, timeout); +	error = ep_poll(ep, events, maxevents, to);  error_fput:  	fdput(f); @@ -2219,7 +2227,10 @@ error_fput:  SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events,  		int, maxevents, int, timeout)  { -	return do_epoll_wait(epfd, events, maxevents, timeout); +	struct timespec64 to; + +	return do_epoll_wait(epfd, events, maxevents, +			     ep_timeout_to_timespec(&to, timeout));  }  /* @@ -2230,6 +2241,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,  		int, maxevents, int, timeout, const sigset_t __user *, sigmask,  		size_t, sigsetsize)  { +	struct timespec64 to;  	int error;  	/* @@ -2240,7 +2252,9 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,  	if (error)  		return error; -	error = do_epoll_wait(epfd, events, maxevents, timeout); +	error = do_epoll_wait(epfd, events, maxevents, +			      ep_timeout_to_timespec(&to, timeout)); +  	restore_saved_sigmask_unless(error == -EINTR);  	return error; @@ -2253,6 +2267,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,  			const compat_sigset_t __user *, sigmask,  			compat_size_t, sigsetsize)  { +	struct timespec64 to;  	long err;  	/* @@ -2263,7 +2278,9 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,  	if (err)  		return err; -	err = do_epoll_wait(epfd, events, maxevents, timeout); +	err = do_epoll_wait(epfd, events, maxevents, +			    ep_timeout_to_timespec(&to, timeout)); +  	restore_saved_sigmask_unless(err == -EINTR);  	return err;  | 
