aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Margaine <florian@platform.sh>2015-11-13 18:09:05 +0100
committerDavid Sterba <dsterba@suse.com>2015-11-16 14:23:46 +0100
commit0cf3b78f404b01b6e400fac6eb29890fc430b20e (patch)
tree9d0162a9aeac063ca3fd30ac00ac4350aa88b146
parent214308422933601138ee484e81dade47edcb442c (diff)
downloadbtrfs-progs-0cf3b78f404b01b6e400fac6eb29890fc430b20e.tar.gz
btrfs-progs: Fix partitioned loop devices resolving
When using partitions on a loop device, the device's name can be e.g. /dev/loop0p1 or similar, and no relevant entry exists in the /sys filesystem, so the current resolve_loop_device function fails. Instead of using string functions to extract the device name and reading this file, this patch uses the loop device API through ioctl to get the correct backing file. Signed-off-by: Florian Margaine <florian@platform.sh> [ changed checks of error values from open and ioctl ] Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--utils.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/utils.c b/utils.c
index 17f47574..4f3fbbae 100644
--- a/utils.c
+++ b/utils.c
@@ -1172,6 +1172,28 @@ static int is_loop_device (const char* device) {
MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
}
+/*
+ * Takes a loop device path (e.g. /dev/loop0) and returns
+ * the associated file (e.g. /images/my_btrfs.img) using
+ * loopdev API
+ */
+static int resolve_loop_device_with_loopdev(const char* loop_dev, char* loop_file)
+{
+ int fd;
+ struct loop_info64 lo64;
+
+ fd = open(loop_dev, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+ if (ioctl(fd, LOOP_GET_STATUS64, &lo64) < 0)
+ return -errno;
+
+ memcpy(loop_file, lo64.lo_file_name, strlen(lo64.lo_file_name) + 1);
+ if (close(fd) < 0)
+ return -errno;
+
+ return 0;
+}
/* Takes a loop device path (e.g. /dev/loop0) and returns
* the associated file (e.g. /images/my_btrfs.img) */
@@ -1187,8 +1209,15 @@ static int resolve_loop_device(const char* loop_dev, char* loop_file,
if (!realpath(loop_dev, real_loop_dev))
return -errno;
snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/'));
- if (!(f = fopen(p, "r")))
+ if (!(f = fopen(p, "r"))) {
+ if (errno == ENOENT)
+ /*
+ * It's possibly a partitioned loop device, which is
+ * resolvable with loopdev API.
+ */
+ return resolve_loop_device_with_loopdev(loop_dev, loop_file);
return -errno;
+ }
snprintf(fmt, 20, "%%%i[^\n]", max_len-1);
ret = fscanf(f, fmt, loop_file);