diff --git a/passt.1 b/passt.1 index dc2d719..e97ef73 100644 --- a/passt.1 +++ b/passt.1 @@ -550,8 +550,12 @@ without \-\-userns. .TP .BR \-\-no-netns-quit -If the target network namespace is bound to the filesystem (that is, if PATH or -NAME are given as target), do not exit once the network namespace is deleted. +Do not exit once the target namespace reference is removed. + +Without this option, \fBpasta\fR will terminate if the target network namespace +is bound to the filesystem, and the given path is deleted, or if the target +network namespace is represented by a procfs entry, and that entry is deleted, +representing the fact that a process with the given PID terminated. .TP .BR \-\-config-net diff --git a/pasta.c b/pasta.c index 01d1511..61feaa9 100644 --- a/pasta.c +++ b/pasta.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include "util.h" #include "passt.h" @@ -390,12 +392,21 @@ void pasta_netns_quit_init(const struct ctx *c) union epoll_ref ref = { .type = EPOLL_TYPE_NSQUIT_INOTIFY }; struct epoll_event ev = { .events = EPOLLIN }; int flags = O_NONBLOCK | O_CLOEXEC; - int fd; + struct statfs s = { 0 }; + bool try_inotify = true; + int fd = -1, dir_fd; if (c->mode != MODE_PASTA || c->no_netns_quit || !*c->netns_base) return; - if ((fd = inotify_init1(flags)) < 0) + if ((dir_fd = open(c->netns_dir, O_CLOEXEC | O_RDONLY)) < 0) + die("netns dir open: %s, exiting", strerror(errno)); + + if (fstatfs(dir_fd, &s) || s.f_type == DEVPTS_SUPER_MAGIC || + s.f_type == PROC_SUPER_MAGIC || s.f_type == SYSFS_MAGIC) + try_inotify = false; + + if (try_inotify && (fd = inotify_init1(flags)) < 0) warn("inotify_init1(): %s, use a timer", strerror(errno)); if (fd >= 0 && inotify_add_watch(fd, c->netns_dir, IN_DELETE) < 0) { @@ -409,11 +420,11 @@ void pasta_netns_quit_init(const struct ctx *c) if ((fd = pasta_netns_quit_timer()) < 0) die("Failed to set up fallback netns timer, exiting"); - ref.nsdir_fd = open(c->netns_dir, O_CLOEXEC | O_RDONLY); - if (ref.nsdir_fd < 0) - die("netns dir open: %s, exiting", strerror(errno)); + ref.nsdir_fd = dir_fd; ref.type = EPOLL_TYPE_NSQUIT_TIMER; + } else { + close(dir_fd); } if (fd > FD_REF_MAX) @@ -463,6 +474,9 @@ void pasta_netns_quit_timer_handler(struct ctx *c, union epoll_ref ref) fd = openat(ref.nsdir_fd, c->netns_base, O_PATH | O_CLOEXEC); if (fd < 0) { + if (errno == EACCES) /* Expected for existing procfs entry */ + return; + info("Namespace %s is gone, exiting", c->netns_base); exit(EXIT_SUCCESS); }