Anand Jain
2013-Oct-25 17:10 UTC
[PATCH] btrfs: add framework to read fs info from btrfs-control
This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs info through the btrfs-control Signed-off-by: Anand Jain <anand.jain@oracle.com> --- fs/btrfs/super.c | 47 ++++++++++++++++++++++++++++++++++++++----- fs/btrfs/volumes.c | 33 ++++++++++++++++++++++++++++++ fs/btrfs/volumes.h | 2 + include/uapi/linux/btrfs.h | 19 +++++++++++++++++ 4 files changed, 95 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 0991fb1..bae53ba 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1641,38 +1641,73 @@ static struct file_system_type btrfs_fs_type = { }; MODULE_ALIAS_FS("btrfs"); +static int btrfs_ioc_get_fslist(void __user *arg) +{ + int ret = 0; + u64 sz_fslist_arg; + u64 sz_fslist; + struct btrfs_ioctl_fslist_args *fslist_arg; + struct btrfs_ioctl_fslist *fslist; + + sz_fslist_arg = sizeof(*fslist_arg); + fslist_arg = memdup_user(arg, sz_fslist_arg); + + sz_fslist = sizeof(*fslist) * fslist_arg->count; + kfree(fslist_arg); + fslist_arg = memdup_user(arg, sz_fslist_arg + sz_fslist); + fslist = (struct btrfs_ioctl_fslist *) (fslist_arg + sz_fslist_arg); + + ret = btrfs_get_fslist(fslist_arg, fslist); + + fslist->self_sz = sz_fslist; + fslist_arg->self_sz = sz_fslist_arg; + + if (copy_to_user(arg, fslist_arg, sz_fslist_arg + sz_fslist)) + ret = -EFAULT; + + kfree(fslist_arg); + return ret; +} + /* * used by btrfsctl to scan devices when no FS is mounted */ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct btrfs_ioctl_vol_args *vol; + struct btrfs_ioctl_vol_args *vol = NULL; struct btrfs_fs_devices *fs_devices; int ret = -ENOTTY; + void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vol = memdup_user((void __user *)arg, sizeof(*vol)); - if (IS_ERR(vol)) - return PTR_ERR(vol); - switch (cmd) { case BTRFS_IOC_SCAN_DEV: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); break; case BTRFS_IOC_DEVICES_READY: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); if (ret) break; ret = !(fs_devices->num_devices == fs_devices->total_devices); break; + case BTRFS_IOC_GET_FSLIST: + ret = btrfs_ioc_get_fslist(argp); + break; } - kfree(vol); return ret; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fe0f2ef..a7b8f26 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6284,3 +6284,36 @@ int btrfs_scratch_superblock(struct btrfs_device *device) return 0; } + +/* return 1 if allocation count exceed the num of fs list + * in the kernel + */ +int btrfs_get_fslist(struct btrfs_ioctl_fslist_args *fslist_arg, + struct btrfs_ioctl_fslist *fslist) +{ + u64 cnt = 0, ucnt; + struct btrfs_fs_devices *fs_devices; + + ucnt = fslist_arg->count; + + list_for_each_entry(fs_devices, &fs_uuids, list) { + if (cnt < ucnt) { + memcpy(fslist->fsid, fs_devices->fsid, + BTRFS_FSID_SIZE); + fslist->num_devices = fs_devices->num_devices; + fslist->missing_devices = fs_devices->missing_devices; + fslist->total_devices = fs_devices->total_devices; + + if (fs_devices->opened) + fslist->flags = BTRFS_FS_MOUNTED; + + fslist = (struct btrfs_ioctl_fslist *) fslist + + sizeof(*fslist); + } + cnt++; + } + fslist_arg->count = cnt; + if (cnt > ucnt) + return 1; + return 0; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index b72f540..e68a1c8 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -388,4 +388,6 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, { btrfs_dev_stat_set(dev, index, 0); } +int btrfs_get_fslist(struct btrfs_ioctl_fslist_args *fslist_arg, + struct btrfs_ioctl_fslist *fslist); #endif diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 45e6189..6690551 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -512,6 +512,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -606,5 +623,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #endif /* _UAPI_LINUX_BTRFS_H */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Oct-25 17:10 UTC
[PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo from btrfs-control
need fsinfo from btrfs-control that is when mount path is not known. current method of going through each mount points isn''t efficient, and multiple subvol of a fsid could be mounted means extra logic to handle that. Further this will help to revamp check_mounted() (planned) check_mounted is heavily used in the btrfs-progs, it does full scan of all the disks in the system to confirm if a multi-disk btrfs is mounted it doesn''t scalable well with few hundreds luns, check_mounted for sure needs a revamp. using this it can be done easily. which is planned. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- ioctl.h | 19 +++++++++++++++ utils.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.h | 1 + 3 files changed, 100 insertions(+), 0 deletions(-) diff --git a/ioctl.h b/ioctl.h index d21413f..29575d8 100644 --- a/ioctl.h +++ b/ioctl.h @@ -506,6 +506,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -604,6 +621,8 @@ struct btrfs_ioctl_clone_range_args { struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_DEDUP_CTL _IOWR(BTRFS_IOCTL_MAGIC, 55, \ struct btrfs_ioctl_dedup_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #ifdef __cplusplus } #endif diff --git a/utils.c b/utils.c index 5bedd97..1798a7c 100644 --- a/utils.c +++ b/utils.c @@ -2087,3 +2087,83 @@ int lookup_ino_rootid(int fd, u64 *rootid) return 0; } + +/* scans for fsid(s) in the kernel using the btrfs-control + * interface. + */ +int get_fslist(struct btrfs_ioctl_fslist **out_fslist, int *out_count) +{ + int ret, fd, e; + struct btrfs_ioctl_fslist_args *fsargs; + struct btrfs_ioctl_fslist *fslist; + struct btrfs_ioctl_fslist *fslist_tmp; + 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(*fsargs) + sizeof(*fslist) * count; + + fsargs = (struct btrfs_ioctl_fslist_args *) malloc(sz); + memset(fsargs, 0, sz); + + if (!fsargs) { + close(fd); + return -ENOMEM; + } + fsargs->count = count; + + ret = ioctl(fd, BTRFS_IOC_GET_FSLIST, fsargs); + e = errno; + if (ret == 1) { + /* out of size so reallocate */ + count = fsargs->count; + free(fsargs); + goto again; + } else if (ret < 0) { + printf("ERROR: scan_fsid ioctl failed - %s\n", + strerror(e)); + ret = -e; + goto out; + } + + /* ioctl returns fsid count in count parameter*/ + + *out_count = count = fsargs->count; + if (count == 0) { + *out_fslist = NULL; + ret = 0; + goto out; + } + + fslist = (struct btrfs_ioctl_fslist *) (fsargs + + sizeof(*fsargs)); + + fslist_tmp = *out_fslist = (struct btrfs_ioctl_fslist *) + malloc(sizeof(*fslist) * count); + if (!fslist_tmp) { + ret = -ENOMEM; + goto out; + } + + while (count--) { + memcpy(fslist_tmp, fslist, sizeof(*fslist)); + fslist_tmp = fslist_tmp + sizeof(*fslist_tmp); + fslist = fslist + sizeof(*fslist); + } + ret = 0; +out: + free(fsargs); + close(fd); + return 0; +} diff --git a/utils.h b/utils.h index 6f4b10c..e20ad74 100644 --- a/utils.h +++ b/utils.h @@ -94,5 +94,6 @@ int ask_user(char *question); int lookup_ino_rootid(int fd, u64 *rootid); int btrfs_scan_lblkid(int update_kernel); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); +int get_fslist(struct btrfs_ioctl_fslist **out_fslist, int *out_count); #endif -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Oct-25 17:10 UTC
[PATCH 2/2] btrfs-progs: fs show should handle if subvol(s) mounted
as of now with out this patch user would see fsinfo per btrfs mount path but which mean multiple entry if more than one subvol is mounted of the same fsid. so this patch will handle that nicely. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- cmds-filesystem.c | 90 +++++++++++++++++++++++++++++++++-------------------- utils.c | 61 ++++++++++++++++++++++++++++++++++++ utils.h | 1 + 3 files changed, 118 insertions(+), 34 deletions(-) diff --git a/cmds-filesystem.c b/cmds-filesystem.c index d2cad81..fcabdb0 100644 --- a/cmds-filesystem.c +++ b/cmds-filesystem.c @@ -317,6 +317,29 @@ static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info, return 0; } +static void handle_print(char *mnt, char *label) +{ + int fd; + struct btrfs_ioctl_fs_info_args fs_info_arg; + struct btrfs_ioctl_dev_info_args *dev_info_arg = NULL; + struct btrfs_ioctl_space_args *space_info_arg; + + if (get_fs_info(mnt, &fs_info_arg, &dev_info_arg)) { + fprintf(stdout, "ERROR: get_fs_info failed\n"); + return; + } + + fd = open(mnt, O_RDONLY); + if (fd > 0 && !get_df(fd, &space_info_arg)) { + print_one_fs(&fs_info_arg, dev_info_arg, + space_info_arg, label, mnt); + kfree(space_info_arg); + } + if (fd > 0) + close(fd); + kfree(dev_info_arg); +} + /* This function checks if the given input parameter is * an uuid or a path * return -1: some error in the given input @@ -350,47 +373,39 @@ static int check_arg_type(char *input) static int btrfs_scan_kernel(void *search) { - int ret = 0, fd; - FILE *f; - struct mntent *mnt; - struct btrfs_ioctl_fs_info_args fs_info_arg; - struct btrfs_ioctl_dev_info_args *dev_info_arg = NULL; - struct btrfs_ioctl_space_args *space_info_arg; + int ret = 0; char label[BTRFS_LABEL_SIZE]; - - f = setmntent("/proc/self/mounts", "r"); - if (f == NULL) - return 1; - - memset(label, 0, sizeof(label)); - while ((mnt = getmntent(f)) != NULL) { - if (strcmp(mnt->mnt_type, "btrfs")) + char mnt[BTRFS_PATH_NAME_MAX + 1]; + struct btrfs_ioctl_fslist *fslist; + struct btrfs_ioctl_fslist *fslist_saved; + int cnt_fs; + int cnt_mnt; + __u8 *fsid; + __u64 flags; + + ret = get_fslist(&fslist, &cnt_fs); + if (ret) + return ret; + fslist_saved = fslist; + while (cnt_fs--) { + fsid = fslist->fsid; + flags = fslist->flags; + fslist = fslist + sizeof(*fslist); + if (!(flags & BTRFS_FS_MOUNTED)) continue; - ret = get_fs_info(mnt->mnt_dir, &fs_info_arg, - &dev_info_arg); + memset(mnt, 0, BTRFS_PATH_NAME_MAX + 1); + memset(label, 0, sizeof(label)); + ret = fsid_to_mntpt(fsid, mnt, &cnt_mnt); if (ret) return ret; - - if (get_label_mounted(mnt->mnt_dir, label)) { - kfree(dev_info_arg); + if (get_label_mounted(mnt, label)) return 1; - } - if (search && !match_search_item_kernel(fs_info_arg.fsid, - mnt->mnt_dir, label, search)) { - kfree(dev_info_arg); + + if (search && !match_search_item_kernel(fsid, + mnt, label, search)) continue; - } - fd = open(mnt->mnt_dir, O_RDONLY); - if (fd > 0 && !get_df(fd, &space_info_arg)) { - print_one_fs(&fs_info_arg, dev_info_arg, - space_info_arg, label, mnt->mnt_dir); - kfree(space_info_arg); - memset(label, 0, sizeof(label)); - } - if (fd > 0) - close(fd); - kfree(dev_info_arg); + handle_print(mnt, label); if (search) return 0; } @@ -469,6 +484,13 @@ static int cmd_show(int argc, char **argv) goto devs_only; } } + if (type == BTRFS_ARG_MNTPOINT) { + char label[BTRFS_LABEL_SIZE]; + if (get_label_mounted(search, label)) + return 1; + handle_print(search, label); + return 0; + } } if (where == BTRFS_SCAN_DEV) diff --git a/utils.c b/utils.c index 1798a7c..ab4942e 100644 --- a/utils.c +++ b/utils.c @@ -47,6 +47,7 @@ #include "utils.h" #include "volumes.h" #include "ioctl.h" +#include "btrfs-list.h" #ifndef BLKDISCARD #define BLKDISCARD _IO(0x12,119) @@ -2167,3 +2168,63 @@ out: close(fd); return 0; } + +/* This finds the mount point for a given fsid, + * subvols of the same fs/fsid can be mounted + * so here this picks and lowest subvol id + * and returns the mount point +*/ +int fsid_to_mntpt(__u8 *fsid, char *mntpt, int *mnt_cnt) +{ + int fd = -1, ret = 0; + DIR *dirstream = NULL; + FILE *f; + struct btrfs_ioctl_fs_info_args fi_args; + u64 svid, saved_svid = (u64)-1; + struct mntent *mnt; + int mcnt = 0; + + *mnt_cnt = 0; + f = setmntent("/proc/self/mounts", "r"); + if (f == NULL) + return 1; + + while ((mnt = getmntent(f)) != NULL) { + if (strcmp(mnt->mnt_type, "btrfs")) + continue; + fd = open_file_or_dir(mnt->mnt_dir, &dirstream); + if (fd < 0) { + ret = -errno; + return ret; + } + ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); + if (ret < 0) { + ret = -errno; + close_file_or_dir(fd, dirstream); + break; + } + if (uuid_compare(fsid, fi_args.fsid)) { + close_file_or_dir(fd, dirstream); + continue; + } + + /* found */ + mcnt++; + ret = btrfs_list_get_path_rootid(fd, &svid); + if (ret) { + /* error so just copy and return*/ + strcpy(mntpt, mnt->mnt_dir); + close_file_or_dir(fd, dirstream); + break; + } + if (svid < saved_svid) { + strcpy(mntpt, mnt->mnt_dir); + saved_svid = svid; + } + } + endmntent(f); + if (mcnt) + *mnt_cnt = mcnt; + + return ret; +} diff --git a/utils.h b/utils.h index e20ad74..014abad 100644 --- a/utils.h +++ b/utils.h @@ -95,5 +95,6 @@ int lookup_ino_rootid(int fd, u64 *rootid); int btrfs_scan_lblkid(int update_kernel); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); int get_fslist(struct btrfs_ioctl_fslist **out_fslist, int *out_count); +int fsid_to_mntpt(__u8 *fsid, char *mnt, int *mnt_cnt); #endif -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Oct-29 16:34 UTC
[PATCH 2/3 v2] btrfs-progs: mechanism to fetch fsinfo from btrfs-control
need fsinfo from btrfs-control that is when mount path is not known. current method of going through each mount points isn''t efficient, and multiple subvol of a fsid could be mounted means extra logic to handle that. Further this will help to revamp check_mounted() (planned) check_mounted is heavily used in the btrfs-progs, it does full scan of all the disks in the system to confirm if a multi-disk btrfs is mounted it doesn''t scalable well with few hundreds luns, check_mounted for sure needs a revamp. using this it can be done easily. which is planned. v2: commit reword Signed-off-by: Anand Jain <anand.jain@oracle.com> --- ioctl.h | 19 +++++++++++++++ utils.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.h | 1 + 3 files changed, 100 insertions(+), 0 deletions(-) diff --git a/ioctl.h b/ioctl.h index d21413f..29575d8 100644 --- a/ioctl.h +++ b/ioctl.h @@ -506,6 +506,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -604,6 +621,8 @@ struct btrfs_ioctl_clone_range_args { struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_DEDUP_CTL _IOWR(BTRFS_IOCTL_MAGIC, 55, \ struct btrfs_ioctl_dedup_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #ifdef __cplusplus } #endif diff --git a/utils.c b/utils.c index 5bedd97..1798a7c 100644 --- a/utils.c +++ b/utils.c @@ -2087,3 +2087,83 @@ int lookup_ino_rootid(int fd, u64 *rootid) return 0; } + +/* scans for fsid(s) in the kernel using the btrfs-control + * interface. + */ +int get_fslist(struct btrfs_ioctl_fslist **out_fslist, int *out_count) +{ + int ret, fd, e; + struct btrfs_ioctl_fslist_args *fsargs; + struct btrfs_ioctl_fslist *fslist; + struct btrfs_ioctl_fslist *fslist_tmp; + 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(*fsargs) + sizeof(*fslist) * count; + + fsargs = (struct btrfs_ioctl_fslist_args *) malloc(sz); + memset(fsargs, 0, sz); + + if (!fsargs) { + close(fd); + return -ENOMEM; + } + fsargs->count = count; + + ret = ioctl(fd, BTRFS_IOC_GET_FSLIST, fsargs); + e = errno; + if (ret == 1) { + /* out of size so reallocate */ + count = fsargs->count; + free(fsargs); + goto again; + } else if (ret < 0) { + printf("ERROR: scan_fsid ioctl failed - %s\n", + strerror(e)); + ret = -e; + goto out; + } + + /* ioctl returns fsid count in count parameter*/ + + *out_count = count = fsargs->count; + if (count == 0) { + *out_fslist = NULL; + ret = 0; + goto out; + } + + fslist = (struct btrfs_ioctl_fslist *) (fsargs + + sizeof(*fsargs)); + + fslist_tmp = *out_fslist = (struct btrfs_ioctl_fslist *) + malloc(sizeof(*fslist) * count); + if (!fslist_tmp) { + ret = -ENOMEM; + goto out; + } + + while (count--) { + memcpy(fslist_tmp, fslist, sizeof(*fslist)); + fslist_tmp = fslist_tmp + sizeof(*fslist_tmp); + fslist = fslist + sizeof(*fslist); + } + ret = 0; +out: + free(fsargs); + close(fd); + return 0; +} diff --git a/utils.h b/utils.h index 6f4b10c..e20ad74 100644 --- a/utils.h +++ b/utils.h @@ -94,5 +94,6 @@ int ask_user(char *question); int lookup_ino_rootid(int fd, u64 *rootid); int btrfs_scan_lblkid(int update_kernel); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); +int get_fslist(struct btrfs_ioctl_fslist **out_fslist, int *out_count); #endif -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Zach Brown
2013-Oct-29 21:33 UTC
Re: [PATCH] btrfs: add framework to read fs info from btrfs-control
> This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs > info through the btrfs-controlWhy not use sysfs?> + sz_fslist_arg = sizeof(*fslist_arg); > + fslist_arg = memdup_user(arg, sz_fslist_arg);Doesn''t check allocation failure.> + > + sz_fslist = sizeof(*fslist) * fslist_arg->count; > + kfree(fslist_arg);That allocation and copy and free gets a single u64. Use copy_from_user() for the u64.> + fslist_arg = memdup_user(arg, sz_fslist_arg + sz_fslist);Allocates an arbitrarily huge size that depends only on user input. Doesn''t check failure again. And I bet you can scribble on kernel memory if you wrap the size.> + if (copy_to_user(arg, fslist_arg, sz_fslist_arg + sz_fslist)) > + ret = -EFAULT;And there''s no reason to buffer all this in the kernel to begin with. Just copy_to_user() as you iterate over each fs_devices.> + fslist = (struct btrfs_ioctl_fslist *) fslist + > + sizeof(*fslist);AKA fslist++. - z -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Nov-04 03:39 UTC
Re: [PATCH] btrfs: add framework to read fs info from btrfs-control
(sorry for the delay, various external issues) I have sent out the new patch set. Thanks for the comments. more inline. On 10/30/13 05:33 AM, Zach Brown wrote:> >> This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs >> info through the btrfs-control > > Why not use sysfs?various sysfs interface for btrfs is still being a RFC ioctl would much simpler to get the bug fixed.>> + sz_fslist_arg = sizeof(*fslist_arg); >> + fslist_arg = memdup_user(arg, sz_fslist_arg); > > Doesn''t check allocation failure.fixed it.>> + >> + sz_fslist = sizeof(*fslist) * fslist_arg->count; >> + kfree(fslist_arg); > > That allocation and copy and free gets a single u64. Use > copy_from_user() for the u64.oh yes. thanks.>> + fslist_arg = memdup_user(arg, sz_fslist_arg + sz_fslist); > > Allocates an arbitrarily huge size that depends only on user input. > Doesn''t check failure again. And I bet you can scribble on kernel > memory if you wrap the size.fixed it. now it finds the number of fsid and then allocates mem.>> + if (copy_to_user(arg, fslist_arg, sz_fslist_arg + sz_fslist)) >> + ret = -EFAULT; > > And there''s no reason to buffer all this in the kernel to begin with. > Just copy_to_user() as you iterate over each fs_devices.Ok in the v2 patch I have narrowed the allocation and copy to just what is present. but I still feel one-shot copy is better. Now I have also used uuid_mutex its bit less granular for the purpose here but taking into consideration that thread is from btrfs-control (and so no root pointer is readily available) for which it should be fine IMO. any comments. thanks.>> + fslist = (struct btrfs_ioctl_fslist *) fslist + >> + sizeof(*fslist); > > AKA fslist++.fixed it.> - zPosted V2. Thanks, Anand -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Nov-04 03:45 UTC
[PATCH] btrfs: add framework to read fs info from btrfs-control
This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs info through the btrfs-control v2: accepts Zach suggested now holds uuid_mutex Signed-off-by: Anand Jain <anand.jain@oracle.com> --- fs/btrfs/super.c | 66 ++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/volumes.c | 39 ++++++++++++++++++++++++++ fs/btrfs/volumes.h | 2 + include/uapi/linux/btrfs.h | 19 ++++++++++++ 4 files changed, 120 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index e9c4e41..241f401 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1646,38 +1646,92 @@ static struct file_system_type btrfs_fs_type = { }; MODULE_ALIAS_FS("btrfs"); +static int btrfs_ioc_get_fslist(void __user *arg) +{ + int ret = 0; + u64 sz_fslist_arg; + u64 sz_fslist; + u64 sz_out; + struct btrfs_ioctl_fslist_args *fslist_arg; + struct btrfs_ioctl_fslist_args *fslist_arg_tmp; + struct btrfs_ioctl_fslist *fslist; + + u64 cnt = 0, ucnt; + + sz_fslist_arg = sizeof(*fslist_arg); + sz_fslist = sizeof(*fslist); + if (copy_from_user(&ucnt, + (struct btrfs_ioctl_fslist_args __user *)(arg + + offsetof(struct btrfs_ioctl_fslist_args, count)), + sizeof(ucnt))) + return -EFAULT; + + cnt = btrfs_get_fslist_cnt(); + + if (cnt > ucnt) { + if (copy_to_user(arg + + offsetof(struct btrfs_ioctl_fslist_args, count), + &cnt, sizeof(cnt))) + return -EFAULT; + return 1; + } + + sz_out = sz_fslist_arg + sz_fslist * cnt; + fslist_arg_tmp = fslist_arg = memdup_user(arg, sz_out); + if (IS_ERR(fslist_arg)) + return PTR_ERR(fslist_arg); + fslist = (struct btrfs_ioctl_fslist *) (++fslist_arg_tmp); + cnt = btrfs_get_fslist(fslist, cnt); + fslist_arg->count = cnt; + if (copy_to_user(arg, fslist_arg, sz_out)) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + kfree(fslist_arg); + return ret; +} + /* * used by btrfsctl to scan devices when no FS is mounted */ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct btrfs_ioctl_vol_args *vol; + struct btrfs_ioctl_vol_args *vol = NULL; struct btrfs_fs_devices *fs_devices; int ret = -ENOTTY; + void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vol = memdup_user((void __user *)arg, sizeof(*vol)); - if (IS_ERR(vol)) - return PTR_ERR(vol); - switch (cmd) { case BTRFS_IOC_SCAN_DEV: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); break; case BTRFS_IOC_DEVICES_READY: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); if (ret) break; ret = !(fs_devices->num_devices == fs_devices->total_devices); break; + case BTRFS_IOC_GET_FSLIST: + ret = btrfs_ioc_get_fslist(argp); + break; } - kfree(vol); return ret; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5103cfe..b114372 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6289,3 +6289,42 @@ int btrfs_scratch_superblock(struct btrfs_device *device) return 0; } + +int btrfs_get_fslist_cnt(void) +{ + int cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) + cnt++; + mutex_unlock(&uuid_mutex); + + return cnt; +} + +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt) +{ + u64 cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) { + if (!(cnt < ucnt)) + break; + memcpy(fslist->fsid, fs_devices->fsid, + BTRFS_FSID_SIZE); + fslist->num_devices = fs_devices->num_devices; + fslist->missing_devices = fs_devices->missing_devices; + fslist->total_devices = fs_devices->total_devices; + + if (fs_devices->opened) + fslist->flags = BTRFS_FS_MOUNTED; + + fslist++; + cnt++; + } + mutex_unlock(&uuid_mutex); + + return cnt; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index b72f540..d8079e6 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -388,4 +388,6 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, { btrfs_dev_stat_set(dev, index, 0); } +int btrfs_get_fslist_cnt(void); +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt); #endif diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 45e6189..6690551 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -512,6 +512,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -606,5 +623,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #endif /* _UAPI_LINUX_BTRFS_H */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Nov-04 04:34 UTC
[PATCH v2] btrfs: add framework to read fs info from btrfs-control
This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs info through the btrfs-control v2: accepts Zach suggested now holds uuid_mutex Signed-off-by: Anand Jain <anand.jain@oracle.com> --- fs/btrfs/super.c | 66 ++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/volumes.c | 39 ++++++++++++++++++++++++++ fs/btrfs/volumes.h | 2 + include/uapi/linux/btrfs.h | 19 ++++++++++++ 4 files changed, 120 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index e9c4e41..241f401 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1646,38 +1646,92 @@ static struct file_system_type btrfs_fs_type = { }; MODULE_ALIAS_FS("btrfs"); +static int btrfs_ioc_get_fslist(void __user *arg) +{ + int ret = 0; + u64 sz_fslist_arg; + u64 sz_fslist; + u64 sz_out; + struct btrfs_ioctl_fslist_args *fslist_arg; + struct btrfs_ioctl_fslist_args *fslist_arg_tmp; + struct btrfs_ioctl_fslist *fslist; + + u64 cnt = 0, ucnt; + + sz_fslist_arg = sizeof(*fslist_arg); + sz_fslist = sizeof(*fslist); + if (copy_from_user(&ucnt, + (struct btrfs_ioctl_fslist_args __user *)(arg + + offsetof(struct btrfs_ioctl_fslist_args, count)), + sizeof(ucnt))) + return -EFAULT; + + cnt = btrfs_get_fslist_cnt(); + + if (cnt > ucnt) { + if (copy_to_user(arg + + offsetof(struct btrfs_ioctl_fslist_args, count), + &cnt, sizeof(cnt))) + return -EFAULT; + return 1; + } + + sz_out = sz_fslist_arg + sz_fslist * cnt; + fslist_arg_tmp = fslist_arg = memdup_user(arg, sz_out); + if (IS_ERR(fslist_arg)) + return PTR_ERR(fslist_arg); + fslist = (struct btrfs_ioctl_fslist *) (++fslist_arg_tmp); + cnt = btrfs_get_fslist(fslist, cnt); + fslist_arg->count = cnt; + if (copy_to_user(arg, fslist_arg, sz_out)) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + kfree(fslist_arg); + return ret; +} + /* * used by btrfsctl to scan devices when no FS is mounted */ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct btrfs_ioctl_vol_args *vol; + struct btrfs_ioctl_vol_args *vol = NULL; struct btrfs_fs_devices *fs_devices; int ret = -ENOTTY; + void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vol = memdup_user((void __user *)arg, sizeof(*vol)); - if (IS_ERR(vol)) - return PTR_ERR(vol); - switch (cmd) { case BTRFS_IOC_SCAN_DEV: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); break; case BTRFS_IOC_DEVICES_READY: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); if (ret) break; ret = !(fs_devices->num_devices == fs_devices->total_devices); break; + case BTRFS_IOC_GET_FSLIST: + ret = btrfs_ioc_get_fslist(argp); + break; } - kfree(vol); return ret; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5103cfe..b114372 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6289,3 +6289,42 @@ int btrfs_scratch_superblock(struct btrfs_device *device) return 0; } + +int btrfs_get_fslist_cnt(void) +{ + int cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) + cnt++; + mutex_unlock(&uuid_mutex); + + return cnt; +} + +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt) +{ + u64 cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) { + if (!(cnt < ucnt)) + break; + memcpy(fslist->fsid, fs_devices->fsid, + BTRFS_FSID_SIZE); + fslist->num_devices = fs_devices->num_devices; + fslist->missing_devices = fs_devices->missing_devices; + fslist->total_devices = fs_devices->total_devices; + + if (fs_devices->opened) + fslist->flags = BTRFS_FS_MOUNTED; + + fslist++; + cnt++; + } + mutex_unlock(&uuid_mutex); + + return cnt; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index b72f540..d8079e6 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -388,4 +388,6 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, { btrfs_dev_stat_set(dev, index, 0); } +int btrfs_get_fslist_cnt(void); +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt); #endif diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 45e6189..6690551 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -512,6 +512,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -606,5 +623,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #endif /* _UAPI_LINUX_BTRFS_H */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand Jain
2013-Dec-19 03:59 UTC
[PATCH v3] btrfs: add framework to read fs info from btrfs-control
This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs info through the btrfs-control, needed to optimize heavily used btrfs-progs function check_mounted() plus few other minor uses. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- v3: rebase and update commit v2: accepts Zach suggested and now holds uuid_mutex fs/btrfs/super.c | 66 ++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/volumes.c | 39 ++++++++++++++++++++++++++ fs/btrfs/volumes.h | 2 + include/uapi/linux/btrfs.h | 19 ++++++++++++ 4 files changed, 120 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 0d4b1c3..13884c5 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1645,38 +1645,92 @@ static struct file_system_type btrfs_fs_type = { }; MODULE_ALIAS_FS("btrfs"); +static int btrfs_ioc_get_fslist(void __user *arg) +{ + int ret = 0; + u64 sz_fslist_arg; + u64 sz_fslist; + u64 sz_out; + struct btrfs_ioctl_fslist_args *fslist_arg; + struct btrfs_ioctl_fslist_args *fslist_arg_tmp; + struct btrfs_ioctl_fslist *fslist; + + u64 cnt = 0, ucnt; + + sz_fslist_arg = sizeof(*fslist_arg); + sz_fslist = sizeof(*fslist); + if (copy_from_user(&ucnt, + (struct btrfs_ioctl_fslist_args __user *)(arg + + offsetof(struct btrfs_ioctl_fslist_args, count)), + sizeof(ucnt))) + return -EFAULT; + + cnt = btrfs_get_fslist_cnt(); + + if (cnt > ucnt) { + if (copy_to_user(arg + + offsetof(struct btrfs_ioctl_fslist_args, count), + &cnt, sizeof(cnt))) + return -EFAULT; + return 1; + } + + sz_out = sz_fslist_arg + sz_fslist * cnt; + fslist_arg_tmp = fslist_arg = memdup_user(arg, sz_out); + if (IS_ERR(fslist_arg)) + return PTR_ERR(fslist_arg); + fslist = (struct btrfs_ioctl_fslist *) (++fslist_arg_tmp); + cnt = btrfs_get_fslist(fslist, cnt); + fslist_arg->count = cnt; + if (copy_to_user(arg, fslist_arg, sz_out)) { + ret = -EFAULT; + goto out; + } + ret = 0; +out: + kfree(fslist_arg); + return ret; +} + /* * used by btrfsctl to scan devices when no FS is mounted */ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct btrfs_ioctl_vol_args *vol; + struct btrfs_ioctl_vol_args *vol = NULL; struct btrfs_fs_devices *fs_devices; int ret = -ENOTTY; + void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - vol = memdup_user((void __user *)arg, sizeof(*vol)); - if (IS_ERR(vol)) - return PTR_ERR(vol); - switch (cmd) { case BTRFS_IOC_SCAN_DEV: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); break; case BTRFS_IOC_DEVICES_READY: + vol = memdup_user((void __user *)arg, sizeof(*vol)); + if (IS_ERR(vol)) + return PTR_ERR(vol); ret = btrfs_scan_one_device(vol->name, FMODE_READ, &btrfs_fs_type, &fs_devices); + kfree(vol); if (ret) break; ret = !(fs_devices->num_devices == fs_devices->total_devices); break; + case BTRFS_IOC_GET_FSLIST: + ret = btrfs_ioc_get_fslist(argp); + break; } - kfree(vol); return ret; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 92303f4..debd619 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6284,3 +6284,42 @@ int btrfs_scratch_superblock(struct btrfs_device *device) return 0; } + +int btrfs_get_fslist_cnt(void) +{ + int cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) + cnt++; + mutex_unlock(&uuid_mutex); + + return cnt; +} + +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt) +{ + u64 cnt = 0; + struct btrfs_fs_devices *fs_devices; + + mutex_lock(&uuid_mutex); + list_for_each_entry(fs_devices, &fs_uuids, list) { + if (!(cnt < ucnt)) + break; + memcpy(fslist->fsid, fs_devices->fsid, + BTRFS_FSID_SIZE); + fslist->num_devices = fs_devices->num_devices; + fslist->missing_devices = fs_devices->missing_devices; + fslist->total_devices = fs_devices->total_devices; + + if (fs_devices->opened) + fslist->flags = BTRFS_FS_MOUNTED; + + fslist++; + cnt++; + } + mutex_unlock(&uuid_mutex); + + return cnt; +} diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 8b3cd14..ebb0d0c 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -390,4 +390,6 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, { btrfs_dev_stat_set(dev, index, 0); } +int btrfs_get_fslist_cnt(void); +u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt); #endif diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 1b8a0f4..7d7f776 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -518,6 +518,23 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) } } +/* fs flags */ +#define BTRFS_FS_MOUNTED (1LLU << 0) + +struct btrfs_ioctl_fslist { + __u64 self_sz; /* in/out */ + __u8 fsid[BTRFS_FSID_SIZE]; /* out */ + __u64 num_devices; + __u64 missing_devices; + __u64 total_devices; + __u64 flags; +}; + +struct btrfs_ioctl_fslist_args { + __u64 self_sz; /* in/out */ + __u64 count; /* 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, \ @@ -613,6 +630,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_args) +#define BTRFS_IOC_GET_FSLIST _IOWR(BTRFS_IOCTL_MAGIC, 56, \ + struct btrfs_ioctl_fslist_args) #define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ struct btrfs_ioctl_feature_flags) #define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html