Linux Btrfs filesystem development
 help / color / mirror / Atom feed
From: Li Zhang <zhanglikernel@gmail.com>
To: linux-btrfs@vger.kernel.org
Cc: Li Zhang <zhanglikernel@gmail.com>
Subject: [PATCH] Make btrfs_prepare_device parallel during mkfs.btrfs
Date: Thu, 25 Aug 2022 00:05:03 +0800	[thread overview]
Message-ID: <1661357103-22735-1-git-send-email-zhanglikernel@gmail.com> (raw)

[enhancement]
When a disk is formatted as btrfs, it calls
btrfs_prepare_device for each device, which takes too much time.

[implementation]
Put each btrfs_prepare_device into a thread,
wait for the first thread to complete to mkfs.btrfs,
and wait for other threads to complete before adding
other devices to the file system.

[test]
Using the btrfs-progs test case mkfs-tests, mkfs.btrfs works fine.

But I don't have an actual zoed device,
so I don't know how much time it saves, If you guys
have a way to test it, please let me know.

Signed-off-by: Li Zhang <zhanglikernel@gmail.com>
---
Issue: 496

 mkfs/main.c | 113 +++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 86 insertions(+), 27 deletions(-)

diff --git a/mkfs/main.c b/mkfs/main.c
index ce096d3..35fefe2 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -31,6 +31,7 @@
 #include <uuid/uuid.h>
 #include <ctype.h>
 #include <blkid/blkid.h>
+#include <pthread.h>
 #include "kernel-shared/ctree.h"
 #include "kernel-shared/disk-io.h"
 #include "kernel-shared/free-space-tree.h"
@@ -60,6 +61,18 @@ struct mkfs_allocation {
 	u64 system;
 };
 
+
+struct prepare_device_progress {
+	char *file;
+	u64 dev_block_count;
+	u64 block_count;
+	bool zero_end;
+	bool discard;
+	bool zoned;
+	int oflags;
+	int ret;
+};
+
 static int create_metadata_block_groups(struct btrfs_root *root, bool mixed,
 				struct mkfs_allocation *allocation)
 {
@@ -969,6 +982,28 @@ fail:
 	return ret;
 }
 
+static void *prepare_one_dev(void *ctx)
+{
+	struct prepare_device_progress *prepare_ctx = ctx;
+	int fd;
+
+	fd = open(prepare_ctx->file, prepare_ctx->oflags);
+	if (fd < 0) {
+		error("unable to open %s: %m", prepare_ctx->file);
+		prepare_ctx->ret = fd;
+		return NULL;
+	}
+	prepare_ctx->ret = btrfs_prepare_device(fd,
+		prepare_ctx->file, &prepare_ctx->dev_block_count,
+		prepare_ctx->block_count,
+		(bconf.verbose ? PREP_DEVICE_VERBOSE : 0) |
+		(prepare_ctx->zero_end ? PREP_DEVICE_ZERO_END : 0) |
+		(prepare_ctx->discard ? PREP_DEVICE_DISCARD : 0) |
+		(prepare_ctx->zoned ? PREP_DEVICE_ZONED : 0));
+	close(fd);
+	return NULL;
+}
+
 int BOX_MAIN(mkfs)(int argc, char **argv)
 {
 	char *file;
@@ -997,7 +1032,6 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	bool ssd = false;
 	bool zoned = false;
 	bool force_overwrite = false;
-	int oflags;
 	char *source_dir = NULL;
 	bool source_dir_set = false;
 	bool shrink_rootdir = false;
@@ -1006,6 +1040,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	u64 shrink_size;
 	int dev_cnt = 0;
 	int saved_optind;
+	pthread_t *t_prepare = NULL;
+	struct prepare_device_progress *prepare_ctx = NULL;
 	char fs_uuid[BTRFS_UUID_UNPARSED_SIZE] = { 0 };
 	u64 features = BTRFS_MKFS_DEFAULT_FEATURES;
 	u64 runtime_features = BTRFS_MKFS_DEFAULT_RUNTIME_FEATURES;
@@ -1428,29 +1464,45 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 		goto error;
 	}
 
-	dev_cnt--;
-
-	oflags = O_RDWR;
-	if (zoned && zoned_model(file) == ZONED_HOST_MANAGED)
-		oflags |= O_DIRECT;
+	t_prepare = malloc(dev_cnt * sizeof(*t_prepare));
+	prepare_ctx = malloc(dev_cnt * sizeof(*prepare_ctx));
 
