From: Eric W. Biederman Date: Thu, 17 Jan 2013 14:47:18 +0000 (+0000) Subject: iproute2: Make "ip netns delete" more likely to succeed X-Git-Tag: v3.8.0~3^2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=58a3e8270fe72f8ed92687d3a3132c2a708582dd;p=thirdparty%2Fiproute2.git 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" --- 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) {