@@ -758,13 +758,13 @@ static int netns_delete(int argc, char **argv)
return on_netns_del(argv[0], NULL);
}
-static int create_netns_dir(void)
+static int ensure_dir(const char *path)
{
/* Create the base netns directory if it doesn't exist */
- if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
+ if (mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
if (errno != EEXIST) {
fprintf(stderr, "mkdir %s failed: %s\n",
- NETNS_RUN_DIR, strerror(errno));
+ path, strerror(errno));
return -1;
}
}
@@ -899,53 +899,15 @@ static pid_t bind_ns_files_from_child(const char *ns_name, pid_t target_pid,
exit(EXIT_SUCCESS);
}
-static int netns_add(int argc, char **argv, bool create)
+static int prepare_ns_mount_dir(const char *target_dir, int mount_flag)
{
- /* This function creates a new network namespace and
- * a new mount namespace and bind them into a well known
- * location in the filesystem based on the name provided.
- *
- * If create is true, a new namespace will be created,
- * otherwise an existing one will be attached to the file.
- *
- * The mount namespace is created so that any necessary
- * userspace tweaks like remounting /sys, or bind mounting
- * a new /etc/resolv.conf can be shared between users.
- */
- const char *name;
- pid_t pid, child;
- int event_fd;
+ int made_dir_mount = 0;
int lock;
- int made_netns_run_dir_mount = 0;
- if (create) {
- if (argc < 1) {
- fprintf(stderr, "No netns name specified\n");
- return -1;
- }
- pid = getpid();
- } else {
- if (argc < 2) {
- fprintf(stderr, "No netns name and PID specified\n");
- return -1;
- }
-
- if (get_s32(&pid, argv[1], 0) || !pid) {
- fprintf(stderr, "Invalid PID: %s\n", argv[1]);
- return -1;
- }
- }
- name = argv[0];
-
- if (create_netns_dir())
+ if (ensure_dir(target_dir))
return -1;
- /* Make it possible for network namespace mounts to propagate 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.
- * These setup steps need to happen only once, as if multiple ip processes
+ /* These setup steps need to happen only once, as if multiple ip processes
* try to attempt the same operation at the same time, the mountpoints will
* be recursively created multiple times, eventually causing the system
* to lock up. For example, this has been observed when multiple netns
@@ -955,23 +917,23 @@ static int netns_add(int argc, char **argv, bool create)
* this cannot happen, but proceed nonetheless if it cannot happen for any
* reason.
*/
- lock = open(NETNS_RUN_DIR, O_RDONLY|O_DIRECTORY, 0);
+ lock = open(target_dir, O_RDONLY|O_DIRECTORY, 0);
if (lock < 0) {
- fprintf(stderr, "Cannot open netns runtime directory \"%s\": %s\n",
- NETNS_RUN_DIR, strerror(errno));
+ fprintf(stderr, "Cannot open ns runtime directory \"%s\": %s\n",
+ target_dir, strerror(errno));
return -1;
}
if (flock(lock, LOCK_EX) < 0) {
- fprintf(stderr, "Warning: could not flock netns runtime directory \"%s\": %s\n",
- NETNS_RUN_DIR, strerror(errno));
+ fprintf(stderr, "Warning: could not flock ns runtime directory \"%s\": %s\n",
+ target_dir, strerror(errno));
close(lock);
lock = -1;
}
- while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
+ while (mount("", target_dir, "none", mount_flag | MS_REC, NULL)) {
/* Fail unless we need to make the mount point */
- if (errno != EINVAL || made_netns_run_dir_mount) {
+ if (errno != EINVAL || made_dir_mount) {
fprintf(stderr, "mount --make-shared %s failed: %s\n",
- NETNS_RUN_DIR, strerror(errno));
+ target_dir, strerror(errno));
if (lock != -1) {
flock(lock, LOCK_UN);
close(lock);
@@ -979,23 +941,72 @@ static int netns_add(int argc, char **argv, bool create)
return -1;
}
- /* Upgrade NETNS_RUN_DIR to a mount point */
- if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
+ /* Upgrade target directory to a mount point */
+ if (mount(target_dir, target_dir, "none", MS_BIND | MS_REC, NULL)) {
fprintf(stderr, "mount --bind %s %s failed: %s\n",
- NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
+ target_dir, target_dir, strerror(errno));
if (lock != -1) {
flock(lock, LOCK_UN);
close(lock);
}
return -1;
}
- made_netns_run_dir_mount = 1;
+ made_dir_mount = 1;
}
if (lock != -1) {
flock(lock, LOCK_UN);
close(lock);
}
+ return 0;
+}
+
+static int netns_add(int argc, char **argv, bool create)
+{
+ /* This function creates a new network namespace and
+ * a new mount namespace and bind them into a well known
+ * location in the filesystem based on the name provided.
+ *
+ * If create is true, a new namespace will be created,
+ * otherwise an existing one will be attached to the file.
+ *
+ * The mount namespace is created so that any necessary
+ * userspace tweaks like remounting /sys, or bind mounting
+ * a new /etc/resolv.conf can be shared between users.
+ */
+ const char *name;
+ pid_t pid, child;
+ int event_fd;
+
+ if (create) {
+ if (argc < 1) {
+ fprintf(stderr, "No netns name specified\n");
+ return -1;
+ }
+ pid = getpid();
+ } else {
+ if (argc < 2) {
+ fprintf(stderr, "No netns name and PID specified\n");
+ return -1;
+ }
+
+ if (get_s32(&pid, argv[1], 0) || !pid) {
+ fprintf(stderr, "Invalid PID: %s\n", argv[1]);
+ return -1;
+ }
+ }
+ name = argv[0];
+
+ /* Pass the MS_SHARED flag to the mount of the network namespace
+ * directory to make it possible for network namespace mounts to
+ * propagate 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.
+ */
+ if (prepare_ns_mount_dir(NETNS_RUN_DIR, MS_SHARED))
+ return -1;
+
child = bind_ns_files_from_child(name, pid, &event_fd);
if (child < 0)
exit(EXIT_FAILURE);
@@ -1079,7 +1090,7 @@ static int netns_monitor(int argc, char **argv)
return -1;
}
- if (create_netns_dir())
+ if (ensure_dir(NETNS_RUN_DIR))
return -1;
if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
Move the code creating the parent directory for namespace references into its own function, so it can be reused for creating a separate directory to contain mount namespace references. No functional change is intended with this patch. Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com> --- ip/ipnetns.c | 127 ++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 58 deletions(-)