When ip creates a netns, there is a small time interval between the placeholder file creation in NETNS_RUN_DIR and the bind mount from /proc.
Add a temporary file named .mounting-$netns which gets deleted after the bind mount, so watching for delete event matching the .mounting-* name will notify watchers only after the bind mount has been done. Signed-off-by: Matteo Croce <mcr...@redhat.com> --- ip/ipnetns.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index a883f210..23b95173 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -24,6 +24,8 @@ #include "namespace.h" #include "json_print.h" +#define TMP_PREFIX ".mounting-" + static int usage(void) { fprintf(stderr, @@ -47,6 +49,10 @@ static struct rtnl_handle rtnsh = { .fd = -1 }; static int have_rtnl_getnsid = -1; static int saved_netns = -1; +static int is_mounting_stab(const char *name) { + return !strncmp(name, TMP_PREFIX, sizeof(TMP_PREFIX) - 1); +} + static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { @@ -379,6 +385,8 @@ static int netns_list(int argc, char **argv) continue; if (strcmp(entry->d_name, "..") == 0) continue; + if (is_mounting_stab(entry->d_name)) + continue; open_json_object(NULL); print_string(PRINT_ANY, "name", @@ -676,7 +684,7 @@ static int netns_add(int argc, char **argv, bool create) * userspace tweaks like remounting /sys, or bind mounting * a new /etc/resolv.conf can be shared between users. */ - char netns_path[PATH_MAX], proc_path[PATH_MAX]; + char netns_path[PATH_MAX], tmp_path[PATH_MAX], proc_path[PATH_MAX]; const char *name; pid_t pid; int fd; @@ -701,6 +709,7 @@ static int netns_add(int argc, char **argv, bool create) name = argv[0]; snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name); + snprintf(tmp_path, sizeof(tmp_path), "%s/"TMP_PREFIX"%s", NETNS_RUN_DIR, name); if (create_netns_dir()) return -1; @@ -737,6 +746,14 @@ static int netns_add(int argc, char **argv, bool create) } close(fd); + fd = open(tmp_path, O_RDONLY|O_CREAT|O_EXCL, 0); + if (fd < 0) { + fprintf(stderr, "Cannot create namespace file \"%s\": %s\n", + tmp_path, strerror(errno)); + goto out_delete; + } + close(fd); + if (create) { netns_save(); if (unshare(CLONE_NEWNET) < 0) { @@ -757,6 +774,7 @@ static int netns_add(int argc, char **argv, bool create) goto out_delete; } netns_restore(); + unlink(tmp_path); return 0; out_delete: @@ -767,6 +785,10 @@ out_delete: fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n", netns_path, strerror(errno)); } + if (unlink(tmp_path) < 0) { + fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n", + tmp_path, strerror(errno)); + } return -1; } @@ -849,7 +871,7 @@ static int netns_monitor(int argc, char **argv) if (create_netns_dir()) return -1; - if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) { + if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_DELETE) < 0) { fprintf(stderr, "inotify_add_watch failed: %s\n", strerror(errno)); return -1; @@ -865,9 +887,9 @@ static int netns_monitor(int argc, char **argv) for (event = (struct inotify_event *)buf; (char *)event < &buf[len]; event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) { - if (event->mask & IN_CREATE) - printf("add %s\n", event->name); - if (event->mask & IN_DELETE) + if (is_mounting_stab(event->name)) + printf("add %s\n", event->name + sizeof(TMP_PREFIX) - 1); + else printf("delete %s\n", event->name); } } @@ -876,8 +898,9 @@ static int netns_monitor(int argc, char **argv) static int invalid_name(const char *name) { - return !*name || strlen(name) > NAME_MAX || - strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, ".."); + return !*name || strlen(name) + sizeof(TMP_PREFIX) - 1 > NAME_MAX || + strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..") || + is_mounting_stab(name); } int do_netns(int argc, char **argv) -- 2.21.0