diff options
author | Jielong Zhou <jielong.zjl@antfin.com> | 2021-08-09 20:01:05 +0800 |
---|---|---|
committer | Jielong Zhou <jielong.zjl@antfin.com> | 2021-08-09 20:07:58 +0800 |
commit | 57da3c7ddd50f9a909d9b0022fe63eb201a2ca0e (patch) | |
tree | 9a737ecb4f8d84eb2f58624f58d2ac93de46555d /pkg/sentry | |
parent | c07dc3828a0330a3804514094d45e6362ae2de30 (diff) |
vfs2/epoll: fix missing event trigger in epoll-in-epoll case
In some cases, epoll fd would be registered in another epoll fd. Process
may call epoll_wait on the upper layer epoll fd, and the lower layer epoll
fd should generate EPOLLIN event if itself get any event.
But in VFS2, events generated for epoll fd could only be cleaned when
(*EpollInstance).ReadEvents is called. And this function is only called
when epoll_wait on the epoll fd. Therefore, when epoll_wait on the upper
layer epoll fd, the events generated in lower layer epoll fd would not
be cleaned even if it's not valid anymore, and lower layer epoll fd would
not report event to upper layer even if new event is triggered.
In this commit, (*EpollInstance).Readiness would also clean invalid events.
So, when epoll_wait on the upper layer epoll fd, Readiness function called
on lower layer epoll fd would clean invalid events. And lower layer could
report event to upper layer if new event is triggered.
A syscall test case is added to verify the commit.
Fixes https://github.com/google/gvisor/issues/6427
Signed-off-by: Jielong Zhou <jielong.zjl@antgroup.com>
Diffstat (limited to 'pkg/sentry')
-rw-r--r-- | pkg/sentry/vfs/epoll.go | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/pkg/sentry/vfs/epoll.go b/pkg/sentry/vfs/epoll.go index befe3ca25..23ccc6b66 100644 --- a/pkg/sentry/vfs/epoll.go +++ b/pkg/sentry/vfs/epoll.go @@ -136,12 +136,16 @@ func (ep *EpollInstance) Readiness(mask waiter.EventMask) waiter.EventMask { return 0 } ep.mu.Lock() - for epi := ep.ready.Front(); epi != nil; epi = epi.Next() { + var next *epollInterest + for epi := ep.ready.Front(); epi != nil; epi = next { + next = epi.Next() wmask := waiter.EventMaskFromLinux(epi.mask) if epi.key.file.Readiness(wmask)&wmask != 0 { ep.mu.Unlock() return waiter.ReadableEvents } + ep.ready.Remove(epi) + epi.ready = false } ep.mu.Unlock() return 0 |