diff options
Diffstat (limited to 'fs/eventpoll.c')
| -rw-r--r-- | fs/eventpoll.c | 56 | 
1 files changed, 53 insertions, 3 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 557d5b614fa..ae228ec54e9 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -105,6 +105,8 @@  /* Maximum msec timeout value storeable in a long int */  #define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ) +#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) +  struct epoll_filefd {  	struct file *file; @@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)   */  asmlinkage long sys_epoll_create(int size)  { -	int error, fd; +	int error, fd = -1;  	struct eventpoll *ep;  	struct inode *inode;  	struct file *file; @@ -640,7 +642,6 @@ eexit_1:  	return error;  } -#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))  /*   * Implement the event wait interface for the eventpoll file. It is the kernel @@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,  		     current, epfd, events, maxevents, timeout));  	/* The maximum number of event must be greater than zero */ -	if (maxevents <= 0 || maxevents > MAX_EVENTS) +	if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)  		return -EINVAL;  	/* Verify that the area passed by the user is writeable */ @@ -699,6 +700,55 @@ eexit_1:  } +#ifdef TIF_RESTORE_SIGMASK + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_pwait(2). + */ +asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, +		int maxevents, int timeout, const sigset_t __user *sigmask, +		size_t sigsetsize) +{ +	int error; +	sigset_t ksigmask, sigsaved; + +	/* +	 * If the caller wants a certain signal mask to be set during the wait, +	 * we apply it here. +	 */ +	if (sigmask) { +		if (sigsetsize != sizeof(sigset_t)) +			return -EINVAL; +		if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) +			return -EFAULT; +		sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); +		sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); +	} + +	error = sys_epoll_wait(epfd, events, maxevents, timeout); + +	/* +	 * If we changed the signal mask, we need to restore the original one. +	 * In case we've got a signal while waiting, we do not restore the +	 * signal mask yet, and we allow do_signal() to deliver the signal on +	 * the way back to userspace, before the signal mask is restored. +	 */ +	if (sigmask) { +		if (error == -EINTR) { +			memcpy(¤t->saved_sigmask, &sigsaved, +				sizeof(sigsaved)); +			set_thread_flag(TIF_RESTORE_SIGMASK); +		} else +			sigprocmask(SIG_SETMASK, &sigsaved, NULL); +	} + +	return error; +} + +#endif /* #ifdef TIF_RESTORE_SIGMASK */ + +  /*   * Creates the file descriptor to be used by the epoll interface.   */  | 
