Message ID | 201012051847.15633.kreijack@libero.it (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
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 > >
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"