From b8435c569398fbc8a4a209dcd55cb660b6577d3d Mon Sep 17 00:00:00 2001
From: Kent Overstreet <kent.overstreet@linux.dev>
Date: Sun, 23 Mar 2025 11:03:42 -0400
Subject: [PATCH] bch2_format() now takes a darray of dev_opts

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 c_src/cmd_device.c  |  9 +++----
 c_src/cmd_format.c  | 10 +++-----
 c_src/cmd_migrate.c |  7 ++++--
 c_src/libbcachefs.c | 58 +++++++++++++++++++--------------------------
 c_src/libbcachefs.h |  5 +++-
 5 files changed, 42 insertions(+), 47 deletions(-)

diff --git a/c_src/cmd_device.c b/c_src/cmd_device.c
index a1e78e25..d953055c 100644
--- a/c_src/cmd_device.c
+++ b/c_src/cmd_device.c
@@ -137,10 +137,11 @@ int cmd_device_add(int argc, char *argv[])
 	opt_set(fs_opts, btree_node_size,
 		read_file_u64(fs.sysfs_fd, "options/btree_node_size"));
 
-	struct bch_sb *sb = bch2_format(fs_opt_strs,
-					fs_opts,
-					format_opts,
-					&dev_opts, 1);
+	dev_opts_list devs = {};
+	darray_push(&devs, dev_opts);
+
+	struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, format_opts, devs);
+	darray_exit(&devs);
 	free(sb);
 	bchu_disk_add(fs, dev_opts.path);
 	return 0;
diff --git a/c_src/cmd_format.c b/c_src/cmd_format.c
index 4fbf3a4b..7c0d1920 100644
--- a/c_src/cmd_format.c
+++ b/c_src/cmd_format.c
@@ -126,8 +126,8 @@ void build_fs(struct bch_fs *c, const char *src_path)
 
 int cmd_format(int argc, char *argv[])
 {
-	DARRAY(struct dev_opts) devices = { 0 };
-	DARRAY(char *) device_paths = { 0 };
+	dev_opts_list devices = {};
+	darray_str device_paths = {};
 	struct format_opts opts	= format_opts_default();
 	struct dev_opts dev_opts = dev_opts_default();
 	bool force = false, no_passphrase = false, quiet = false, initialize = true, verbose = false;
@@ -277,11 +277,7 @@ int cmd_format(int argc, char *argv[])
 			die("Error opening %s: %s", dev_opts.path, strerror(-ret));
 	}
 
-	struct bch_sb *sb =
-		bch2_format(fs_opt_strs,
-			    fs_opts,
-			    opts,
-			    devices.data, devices.nr);
+	struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, opts, devices);
 	bch2_opt_strs_free(&fs_opt_strs);
 
 	if (!quiet) {
diff --git a/c_src/cmd_migrate.c b/c_src/cmd_migrate.c
index 698cfd55..109416a8 100644
--- a/c_src/cmd_migrate.c
+++ b/c_src/cmd_migrate.c
@@ -239,8 +239,11 @@ static int migrate_fs(const char		*fs_path,
 
 	find_superblock_space(extents, format_opts, &dev);
 
-	struct bch_sb *sb = bch2_format(fs_opt_strs,
-					fs_opts, format_opts, &dev, 1);
+	dev_opts_list devs = {};
+	darray_push(&devs, dev);
+	struct bch_sb *sb = bch2_format(fs_opt_strs, fs_opts, format_opts, devs);
+	darray_exit(&devs);
+
 	u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);
 
 	if (format_opts.passphrase)
diff --git a/c_src/libbcachefs.c b/c_src/libbcachefs.c
index d212b6ef..50ac96a8 100644
--- a/c_src/libbcachefs.c
+++ b/c_src/libbcachefs.c
@@ -116,20 +116,17 @@ void bch2_check_bucket_size(struct bch_opts opts, struct dev_opts *dev)
 }
 
 static unsigned parse_target(struct bch_sb_handle *sb,
-			     struct dev_opts *devs, size_t nr_devs,
+			     dev_opts_list devs,
 			     const char *s)
 {
-	struct dev_opts *i;
-	int idx;
-
 	if (!s)
 		return 0;
 
-	for (i = devs; i < devs + nr_devs; i++)
+	darray_for_each(devs, i)
 		if (!strcmp(s, i->path))
-			return dev_to_target(i - devs);
+			return dev_to_target(i - devs.data);
 
-	idx = bch2_disk_path_find(sb, s);
+	int idx = bch2_disk_path_find(sb, s);
 	if (idx >= 0)
 		return group_to_target(idx);
 
@@ -151,15 +148,13 @@ static void bch2_opt_set_sb_all(struct bch_sb *sb, int dev_idx, struct bch_opts
 struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 			   struct bch_opts	fs_opts,
 			   struct format_opts	opts,
-			   struct dev_opts	*devs,
-			   size_t		nr_devs)
+			   dev_opts_list devs)
 {
 	struct bch_sb_handle sb = { NULL };
-	struct dev_opts *i;
 	unsigned max_dev_block_size = 0;
 	u64 min_bucket_size = U64_MAX;
 
-	for (i = devs; i < devs + nr_devs; i++)
+	darray_for_each(devs, i)
 		max_dev_block_size = max(max_dev_block_size, get_blocksize(i->bdev->bd_fd));
 
 	/* calculate block size: */
@@ -171,20 +166,20 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 		    fs_opts.block_size, max_dev_block_size);
 
 	/* get device size, if it wasn't specified: */
-	for (i = devs; i < devs + nr_devs; i++)
+	darray_for_each(devs, i)
 		if (!opt_defined(i->opts, fs_size))
 			opt_set(i->opts, fs_size, get_size(i->bdev->bd_fd));
 
 	/* calculate bucket sizes: */
