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

Reply via email to