[lxc-devel] [PATCH 8/8] allow to specify a image or a device block as rootfs

Daniel Lezcano daniel.lezcano at free.fr
Sun Oct 3 21:46:37 UTC 2010


This patch allows to specify an image or a block device.

The image or the block device is mounted on rootfs->mount.

Signed-off-by: Daniel Lezcano <dlezcano at fr.ibm.com>
---
 src/lxc/conf.c |  223 +++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 132 insertions(+), 91 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index dac5b45..adfe862 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -48,6 +48,8 @@
 #include <net/if.h>
 #include <libgen.h>
 
+#include <linux/loop.h>
+
 #include "network.h"
 #include "error.h"
 #include "parse.h"
@@ -142,7 +144,7 @@ static struct mount_opt mount_opt[] = {
 };
 
 static struct caps_opt caps_opt[] = {
-	{ "chown",             CAP_CHOWN 	     },
+	{ "chown",             CAP_CHOWN             },
 	{ "dac_override",      CAP_DAC_OVERRIDE      },
 	{ "dac_read_search",   CAP_DAC_READ_SEARCH   },
 	{ "fowner",            CAP_FOWNER            },
@@ -182,13 +184,11 @@ static struct caps_opt caps_opt[] = {
 	{ "mac_admin",         CAP_MAC_ADMIN         },
 };
 
-#if 0 /* will be reactivated with image mounting support */
-static int configure_find_fstype_cb(char* buffer, void *data)
+static int find_fstype_cb(char* buffer, void *data)
 {
 	struct cbarg {
 		const char *rootfs;
-		const char *testdir;
-		char *fstype;
+		const char *target;
 		int mntopt;
 	} *cbarg = data;
 
@@ -202,33 +202,38 @@ static int configure_find_fstype_cb(char* buffer, void *data)
 	fstype += lxc_char_left_gc(fstype, strlen(fstype));
 	fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
 
-	if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL))
+	DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
+	      cbarg->rootfs, cbarg->target, fstype);
+
+	if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
+		DEBUG("mount failed with error: %s", strerror(errno));
 		return 0;
+	}
 
-	/* found ! */
-	umount(cbarg->testdir);
-	strcpy(cbarg->fstype, fstype);
+	INFO("mounted '%s' on '%s', with fstype '%s'",
+	     cbarg->rootfs, cbarg->target, fstype);
 
 	return 1;
 }
 
-/* find the filesystem type with brute force */
-static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt)
+static int setup_mount_unknow_fs(const char *rootfs,
+				 const char *target, int mntopt)
 {
-	int i, found;
+	int i;
 
 	struct cbarg {
 		const char *rootfs;
-		const char *testdir;
-		char *fstype;
+		const char *target;
 		int mntopt;
 	} cbarg = {
 		.rootfs = rootfs,
-		.fstype = fstype,
+		.target = target,
 		.mntopt = mntopt,
 	};
 
-	/* first we check with /etc/filesystems, in case the modules
+	/*
+	 * find the filesystem type with brute force:
+	 * first we check with /etc/filesystems, in case the modules
 	 * are auto-loaded and fall back to the supported kernel fs
 	 */
 	char *fsfile[] = {
@@ -236,79 +241,144 @@ static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt)
 		"/proc/filesystems",
 	};
 
-	cbarg.testdir = tempnam("/tmp", "lxc-");
-	if (!cbarg.testdir) {
-		SYSERROR("failed to build a temp name");
-		return -1;
+	for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
+
+		int ret;
+
+		if (access(fsfile[i], F_OK))
+			continue;
+
+		ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
+		if (ret < 0) {
+			ERROR("failed to parse '%s'", fsfile[i]);
+			return -1;
+		}
+
+		if (ret)
+			return 0;
 	}
 
-	if (mkdir(cbarg.testdir, 0755)) {
-		SYSERROR("failed to create temporary directory");
+	ERROR("failed to determine fs type for '%s'", rootfs);
+	return -1;
+}
+
+static int setup_mount_rootfs_dir(const char *rootfs, const char *target)
+{
+	return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL);
+}
+
+static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
+{
+	int rfd;
+	int ret = -1;
+
+	rfd = open(rootfs, O_RDWR);
+	if (rfd < 0) {
+		SYSERROR("failed to open '%s'", rootfs);
 		return -1;
 	}
 
-	for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
-
-		found = lxc_file_for_each_line(fsfile[i],
-					       configure_find_fstype_cb,
-					       &cbarg);
+	memset(loinfo, 0, sizeof(*loinfo));
 
-		if (found < 0) {
-			SYSERROR("failed to read '%s'", fsfile[i]);
-			goto out;
-		}
+	loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
 
-		if (found)
-			break;
+	if (ioctl(fd, LOOP_SET_FD, rfd)) {
+		SYSERROR("failed to LOOP_SET_FD");
+		goto out;
 	}
 
-	if (!found) {
-		ERROR("failed to determine fs type for '%s'", rootfs);
+	if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
+		SYSERROR("failed to LOOP_SET_STATUS64");
 		goto out;
 	}
 
+	ret = 0;
 out:
-	rmdir(cbarg.testdir);
-	return found - 1;
-}
+	close(rfd);
 
-static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs,
-				   FILE *f)
-{
-	return fprintf(f, "%s %s none rbind 0 0\n", absrootfs, rootfs);
+	return ret;
 }
 
