aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2020-09-10 08:33:27 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-10-07 08:01:30 +0200
commit8e58bad666bb11432201d0c6020cffc73780bdd0 (patch)
tree4078bb09ee912ffc2213c8a9ef8e3d2bef29aad4
parentepoll: replace ->visited/visited_list with generation count (diff)
downloadwireguard-linux-8e58bad666bb11432201d0c6020cffc73780bdd0.tar.xz
wireguard-linux-8e58bad666bb11432201d0c6020cffc73780bdd0.zip
epoll: EPOLL_CTL_ADD: close the race in decision to take fast path
commit fe0a916c1eae8e17e86c3753d13919177d63ed7e upstream. Checking for the lack of epitems refering to the epoll we want to insert into is not enough; we might have an insertion of that epoll into another one that has already collected the set of files to recheck for excessive reverse paths, but hasn't gotten to creating/inserting the epitem for it. However, any such insertion in progress can be detected - it will update the generation count in our epoll when it's done looking through it for files to check. That gets done under ->mtx of our epoll and that allows us to detect that safely. We are *not* holding epmutex here, so the generation count is not stable. However, since both the update of ep->gen by loop check and (later) insertion into ->f_ep_link are done with ep->mtx held, we are fine - the sequence is grab epmutex bump loop_check_gen ... grab tep->mtx // 1 tep->gen = loop_check_gen ... drop tep->mtx // 2 ... grab tep->mtx // 3 ... insert into ->f_ep_link ... drop tep->mtx // 4 bump loop_check_gen drop epmutex and if the fastpath check in another thread happens for that eventpoll, it can come * before (1) - in that case fastpath is just fine * after (4) - we'll see non-empty ->f_ep_link, slow path taken * between (2) and (3) - loop_check_gen is stable, with ->mtx providing barriers and we end up taking slow path. Note that ->f_ep_link emptiness check is slightly racy - we are protected against insertions into that list, but removals can happen right under us. Not a problem - in the worst case we'll end up taking a slow path for no good reason. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/eventpoll.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 4962321c9fcd..333bb8f9ed0e 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -2175,6 +2175,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
mutex_lock_nested(&ep->mtx, 0);
if (op == EPOLL_CTL_ADD) {
if (!list_empty(&f.file->f_ep_links) ||
+ ep->gen == loop_check_gen ||
is_file_epoll(tf.file)) {
full_check = 1;
mutex_unlock(&ep->mtx);