diff mbox

[v2] btrfs: introduce BTRFS_IOC_GET_DEVS

Message ID 1393242525-18587-2-git-send-email-Anand.Jain@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Anand Jain Feb. 24, 2014, 11:48 a.m. UTC
From: Anand Jain <anand.jain@oracle.com>

The user land progs needs   a simple way to see
the raw list of disks and its parameters as seen
by the btrfs kernel.
As of now btrfs-devlist uses this ioctl.

Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
v2: add more parameter to get from the kernel

 fs/btrfs/super.c           |  56 ++++++++++++++++++
 fs/btrfs/volumes.c         | 140 +++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/volumes.h         |   2 +
 include/uapi/linux/btrfs.h |  49 ++++++++++++++++
 4 files changed, 247 insertions(+)

Comments

David Sterba Feb. 25, 2014, 5:51 p.m. UTC | #1
On Mon, Feb 24, 2014 at 07:48:45PM +0800, Anand Jain wrote:
> The user land progs needs   a simple way to see
> the raw list of disks and its parameters as seen
> by the btrfs kernel.
> As of now btrfs-devlist uses this ioctl.

As discussed before together with Hugo, the ioctl could exist parallel
to sysfs export of the device data. From that point it's easier to
maintain and update a set of sysfs files than an ioctl. The way you
suggest it right now lacks future-proof extensibility and backward
compatibility handling.

The userspace code is said to be a small and debug program, the sysfs
would IMHO satsify it needs as well, so I suggest not to continue on the
ioctl approach.
--
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 Feb. 26, 2014, 3:03 a.m. UTC | #2
On 26/02/2014 01:51, David Sterba wrote:
> On Mon, Feb 24, 2014 at 07:48:45PM +0800, Anand Jain wrote:
>> The user land progs needs   a simple way to see
>> the raw list of disks and its parameters as seen
>> by the btrfs kernel.
>> As of now btrfs-devlist uses this ioctl.
>
> As discussed before together with Hugo, the ioctl could exist parallel
> to sysfs export of the device data. From that point it's easier to
> maintain and update a set of sysfs files than an ioctl. The way you
> suggest it right now lacks future-proof extensibility and backward
> compatibility handling.
>
> The userspace code is said to be a small and debug program, the sysfs
> would IMHO satsify it needs as well, so I suggest not to continue on the
> ioctl approach.


  sysfs interface has its advantage, but please lets not clutter
  it with the debug info as it just don't belong there. And one
  should be care full enough not to introduce regressions [1]
  when writing sysfs interfaces (sysfs has to be "managed"
  VS debug-friendly memory-dump/ioctl-dump).

  Next, btrfs-kernel device management isn't just ready
  fully[2] so that sysfs interface can be developed as
  of now. It better wait.

[1]
    https://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg31432.html
    http://comments.gmane.org/gmane.comp.file-systems.btrfs/31915

[2] btrfs-kernel has no idea when disk disappears.
     To get this done we appear to need more enhancements
     related to the usage of kobjects with in kernel.

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
diff mbox

Patch

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index afb719e..f3c0247 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1717,6 +1717,59 @@  static struct file_system_type btrfs_fs_type = {
 };
 MODULE_ALIAS_FS("btrfs");
 
