This is a small (debug) program to dump the device list in the raw format from the btrfs kernel. here I use ioctl which was introduced in the below kernel patch
btrfs: introduce BTRFS_IOC_GET_DEVS Signed-off-by: Anand Jain <anand.j...@oracle.com> --- .gitignore | 1 + Makefile | 4 +- btrfs-devlist.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ioctl.h | 45 +++++++++++ 4 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 btrfs-devlist.c diff --git a/.gitignore b/.gitignore index ab8b81c..0928374 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ libbtrfs.a libbtrfs.so libbtrfs.so.0 libbtrfs.so.0.1 +btrfs-devlist diff --git a/Makefile b/Makefile index f99ca7c..2a52c17 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ MAKEOPTS = --no-print-directory Q=$(Q) progs = mkfs.btrfs btrfs-debug-tree btrfsck \ btrfs btrfs-map-logical btrfs-image btrfs-zero-log btrfs-convert \ - btrfs-find-root btrfstune btrfs-show-super + btrfs-find-root btrfstune btrfs-show-super btrfs-devlist # external libs required by various binaries; for btrfs-foo, # specify btrfs_foo_libs = <list of libs>; see $($(subst...)) rules below @@ -226,7 +226,7 @@ clean: $(CLEANDIRS) @echo "Cleaning" $(Q)rm -f $(progs) cscope.out *.o *.o.d btrfs-convert btrfs-image btrfs-select-super \ btrfs-zero-log btrfstune dir-test ioctl-test quick-test send-test btrfsck \ - btrfs.static mkfs.btrfs.static btrfs-calc-size \ + btrfs.static mkfs.btrfs.static btrfs-calc-size btrfs-devlist\ version.h $(check_defs) \ $(libs) $(lib_links) diff --git a/btrfs-devlist.c b/btrfs-devlist.c new file mode 100644 index 0000000..7d9ef73 --- /dev/null +++ b/btrfs-devlist.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2014 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <unistd.h> +#include <getopt.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <uuid/uuid.h> + +#include "ctree.h" +#include "ioctl.h" +#include "commands.h" +#include "utils.h" + +void print_header(void) +{ + printf( + "fsid "\ + "uuid "\ + "name \n"\ + "\tfs_latest_devid "\ + "fs_latest_trans "\ + "fs_num_devices "\ + "fs_open_devices "\ + "fs_rw_devices "\ + "fs_missing_devices "\ + "fs_total_rw_bytes "\ + "fs_num_can_discard "\ + "fs_total_devices \n"\ + "\tgen "\ + "devid "\ + "total_bytes "\ + "disk_total_bytes "\ + "bytes_used "\ + "type "\ + "io_align "\ + "io_width "\ + "sector_size \n"\ + "\tflags\n"); +} + +void print_dev(struct btrfs_ioctl_devlist *dev) +{ + char uuid[BTRFS_UUID_UNPARSED_SIZE]; + char fsid[BTRFS_UUID_UNPARSED_SIZE]; + + uuid_unparse(dev->uuid, uuid); + uuid_unparse(dev->fsid, fsid); + + printf("\n%s %s %s\n"\ + "\t%llu %llu %llu %llu %llu %llu %llu %llu %llu\n"\ + "\t%llu %llu %llu %llu %llu %llu %u %u %u\n"\ + "\t%s|%s|%s\n"\ + "\t%s|%s|%s|%s|%s|%s|%s|%s|%s\n", + fsid, + uuid, + dev->name, + dev->fs_latest_devid, + dev->fs_latest_trans, + dev->fs_num_devices, + dev->fs_open_devices, + dev->fs_rw_devices, + dev->fs_missing_devices, + dev->fs_total_rw_bytes, + dev->fs_num_can_discard, + dev->fs_total_devices, + dev->gen, + dev->devid, + dev->total_bytes, + dev->disk_total_bytes, + dev->bytes_used, + dev->type, + dev->io_align, + dev->io_width, + dev->sector_size, + dev->flags & BTRFS_FS_MOUNTED ? "fs_Mounted":"not_fs_Mounted", + dev->flags & BTRFS_FS_SEEDING ? "fs_Seeding":"not_fs_Seeding", + dev->flags & BTRFS_FS_ROTATING ? "fs_Rotating":"not_fs_Rotating", + dev->flags & BTRFS_DEV_WRITEABLE ? "Writable":"not_Writable", + dev->flags & BTRFS_DEV_IN_FS_MD ? "MD":"not_MD", + dev->flags & BTRFS_DEV_MISSING ? "Missing":"not_Missing", + dev->flags & BTRFS_DEV_CAN_DISCARD ? "Discard":"not_Discard", + dev->flags & BTRFS_DEV_SUBSTITUTED ? "Substituted":"not_Substituted", + dev->flags & BTRFS_DEV_RUN_PENDING ? "Run_pending":"not_Run_pending", + dev->flags & BTRFS_DEV_NOBARRIERS ? "Nobarriers":"not_Nobarriers", + dev->flags & BTRFS_DEV_STATS_VALID ? "Stat_valid":"not_Stat_valid", + dev->flags & BTRFS_DEV_STATS_DIRTY ? "Stat_dirty":"not_Stat_dirty"); +} + +int get_devlist(struct btrfs_ioctl_devlist **out_devlist, u64 *out_count) +{ + int ret, fd, e; + struct btrfs_ioctl_devlist_args *devargs; + struct btrfs_ioctl_devlist_args *devargs_saved = NULL; + struct btrfs_ioctl_devlist *devlist; + u64 sz; + int count; + + fd = open("/dev/btrfs-control", O_RDWR); + e = errno; + if (fd < 0) { + perror("failed to open /dev/btrfs-control"); + return -e; + } + + /* space to hold 512 fsids, doesn't matter if small + * it would fail and return count so then we try again + */ + count = 512; +again: + sz = sizeof(*devargs) + sizeof(*devlist) * count; + + devargs_saved = devargs = malloc(sz); + if (!devargs) { + close(fd); + return -ENOMEM; + } + + memset(devargs, 0, sz); + devargs->count = count; + + ret = ioctl(fd, BTRFS_IOC_GET_DEVS, devargs); + e = errno; + if (ret == 1) { + /* out of size so reallocate */ + count = devargs->count; + free(devargs); + goto again; + } else if (ret < 0) { + printf("ERROR: scan_fsid ioctl failed - %s\n", + strerror(e)); + ret = -e; + goto out; + } + + /* ioctl returns devs count in count parameter*/ + + *out_count = devargs->count; + if (*out_count == 0) { + *out_devlist = NULL; + ret = 0; + goto out; + } + + devlist = (struct btrfs_ioctl_devlist *) (++devargs); + + sz = sizeof(*devlist) * *out_count; + *out_devlist = malloc(sz); + if (*out_devlist == NULL) { + ret = -ENOMEM; + goto out; + } + + memcpy(*out_devlist, devlist, sz); + ret = 0; + +out: + free(devargs_saved); + close(fd); + return ret; +} + +static void local_usage(void) +{ + printf("btrfs_devlist [options]\n"\ + " Dumps the device list from the btrfs kernel "\ + "without altering at the user level\n"\ + " options:\n"\ + " -h|--help prints this usage\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int ret; + u64 cnt; + struct btrfs_ioctl_devlist *devlist; + struct btrfs_ioctl_devlist *tmp_devlist; + + while(1) { + int long_index; + static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + { NULL, no_argument, NULL, 0 } + }; + + int c = getopt_long(argc, argv, "h", long_options, + &long_index); + + if(c < 0) + break; + + switch(c) { + case 'h': + default: + local_usage(); + } + } + + ret = get_devlist(&devlist, &cnt); + if (ret) { + fprintf(stderr, "get devlist failed %d\n", ret); + return 1; + } + + tmp_devlist = devlist; + + print_header(); + while (cnt--) { + print_dev(devlist); + devlist++; + } + kfree(tmp_devlist); + return ret; +} diff --git a/ioctl.h b/ioctl.h index f84300b..7343a33 100644 --- a/ioctl.h +++ b/ioctl.h @@ -508,6 +508,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) /* fs flags */ #define BTRFS_FS_MOUNTED (1LLU << 0) +#define BTRFS_FS_SEEDING (1LLU << 1) +#define BTRFS_FS_ROTATING (1LLU << 2) struct btrfs_ioctl_fslist { __u64 self_sz; /* in/out */ @@ -523,6 +525,47 @@ struct btrfs_ioctl_fslist_args { __u64 count; /* out */ }; +#define BTRFS_DEV_WRITEABLE (1LLU << 8) +#define BTRFS_DEV_IN_FS_MD (1LLU << 9) +#define BTRFS_DEV_MISSING (1LLU << 10) +#define BTRFS_DEV_CAN_DISCARD (1LLU << 11) +#define BTRFS_DEV_SUBSTITUTED (1LLU << 12) +#define BTRFS_DEV_RUN_PENDING (1LLU << 13) +#define BTRFS_DEV_NOBARRIERS (1LLU << 14) +#define BTRFS_DEV_STATS_VALID (1LLU << 15) +#define BTRFS_DEV_STATS_DIRTY (1LLU << 16) + +struct btrfs_ioctl_devlist { + __u64 sz_self; + __u64 fs_latest_devid; + __u64 fs_latest_trans; + __u64 fs_num_devices; + __u64 fs_open_devices; + __u64 fs_rw_devices; + __u64 fs_missing_devices; + __u64 fs_total_rw_bytes; + __u64 fs_num_can_discard; + __u64 fs_total_devices; + __u64 gen; + __u64 flags; + __u64 devid; + __u64 total_bytes; + __u64 disk_total_bytes; + __u64 bytes_used; + __u64 type; + __u32 io_align; + __u32 io_width; + __u32 sector_size; + __u8 fsid[BTRFS_FSID_SIZE]; + __u8 uuid[BTRFS_UUID_SIZE]; + __u8 name[BTRFS_PATH_NAME_MAX]; +}__attribute__ ((__packed__)); + +struct btrfs_ioctl_devlist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* in/out */ +}; + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ @@ -631,6 +674,8 @@ struct btrfs_ioctl_clone_range_args { struct btrfs_ioctl_feature_flags[2]) #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ struct btrfs_ioctl_feature_flags[3]) +#define BTRFS_IOC_GET_DEVS _IOWR(BTRFS_IOCTL_MAGIC, 58, \ + struct btrfs_ioctl_devlist_args) #ifdef __cplusplus } #endif -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html