> No feedback.. so applied (we will see ... :-) didn`t i really comment on that? mhh - weird! > Roland, didn't you ask for more than 256 loop devices? > http://www.mail-archive.com/util-linux-ng@xxxxxxxxxxxxxxx/msg00842.html oh yes, indeed! actually i have a system where i use more than 256 loop devices (central cd-rom server) and it`s working very well. i`m sure i did try the patch once and it seemed to work, but since the cd-rom server was already in production, i was using a less intrusive hack on that to work arond the problem. iirc, the patch didn`t apply to suse util-linux package and i didnŽt want to replace it by the original util-linux package. will try your patch again very soon and give feedback - thank you for asking! regards roland > > Karel > > -----Ursprüngliche Nachricht----- > Von: "Karel Zak" <kzak@xxxxxxxxxx> > Gesendet: 08.02.08 02:17:07 > An: util-linux-ng@xxxxxxxxxxxxxxx > Betreff: Re: [PATCH] losetup: support unlimited number of loops > > > No feedback.. so applied (we will see ... :-) > > Roland, didn't you ask for more than 256 loop devices? > http://www.mail-archive.com/util-linux-ng@xxxxxxxxxxxxxxx/msg00842.html > > Karel > > On Mon, Nov 26, 2007 at 12:37:42PM +0100, Karel Zak wrote: > > Old implementation: > > > > - supports 256 loop devices only > > - doesn't support gaps in list of loop devices > > (e.g. loop0, loop1, loop3 -- loop3 is invisible) > > > > Kernel 2.6.21 removes artificial maximum 256 loop device. Now the maximum > > of loop devices could be really huge (depends on limit of MINOR > > numbers). It means we need a better way how work with loop devices > > than blindly call stat(2) for all 0-1048575 devices. > > > > This patch uses three methods: > > > > a) scan /sys/block/loopN (used for losetup -a only). This method is > > probably the fastest way how found used loop device on machine with > > huge number of devices in /dev. > > > > b) classic way, stat(2) for all loop[0-7] devices (default number of > > loop devices). This cheap method is sufficient for 99% of all machines. > > > > c) scan all /dev/loopN or /dev/loop/N > > > > Signed-off-by: Karel Zak <kzak@xxxxxxxxxx> > > --- > > mount/lomount.c | 427 +++++++++++++++++++++++++++++++++++++++++-------------- > > 1 files changed, 318 insertions(+), 109 deletions(-) > > > > diff --git a/mount/lomount.c b/mount/lomount.c > > index 5bd8954..01bfa14 100644 > > --- a/mount/lomount.c > > +++ b/mount/lomount.c > > @@ -1,7 +1,4 @@ > > /* Originally from Ted's losetup.c */ > > - > > -#define LOOPMAJOR 7 > > - > > /* > > * losetup.c - setup and control loop devices > > */ > > @@ -17,6 +14,7 @@ > > #include <sys/stat.h> > > #include <sys/mman.h> > > #include <sys/sysmacros.h> > > +#include <dirent.h> > > > > #include "loop.h" > > #include "lomount.h" > > @@ -60,20 +58,260 @@ loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) > > return 0; > > } > > > > +#define DEV_LOOP_PATH "/dev/loop" > > +#define DEV_PATH "/dev" > > +#define SYSFS_BLOCK_PATH "/sys/block" > > +#define LOOPMAJOR 7 > > +#define NLOOPS_DEFAULT 8 /* /dev/loop[0-7] */ > > + > > +struct looplist { > > + int flag; /* scanning options */ > > + int ndef; /* number of tested default devices */ > > + struct dirent **names; /* scandir-like list of loop devices */ > > + int nnames; /* number of items in names */ > > + int ncur; /* current possition in direcotry */ > > + char name[32]; /* device name */ > > + int ct_perm; /* count permission problems */ > > + int ct_succ; /* count number of successfully > > + detected devices */ > > +}; > > + > > +#define LLFLG_USEDONLY (1 << 1) /* return used devices only */ > > +#define LLFLG_FREEONLY (1 << 2) /* return non-used devices */ > > +#define LLFLG_DONE (1 << 3) /* all is done */ > > +#define LLFLG_SYSFS (1 << 4) /* try to use /sys/block */ > > +#define LLFLG_SUBDIR (1 << 5) /* /dev/loop/N */ > > +#define LLFLG_DFLT (1 << 6) /* directly try to check default loops */ > > + > > +int > > +is_loop_device (const char *device) { > > + struct stat st; > > + > > + return (stat(device, &st) == 0 && > > + S_ISBLK(st.st_mode) && > > + major(st.st_rdev) == LOOPMAJOR); > > +} > > + > > +static int > > +is_loop_used(int fd) > > +{ > > + struct loop_info li; > > + return ioctl (fd, LOOP_GET_STATUS, &li) == 0; > > +} > > + > > +static char * > > +looplist_mk_devname(struct looplist *ll, int num) > > +{ > > + if (ll->flag & LLFLG_SUBDIR) > > + snprintf(ll->name, sizeof(ll->name), > > + DEV_LOOP_PATH "/%d", num); > > + else > > + snprintf(ll->name, sizeof(ll->name), > > + DEV_PATH "/loop%d", num); > > + > > + return is_loop_device(ll->name) ? ll->name : NULL; > > +} > > + > > +/* ignores all non-loop devices, default loop devices */ > > +static int > > +filter_loop(const struct dirent *d) > > +{ > > + return strncmp(d->d_name, "loop", 4) == 0; > > +} > > + > > +/* all loops exclude default loops */ > > +static int > > +filter_loop_ndflt(const struct dirent *d) > > +{ > > + int mn; > > + > > + if (strncmp(d->d_name, "loop", 4) == 0 && > > + sscanf(d->d_name, "loop%d", &mn) == 1 && > > + mn >= NLOOPS_DEFAULT) > > + return 1; > > + return 0; > > +} > > + > > +static int > > +filter_loop_num(const struct dirent *d) > > +{ > > + char *end = NULL; > > + int mn = strtol(d->d_name, &end, 10); > > + > > + if (mn >= NLOOPS_DEFAULT && end && *end == '\0') > > + return 1; > > + return 0; > > +} > > + > > +static int > > +looplist_open(struct looplist *ll, int flag) > > +{ > > + struct stat st; > > + > > + memset(ll, 0, sizeof(*ll)); > > + ll->flag = flag; > > + ll->ndef = -1; > > + ll->ncur = -1; > > + > > + if (stat(DEV_PATH, &st) == -1 || (!S_ISDIR(st.st_mode))) > > + return -1; /* /dev doesn't exist */ > > + > > + if (stat(DEV_LOOP_PATH, &st) == 0 && S_ISDIR(st.st_mode)) > > + ll->flag |= LLFLG_SUBDIR; /* /dev/loop/ exists */ > > + > > + if ((ll->flag & LLFLG_USEDONLY) && > > + stat(SYSFS_BLOCK_PATH, &st) == 0 && > > + S_ISDIR(st.st_mode)) > > + ll->flag |= LLFLG_SYSFS; /* try to use /sys/block/loopN */ > > + > > + ll->flag |= LLFLG_DFLT; /* required! */ > > + return 0; > > +} > > + > > +static void > > +looplist_close(struct looplist *ll) > > +{ > > + if (ll->names) { > > + for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) > > + free(ll->names[ll->ncur]); > > + > > + free(ll->names); > > + ll->names = NULL; > > + ll->nnames = 0; > > + } > > + ll->ncur = -1; > > + ll->flag |= LLFLG_DONE; > > +} > > + > > +static int > > +looplist_is_wanted(struct looplist *ll, int fd) > > +{ > > + int ret; > > + > > + if (!(ll->flag & (LLFLG_USEDONLY | LLFLG_FREEONLY))) > > + return 1; > > + ret = is_loop_used(fd); > > + > > + if ((ll->flag & LLFLG_USEDONLY) && ret == 0) > > + return 0; > > + if ((ll->flag & LLFLG_FREEONLY) && ret == 1) > > + return 0; > > + > > + return 1; > > +} > > + > > +static int > > +looplist_next(struct looplist *ll) > > +{ > > + int fd; > > + int ret; > > + char *dirname, *dev; > > + > > + if (ll->flag & LLFLG_DONE) > > + return -1; > > + > > + /* A) try to use /sys/block/loopN devices (for losetup -a only) > > + */ > > + if (ll->flag & LLFLG_SYSFS) { > > + int mn; > > + > > + if (!ll->nnames) { > > + ll->nnames = scandir(SYSFS_BLOCK_PATH, &ll->names, > > + filter_loop, versionsort); > > + ll->ncur = -1; > > + } > > + for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) { > > + ret = sscanf(ll->names[ll->ncur]->d_name, "loop%d", &mn); > > + free(ll->names[ll->ncur]); > > + if (ret != 1) > > + continue; > > + dev = looplist_mk_devname(ll, mn); > > + if (dev) { > > + ll->ct_succ++; > > + if ((fd = open(dev, O_RDONLY)) > -1) { > > + if (looplist_is_wanted(ll, fd)) > > + return fd; > > + close(fd); > > + } else if (errno == EACCES) > > + ll->ct_perm++; > > + } > > + } > > + if (ll->nnames) > > + free(ll->names); > > + ll->names = NULL; > > + ll->ncur = -1; > > + ll->nnames = 0; > > + ll->flag &= ~LLFLG_SYSFS; > > + goto done; > > + } > > + > > + /* B) Classic way, try first eight loop devices (default number > > + * of loop devices). This is enough for 99% of all cases. > > + */ > > + if (ll->flag & LLFLG_DFLT) { > > + for (++ll->ncur; ll->ncur < NLOOPS_DEFAULT; ll->ncur++) { > > + dev = looplist_mk_devname(ll, ll->ncur); > > + if (dev) { > > + ll->ct_succ++; > > + if ((fd = open(dev, O_RDONLY)) > -1) { > > + if (looplist_is_wanted(ll, fd)) > > + return fd; > > + close(fd); > > + } else if (errno == EACCES) > > + ll->ct_perm++; > > + } > > + } > > + ll->flag &= ~LLFLG_DFLT; > > + ll->ncur = -1; > > + } > > + > > + > > + /* C) the worst posibility, scan all /dev or /dev/loop > > + */ > > + dirname = ll->flag & LLFLG_SUBDIR ? DEV_LOOP_PATH : DEV_PATH; > > + > > + if (!ll->nnames) { > > + ll->nnames = scandir(dirname, &ll->names, > > + ll->flag & LLFLG_SUBDIR ? > > + filter_loop_num : filter_loop_ndflt, > > + versionsort); > > + ll->ncur = -1; > > + } > > + > > + for(++ll->ncur; ll->ncur < ll->nnames; ll->ncur++) { > > + struct stat st; > > + > > + snprintf(ll->name, sizeof(ll->name), > > + "%s/%s", dirname, ll->names[ll->ncur]->d_name); > > + free(ll->names[ll->ncur]); > > + ret = stat(ll->name, &st); > > + > > + if (ret == 0 && S_ISBLK(st.st_mode) && > > + major(st.st_rdev) == LOOPMAJOR && > > + minor(st.st_rdev) >= NLOOPS_DEFAULT) { > > + ll->ct_succ++; > > + fd = open(ll->name, O_RDONLY); > > + > > + if (fd != -1) { > > + if (looplist_is_wanted(ll, fd)) > > + return fd; > > + close(fd); > > + } else if (errno == EACCES) > > + ll->ct_perm++; > > + } > > + } > > +done: > > + looplist_close(ll); > > + return -1; > > +} > > + > > #ifdef MAIN > > > > static int > > -show_loop(char *device) { > > +show_loop_fd(int fd, char *device) { > > struct loop_info loopinfo; > > struct loop_info64 loopinfo64; > > - int fd, errsv; > > - > > - if ((fd = open(device, O_RDONLY)) < 0) { > > - int errsv = errno; > > - fprintf(stderr, _("loop: can't open device %s: %s\n"), > > - device, strerror (errsv)); > > - return 2; > > - } > > + int errsv; > > > > if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) { > > > > @@ -101,7 +339,6 @@ show_loop(char *device) { > > e, loopinfo64.lo_encrypt_type); > > } > > printf("\n"); > > - close (fd); > > return 0; > > } > > > > @@ -118,52 +355,55 @@ show_loop(char *device) { > > loopinfo.lo_encrypt_type); > > > > printf("\n"); > > - close (fd); > > return 0; > > } > > > > errsv = errno; > > fprintf(stderr, _("loop: can't get info on device %s: %s\n"), > > device, strerror (errsv)); > > - close (fd); > > return 1; > > } > > > > static int > > +show_loop(char *device) { > > + int ret, fd; > > + > > + if ((fd = open(device, O_RDONLY)) < 0) { > > + int errsv = errno; > > + fprintf(stderr, _("loop: can't open device %s: %s\n"), > > + device, strerror (errsv)); > > + return 2; > > + } > > + ret = show_loop_fd(fd, device); > > + close(fd); > > + return ret; > > +} > > + > > + > > +static int > > show_used_loop_devices (void) { > > - char dev[20]; > > - char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; > > - int i, j, fd, permission = 0, somedev = 0; > > - struct stat statbuf; > > - struct loop_info loopinfo; > > + struct looplist ll; > > + int fd; > > > > - for (j = 0; j < SIZE(loop_formats); j++) { > > - for(i = 0; i < 256; i++) { > > - snprintf(dev, sizeof(dev), loop_formats[j], i); > > - if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { > > - fd = open (dev, O_RDONLY); > > - if (fd >= 0) { > > - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) > > - show_loop(dev); > > - close (fd); > > - somedev++; > > - } else if (errno == EACCES) > > - permission++; > > - continue; /* continue trying as long as devices exist */ > > - } > > - break; > > - } > > + if (looplist_open(&ll, LLFLG_USEDONLY) == -1) { > > + error(_("%s: /dev directory does not exist."), progname); > > + return 1; > > + } > > + > > + while((fd = looplist_next(&ll)) != -1) { > > + show_loop_fd(fd, ll.name); > > + close(fd); > > } > > + looplist_close(&ll); > > > > - if (somedev==0 && permission) { > > + if (ll.ct_succ && ll.ct_perm) { > > error(_("%s: no permission to look at /dev/loop#"), progname); > > return 1; > > } > > return 0; > > } > > > > - > > -#endif > > +#endif /* MAIN */ > > > > /* check if the loopfile is already associated with the same given > > * parameters. > > @@ -203,37 +443,32 @@ is_associated(int dev, struct stat *file, unsigned long long offset) > > */ > > char * > > loopfile_used (const char *filename, unsigned long long offset) { > > - char dev[20]; > > - char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" }; > > - int i, j, fd; > > - struct stat devstat, filestat; > > - struct loop_info loopinfo; > > + struct looplist ll; > > + char *devname = NULL; > > + struct stat filestat; > > + int fd; > > > > if (stat(filename, &filestat) == -1) { > > perror(filename); > > return NULL; > > } > > > > - for (j = 0; j < SIZE(loop_formats); j++) { > > - for(i = 0; i < 256; i++) { > > - snprintf(dev, sizeof(dev), loop_formats[j], i); > > - if (stat (dev, &devstat) == 0 && S_ISBLK(devstat.st_mode)) { > > - fd = open (dev, O_RDONLY); > > - if (fd >= 0) { > > - int res = 0; > > + if (looplist_open(&ll, LLFLG_USEDONLY) == -1) { > > + error(_("%s: /dev directory does not exist."), progname); > > + return NULL; > > + } > > > > - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) > > - res = is_associated(fd, &filestat, offset); > > - close (fd); > > - if (res == 1) > > - return xstrdup(dev); > > - } > > - continue; /* continue trying as long as devices exist */ > > + while((fd = looplist_next(&ll)) != -1) { > > + int res = is_associated(fd, &filestat, offset); > > + close(fd); > > + if (res == 1) { > > + devname = xstrdup(ll.name); > > + break; > > } > > - break; > > - } > > } > > - return NULL; > > + looplist_close(&ll); > > + > > + return devname; > > } > > > > int > > @@ -261,62 +496,36 @@ loopfile_used_with(char *devname, const char *filename, unsigned long long offse > > return ret; > > } > > > > -int > > -is_loop_device (const char *device) { > > - struct stat statbuf; > > - > > - return (stat(device, &statbuf) == 0 && > > - S_ISBLK(statbuf.st_mode) && > > - major(statbuf.st_rdev) == LOOPMAJOR); > > -} > > - > > char * > > 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, somedev = 0, someloop = 0, permission = 0; > > - struct stat statbuf; > > - struct loop_info loopinfo; > > + struct looplist ll; > > + char *devname = NULL; > > + int fd; > > > > - for (j = 0; j < SIZE(loop_formats); j++) { > > - for(i = 0; 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) { > > - if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) > > - someloop++; /* in use */ > > - else if (errno == ENXIO) { > > - close (fd); > > - return xstrdup(dev);/* probably free */ > > - } > > - close (fd); > > - } else if (errno == EACCES) > > - permission++; > > + if (looplist_open(&ll, LLFLG_FREEONLY) == -1) { > > + error(_("%s: /dev directory does not exist."), progname); > > + return NULL; > > + } > > > > - continue;/* continue trying as long as devices exist */ > > - } > > - break; > > - } > > + if ((fd = looplist_next(&ll)) != -1) { > > + close(fd); > > + devname = xstrdup(ll.name); > > } > > + looplist_close(&ll); > > + if (devname) > > + return devname; > > > > - if (!somedev) > > - error(_("%s: could not find any device /dev/loop#"), progname); > > - else if (!someloop && permission) > > + if (ll.ct_succ && ll.ct_perm) > > error(_("%s: no permission to look at /dev/loop#"), progname); > > - else if (!someloop) > > + else if (ll.ct_succ) > > + error(_("%s: could not find any free loop device"), progname); > > + else > > error(_( > > "%s: Could not find any loop device. Maybe this kernel " > > "does not know\n" > > " about the loop device? (If so, recompile or " > > "`modprobe loop'.)"), progname); > > - else > > - error(_("%s: could not find any free loop device"), progname); > > - return 0; > > + return NULL; > > } > > > > /* > > @@ -529,7 +738,7 @@ mutter(void) { > > fprintf(stderr, > > _("This mount was compiled without loop support. " > > "Please recompile.\n")); > > -} > > +} > > > > int > > set_loop (const char *device, const char *file, unsigned long long offset, > > @@ -550,7 +759,7 @@ find_unused_loop_device (void) { > > return 0; > > } > > > > -#endif > > +#endif /* !LOOP_SET_FD */ > > > > #ifdef MAIN > > > > @@ -726,5 +935,5 @@ main(int argc, char **argv) { > > "Please recompile.\n")); > > return -1; > > } > > -#endif > > -#endif > > +#endif /* !LOOP_SET_FD*/ > > +#endif /* MAIN */ > > -- > > 1.5.3.1 > > > > - > > To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at http://vger.kernel.org/majordomo-info.html > > > > -- > Karel Zak <kzak@xxxxxxxxxx> > _____________________________________________________________________ Der WEB.DE SmartSurfer hilft bis zu 70% Ihrer Onlinekosten zu sparen! http://smartsurfer.web.de/?mc=100071&distributionid=000000000066 - To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html