+static int btrfs_ioc_get_devlist(void __user *arg)
+{
+	int ret = 0;
+	u64 sz_devlist_arg;
+	u64 sz_devlist;
+	u64 sz_out;
+
+	struct btrfs_ioctl_devlist_args *devlist_arg;
+	struct btrfs_ioctl_devlist_args *tmp_devlist_arg;
+	struct btrfs_ioctl_devlist *devlist;
+
+	u64 cnt = 0, ucnt;
+
+	sz_devlist_arg = sizeof(*devlist_arg);
+	sz_devlist = sizeof(*devlist);
+
+	if (copy_from_user(&ucnt,
+		(struct btrfs_ioctl_devlist_args __user *)(arg +
+		offsetof(struct btrfs_ioctl_devlist_args, count)),
+			sizeof(ucnt)))
+		return -EFAULT;
+
+	cnt = btrfs_get_devlist_cnt();
+
+	if (cnt > ucnt) {
+		if (copy_to_user(arg +
+		offsetof(struct btrfs_ioctl_devlist_args, count),
+			&cnt, sizeof(cnt)))
+			return -EFAULT;
+		return 1;
+	}
+
+	sz_out = sz_devlist_arg + sz_devlist * cnt;
+
+	tmp_devlist_arg = devlist_arg = memdup_user(arg, sz_out);
+	if (IS_ERR(devlist_arg))
+		return PTR_ERR(devlist_arg);
+
+	devlist = (struct btrfs_ioctl_devlist *) (++tmp_devlist_arg);
+	cnt = btrfs_get_devlist(devlist, cnt);
+	devlist_arg->count = cnt;
+
+	if (copy_to_user(arg, devlist_arg, sz_out)) {
+		ret = -EFAULT;
+		goto out;
+	}
+	ret = 0;
+out:
+	kfree(devlist_arg);
+	return ret;
+
+}
+
 static int btrfs_ioc_get_fslist(void __user *arg)
 {
 	int ret = 0;
@@ -1801,6 +1854,9 @@  static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
 	case BTRFS_IOC_GET_FSLIST:
 		ret = btrfs_ioc_get_fslist(argp);
 		break;
+	case BTRFS_IOC_GET_DEVS:
+		ret = btrfs_ioc_get_devlist(argp);
+		break;
 	}
 
 	return ret;
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 253fd9f..3c44800 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6338,3 +6338,143 @@  u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt)
 
 	return cnt;
 }