-static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs,
-				   FILE *f)
+static int setup_mount_rootfs_file(const char *rootfs, const char *target)
 {
-	char fstype[MAXPATHLEN];
+	struct dirent dirent, *direntp;
+	struct loop_info64 loinfo;
+	int ret = -1, fd = -1;
+	DIR *dir;
+	char path[MAXPATHLEN];
 
-	if (configure_find_fstype(absrootfs, fstype, 0)) {
-		ERROR("failed to configure mount for block device '%s'",
-			      absrootfs);
+	dir = opendir("/dev");
+	if (!dir) {
+		SYSERROR("failed to open '/dev'");
 		return -1;
 	}
 
-	return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype);
+	while (!readdir_r(dir, &dirent, &direntp)) {
+
+		if (!direntp)
+			break;
+
+		if (!strcmp(direntp->d_name, "."))
+			continue;
+
+		if (!strcmp(direntp->d_name, ".."))
+			continue;
+
+		if (strncmp(direntp->d_name, "loop", 4))
+			continue;
+
+		sprintf(path, "/dev/%s", direntp->d_name);
+		fd = open(path, O_RDWR);
+		if (fd < 0)
+			continue;
+
+		if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
+			close(fd);
+			continue;
+		}
+
+		if (errno != ENXIO) {
+			WARN("unexpected error for ioctl on '%s': %m",
+			     direntp->d_name);
+			continue;
+		}
+
+		DEBUG("found '%s' free lodev", path);
+
+		ret = setup_lodev(rootfs, fd, &loinfo);
+		if (!ret)
+			ret = setup_mount_unknow_fs(path, target, 0);
+		close(fd);
+
+		break;
+	}
+
+	if (closedir(dir))
+		WARN("failed to close directory");
+
+	return ret;
 }
 
-static int configure_rootfs(const char *name, const char *rootfs)
+static int setup_mount_rootfs_block(const char *rootfs, const char *target)
+{
+	return setup_mount_unknow_fs(rootfs, target, 0);
+}
+
+static int setup_mount_rootfs(const char *rootfs, const char *target)
 {
-	char path[MAXPATHLEN];
 	char absrootfs[MAXPATHLEN];
-	char fstab[MAXPATHLEN];
 	struct stat s;
-	FILE *f;
-	int i, ret;
+	int i;
 
-	typedef int (*rootfs_cb)(const char *, const char *, FILE *);
+	typedef int (*rootfs_cb)(const char *, const char *);
 
 	struct rootfs_type {
 		int type;
 		rootfs_cb cb;
 	} rtfs_type[] = {
-		{ __S_IFDIR, configure_rootfs_dir_cb },
-		{ __S_IFBLK, configure_rootfs_blk_cb },
+		{ S_IFDIR, setup_mount_rootfs_dir },
+		{ S_IFBLK, setup_mount_rootfs_block },
+		{ S_IFREG, setup_mount_rootfs_file },
 	};
 
 	if (!realpath(rootfs, absrootfs)) {
@@ -316,13 +386,6 @@ static int configure_rootfs(const char *name, const char *rootfs)
 		return -1;
 	}
 
-	snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
-
-	if (mkdir(path, 0755)) {
-		SYSERROR("failed to create the '%s' directory", path);
-		return -1;
-	}
-
 	if (access(absrootfs, F_OK)) {
 		SYSERROR("'%s' is not accessible", absrootfs);
 		return -1;
@@ -338,32 +401,12 @@ static int configure_rootfs(const char *name, const char *rootfs)
 		if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
 			continue;
 
-		snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name);
-
-		f = fopen(fstab, "a+");
-		if (!f) {
-			SYSERROR("failed to open fstab file");
-			return -1;
-		}
-
-		ret = rtfs_type[i].cb(path, absrootfs, f);
-
-		fclose(f);
-
-		if (ret < 0) {
-			ERROR("failed to add rootfs mount in fstab");
-			return -1;
-		}
-
-		snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name);
-
-		return symlink(absrootfs, path);
+		return rtfs_type[i].cb(absrootfs, target);
 	}
 
 	ERROR("unsupported rootfs type for '%s'", absrootfs);
 	return -1;
 }
-#endif
 
 static int setup_utsname(struct utsname *utsname)
 {
@@ -603,9 +646,8 @@ static int setup_rootfs(const struct lxc_rootfs *rootfs)
 		return -1;
 	}
 
-	if (mount(rootfs->path, rootfs->mount, "none", MS_BIND|MS_REC, NULL)) {
-		SYSERROR("failed to mount '%s'->'%s'",
-			 rootfs->path, rootfs->mount);
+	if (setup_mount_rootfs(rootfs->path, rootfs->mount)) {
+		ERROR("failed to mount rootfs");
 		return -1;
 	}
 
@@ -624,8 +666,6 @@ int setup_pivot_root(const struct lxc_rootfs *rootfs)
 		return -1;
 	}
 
-	DEBUG("pivot rooted to '%s'", rootfs->mount);
-
 	return 0;
 }
 
@@ -639,7 +679,8 @@ static int setup_pts(int pts)
 		return -1;
 	}
 
-	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666")) {
+	if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
+		  "newinstance,ptmxmode=0666")) {
 		SYSERROR("failed to mount a new instance of '/dev/pts'");
 		return -1;
 	}
-- 
1.7.0.4





More information about the lxc-devel mailing list