[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