[lxc-devel] [lxd/master] storage_cgo: detect if loop file is already in use

brauner on Github lxc-bot at linuxcontainers.org
Tue Feb 28 23:46:26 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 481 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170228/671c9f0f/attachment.bin>
-------------- next part --------------
From c8e82645284a17f333b050ce60eb5b2294fdedf1 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 1 Mar 2017 00:23:26 +0100
Subject: [PATCH] storage_cgo: detect if loop file is already in use

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_cgo.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 3 deletions(-)

diff --git a/lxd/storage_cgo.go b/lxd/storage_cgo.go
index 76ae34c..95ede6f 100644
--- a/lxd/storage_cgo.go
+++ b/lxd/storage_cgo.go
@@ -23,6 +23,100 @@ package main
 #define LO_FLAGS_AUTOCLEAR 4
 #endif
 
+#define LXD_MAXPATH 4096
+#define LXD_NUMSTRLEN64 21
+#define LXD_MAX_LOOP_PATHLEN (2 * sizeof("loop/")) + LXD_NUMSTRLEN64 + sizeof("backing_file") + 1
+
+// If a loop file is already associated with a loop device, find it.
+static int find_associated_loop_device(const char *loop_file,
+				       char *loop_dev_name)
+{
+	char looppath[LXD_MAX_LOOP_PATHLEN];
+	char buf[LXD_MAXPATH];
+	struct dirent *dp;
+	DIR *dir;
+	int dfd = -1, fd = -1;
+
+	dir = opendir("/sys/block");
+	if (!dir)
+		return -1;
+
+	while ((dp = readdir(dir))) {
+		int ret = -1;
+		size_t totlen;
+		struct stat fstatbuf;
+		char *delsuffix = " (deleted)";
+		size_t dellen = sizeof(delsuffix);
+
+		if (!dp)
+			break;
+
+		if (strncmp(dp->d_name, "loop", 4) != 0)
+			continue;
+
+		dfd = dirfd(dir);
+		if (dfd < 0)
+			continue;
+
+		ret = snprintf(looppath, sizeof(looppath),
+			       "%s/loop/backing_file", dp->d_name);
+		if (ret < 0 || (size_t)ret >= sizeof(looppath))
+			continue;
+
+		ret = fstatat(dfd, looppath, &fstatbuf, 0);
+		if (ret < 0)
+			continue;
+
+		fd = openat(dfd, looppath, O_RDONLY | O_CLOEXEC, 0);
+		if (ret < 0)
+			continue;
+
+		// Clear buffer.
+		memset(buf, 0, sizeof(buf));
+		ret = read(fd, buf, sizeof(buf));
+		if (ret < 0)
+			continue;
+
+		totlen = strlen(buf);
+		// Trim newline.
+		if (buf[totlen - 1] == '\n') {
+			buf[totlen - 1] = '\0';
+			totlen--;
+		}
+
+		if (totlen > dellen) {
+			char *deleted = &buf[totlen - dellen];
+
+			// Skip deleted loop files.
+			if (!strcmp(deleted, delsuffix))
+				continue;
+		}
+
+		if (strcmp(buf, loop_file)) {
+			close(fd);
+			fd = -1;
+			continue;
+		}
+
+		ret = snprintf(loop_dev_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 get_unused_loop_dev_legacy(char *loop_name)
 {
 	struct dirent *dp;
@@ -50,14 +144,14 @@ static int get_unused_loop_dev_legacy(char *loop_name)
 			continue;
 
 		ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
-		if (ret < 0)
-
+		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) {
@@ -166,8 +260,16 @@ func prepareLoopDev(source string) (*os.File, error) {
 
 	cSource := C.CString(source)
 	defer C.free(unsafe.Pointer(cSource))
-	loopFd := int(C.prepare_loop_dev(cSource, (*C.char)(cLoopDev)))
+	loopFd, _ := C.find_associated_loop_device(cSource, (*C.char)(cLoopDev))
+	if loopFd >= 0 {
+		return os.NewFile(uintptr(loopFd), C.GoString((*C.char)(cLoopDev))), nil
+	}
+
+	loopFd, err := C.prepare_loop_dev(cSource, (*C.char)(cLoopDev))
 	if loopFd < 0 {
+		if err != nil {
+			return nil, fmt.Errorf("Failed to prepare loop device: %s.", err)
+		}
 		return nil, fmt.Errorf("Failed to prepare loop device.")
 	}
 


More information about the lxc-devel mailing list