aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--passt.18
-rw-r--r--pasta.c24
2 files changed, 25 insertions, 7 deletions
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 <sys/timerfd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
@@ -41,6 +42,7 @@
#include <netinet/in.h>
#include <net/ethernet.h>
#include <sys/syscall.h>
+#include <linux/magic.h>
#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);
}