+
+int btrfs_get_devlist_cnt(void)
+{
+	int cnt = 0;
+	struct btrfs_device *device;
+	struct btrfs_fs_devices *fs_devices;
+	struct btrfs_fs_devices *cur_fs_devices;
+
+	mutex_lock(&uuid_mutex);
+	list_for_each_entry(cur_fs_devices, &fs_uuids, list) {
+
+		fs_devices = cur_fs_devices;
+again_dev_cnt:
+		list_for_each_entry(device, &fs_devices->devices, dev_list)
+			cnt++;
+
+		fs_devices = fs_devices->seed;
+		if (fs_devices)
+			goto again_dev_cnt;
+	}
+
+	mutex_unlock(&uuid_mutex);
+
+	return cnt;
+}
+
+u64 btrfs_get_devlist(struct btrfs_ioctl_devlist *dev, u64 alloc_cnt)
+{
+	u64 cnt = 0;
+
+	struct btrfs_device *device;
+	struct btrfs_fs_devices *fs_devices;
+	struct btrfs_fs_devices *cur_fs_devices;
+	struct btrfs_fs_devices *sprout_fs_devices;
+
+	mutex_lock(&uuid_mutex);
+	/* Todo: there must be better way of doing this */
+	list_for_each_entry(cur_fs_devices, &fs_uuids, list) {
+
+		mutex_lock(&cur_fs_devices->device_list_mutex);
+
+		fs_devices = cur_fs_devices;
+		sprout_fs_devices = NULL;
+
+again_dev:
+		list_for_each_entry(device, &fs_devices->devices, dev_list) {
+
+			if (!(cnt < alloc_cnt))
+				break;
+
+			memcpy(dev->fsid, fs_devices->fsid, BTRFS_FSID_SIZE);
+
+			if (fs_devices->seed)
+				memcpy(dev->seed_fsid, fs_devices->seed->fsid,
+						BTRFS_FSID_SIZE);
+			else
+				memset(dev->seed_fsid, 0, BTRFS_FSID_SIZE);
+
+			if (sprout_fs_devices)
+				memcpy(dev->sprout_fsid, sprout_fs_devices->fsid,
+						BTRFS_FSID_SIZE);
+			else
+				memset(dev->sprout_fsid, 0, BTRFS_FSID_SIZE);
+
+			dev->fs_latest_devid = fs_devices->latest_devid;
+			dev->fs_latest_trans = fs_devices->latest_trans;
+			dev->fs_num_devices = fs_devices->num_devices;
+			dev->fs_open_devices = fs_devices->open_devices;
+			dev->fs_rw_devices = fs_devices->rw_devices;
+			dev->fs_missing_devices = fs_devices->missing_devices;
+			dev->fs_total_rw_bytes = fs_devices->total_rw_bytes;
+			dev->fs_num_can_discard = fs_devices->num_can_discard;
+			dev->fs_total_devices = fs_devices->total_devices;
+
+			dev->flags = 0;
+
+			if (fs_devices->opened)
+				dev->flags |= BTRFS_FS_MOUNTED;
+			if (fs_devices->seeding)
+				dev->flags |= BTRFS_FS_SEEDING;
+			if (fs_devices->rotating)
+				dev->flags |= BTRFS_FS_ROTATING;
+
+			dev->gen = device->generation;
+			dev->devid = device->devid;
+			dev->total_bytes = device->total_bytes;
+			dev->disk_total_bytes = device->disk_total_bytes;
+			dev->bytes_used = device->bytes_used;
+			dev->type = device->type;
+			dev->io_align = device->io_align;
+			dev->io_width = device->io_width;
+			dev->sector_size = device->sector_size;
+			dev->fmode = device->mode;
+
+			if (device->writeable)
+				dev->flags |= BTRFS_DEV_WRITEABLE;
+			if (device->in_fs_metadata)
+				dev->flags |= BTRFS_DEV_IN_FS_MD;
+			if (device->missing)
+				dev->flags |= BTRFS_DEV_MISSING;
+			if (device->can_discard)
+				dev->flags |= BTRFS_DEV_CAN_DISCARD;
+			if (device->is_tgtdev_for_dev_replace)
+				dev->flags |= BTRFS_DEV_REPLACE_TGT;
+			if (device->running_pending)
+				dev->flags |= BTRFS_DEV_RUN_PENDING;
+			if (device->nobarriers)
+				dev->flags |= BTRFS_DEV_NOBARRIERS;
+			if (device->dev_stats_valid)
+				dev->flags |= BTRFS_DEV_STATS_VALID;
+			if (device->dev_stats_dirty)
+				dev->flags |= BTRFS_DEV_STATS_DIRTY;
+			if (device->bdev)
+				dev->flags |= BTRFS_DEV_BDEV;
+
+			memcpy(dev->uuid, device->uuid, BTRFS_UUID_SIZE);
+			if (device->name) {
+				rcu_read_lock();
+				memcpy(dev->name, rcu_str_deref(device->name),
+					BTRFS_PATH_NAME_MAX);
+				rcu_read_unlock();
+			} else {
+				memset(dev->name, 0, BTRFS_PATH_NAME_MAX);
+			}
+			dev++;
+			cnt++;
+		}
+
+		if (fs_devices->seed) {
+			sprout_fs_devices = fs_devices;
+			fs_devices = fs_devices->seed;
+			goto again_dev;
+		}
+
+		mutex_unlock(&cur_fs_devices->device_list_mutex);
+	}
+	mutex_unlock(&uuid_mutex);
+
+	return cnt;
+}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 0b97fcf..91b7596 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -393,4 +393,6 @@  static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
 }
 int btrfs_get_fslist_cnt(void);
 u64 btrfs_get_fslist(struct btrfs_ioctl_fslist *fslist, u64 ucnt);
+int btrfs_get_devlist_cnt(void);
+u64 btrfs_get_devlist(struct btrfs_ioctl_devlist *devlist, u64 ucnt);
 #endif
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 76b91d6..23541b2 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -520,6 +520,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 */
@@ -535,6 +537,51 @@  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_REPLACE_TGT	(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)
+#define BTRFS_DEV_BDEV		(1LLU << 17)
+
+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;
+	__u64 fmode;
+	__u32 io_align;
+	__u32 io_width;
+	__u32 sector_size;
+	__u8 fsid[BTRFS_FSID_SIZE];
+	__u8 uuid[BTRFS_UUID_SIZE];
+	__u8 seed_fsid[BTRFS_FSID_SIZE];
+	__u8 sprout_fsid[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, \
@@ -637,5 +684,7 @@  struct btrfs_ioctl_fslist_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)
 
 #endif /* _UAPI_LINUX_BTRFS_H */