Skip to content

Commit 68514da

Browse files
jankaratorvalds
authored andcommitted
select: Fix indefinitely sleeping task in poll_schedule_timeout()
A task can end up indefinitely sleeping in do_select() -> poll_schedule_timeout() when the following race happens: TASK1 (thread1) TASK2 TASK1 (thread2) do_select() setup poll_wqueues table with 'fd' write data to 'fd' pollwake() table->triggered = 1 closes 'fd' thread1 is waiting for poll_schedule_timeout() - sees table->triggered table->triggered = 0 return -EINTR loop back in do_select() But at this point when TASK1 loops back, the fdget() in the setup of poll_wqueues fails. So now so we never find 'fd' is ready for reading and sleep in poll_schedule_timeout() indefinitely. Treat an fd that got closed as a fd on which some event happened. This makes sure cannot block indefinitely in do_select(). Another option would be to return -EBADF in this case but that has a potential of subtly breaking applications that excercise this behavior and it happens to work for them. So returning fd as active seems like a safer choice. Suggested-by: Linus Torvalds <[email protected]> CC: [email protected] Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fe8152b commit 68514da

File tree

1 file changed

+33
-30
lines changed

1 file changed

+33
-30
lines changed

fs/select.c

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,11 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds)
459459
return max;
460460
}
461461

462-
#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR)
463-
#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR)
464-
#define POLLEX_SET (EPOLLPRI)
462+
#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\
463+
EPOLLNVAL)
464+
#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\
465+
EPOLLNVAL)
466+
#define POLLEX_SET (EPOLLPRI | EPOLLNVAL)
465467

466468
static inline void wait_key_set(poll_table *wait, unsigned long in,
467469
unsigned long out, unsigned long bit,
@@ -528,41 +530,42 @@ static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
528530
break;
529531
if (!(bit & all_bits))
530532
continue;
533+
mask = EPOLLNVAL;
531534
f = fdget(i);
532535
if (f.file) {
533536
wait_key_set(wait, in, out, bit,
534537
busy_flag);
535538
mask = vfs_poll(f.file, wait);
536539

537540
fdput(f);
538-
if ((mask & POLLIN_SET) && (in & bit)) {
539-
res_in |= bit;
540-
retval++;
541-
wait->_qproc = NULL;
542-
}
543-
if ((mask & POLLOUT_SET) && (out & bit)) {
544-
res_out |= bit;
545-
retval++;
546-
wait->_qproc = NULL;
547-
}
548-
if ((mask & POLLEX_SET) && (ex & bit)) {
549-
res_ex |= bit;
550-
retval++;
551-
wait->_qproc = NULL;
552-
}
553-
/* got something, stop busy polling */
554-
if (retval) {
555-
can_busy_loop = false;
556-
busy_flag = 0;
557-
558-
/*
559-
* only remember a returned
560-
* POLL_BUSY_LOOP if we asked for it
561-
*/
562-
} else if (busy_flag & mask)
563-
can_busy_loop = true;
564-
565541
}
542+
if ((mask & POLLIN_SET) && (in & bit)) {
543+
res_in |= bit;
544+
retval++;
545+
wait->_qproc = NULL;
546+
}
547+
if ((mask & POLLOUT_SET) && (out & bit)) {
548+
res_out |= bit;
549+
retval++;
550+
wait->_qproc = NULL;
551+
}
552+
if ((mask & POLLEX_SET) && (ex & bit)) {
553+
res_ex |= bit;
554+
retval++;
555+
wait->_qproc = NULL;
556+
}
557+
/* got something, stop busy polling */
558+
if (retval) {
559+
can_busy_loop = false;
560+
busy_flag = 0;
561+
562+
/*
563+
* only remember a returned
564+
* POLL_BUSY_LOOP if we asked for it
565+
*/
566+
} else if (busy_flag & mask)
567+
can_busy_loop = true;
568+
566569
}
567570
if (res_in)
568571
*rinp = res_in;

0 commit comments

Comments
 (0)