summaryrefslogtreecommitdiffstats
path: root/lib/loopdev.c
diff options
context:
space:
mode:
authorKarel Zak2012-06-12 15:41:47 +0200
committerKarel Zak2012-06-12 15:41:47 +0200
commite4062c72d1733b0b99ed1c6269c996d6194e869b (patch)
tree53050523c6c19d6f2413130eecde9b9bf5249c64 /lib/loopdev.c
parentlosetup: warn about backing file size (diff)
downloadkernel-qcow2-util-linux-e4062c72d1733b0b99ed1c6269c996d6194e869b.tar.gz
kernel-qcow2-util-linux-e4062c72d1733b0b99ed1c6269c996d6194e869b.tar.xz
kernel-qcow2-util-linux-e4062c72d1733b0b99ed1c6269c996d6194e869b.zip
losetup: improve -a to report loopdevs < 512 bytes
# ll ~/xxx2 -rw-r--r-- 1 root root 500 Jun 12 14:30 /root/xxx2 old version: # losetup -a new version: # losetup -a /dev/loop0: [2052]:535312 (/root/xxx2) The new version scans /sys/block/loopN, kernel >= 2.6.37 is required otherwise fallback to the original not-so-smart /proc/partitions scan. Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=730266 Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib/loopdev.c')
-rw-r--r--lib/loopdev.c112
1 files changed, 95 insertions, 17 deletions
diff --git a/lib/loopdev.c b/lib/loopdev.c
index c0f701896..8e5706735 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -37,6 +37,7 @@
#include "pathnames.h"
#include "loopdev.h"
#include "canonicalize.h"
+#include "at.h"
#define CONFIG_LOOPDEV_DEBUG
@@ -64,8 +65,12 @@ loopdev_debug(const char *mesg, ...)
# define DBG(m,x) do { ; } while(0)
#endif
-
+/*
+ * see loopcxt_init()
+ */
#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL))
+#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \
+ && !loopcxt_ioctl_enabled(_lc)
/*
* @lc: context
@@ -337,8 +342,11 @@ int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
free(iter->minors);
if (iter->proc)
fclose(iter->proc);
+ if (iter->sysblock)
+ closedir(iter->sysblock);
iter->minors = NULL;
iter->proc = NULL;
+ iter->sysblock = NULL;
iter->done = 1;
return 0;
}
@@ -448,6 +456,85 @@ static int loop_scandir(const char *dirname, int **ary, int hasprefix)
}
/*
+ * Set the next *used* loop device according to /proc/partitions.
+ *
+ * Loop devices smaller than 512 bytes are invisible for this function.
+ */
+static int loopcxt_next_from_proc(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter = &lc->iter;
+ char buf[BUFSIZ];
+
+ DBG(lc, loopdev_debug("iter: scan /proc/partitions"));
+
+ if (!iter->proc)
+ iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
+ if (!iter->proc)
+ return 1;
+
+ while (fgets(buf, sizeof(buf), iter->proc)) {
+ unsigned int m;
+ char name[128];
+
+
+ if (sscanf(buf, " %u %*s %*s %128[^\n ]",
+ &m, name) != 2 || m != LOOPDEV_MAJOR)
+ continue;
+
+ DBG(lc, loopdev_debug("iter: check %s", name));
+
+ if (loopiter_set_device(lc, name) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Set the next *used* loop device according to
+ * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required).
+ *
+ * This is preferred method.
+ */
+static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc)
+{
+ struct loopdev_iter *iter = &lc->iter;
+ struct dirent *d;
+ int fd;
+
+ DBG(lc, loopdev_debug("iter: scan /sys/block"));
+
+ if (!iter->sysblock)
+ iter->sysblock = opendir(_PATH_SYS_BLOCK);
+
+ if (!iter->sysblock)
+ return 1;
+
+ fd = dirfd(iter->sysblock);
+
+ while ((d = readdir(iter->sysblock))) {
+ char name[256];
+ struct stat st;
+
+ DBG(lc, loopdev_debug("iter: check %s", d->d_name));
+
+ if (strcmp(d->d_name, ".") == 0
+ || strcmp(d->d_name, "..") == 0
+ || strncmp(d->d_name, "loop", 4) != 0)
+ continue;
+
+ snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name);
+ if (fstat_at(fd, _PATH_SYS_BLOCK, name, &st, 0) != 0)
+ continue;
+
+ if (loopiter_set_device(lc, d->d_name) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* @lc: context, has to initialized by loopcxt_init_iterator()
*
* Returns: 0 on success, -1 on error, 1 at the end of scanning. The details
@@ -470,23 +557,14 @@ int loopcxt_next(struct loopdev_cxt *lc)
/* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
*/
if (iter->flags & LOOPITER_FL_USED) {
- char buf[BUFSIZ];
-
- if (!iter->proc)
- iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
-
- while (iter->proc && fgets(buf, sizeof(buf), iter->proc)) {
- unsigned int m;
- char name[128];
-
- if (sscanf(buf, " %u %*s %*s %128[^\n ]",
- &m, name) != 2 || m != LOOPDEV_MAJOR)
- continue;
-
- if (loopiter_set_device(lc, name) == 0)
- return 0;
- }
+ int rc;
+ if (loopcxt_sysfs_available(lc))
+ rc = loopcxt_next_from_sysfs(lc);
+ else
+ rc = loopcxt_next_from_proc(lc);
+ if (rc == 0)
+ return 0;
goto done;
}