-	/*
-	 * Open without O_EXCL so that the problem should not occur by the
-	 * following operation in kernel:
-	 * (btrfs_register_one_device() fails if O_EXCL is on)
-	 */
-	fd = open(file, oflags);
-	if (fd < 0) {
-		error("unable to open %s: %m", file);
+	if (!t_prepare || !prepare_ctx) {
+		error("unable to prepare dev");
 		goto error;
 	}
-	ret = btrfs_prepare_device(fd, file, &dev_block_count, block_count,
-			(zero_end ? PREP_DEVICE_ZERO_END : 0) |
-			(discard ? PREP_DEVICE_DISCARD : 0) |
-			(bconf.verbose ? PREP_DEVICE_VERBOSE : 0) |
-			(zoned ? PREP_DEVICE_ZONED : 0));
+
+	for (i = 0; i < dev_cnt; i++) {
+		prepare_ctx[i].file = argv[optind + i - 1];
+		prepare_ctx[i].block_count = block_count;
+		prepare_ctx[i].dev_block_count = block_count;
+		prepare_ctx[i].zero_end = zero_end;
+		prepare_ctx[i].discard = discard;
+		prepare_ctx[i].zoned = zoned;
+		if (i == 0) {
+			prepare_ctx[i].oflags = O_RDWR;
+			/*
+			 * Open without O_EXCL so that the problem should
+			 * not occur by the following operation in kernel:
+			 * (btrfs_register_one_device() fails if O_EXCL is on)
+			 */
+			if (zoned && zoned_model(file) == ZONED_HOST_MANAGED)
+				prepare_ctx[i].oflags = O_RDWR | O_DIRECT;
+		} else {
+			prepare_ctx[i].oflags = O_RDWR;
+		}
+		ret = pthread_create(&t_prepare[i], NULL,
+			prepare_one_dev, &prepare_ctx[i]);
+	}
+	pthread_join(t_prepare[0], NULL);
+	ret = prepare_ctx[0].ret;
+
 	if (ret)
 		goto error;
+
+	dev_cnt--;
+	fd = open(file, prepare_ctx[0].oflags);
+	dev_block_count = prepare_ctx[0].dev_block_count;
 	if (block_count && block_count > dev_block_count) {
 		error("%s is smaller than requested size, expected %llu, found %llu",
 		      file, (unsigned long long)block_count,
@@ -1459,7 +1511,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	}
 
 	/* To create the first block group and chunk 0 in make_btrfs */
-	system_group_size = zoned ?  zone_size(file) : BTRFS_MKFS_SYSTEM_GROUP_SIZE;
+	system_group_size = zoned ? zone_size(file) : BTRFS_MKFS_SYSTEM_GROUP_SIZE;
 	if (dev_block_count < system_group_size) {
 		error("device is too small to make filesystem, must be at least %llu",
 				(unsigned long long)system_group_size);
@@ -1557,6 +1609,12 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 	if (dev_cnt == 0)
 		goto raid_groups;
 
+	for (i = 0 ; i < dev_cnt; i++) {
+		pthread_join(t_prepare[i+1], NULL);
+		if (prepare_ctx[i+1].ret) {
+			goto error;
+		}
+	}
 	while (dev_cnt-- > 0) {
 		file = argv[optind++];
 
@@ -1578,12 +1636,9 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
 			close(fd);
 			continue;
 		}
-		ret = btrfs_prepare_device(fd, file, &dev_block_count,
-				block_count,
-				(bconf.verbose ? PREP_DEVICE_VERBOSE : 0) |
-				(zero_end ? PREP_DEVICE_ZERO_END : 0) |
-				(discard ? PREP_DEVICE_DISCARD : 0) |
-				(zoned ? PREP_DEVICE_ZONED : 0));
+		dev_block_count = prepare_ctx[argc - saved_optind - dev_cnt - 1]
+			.dev_block_count;
+
 		if (ret) {
 			goto error;
 		}
@@ -1763,12 +1818,16 @@ out:
 
 	btrfs_close_all_devices();
 	free(label);
-
+	free(t_prepare);
+	free(prepare_ctx);
 	return !!ret;
+
 error:
 	if (fd > 0)
 		close(fd);
 
+	free(t_prepare);
+	free(prepare_ctx);
 	free(label);
 	exit(1);
 success:
-- 
1.8.3.1


             reply	other threads:[~2022-08-24 16:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-24 16:05 Li Zhang [this message]
2022-08-25  5:20 ` [PATCH] Make btrfs_prepare_device parallel during mkfs.btrfs Qu Wenruo
2022-08-25  8:31   ` Johannes Thumshirn
2022-08-25  8:36     ` Qu Wenruo
2022-08-25  8:40       ` Johannes Thumshirn
2022-08-28  8:53     ` li zhang
2022-08-28  9:54       ` Qu Wenruo
2022-08-28 14:26         ` li zhang
2022-08-28 14:33           ` li zhang
2022-08-29  0:36           ` Qu Wenruo
2022-08-25  8:33 ` Johannes Thumshirn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1661357103-22735-1-git-send-email-zhanglikernel@gmail.com \
    --to=zhanglikernel@gmail.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox