* [PATCH] btrfs: add framework to read fs info from btrfs-control
@ 2013-10-25 17:10 Anand Jain
2013-10-25 17:10 ` [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo " Anand Jain
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Anand Jain @ 2013-10-25 17:10 UTC (permalink / raw)
To: linux-btrfs
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo from btrfs-control
2013-10-25 17:10 [PATCH] btrfs: add framework to read fs info from btrfs-control Anand Jain
@ 2013-10-25 17:10 ` Anand Jain
2013-10-29 16:34 ` [PATCH 2/3 v2] " Anand Jain
2013-10-25 17:10 ` [PATCH 2/2] btrfs-progs: fs show should handle if subvol(s) mounted Anand Jain
2013-10-29 21:33 ` [PATCH] btrfs: add framework to read fs info from btrfs-control Zach Brown
2 siblings, 1 reply; 6+ messages in thread
From: Anand Jain @ 2013-10-25 17:10 UTC (permalink / raw)
To: linux-btrfs
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] btrfs-progs: fs show should handle if subvol(s) mounted
2013-10-25 17:10 [PATCH] btrfs: add framework to read fs info from btrfs-control Anand Jain
2013-10-25 17:10 ` [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo " Anand Jain
@ 2013-10-25 17:10 ` Anand Jain
2013-10-29 21:33 ` [PATCH] btrfs: add framework to read fs info from btrfs-control Zach Brown
2 siblings, 0 replies; 6+ messages in thread
From: Anand Jain @ 2013-10-25 17:10 UTC (permalink / raw)
To: linux-btrfs
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3 v2] btrfs-progs: mechanism to fetch fsinfo from btrfs-control
2013-10-25 17:10 ` [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo " Anand Jain
@ 2013-10-29 16:34 ` Anand Jain
0 siblings, 0 replies; 6+ messages in thread
From: Anand Jain @ 2013-10-29 16:34 UTC (permalink / raw)
To: linux-btrfs
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] btrfs: add framework to read fs info from btrfs-control
2013-10-25 17:10 [PATCH] btrfs: add framework to read fs info from btrfs-control Anand Jain
2013-10-25 17:10 ` [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo " Anand Jain
2013-10-25 17:10 ` [PATCH 2/2] btrfs-progs: fs show should handle if subvol(s) mounted Anand Jain
@ 2013-10-29 21:33 ` Zach Brown
2013-11-04 3:39 ` Anand Jain
2 siblings, 1 reply; 6+ messages in thread
From: Zach Brown @ 2013-10-29 21:33 UTC (permalink / raw)
To: Anand Jain; +Cc: linux-btrfs
> This adds ioctl BTRFS_IOC_GET_FSIDS which reads the fs
> info through the btrfs-control
Why 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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] btrfs: add framework to read fs info from btrfs-control
2013-10-29 21:33 ` [PATCH] btrfs: add framework to read fs info from btrfs-control Zach Brown
@ 2013-11-04 3:39 ` Anand Jain
0 siblings, 0 replies; 6+ messages in thread
From: Anand Jain @ 2013-11-04 3:39 UTC (permalink / raw)
To: Zach Brown; +Cc: linux-btrfs
(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.
> - z
Posted V2.
Thanks, Anand
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-11-04 3:40 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-25 17:10 [PATCH] btrfs: add framework to read fs info from btrfs-control Anand Jain
2013-10-25 17:10 ` [PATCH 1/2] btrfs-progs: mechanism to fetch fsinfo " Anand Jain
2013-10-29 16:34 ` [PATCH 2/3 v2] " Anand Jain
2013-10-25 17:10 ` [PATCH 2/2] btrfs-progs: fs show should handle if subvol(s) mounted Anand Jain
2013-10-29 21:33 ` [PATCH] btrfs: add framework to read fs info from btrfs-control Zach Brown
2013-11-04 3:39 ` Anand Jain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).