diff mbox series

[RFC,iproute2-next,2/5] ip: Split out code creating namespace mount dir so it can be reused

Message ID 20231009182753.851551-3-toke@redhat.com (mailing list archive)
State RFC
Delegated to: David Ahern
Headers show
Series Persisting of mount namespaces along with network namespaces | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Toke Høiland-Jørgensen Oct. 9, 2023, 6:27 p.m. UTC
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(-)
diff mbox series

Patch

diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index a05d84514326..529790482683 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -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) {