The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/2979

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>

Improces the the logic a little and might come in handy once I figured out how to use loop-file backed lvm pools.
From c8e82645284a17f333b050ce60eb5b2294fdedf1 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@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.brau...@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.")
        }
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to