-	for (i = devs; i < devs + nr_devs; i++)
+	darray_for_each(devs, i)
 		min_bucket_size = min(min_bucket_size,
 			i->opts.bucket_size ?: bch2_pick_bucket_size(fs_opts, i));
 
-	for (i = devs; i < devs + nr_devs; i++)
+	darray_for_each(devs, i)
 		if (!opt_defined(i->opts, bucket_size))
 			opt_set(i->opts, bucket_size, min_bucket_size);
 
-	for (i = devs; i < devs + nr_devs; i++) {
+	darray_for_each(devs, i) {
 		i->nbuckets = i->opts.fs_size / i->opts.bucket_size;
 		bch2_check_bucket_size(fs_opts, i);
 	}
@@ -193,7 +188,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 	if (!opt_defined(fs_opts, btree_node_size)) {
 		unsigned s = bch2_opts_default.btree_node_size;
 
-		for (i = devs; i < devs + nr_devs; i++)
+		darray_for_each(devs, i)
 			s = min(s, i->opts.bucket_size);
 		opt_set(fs_opts, btree_node_size, s);
 	}
@@ -208,7 +203,7 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 	sb.sb->version_min	= le16_to_cpu(opts.version);
 	sb.sb->magic		= BCHFS_MAGIC;
 	sb.sb->user_uuid	= opts.uuid;
-	sb.sb->nr_devices	= nr_devs;
+	sb.sb->nr_devices	= devs.nr;
 	SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(sb.sb, opts.version);
 
 	if (opts.version == bcachefs_metadata_version_current)
@@ -233,11 +228,11 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 	/* Member info: */
 	struct bch_sb_field_members_v2 *mi =
 		bch2_sb_field_resize(&sb, members_v2,
-			(sizeof(*mi) + sizeof(struct bch_member) *
-			nr_devs) / sizeof(u64));
+			(sizeof(*mi) + sizeof(struct bch_member) * devs.nr) / sizeof(u64));
+
 	mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
-	for (i = devs; i < devs + nr_devs; i++) {
-		unsigned idx = i - devs;
+	darray_for_each(devs, i) {
+		unsigned idx = i - devs.data;
 		struct bch_member *m = bch2_members_v2_get_mut(sb.sb, idx);
 
 		uuid_generate(m->uuid.b);
@@ -247,14 +242,11 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 	}
 
 	/* Disk labels*/
-	for (i = devs; i < devs + nr_devs; i++) {
-		struct bch_member *m;
-		int idx;
-
+	darray_for_each(devs, i) {
 		if (!i->label)
 			continue;
 
-		idx = bch2_disk_path_find_or_create(&sb, i->label);
+		int idx = bch2_disk_path_find_or_create(&sb, i->label);
 		if (idx < 0)
 			die("error creating disk path: %s", strerror(-idx));
 
@@ -262,18 +254,18 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 		 * Recompute mi and m after each sb modification: its location
 		 * in memory may have changed due to reallocation.
 		 */
-		m = bch2_members_v2_get_mut(sb.sb, (i - devs));
+		struct bch_member *m = bch2_members_v2_get_mut(sb.sb, (i - devs.data));
 		SET_BCH_MEMBER_GROUP(m,	idx + 1);
 	}
 
 	SET_BCH_SB_FOREGROUND_TARGET(sb.sb,
-		parse_target(&sb, devs, nr_devs, fs_opt_strs.foreground_target));
+		parse_target(&sb, devs, fs_opt_strs.foreground_target));
 	SET_BCH_SB_BACKGROUND_TARGET(sb.sb,
-		parse_target(&sb, devs, nr_devs, fs_opt_strs.background_target));
+		parse_target(&sb, devs, fs_opt_strs.background_target));
 	SET_BCH_SB_PROMOTE_TARGET(sb.sb,
-		parse_target(&sb, devs, nr_devs, fs_opt_strs.promote_target));
+		parse_target(&sb, devs, fs_opt_strs.promote_target));
 	SET_BCH_SB_METADATA_TARGET(sb.sb,
-		parse_target(&sb, devs, nr_devs, fs_opt_strs.metadata_target));
+		parse_target(&sb, devs, fs_opt_strs.metadata_target));
 
 	/* Crypt: */
 	if (opts.encrypted) {
@@ -286,10 +278,10 @@ struct bch_sb *bch2_format(struct bch_opt_strs	fs_opt_strs,
 
 	bch2_sb_members_cpy_v2_v1(&sb);
 
-	for (i = devs; i < devs + nr_devs; i++) {
+	darray_for_each(devs, i) {
 		u64 size_sectors = i->opts.fs_size >> 9;
 
-		sb.sb->dev_idx = i - devs;
+		sb.sb->dev_idx = i - devs.data;
 
 		if (!i->sb_offset) {
 			i->sb_offset	= BCH_SB_SECTOR;
diff --git a/c_src/libbcachefs.h b/c_src/libbcachefs.h
index 05ba1069..4185cebb 100644
--- a/c_src/libbcachefs.h
+++ b/c_src/libbcachefs.h
@@ -83,9 +83,12 @@ void bch2_sb_layout_init(struct bch_sb_layout *,
 u64 bch2_pick_bucket_size(struct bch_opts, struct dev_opts *);
 void bch2_check_bucket_size(struct bch_opts, struct dev_opts *);
 
+typedef DARRAY(struct dev_opts) dev_opts_list;
+
 struct bch_sb *bch2_format(struct bch_opt_strs,
 			   struct bch_opts,
-			   struct format_opts, struct dev_opts *, size_t);
+			   struct format_opts,
+			   dev_opts_list devs);
 
 void bch2_super_write(int, struct bch_sb *);
 struct bch_sb *__bch2_super_read(int, u64);