diff mbox series

[3/3] btrfs-progs: use the new ioctl BTRFS_IOC_GET_CHUNK_INFO

Message ID 20200315152430.7532-4-kreijack@libero.it (mailing list archive)
State New, archived
Headers show
Series [1/3] btrfs-progs: remove use BLKGETSIZE64 | expand

Commit Message

Goffredo Baroncelli March 15, 2020, 3:24 p.m. UTC
From: Goffredo Baroncelli <kreijack@inwind.it>

Use the new ioctl BTRFS_IOC_GET_CHUNK_INFO in load_chunk_info() instead of
the BTRFS_IOC_TREE_SEARCH. The old method is still present as fallback for
compatibility reason.

The goal is to avoid BTRFS_IOC_TREE_SEARCH because it requires root
privileges.

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
---
 cmds/filesystem-usage.c | 108 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/cmds/filesystem-usage.c b/cmds/filesystem-usage.c
index aa7065d5..79792ee1 100644
--- a/cmds/filesystem-usage.c
+++ b/cmds/filesystem-usage.c
@@ -39,7 +39,7 @@ 
 /*
  * Add the chunk info to the chunk_info list
  */
-static int add_info_to_list(struct chunk_info **info_ptr,
+static int legacy_add_info_to_list(struct chunk_info **info_ptr,
 			int *info_count,
 			struct btrfs_chunk *chunk)
 {
@@ -130,7 +130,8 @@  static int cmp_chunk_info(const void *a, const void *b)
 		((struct chunk_info *)b)->type);
 }
 
-static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count)
+static int legacy_load_chunk_info(int fd, struct chunk_info **info_ptr,
+					int *info_count)
 {
 	int ret;
 	struct btrfs_ioctl_search_args args;
@@ -182,7 +183,7 @@  static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count
 			off += sizeof(*sh);
 			item = (struct btrfs_chunk *)(args.buf + off);
 
-			ret = add_info_to_list(info_ptr, info_count, item);
+			ret = legacy_add_info_to_list(info_ptr, info_count, item);
 			if (ret) {
 				*info_ptr = NULL;
 				return 1;
@@ -215,6 +216,107 @@  static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count
 	return 0;
 }
 
+/*
+ * Add the chunk info to the chunk_info list
+ */
+static int add_info_to_list(struct chunk_info **info_ptr,
+			int *info_count,
+			struct btrfs_chunk_info *chunk)
+{
+
+	u64 type = chunk->type;
+	u64 size = chunk->length;
+	int num_stripes = chunk->num_stripes;
+	int j;
+
+	for (j = 0 ; j < num_stripes ; j++) {
+		int i;
+		struct chunk_info *p = NULL;
+		u64    devid;
+
+		devid = chunk->stripes[j].devid;
+
+		for (i = 0 ; i < *info_count ; i++)
+			if ((*info_ptr)[i].type == type &&
+			    (*info_ptr)[i].devid == devid &&
+			    (*info_ptr)[i].num_stripes == num_stripes) {
+				p = (*info_ptr) + i;
+				break;
+			}
+
+		if (!p) {
+			int tmp = sizeof(struct btrfs_chunk) *
+						(*info_count + 1);
+			struct chunk_info *res = realloc(*info_ptr, tmp);
+
+			if (!res) {
+				free(*info_ptr);
+				error("not enough memory");
+				return -ENOMEM;
+			}
+
+			*info_ptr = res;
+			p = res + *info_count;
+			(*info_count)++;
+
+			p->devid = devid;
+			p->type = type;
+			p->size = 0;
+			p->num_stripes = num_stripes;
+		}
+
+		p->size += size;
+
+	}
+
+	return 0;
+
+}
+
+static int load_chunk_info(int fd, struct chunk_info **info_ptr,
+				int *info_count)
+{
+
+	char buf[4096];
+	struct btrfs_ioctl_chunk_info *bici =
+		(struct btrfs_ioctl_chunk_info *)buf;
+	int cont;
+
+	bici->buf_size = sizeof(buf);
+	bici->offset = (u64)0;
+
+	do {
+		int i;
+		struct btrfs_chunk_info *ci;
+		int ret;
+
+		cont = false;
+		ret = ioctl(fd, BTRFS_IOC_GET_CHUNK_INFO, bici);
+		if (ret < 0) {
+			int e = errno;
+
+			if (e == ENOTTY)
+				return legacy_load_chunk_info(fd, info_ptr,
+								info_count);
+			else if (e == EAGAIN)
+				cont = true;
+			else
+				return -e;
+		}
+
+		ci = btrfs_first_chunk_info(bici);
+		for (i = 0 ; i < bici->items_count ; i++) {
+			add_info_to_list(info_ptr, info_count, ci);
+			ci = btrfs_next_chunk_info(ci);
+		}
+
+	} while (cont);
+
+	qsort(*info_ptr, *info_count, sizeof(struct chunk_info),
+		cmp_chunk_info);
+
+	return 0;
+}
 /*
  * Helper to sort the struct btrfs_ioctl_space_info
  */