>  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@vger.kernel.org/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" <[EMAIL PROTECTED]>
> Gesendet: 08.02.08 02:17:07
> An: util-linux-ng@vger.kernel.org
> 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@vger.kernel.org/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 <[EMAIL PROTECTED]>
> > ---
> >  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 [EMAIL PROTECTED]
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 
> 
> -- 
>  Karel Zak  <[EMAIL PROTECTED]>
> 


_____________________________________________________________________
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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to