[lxc-devel] [lxc/master] utils: use loop device helpers from LXD

brauner on Github lxc-bot at linuxcontainers.org
Sat Apr 22 12:04:14 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 459 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170422/4a99af18/attachment.bin>
-------------- next part --------------
From d435aae15b6b4a715d6ca60b8c7a2610b074863c Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 22 Apr 2017 13:22:16 +0200
Subject: [PATCH 1/2] conf: non-functional changes

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/conf.c | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index b648ca1..5f5d34c 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -573,7 +573,7 @@ static int run_script(const char *name, const char *section, const char *script,
 }
 
 static int mount_rootfs_dir(const char *rootfs, const char *target,
-			                const char *options)
+			    const char *options)
 {
 	unsigned long mntflags;
 	char *mntdata;
@@ -590,10 +590,9 @@ static int mount_rootfs_dir(const char *rootfs, const char *target,
 	return ret;
 }
 
-static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
+static int lxc_setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
 {
 	int rfd;
-	int ret = -1;
 
 	rfd = open(rootfs, O_RDWR);
 	if (rfd < 0) {
@@ -603,33 +602,30 @@ static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
 
 	memset(loinfo, 0, sizeof(*loinfo));
 
-	loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
-
 	if (ioctl(fd, LOOP_SET_FD, rfd)) {
 		SYSERROR("failed to LOOP_SET_FD");
-		goto out;
+		close(rfd);
+		return -1;
 	}
 
+	loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
 	if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
 		SYSERROR("failed to LOOP_SET_STATUS64");
-		goto out;
+		close(rfd);
+		return -1;
 	}
 
-	ret = 0;
-out:
-	close(rfd);
-
-	return ret;
+	return 0;
 }
 
 static int mount_rootfs_file(const char *rootfs, const char *target,
-				             const char *options)
+			     const char *options)
 {
 	struct dirent *direntp;
 	struct loop_info64 loinfo;
-	int ret = -1, fd = -1, rc;
 	DIR *dir;
 	char path[MAXPATHLEN];
+	int ret = -1, fd = -1, rc;
 
 	dir = opendir("/dev");
 	if (!dir) {
@@ -673,7 +669,7 @@ static int mount_rootfs_file(const char *rootfs, const char *target,
 
 		DEBUG("found '%s' free lodev", path);
 
-		ret = setup_lodev(rootfs, fd, &loinfo);
+		ret = lxc_setup_lodev(rootfs, fd, &loinfo);
 		if (!ret)
 			ret = mount_unknown_fs(path, target, options);
 		close(fd);

From 01d27ed730abdd241b000d53d075a3e0e1ddb19e Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 22 Apr 2017 14:01:59 +0200
Subject: [PATCH 2/2] utils: use loop device helpers from LXD

Use the loop devie helpers I wrote for LXD in LXC as well. They should be more
efficient.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/bdev/lxcloop.c | 109 ++++---------------------------------------
 src/lxc/conf.c         |  92 ++++--------------------------------
 src/lxc/utils.c        | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/utils.h        |  18 +++++++-
 4 files changed, 158 insertions(+), 184 deletions(-)

diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
index b322002..a4633e4 100644
--- a/src/lxc/bdev/lxcloop.c
+++ b/src/lxc/bdev/lxcloop.c
@@ -35,19 +35,9 @@
 #include "lxcloop.h"
 #include "utils.h"
 
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef LOOP_CTL_GET_FREE
-#define LOOP_CTL_GET_FREE 0x4C82
-#endif
-
 lxc_log_define(lxcloop, lxc);
 
 static int do_loop_create(const char *path, uint64_t size, const char *fstype);
-static int find_free_loopdev_no_control(int *retfd, char *namep);
-static int find_free_loopdev(int *retfd, char *namep);
 
 /*
  * No idea what the original blockdev will be called, but the copy will be
@@ -174,47 +164,26 @@ int loop_detect(const char *path)
 
 int loop_mount(struct bdev *bdev)
 {
-	int lfd, ffd = -1, ret = -1;
-	struct loop_info64 lo;
-	char loname[100];
+	int ret, loopfd;
+	char loname[MAXPATHLEN];
 
 	if (strcmp(bdev->type, "loop"))
 		return -22;
 	if (!bdev->src || !bdev->dest)
 		return -22;
-	if (find_free_loopdev(&lfd, loname) < 0)
-		return -22;
-
-	ffd = open(bdev->src + 5, O_RDWR);
-	if (ffd < 0) {
-		SYSERROR("Error opening backing file %s", bdev->src);
-		goto out;
-	}
 
-	if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) {
-		SYSERROR("Error attaching backing file to loop dev");
-		goto out;
-	}
-	memset(&lo, 0, sizeof(lo));
-	lo.lo_flags = LO_FLAGS_AUTOCLEAR;
-	if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) {
-		SYSERROR("Error setting autoclear on loop dev");
-		goto out;
-	}
+	loopfd = lxc_prepare_loop_dev(bdev->src + 5, loname, LO_FLAGS_AUTOCLEAR);
+	if (loopfd < 0)
+		return -1;
+	DEBUG("prepared loop device \"%s\"", loname);
 
 	ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
 	if (ret < 0)
-		ERROR("Error mounting %s", bdev->src);
+		ERROR("failed to mount rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
 	else
-		bdev->lofd = lfd;
+		bdev->lofd = loopfd;
+	DEBUG("mounted rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
 
-out:
-	if (ffd > -1)
-		close(ffd);
-	if (ret < 0) {
-		close(lfd);
-		bdev->lofd = -1;
-	}
 	return ret;
 }
 
@@ -266,63 +235,3 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype)
 
 	return 0;
 }
-
-static int find_free_loopdev_no_control(int *retfd, char *namep)
-{
-	struct dirent *direntp;
-	struct loop_info64 lo;
-	DIR *dir;
-	int fd = -1;
-
-	dir = opendir("/dev");
-	if (!dir) {
-		SYSERROR("Error opening /dev");
-		return -1;
-	}
-	while ((direntp = readdir(dir))) {
-
-		if (!direntp)
-			break;
-		if (strncmp(direntp->d_name, "loop", 4) != 0)
-			continue;
-		fd = openat(dirfd(dir), direntp->d_name, O_RDWR);
-		if (fd < 0)
-			continue;
-		if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) {
-			close(fd);
-			fd = -1;
-			continue;
-		}
-		// We can use this fd
-		snprintf(namep, 100, "/dev/%s", direntp->d_name);
-		break;
-	}
-	closedir(dir);
-	if (fd == -1) {
-		ERROR("No loop device found");
-		return -1;
-	}
-
-	*retfd = fd;
-	return 0;
-}
-
-static int find_free_loopdev(int *retfd, char *namep)
-{
-	int rc, fd = -1;
-	int ctl = open("/dev/loop-control", O_RDWR);
-	if (ctl < 0)
-		return find_free_loopdev_no_control(retfd, namep);
-	rc = ioctl(ctl, LOOP_CTL_GET_FREE);
-	if (rc >= 0) {
-		snprintf(namep, 100, "/dev/loop%d", rc);
-		fd = open(namep, O_RDWR);
-	}
-	close(ctl);
-	if (fd == -1) {
-		ERROR("No loop device found");
-		return -1;
-	}
-	*retfd = fd;
-	return 0;
-}
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 5f5d34c..fc7fb18 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -590,95 +590,21 @@ static int mount_rootfs_dir(const char *rootfs, const char *target,
 	return ret;
 }
 
-static int lxc_setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
-{
-	int rfd;
-
-	rfd = open(rootfs, O_RDWR);
-	if (rfd < 0) {
-		SYSERROR("failed to open '%s'", rootfs);
-		return -1;
-	}
-
-	memset(loinfo, 0, sizeof(*loinfo));
-
-	if (ioctl(fd, LOOP_SET_FD, rfd)) {
-		SYSERROR("failed to LOOP_SET_FD");
-		close(rfd);
-		return -1;
-	}
-
-	loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
-	if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
-		SYSERROR("failed to LOOP_SET_STATUS64");
-		close(rfd);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int mount_rootfs_file(const char *rootfs, const char *target,
+static int lxc_mount_rootfs_file(const char *rootfs, const char *target,
 			     const char *options)
 {
-	struct dirent *direntp;
-	struct loop_info64 loinfo;
-	DIR *dir;
+	int ret, loopfd;
 	char path[MAXPATHLEN];
-	int ret = -1, fd = -1, rc;
 
-	dir = opendir("/dev");
-	if (!dir) {
-		SYSERROR("failed to open '/dev'");
+	loopfd = lxc_prepare_loop_dev(rootfs, path, LO_FLAGS_AUTOCLEAR);
+	if (loopfd < 0)
 		return -1;
-	}
-
-	while ((direntp = readdir(dir))) {
-
-		if (!direntp)
-			break;
-
-		if (!strcmp(direntp->d_name, "."))
-			continue;
+	DEBUG("prepared loop device \"%s\"", path);
 
-		if (!strcmp(direntp->d_name, ".."))
-			continue;
-
-		if (strncmp(direntp->d_name, "loop", 4))
-			continue;
-
-		rc = snprintf(path, MAXPATHLEN, "/dev/%s", direntp->d_name);
-		if (rc < 0 || rc >= MAXPATHLEN)
-			continue;
-
-		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);
-			close(fd);
-			continue;
-		}
-
-		DEBUG("found '%s' free lodev", path);
-
-		ret = lxc_setup_lodev(rootfs, fd, &loinfo);
-		if (!ret)
-			ret = mount_unknown_fs(path, target, options);
-		close(fd);
-
-		break;
-	}
+	ret = mount_unknown_fs(path, target, options);
+	close(loopfd);
 
-	if (closedir(dir))
-		WARN("failed to close directory");
+	DEBUG("mounted rootfs \"%s\" on loop device \"%s\" via loop device \"%s\"", rootfs, target, path);
 
 	return ret;
 }
@@ -911,7 +837,7 @@ static int mount_rootfs(const char *rootfs, const char *target, const char *opti
 	} rtfs_type[] = {
 		{ S_IFDIR, mount_rootfs_dir },
 		{ S_IFBLK, mount_rootfs_block },
-		{ S_IFREG, mount_rootfs_file },
+		{ S_IFREG, lxc_mount_rootfs_file },
 	};
 
 	if (!realpath(rootfs, absrootfs)) {
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 1154d41..d83e294 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -2070,3 +2070,126 @@ int lxc_setgroups(int size, gid_t list[])
 
 	return 0;
 }
+
+static int lxc_get_unused_loop_dev_legacy(char *loop_name)
+{
+	struct dirent *dp;
+	struct loop_info64 lo64;
+	DIR *dir;
+	int dfd = -1, fd = -1, ret = -1;
+
+	dir = opendir("/dev");
+	if (!dir)
+		return -1;
+
+	while ((dp = readdir(dir))) {
+		if (!dp)
+			break;
+
+		if (strncmp(dp->d_name, "loop", 4) != 0)
+			continue;
+
+		dfd = dirfd(dir);
+		if (dfd < 0)
+			continue;
+
+		fd = openat(dfd, dp->d_name, O_RDWR);
+		if (fd < 0)
+			continue;
+
+		ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
+		if (ret < 0) {
+			if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0 ||
+			    errno != ENXIO) {
+				close(fd);
+				fd = -1;
+				continue;
+			}
+		}
+
+		ret = snprintf(loop_name, LO_NAME_SIZE, "/dev/%s", dp->d_name);
+		if (ret < 0 || ret >= LO_NAME_SIZE) {
+			close(fd);
+			fd = -1;
+			continue;
+		}
+
+		break;
+	}
+
+	closedir(dir);
+
+	if (fd < 0)
+		return -1;
+
+	return fd;
+}
+
+static int lxc_get_unused_loop_dev(char *name_loop)
+{
+	int loop_nr, ret;
+	int fd_ctl = -1, fd_tmp = -1;
+
+	fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
+	if (fd_ctl < 0)
+		return -ENODEV;
+
+	loop_nr = ioctl(fd_ctl, LOOP_CTL_GET_FREE);
+	if (loop_nr < 0)
+		goto on_error;
+
+	ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/loop%d", loop_nr);
+	if (ret < 0 || ret >= LO_NAME_SIZE)
+		goto on_error;
+
+	fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
+	if (fd_tmp < 0)
+		goto on_error;
+
+on_error:
+	close(fd_ctl);
+	return fd_tmp;
+}
+
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags)
+{
+	int ret;
+	struct loop_info64 lo64;
+	int fd_img = -1, fret = -1, fd_loop = -1;
+
+	fd_loop = lxc_get_unused_loop_dev(loop_dev);
+	if (fd_loop < 0) {
+		if (fd_loop == -ENODEV)
+			fd_loop = lxc_get_unused_loop_dev_legacy(loop_dev);
+		else
+			goto on_error;
+	}
+
+	fd_img = open(source, O_RDWR | O_CLOEXEC);
+	if (fd_img < 0)
+		goto on_error;
+
+	ret = ioctl(fd_loop, LOOP_SET_FD, fd_img);
+	if (ret < 0)
+		goto on_error;
+
+	memset(&lo64, 0, sizeof(lo64));
+	lo64.lo_flags = flags;
+
+	ret = ioctl(fd_loop, LOOP_SET_STATUS64, &lo64);
+	if (ret < 0)
+		goto on_error;
+
+	fret = 0;
+
+on_error:
+	if (fd_img >= 0)
+		close(fd_img);
+
+	if (fret < 0 && fd_loop >= 0) {
+		close(fd_loop);
+		fd_loop = -1;
+	}
+
+	return fd_loop;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 19caa6d..b6fc7c5 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -23,15 +23,19 @@
 #ifndef __LXC_UTILS_H
 #define __LXC_UTILS_H
 
+/* Properly support loop devices on 32bit systems. */
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <unistd.h>
+#include <linux/loop.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #include "initutils.h"
 
@@ -164,6 +168,15 @@ static inline int signalfd(int fd, const sigset_t *mask, int flags)
 }
 #endif
 
+/* loop devices */
+#ifndef LO_FLAGS_AUTOCLEAR
+#define LO_FLAGS_AUTOCLEAR 4
+#endif
+
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
 /* Struct to carry child pid from lxc_popen() to lxc_pclose().
  * Not an opaque struct to allow direct access to the underlying FILE *
  * (i.e., struct lxc_popen_FILE *file; fgets(buf, sizeof(buf), file->f))
@@ -332,4 +345,7 @@ int lxc_safe_long(const char *numstr, long int *converted);
 int lxc_switch_uid_gid(uid_t uid, gid_t gid);
 int lxc_setgroups(int size, gid_t list[]);
 
+/* Find an unused loop device and associate it with source. */
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
+
 #endif /* __LXC_UTILS_H */


More information about the lxc-devel mailing list