--- 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 #include #include +#include +#include #include -#include #include #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