summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry
diff options
context:
space:
mode:
authorJielong Zhou <jielong.zjl@antfin.com>2021-08-09 20:01:05 +0800
committerJielong Zhou <jielong.zjl@antfin.com>2021-08-09 20:07:58 +0800
commit57da3c7ddd50f9a909d9b0022fe63eb201a2ca0e (patch)
tree9a737ecb4f8d84eb2f58624f58d2ac93de46555d /pkg/sentry
parentc07dc3828a0330a3804514094d45e6362ae2de30 (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.go6
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