mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Drop one dirent reference after referenced by file
When pipe is created, a dirent of pipe will be
created and its initial reference is set as 0.
Cause all dirent will only be destroyed when
the reference decreased to -1, so there is already
a 'initial reference' of dirent after it created.
For destroying dirent after all reference released,
the correct way is to drop the 'initial reference'
once someone hold a reference to the dirent, such
as fs.NewFile, otherwise the reference of dirent
will stay 0 all the time, and will cause memory
leak of dirent.
Except pipe, timerfd/eventfd/epoll has the same
problem
Here is a simple case to create memory leak of dirent
for pipe/timerfd/eventfd/epoll in C langange, after
run the case, pprof the runsc process, you will
find lots dirents of pipe/timerfd/eventfd/epoll not
freed:
int main(int argc, char *argv[])
{
int i;
int n;
int pipefd[2];
if (argc != 3) {
printf("Usage: %s epoll|timerfd|eventfd|pipe <iterations>\n", argv[0]);
}
n = strtol(argv[2], NULL, 10);
if (strcmp(argv[1], "epoll") == 0) {
for (i = 0; i < n; ++i)
close(epoll_create(1));
} else if (strcmp(argv[1], "timerfd") == 0) {
for (i = 0; i < n; ++i)
close(timerfd_create(CLOCK_REALTIME, 0));
} else if (strcmp(argv[1], "eventfd") == 0) {
for (i = 0; i < n; ++i)
close(eventfd(0, 0));
} else if (strcmp(argv[1], "pipe") == 0) {
for (i = 0; i < n; ++i)
if (pipe(pipefd) == 0) {
close(pipefd[0]);
close(pipefd[1]);
}
}
printf("%s %s test finished\r\n",argv[1],argv[2]);
return 0;
}
Change-Id: Ia1b8a1fb9142edb00c040e44ec644d007f81f5d2
PiperOrigin-RevId: 251531096
This commit is contained in:
@@ -54,6 +54,8 @@ type TimerOperations struct {
|
||||
// NewFile returns a timerfd File that receives time from c.
|
||||
func NewFile(ctx context.Context, c ktime.Clock) *fs.File {
|
||||
dirent := fs.NewDirent(anon.NewInode(ctx), "anon_inode:[timerfd]")
|
||||
// Release the initial dirent reference after NewFile takes a reference.
|
||||
defer dirent.DecRef()
|
||||
tops := &TimerOperations{}
|
||||
tops.timer = ktime.NewTimer(c, tops)
|
||||
// Timerfds reject writes, but the Write flag must be set in order to
|
||||
|
||||
@@ -156,6 +156,8 @@ var cycleMu sync.Mutex
|
||||
func NewEventPoll(ctx context.Context) *fs.File {
|
||||
// name matches fs/eventpoll.c:epoll_create1.
|
||||
dirent := fs.NewDirent(anon.NewInode(ctx), fmt.Sprintf("anon_inode:[eventpoll]"))
|
||||
// Release the initial dirent reference after NewFile takes a reference.
|
||||
defer dirent.DecRef()
|
||||
return fs.NewFile(ctx, dirent, fs.FileFlags{}, &EventPoll{
|
||||
files: make(map[FileIdentifier]*pollEntry),
|
||||
})
|
||||
|
||||
@@ -69,6 +69,8 @@ type EventOperations struct {
|
||||
func New(ctx context.Context, initVal uint64, semMode bool) *fs.File {
|
||||
// name matches fs/eventfd.c:eventfd_file_create.
|
||||
dirent := fs.NewDirent(anon.NewInode(ctx), "anon_inode:[eventfd]")
|
||||
// Release the initial dirent reference after NewFile takes a reference.
|
||||
defer dirent.DecRef()
|
||||
return fs.NewFile(ctx, dirent, fs.FileFlags{Read: true, Write: true}, &EventOperations{
|
||||
val: initVal,
|
||||
semMode: semMode,
|
||||
|
||||
Reference in New Issue
Block a user