You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
7.0 KiB
272 lines
7.0 KiB
--- |
|
kpartx/lopart.c | 206 ++++++++++++++++++++++++++++++++++---------------------- |
|
1 file changed, 127 insertions(+), 79 deletions(-) |
|
|
|
Index: multipath-tools-130222/kpartx/lopart.c |
|
=================================================================== |
|
--- multipath-tools-130222.orig/kpartx/lopart.c |
|
+++ multipath-tools-130222/kpartx/lopart.c |
|
@@ -25,8 +25,9 @@ |
|
#include <sys/ioctl.h> |
|
#include <sys/stat.h> |
|
#include <sys/mman.h> |
|
+#include <sys/types.h> |
|
+#include <dirent.h> |
|
#include <sysmacros.h> |
|
-#include <asm/posix_types.h> |
|
#include <linux/loop.h> |
|
|
|
#include "lopart.h" |
|
@@ -96,97 +97,149 @@ is_loop_device (const char *device) |
|
#define SIZE(a) (sizeof(a)/sizeof(a[0])) |
|
|
|
extern char * |
|
-find_loop_by_file (const char * filename) |
|
+find_loop_by_file(const char *filename) |
|
{ |
|
- char dev[64]; |
|
- char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; |
|
- int i, j, fd; |
|
+ DIR *dir; |
|
+ struct dirent *dent; |
|
+ char dev[64], *found = NULL, *p; |
|
+ int fd, bytes_read; |
|
struct stat statbuf; |
|
struct loop_info loopinfo; |
|
+ const char VIRT_BLOCK[] = "/sys/devices/virtual/block"; |
|
+ char path[PATH_MAX]; |
|
+ char bf_path[PATH_MAX]; |
|
+ char backing_file[PATH_MAX]; |
|
|
|
- for (j = 0; j < SIZE(loop_formats); j++) { |
|
+ dir = opendir(VIRT_BLOCK); |
|
+ if (!dir) |
|
+ return NULL; |
|
|
|
- for (i = 0; i < 256; i++) { |
|
- sprintf (dev, loop_formats[j], i); |
|
+ while ((dent = readdir(dir)) != NULL) { |
|
+ if (strncmp(dent->d_name,"loop",4)) |
|
+ continue; |
|
|
|
- if (stat (dev, &statbuf) != 0 || |
|
- !S_ISBLK(statbuf.st_mode)) |
|
- continue; |
|
+ if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK, |
|
+ dent->d_name) >= PATH_MAX) |
|
+ continue; |
|
|
|
- fd = open (dev, O_RDONLY); |
|
+ fd = open(path, O_RDONLY); |
|
+ if (fd < 0) |
|
+ continue; |
|
|
|
- if (fd < 0) |
|
- break; |
|
+ bytes_read = read(fd, dev, sizeof(dev) - 1); |
|
+ if (bytes_read <= 0) { |
|
+ close(fd); |
|
+ continue; |
|
+ } |
|
|
|
- if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) { |
|
- close (fd); |
|
- continue; |
|
- } |
|
+ close(fd); |
|
|
|
- if (0 == strcmp(filename, loopinfo.lo_name)) { |
|
- close (fd); |
|
- return xstrdup(dev); /*found */ |
|
- } |
|
+ dev[bytes_read] = '\0'; |
|
+ p = strchr(dev, '\n'); |
|
+ if (p != NULL) |
|
+ *p = '\0'; |
|
+ if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX) |
|
+ continue; |
|
|
|
+ fd = open (path, O_RDONLY); |
|
+ if (fd < 0) |
|
+ continue; |
|
+ |
|
+ if (fstat (fd, &statbuf) != 0 || |
|
+ !S_ISBLK(statbuf.st_mode)) { |
|
+ close (fd); |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) { |
|
close (fd); |
|
continue; |
|
} |
|
+ |
|
+ close (fd); |
|
+ |
|
+ if (0 == strcmp(filename, loopinfo.lo_name)) { |
|
+ found = realpath(path, NULL); |
|
+ break; |
|
+ } |
|
+ |
|
+ /* |
|
+ * filename is a realpath, while loopinfo.lo_name may hold just the |
|
+ * basename. If that's the case, try to match filename against the |
|
+ * backing_file entry for this loop entry |
|
+ */ |
|
+ if (snprintf(bf_path, PATH_MAX, "%s/%s/loop/backing_file", |
|
+ VIRT_BLOCK, dent->d_name) >= PATH_MAX) |
|
+ continue; |
|
+ |
|
+ fd = open(bf_path, O_RDONLY); |
|
+ if (fd < 0) |
|
+ continue; |
|
+ |
|
+ bytes_read = read(fd, backing_file, sizeof(backing_file) - 1); |
|
+ if (bytes_read <= 0) { |
|
+ close(fd); |
|
+ continue; |
|
+ } |
|
+ |
|
+ close(fd); |
|
+ |
|
+ backing_file[bytes_read-1] = '\0'; |
|
+ |
|
+ if (0 == strcmp(filename, backing_file)) { |
|
+ found = realpath(path, NULL); |
|
+ break; |
|
+ } |
|
} |
|
- return NULL; |
|
+ closedir(dir); |
|
+ return found; |
|
} |
|
|
|
extern char * |
|
-find_unused_loop_device (void) |
|
+find_unused_loop_device(void) |
|
{ |
|
- /* Just creating a device, say in /tmp, is probably a bad idea - |
|
- people might have problems with backup or so. |
|
- So, we just try /dev/loop[0-7]. */ |
|
- |
|
- char dev[20]; |
|
- char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; |
|
- int i, j, fd, first = 0, somedev = 0, someloop = 0, loop_known = 0; |
|
+ char dev[20], *next_loop_dev = NULL; |
|
+ int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0; |
|
struct stat statbuf; |
|
struct loop_info loopinfo; |
|
FILE *procdev; |
|
|
|
- if (stat("/dev/loop-control", &statbuf) == 0 && |
|
- S_ISCHR(statbuf.st_mode)) { |
|
- fd = open("/dev/loop-control", O_RDWR); |
|
- if (fd >= 0) { |
|
- first = ioctl(fd, LOOP_CTL_GET_FREE); |
|
- close(fd); |
|
+ while (next_loop_dev == NULL) { |
|
+ if (stat("/dev/loop-control", &statbuf) == 0 && |
|
+ S_ISCHR(statbuf.st_mode)) { |
|
+ int next_loop_fd; |
|
+ |
|
+ next_loop_fd = open("/dev/loop-control", O_RDWR); |
|
+ if (next_loop_fd < 0) |
|
+ return NULL; |
|
+ next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE); |
|
+ close(next_loop_fd); |
|
+ if (next_loop < 0) |
|
+ return NULL; |
|
} |
|
- if (first < 0) |
|
- first = 0; |
|
- } |
|
- for (j = 0; j < SIZE(loop_formats); j++) { |
|
- |
|
- for(i = first; i < 256; i++) { |
|
- sprintf(dev, loop_formats[j], i); |
|
- |
|
- if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { |
|
- somedev++; |
|
- fd = open (dev, O_RDONLY); |
|
|
|
- if (fd >= 0) { |
|
+ sprintf(dev, "/dev/loop%d", next_loop); |
|
|
|
+ fd = open (dev, O_RDONLY); |
|
+ if (fd >= 0) { |
|
+ if (fstat (fd, &statbuf) == 0 && |
|
+ S_ISBLK(statbuf.st_mode)) { |
|
+ somedev++; |
|
if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) |
|
- someloop++; /* in use */ |
|
- |
|
- else if (errno == ENXIO) { |
|
- close (fd); |
|
- return xstrdup(dev);/* probably free */ |
|
- } |
|
+ someloop++; /* in use */ |
|
+ else if (errno == ENXIO) |
|
+ next_loop_dev = xstrdup(dev); |
|
|
|
- close (fd); |
|
} |
|
- |
|
+ close (fd); |
|
+ |
|
/* continue trying as long as devices exist */ |
|
continue; |
|
} |
|
break; |
|
- } |
|
} |
|
+ if (next_loop_dev) |
|
+ return next_loop_dev; |
|
|
|
/* Nothing found. Why not? */ |
|
if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) { |
|
@@ -209,29 +262,24 @@ find_unused_loop_device (void) |
|
fprintf(stderr, "mount: could not find any device /dev/loop#"); |
|
|
|
else if (!someloop) { |
|
- |
|
- if (loop_known == 1) |
|
- fprintf(stderr, |
|
- "mount: Could not find any loop device.\n" |
|
- " Maybe /dev/loop# has a wrong major number?"); |
|
- |
|
- else if (loop_known == -1) |
|
- fprintf(stderr, |
|
- "mount: Could not find any loop device, and, according to %s,\n" |
|
- " this kernel does not know about the loop device.\n" |
|
- " (If so, then recompile or `modprobe loop'.)", |
|
- PROC_DEVICES); |
|
- |
|
- else |
|
- fprintf(stderr, |
|
- "mount: Could not find any loop device. Maybe this kernel does not know\n" |
|
- " about the loop device (then recompile or `modprobe loop'), or\n" |
|
- " maybe /dev/loop# has the wrong major number?"); |
|
- |
|
+ if (loop_known == 1) |
|
+ fprintf(stderr, |
|
+ "mount: Could not find any loop device.\n" |
|
+ " Maybe /dev/loop# has a wrong major number?"); |
|
+ else if (loop_known == -1) |
|
+ fprintf(stderr, |
|
+ "mount: Could not find any loop device, and, according to %s,\n" |
|
+ " this kernel does not know about the loop device.\n" |
|
+ " (If so, then recompile or `modprobe loop'.)", |
|
+ PROC_DEVICES); |
|
+ else |
|
+ fprintf(stderr, |
|
+ "mount: Could not find any loop device. Maybe this kernel does not know\n" |
|
+ " about the loop device (then recompile or `modprobe loop'), or\n" |
|
+ " maybe /dev/loop# has the wrong major number?"); |
|
} else |
|
fprintf(stderr, "mount: could not find any free loop device"); |
|
- |
|
- return 0; |
|
+ return NULL; |
|
} |
|
|
|
extern int
|
|
|