diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/fs/select.c b/fs/select.c index a77907faf2b4..e223d1fe9d55 100644 --- a/fs/select.c +++ b/fs/select.c @@ -462,15 +462,22 @@ get_max: EPOLLNVAL) #define POLLEX_SET (EPOLLPRI | EPOLLNVAL) -static inline void wait_key_set(poll_table *wait, unsigned long in, +static inline __poll_t select_poll_one(int fd, poll_table *wait, unsigned long in, unsigned long out, unsigned long bit, __poll_t ll_flag) { + CLASS(fd, f)(fd); + + if (fd_empty(f)) + return EPOLLNVAL; + wait->_key = POLLEX_SET | ll_flag; if (in & bit) wait->_key |= POLLIN_SET; if (out & bit) wait->_key |= POLLOUT_SET; + + return vfs_poll(fd_file(f), wait); } static noinline_for_stack int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) @@ -522,20 +529,12 @@ static noinline_for_stack int do_select(int n, fd_set_bits *fds, struct timespec } for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1) { - struct fd f; if (i >= n) break; if (!(bit & all_bits)) continue; - mask = EPOLLNVAL; - f = fdget(i); - if (fd_file(f)) { - wait_key_set(wait, in, out, bit, - busy_flag); - mask = vfs_poll(fd_file(f), wait); - - fdput(f); - } + mask = select_poll_one(i, wait, in, out, bit, + busy_flag); if ((mask & POLLIN_SET) && (in & bit)) { res_in |= bit; retval++; @@ -856,15 +855,14 @@ static inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait, __poll_t busy_flag) { int fd = pollfd->fd; - __poll_t mask = 0, filter; - struct fd f; + __poll_t mask, filter; if (fd < 0) - goto out; - mask = EPOLLNVAL; - f = fdget(fd); - if (!fd_file(f)) - goto out; + return 0; + + CLASS(fd, f)(fd); + if (fd_empty(f)) + return EPOLLNVAL; /* userland u16 ->events contains POLL... bitmap */ filter = demangle_poll(pollfd->events) | EPOLLERR | EPOLLHUP; @@ -872,13 +870,7 @@ static inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait, mask = vfs_poll(fd_file(f), pwait); if (mask & busy_flag) *can_busy_poll = true; - mask &= filter; /* Mask out unneeded events. */ - fdput(f); - -out: - /* ... and so does ->revents */ - pollfd->revents = mangle_poll(mask); - return mask; + return mask & filter; /* Mask out unneeded events. */ } static int do_poll(struct poll_list *list, struct poll_wqueues *wait, @@ -910,6 +902,7 @@ static int do_poll(struct poll_list *list, struct poll_wqueues *wait, pfd = walk->entries; pfd_end = pfd + walk->len; for (; pfd != pfd_end; pfd++) { + __poll_t mask; /* * Fish for events. If we found one, record it * and kill poll_table->_qproc, so we don't @@ -917,8 +910,9 @@ static int do_poll(struct poll_list *list, struct poll_wqueues *wait, * this. They'll get immediately deregistered * when we break out and return. */ - if (do_pollfd(pfd, pt, &can_busy_loop, - busy_flag)) { + mask = do_pollfd(pfd, pt, &can_busy_loop, busy_flag); + pfd->revents = mangle_poll(mask); + if (mask) { count++; pt->_qproc = NULL; /* found something, stop busy polling */ |