Goffredo - 

   As with the other patch, this is missing S-o-B, and has some damage
from line wrapping. If you fix and re-send, I'll pull into my
integration branch.

   Hugo.

On Sun, Dec 05, 2010 at 06:47:15PM +0100, Goffredo Baroncelli wrote:
> Hi all,
> 
> the commands "btrfs filesystem show" and "btrfs device scan" look at the /dev
> directory (and it subdirectories) for every block devices.
> This is a slow process because floppy and cdrom are also checked. Moreover,
> as highlighted by Helmut, if udev is not used, the /dev directory is populated
> by high number of non-existant devices, which slow the process.
> 
> My patch changes the behaviour of these commands. The list of the devices are
> extracted from /proc/partitions, and on the basis of the file 
> /etc/btrfs.devices some devices may be skipped.
> 
> The file /etc/btrfs.devices contains a list of devices which have to be 
> skipped 
> (if the line starts with '!') or to be evaluated. Shell wildcard may be used.
> 
> If the file doesn't exists the default is to skip cdroms (/dev/cdrom*) and 
> floppies (/dev/fd*).
> 
> To revert to the old behaviour use the switch '--all-devices'.
> 
> Below the patch, but it is possible to pull the changes from:
> 
>       http://cassiopea.homelinux.net/git/btrfs-progs-unstable.git
> 
> branch
> 
>       device-checklist
> 
> Comment are welcome.
> 
> Regards
> G.Baroncelli
> 
> 
>  btrfs.c        |   10 +-
>  btrfs.devices  |   24 ++++++
>  btrfs_cmds.c   |   39 +++++++++--
>  man/btrfs.8.in |   22 ++++--
>  utils.c        |  196 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  utils.h        |    5 +
>  6 files changed, 279 insertions(+), 17 deletions(-)
> 
> 
> 
> diff --git a/btrfs.c b/btrfs.c
> index 46314cf..d850e60 100644
> --- a/btrfs.c
> +++ b/btrfs.c
> @@ -83,9 +83,10 @@ static struct Command commands[] = {
>               "will occupe all available space on the device."
>       },
>       { do_show_filesystem, 999,
> -       "filesystem show", "[<uuid>|<label>]\n"
> +       "filesystem show", "[--all-devices][<uuid>|<label>]\n"
>               "Show the info of a btrfs filesystem. If no <uuid> or <label>\n"
> -             "is passed, info of all the btrfs filesystem are shown."
> +             "is passed, info of all the btrfs filesystem are shown.\n"
> +             "If --all-devices is passed, all devices are scanned."
>       },
>       { do_df_filesystem, 1,
>         "filesystem df", "<path>\n"
> @@ -96,9 +97,10 @@ static struct Command commands[] = {
>               "Balance the chunks across the device."
>       },
>       { do_scan,
> -       999, "device scan", "[<device> [<device>..]\n"
> +       999, "device scan", "[--all-devices|<device> [<device>..]\n"
>               "Scan all device for or the passed device for a btrfs\n"
> -             "filesystem."
> +             "filesystem.\n"
> +             "If --all-devices is passed, all devices are scanned."
>       },
>       { do_add_volume, -2,
>         "device add", "<dev> [<dev>..] <path>\n"
> diff --git a/btrfs.devices b/btrfs.devices
> new file mode 100644
> index 0000000..ffeb8b6
> --- /dev/null
> +++ b/btrfs.devices
> @@ -0,0 +1,24 @@
> +#
> +#    This file lists the devices which have to be skipped or not
> +#    during the command 'btrfs filesystem show' and 'btrfs device scan'
> +#
> +#    These lines may contain a shell wildcard pattern (*,?,[]).
> +#
> +#    If a line starts with "!" and matches a device, the device is skipped
> +#    If a line matches a device, the device is evaluated
> +#    If a device is not matched by any line, the device is evaluated.
> +#
> +#    The lines starting with "#" are comments. The lines empty are
> +#    ignored 
> +#
> +
> +
> +
> +# There are two default rules which are added automatically
> +#
> +# skip floppy
> +# !/dev/fd*
> +#
> +# skip cdrom
> +# !/dev/sr*
> +#
> diff --git a/btrfs_cmds.c b/btrfs_cmds.c
> index 8031c58..a573008 100644
> --- a/btrfs_cmds.c
> +++ b/btrfs_cmds.c
> @@ -529,11 +529,25 @@ int do_fssync(int argc, char **argv)
>  int do_scan(int argc, char **argv)
>  {
>       int     i, fd;
> -     if(argc<=1){
> +     int     checklist = 1;
> +     int     devstart = 1;
> +
> +     if( argc >= 2 && !strcmp(argv[1],"--all-devices")){
> +
> +             if( argc >2 ){
> +                     fprintf(stderr, "ERROR: too may arguments\n");
> +                        return 22;
> +                }
> +
> +             checklist = 0;
> +             devstart += 1;
> +     }
> +
> +     if(argc<=devstart){
>               int ret;
>  
>               printf("Scanning for Btrfs filesystems\n");
> -             ret = btrfs_scan_one_dir("/dev", 1);
> +             ret = btrfs_scan_block_devices(1, checklist);
>               if (ret){
>                       fprintf(stderr, "ERROR: error %d while scanning\n", 
> ret);
>                       return 18;
> @@ -547,7 +561,7 @@ int do_scan(int argc, char **argv)
>               return 10;
>       }
>  
> -     for( i = 1 ; i < argc ; i++ ){
> +     for( i = devstart ; i < argc ; i++ ){
>               struct btrfs_ioctl_vol_args args;
>               int ret;
>  
> @@ -666,15 +680,30 @@ int do_show_filesystem(int argc, char **argv)
>       struct list_head *all_uuids;
>       struct btrfs_fs_devices *fs_devices;
>       struct list_head *cur_uuid;
> -     char *search = argv[1];
> +     char *search=0;
>       int ret;
> +     int checklist = 1;
> +     int searchstart = 1;
>  
> -     ret = btrfs_scan_one_dir("/dev", 0);
> +     if( argc >= 2 && !strcmp(argv[1],"--all-devices")){
> +             checklist = 0;
> +             searchstart += 1;
> +     }
> +
> +     if( argc > searchstart+1 ){
> +             fprintf(stderr, "ERROR: too many arguments\n");
> +             return 22;
> +     }       
> +
> +     ret = btrfs_scan_block_devices(0, checklist);
>       if (ret){
>               fprintf(stderr, "ERROR: error %d while scanning\n", ret);
>               return 18;
>       }
>  
> +     if(searchstart < argc)
> +             search = argv[searchstart];
> +
>       all_uuids = btrfs_scanned_uuids();
>       list_for_each(cur_uuid, all_uuids) {
>               fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
> diff --git a/man/btrfs.8.in b/man/btrfs.8.in
> index 26ef982..77b13f6 100644
> --- a/man/btrfs.8.in
> +++ b/man/btrfs.8.in
> @@ -21,9 +21,9 @@ btrfs \- control a btrfs filesystem
>  .PP
>  \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
>  .PP
> -\fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
> +\fBbtrfs\fP \fBfilesystem show\fP\fI [--all-devices] <uuid>|<label> [<uuid>|
> <label>...]\fP
>  .PP
> -\fBbtrfs\fP \fBdevice show\fP\fI <dev>|<label> [<dev>|<label>...]\fP
> +\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices][<device> [<device>..]]\fP
>  .PP
>  \fBbtrfs\fP \fBdevice balance\fP\fI <path> \fP
>  .PP
> @@ -106,9 +106,10 @@ is returned by the \fBsubvolume list\fR command.
>  Defragment files and/or directories.
>  .TP
>  
> -\fBdevice scan\fR \fI[<device> [<device>..]]\fR
> +\fBdevice scan\fR \fI[--all-devices][<device> [<device>..]]\fR
>  Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR 
> scans
> -all the block devices.
> +all the block devices. If --all-devices is passed, the file 
> /etc/btrfs.devices
> +are ignored and all devices are scanned.
>  .TP
>  
>  \fBfilesystem sync\fR\fI <path> \fR
> @@ -138,9 +139,10 @@ can expand the partition before enlarging the filesystem 
> and shrink the
>  partition after reducing the size of the filesystem.
>  .TP
>  
> -\fBfilesystem show\fR [<uuid>|<label>]\fR
> +\fBfilesystem show\fR [--all-devices][<uuid>|<label>]\fR
>  Show the btrfs filesystem with some additional info. If no UUID or label is
> -passed, \fBbtrfs\fR show info of all the btrfs filesystem.
> +passed, \fBbtrfs\fR show info of all the btrfs filesystem. If --all-devices
> +is passed, the file /etc/btrfs.devices are ignored and all devices are 
> scanned.
>  .TP
>  
>  \fBdevice balance\fR \fI<path>\fR
> @@ -160,6 +162,14 @@ Remove device(s) from a filesystem identified by 
> \fI<path>\fR.
>  \fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned 
> in
>  case of failure.
>  
> +.SH FILES
> +The file \fB/etc/btrfs.devices\fR contains a list of devices which have to be
> +skipped (or not) when the commands \fBbtrfs filesystem show\fR and
> +\fBbtrfs device scan\fR are executed. If a line starts with '!', and matches
> +a device, this device is skipped. If a line matches a device, this device is
> +evaluated. If this file doesn't exists, the default rules are to skip floppy
> +and cdrom.The shell wildcard may be used.
> +
>  .SH AVAILABILITY
>  .B btrfs
>  is part of btrfs-progs. Btrfs filesystem is currently under heavy 
> development,
> diff --git a/utils.c b/utils.c
> index fd894f3..6112137 100644
> --- a/utils.c
> +++ b/utils.c
> @@ -35,6 +35,8 @@
>  #include <linux/major.h>
>  #include <linux/kdev_t.h>
>  #include <limits.h>
> +#include <ctype.h>
> +#include <fnmatch.h>
>  #include "kerncompat.h"
>  #include "radix-tree.h"
>  #include "ctree.h"
> @@ -833,7 +835,185 @@ void btrfs_register_one_device(char *fname)
>       close(fd);
>  }
>  
> -int btrfs_scan_one_dir(char *dirname, int run_ioctl)
> +
> +static char **device_checklist = 0;
> +static int  device_checklist_count = 0;
> +/*
> + *   Default device black list:
> + *   If the line starts with a "!" the device has to be skipped
> + *   otherwise the device is OK
> + */
> +static char *default_checklist[] = {
> +     "!/dev/fd*",
> +     "!/dev/sr*",
> +     0
> +};
> +/* add an entry in the checklist */
> +static int device_checklist_add(char *entry)
> +{
> +     char    *cpy;
> +     char    **res;
> +
> +     device_checklist_count += 1;
> +     res = realloc(device_checklist, 
> +                             sizeof(char*)*device_checklist_count);
> +     if( !res ){
> +             free(device_checklist);
> +             device_checklist_count = 0;
> +             return -1;
> +     }
> +     device_checklist = res;
> +
> +     cpy = strdup(entry);
> +     if( !cpy ){
> +                free(device_checklist);
> +                device_checklist_count = 0;
> +                return -1;
> +        }
> +
> +     device_checklist[device_checklist_count-1] = cpy;
> +     return 0;
> +}
> +
> +/* 
> + * init the check list on teh basis of the default check list
> + * and the check list stored in the file "fn"
> + */
> +static int init_device_checklist(char *fn)
> +{
> +
> +     char    buf[1024];
> +     int     i;
> +     FILE    *fp;
> +
> +     if(device_checklist_count)
> +             return 0;
> +
> +     if( fn == 0 )
> +             return 0;       /* no extra rules provided */
> +
> +     fp = fopen(fn, "r");
> +     if(!fp)
> +             return 0;       /* the file doesn't exist */
> +
> +     while(fgets(buf,1023, fp)){
> +             char    *p = buf;
> +             char    *l;
> +             while (isblank(*p)) p++;
> +             l = p;
> +             while( *l != '\n' && *l != '\r' && *l ) l++;
> +             *l = 0;
> +
> +             if( *p == '#' || *p == 0 )
> +                     continue;
> +
> +             if(device_checklist_add(p)){
> +                     fclose(fp);
> +                     return -2;
> +             }
> +     }
> +     fclose(fp);
> +
> +     for(i=0; default_checklist[i] ; i++ )
> +             if(device_checklist_add(default_checklist[i]))
> +                     return -3;
> +
> +     
> +     return 0;
> +}
> +
> +/* 
> + * This function test if "dev" has to be skipped on the basis of the
> + * checklist; return values:
> + *   0 -> skip the deive
> + *   1 -> teh device is ok
> + */
> +static int test_device(char *dev )
> +{
> +     int     i;
> +     for( i = 0 ; i < device_checklist_count ; i++ ){
> +             int     res;
> +             char    *rule;
> +
> +             rule = device_checklist[i];
> +
> +             if( rule[0] == '!' ){
> +                     res = 0;        /* if match, skip the device */
> +                     rule++;
> +             }else{
> +                     res = 1;        /* if match, the device is ok */
> +             }
> +
> +             if( !fnmatch(rule, dev, 0 ) )
> +                     return res;
> +
> +     }
> +     return 1;
> +}
> +
> +int btrfs_scan_block_devices(int run_ioctl, int checklist)
> +{
> +
> +     struct stat st;
> +     int ret;
> +     int fd;
> +     struct btrfs_fs_devices *tmp_devices;
> +     u64 num_devices;
> +     FILE *proc_partitions;
> +     int i;
> +     char buf[1024];
> +     char name[100], fullpath[110];
> +
> +     if(checklist)
> +             init_device_checklist(BTRFSDEVICELIST);
> +
> +     proc_partitions = fopen("/proc/partitions","r");
> +     if (!proc_partitions) {
> +             fprintf(stderr, "Unable to open '/proc/partitions' for 
> scanning\n");
> +             return -ENOENT;
> +     }
> +     /* skip the header */
> +     for(i=0; i < 2 ; i++)
> +             if(!fgets(buf, 1023, proc_partitions)){
> +             fprintf(stderr, "Unable to read '/proc/partitions' for 
> scanning\n");
> +             fclose(proc_partitions);
> +             return -ENOENT;
> +     }
> +
> +     strcpy(fullpath,"/dev/");
> +     while(fgets(buf, 1023, proc_partitions)) {
> +
> +             i = sscanf(buf," %*d %*d %*d %99s", fullpath+5);
> +             ret = lstat(fullpath, &st);
> +             if (ret < 0) {
> +                     fprintf(stderr, "failed to stat %s\n", fullpath);
> +                     continue;
> +             }
> +             if (!S_ISBLK(st.st_mode)) {
> +                     continue;
> +             }
> +             if (checklist && !test_device(fullpath)){
> +                     continue;
> +             }
> +             fd = open(fullpath, O_RDONLY);
> +             if (fd < 0) {
> +                     fprintf(stderr, "failed to read %s\n", fullpath);
> +                     continue;
> +             }
> +             ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
> +                                         &num_devices,
> +                                         BTRFS_SUPER_INFO_OFFSET);
> +             if (ret == 0 && run_ioctl > 0) {
> +                     btrfs_register_one_device(fullpath);
> +             }
> +             close(fd);
> +     }
> +
> +     fclose(proc_partitions);
> +     return 0;
> +}
> +
> +int btrfs_scan_one_dir_checklist(char *dirname, int run_ioctl, int checklist)
>  {
>       DIR *dirp = NULL;
>       struct dirent *dirent;
> @@ -848,6 +1028,9 @@ int btrfs_scan_one_dir(char *dirname, int run_ioctl)
>       struct btrfs_fs_devices *tmp_devices;
>       u64 num_devices;
>  
> +     if(checklist)
> +             init_device_checklist(BTRFSDEVICELIST);
> +
>       INIT_LIST_HEAD(&pending_list);
>  
>       pending = malloc(sizeof(*pending));
> @@ -867,7 +1050,8 @@ again:
>       }
>       dirp = opendir(dirname);
>       if (!dirp) {
> -             fprintf(stderr, "Unable to open /sys/block for scanning\n");
> +             fprintf(stderr, "Unable to open '%s' for scanning\n", 
> +                     dirname);
>               return -ENOENT;
>       }
>       while(1) {
> @@ -900,6 +1084,9 @@ again:
>               if (!S_ISBLK(st.st_mode)) {
>                       continue;
>               }
> +             if (checklist && !test_device(fullpath)){
> +                     continue;
> +             }
>               fd = open(fullpath, O_RDONLY);
>               if (fd < 0) {
>                       fprintf(stderr, "failed to read %s\n", fullpath);
> @@ -929,6 +1116,11 @@ fail:
>       return ret;
>  }
>  
> +int btrfs_scan_one_dir(char *dirname, int run_ioctl)
> +{
> +     return btrfs_scan_one_dir_checklist(dirname, run_ioctl, 0);
> +}
> +
>  int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
>                       int run_ioctls)
>  {
> diff --git a/utils.h b/utils.h
> index 9dce5b0..b815f9b 100644
> --- a/utils.h
> +++ b/utils.h
> @@ -36,8 +36,13 @@ int btrfs_scan_for_fsid(struct btrfs_fs_devices 
> *fs_devices, 
> u64 
> total_devs,
>                       int run_ioctls);
>  void btrfs_register_one_device(char *fname);
>  int btrfs_scan_one_dir(char *dirname, int run_ioctl);
> +int btrfs_scan_one_dir_checklist(char *dirname, int run_ioctl, int 
> checklist);
>  int check_mounted(const char *devicename);
>  int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
>                                int super_offset);
>  char *pretty_sizes(u64 size);
> +int btrfs_scan_block_devices(int run_ioctl, int checklist);
> +
> +#define BTRFSDEVICELIST "/etc/btrfs.devices"
> +
>  #endif
> 
> 

-- 
=== Hugo Mills: hugo@... carfax.org.uk | darksatanic.net | lug.org.uk ===
  PGP key: 515C238D from wwwkeys.eu.pgp.net or http://www.carfax.org.uk
  --- My doctor tells me that I have a malformed public-duty gland, ---  
                and a natural deficiency in moral fibre.                 

Attachment: signature.asc
Description: Digital signature

Reply via email to