From: Sargun Dhillon <sargun@sargun.me>
To: linux-fsdevel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, viro@zeniv.linux.org.uk,
akpm@linux-foundation.org, willy@infradead.org, arnd@kernel.org,
Willem de Bruijn <willemb@google.com>
Subject: epoll may leak events on dup
Date: Sat, 30 Oct 2021 10:03:19 +0000 [thread overview]
Message-ID: <20211030100319.GA11526@ircssh-3.c.rugged-nimbus-611.internal> (raw)
I discovered an interesting behaviour in epoll today. If I register the same
file twice, under two different file descriptor numbers, and then I close one of
the two file descriptors, epoll "leaks" the first event. This is fine, because
one would think I could just go ahead and remove the event, but alas, that isn't
the case. Some example python code follows to show the issue at hand.
I'm not sure if this is really considered a "bug" or just "interesting epoll
behaviour", but in my opinion this is kind of a bug, especially because leaks
may happen by accident -- especially if files are not immediately freed.
I'm also not sure why epoll events are registered by file, and not just fd.
Is the expectation that you can share a single epoll amongst multiple
"users" and register different files that have the same file descriptor
number (at least for purposes other than CRIU). Maybe someone can shed
light on the behaviour.
(FWIW: On closing of all references the file, the callback finally occurs
clearing the event)
#!/usr/bin/env python3
import select
import socket
import os
n = 2
sockets = []
epoll = select.epoll()
for i in range(n):
sockets.append(socket.socket(socket.AF_INET6, socket.SOCK_DGRAM))
sockets[-1].bind(('::1', 0))
for i in sockets:
epoll.register(i)
clones = [os.dup(i.fileno()) for i in sockets]
epoll.poll()
# Returns: [(4, 4), (5, 4)]
for i in clones:
epoll.register(i)
epoll.poll()
# Returns: [(4, 4), (5, 4), (6, 4), (7, 4)]
socket0name = sockets[0].getsockname()
socket0fileno = sockets[0].fileno()
print(f'Closing {socket0fileno}')
os.close(socket0fileno)
epoll.poll()
# Returns: [(4, 4), (5, 4), (6, 4), (7, 4)]
badsocket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
badsocket.sendto(b'test', (socket0name[0], socket0name[1]))
epoll.poll()
# Returns [(4, 5), (5, 4), (6, 5), (7, 4)]
# Indicating fd 4, and 6 have events.
# Oh whoops, I forgot to unregister 4...
epoll.unregister(4)
# Returns:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# FileNotFoundError: [Errno 2] No such file or directory
print(open(f'/proc/{os.getpid()}/fdinfo/{epoll.fileno()}').read())
# Returns:
# pos: 0
# flags: 02000002
# mnt_id: 15
# ino: 10994
# tfd: 5 events: 1f data: 5 pos:0 ino:30ffc5 sdev:8
# tfd: 7 events: 1f data: 7 pos:0 ino:30ffc5 sdev:8
# tfd: 4 events: 1f data: 4 pos:0 ino:30ffc4 sdev:8
# tfd: 6 events: 1f data: 6 pos:0 ino:30ffc4 sdev:8
next reply other threads:[~2021-10-30 10:03 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-30 10:03 Sargun Dhillon [this message]
2021-10-31 7:39 ` epoll may leak events on dup Eric Wong
2021-10-31 9:53 ` Sargun Dhillon
2021-10-31 10:50 ` Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211030100319.GA11526@ircssh-3.c.rugged-nimbus-611.internal \
--to=sargun@sargun.me \
--cc=akpm@linux-foundation.org \
--cc=arnd@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=willemb@google.com \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).