From 58a3e8270fe72f8ed92687d3a3132c2a708582dd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 17 Jan 2013 14:47:18 +0000 Subject: [PATCH] iproute2: Make "ip netns delete" more likely to succeed Sometimes "ip netns delete" fails because it can not delete the file a network namespace was mounted on. If this only happened when a network namespace was really in use this would be fine, but today it is possible to pin all network namespaces by simply having a long running process started with "ip netns exec". Every mount is copied when a network namespace is created so it is impossible to prevent the mounts from getting into other mount namespaces. Modify all mounts in the files and subdirectories of /var/run/netns to be shared mount points so that unmount events can propogate, making it unlikely that "ip netns delete" will fail because a directory is mounted in another mount namespace. Signed-off-by: "Eric W. Biederman" --- ip/ipnetns.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 4fce379a4..33765b588 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -208,6 +208,7 @@ static int netns_add(int argc, char **argv) char netns_path[MAXPATHLEN]; const char *name; int fd; + int made_netns_run_dir_mount = 0; if (argc < 1) { fprintf(stderr, "No netns name specified\n"); @@ -220,6 +221,29 @@ static int netns_add(int argc, char **argv) /* Create the base netns directory if it doesn't exist */ mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); + /* Make it possible for network namespace mounts to propogate between + * mount namespaces. This makes it likely that a unmounting a network + * namespace file in one namespace will unmount the network namespace + * file in all namespaces allowing the network namespace to be freed + * sooner. + */ + while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) { + /* Fail unless we need to make the mount point */ + if (errno != EINVAL || made_netns_run_dir_mount) { + fprintf(stderr, "mount --make-shared %s failed: %s\n", + NETNS_RUN_DIR, strerror(errno)); + return EXIT_FAILURE; + } + + /* Upgrade NETNS_RUN_DIR to a mount point */ + if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) { + fprintf(stderr, "mount --bind %s %s failed: %s\n", + NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno)); + return EXIT_FAILURE; + } + made_netns_run_dir_mount = 1; + } + /* Create the filesystem state */ fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0); if (fd < 0) { -- 2.47.2