public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments
@ 2023-11-02  5:33 Qu Wenruo
  2023-11-02  5:33 ` [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Qu Wenruo
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Qu Wenruo @ 2023-11-02  5:33 UTC (permalink / raw)
  To: linux-btrfs

This patchset adds the ability to accept multiple arguments for "btrfs
subvolume create" command, just like "mkdir".

And also we follow the error reporting part of "mkdir", any failure
would make the command to return 1 for error.

[PATCHSET STRUCTURE]
During the development, I found two missing error handling for strdup(),
thus here comes the first patch to fix them.

Then the 2nd patch implements the main part.

Finally the last patch is add the new test case for the error handling
part.

Qu Wenruo (3):
  btrfs-progs: subvolume create: handle failure for strdup()
  btrfs-progs: subvolume create: accept multiple arguments
  btrfs-progs: cli-tests: add test case for subvolume create multiple
    arguments

 Documentation/btrfs-subvolume.rst             |  11 +-
 cmds/subvolume.c                              | 223 ++++++++++--------
 .../021-subvolume-multiple-arguments/test.sh  |  37 +++
 3 files changed, 170 insertions(+), 101 deletions(-)
 create mode 100755 tests/cli-tests/021-subvolume-multiple-arguments/test.sh

--
2.42.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup()
  2023-11-02  5:33 [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
@ 2023-11-02  5:33 ` Qu Wenruo
  2023-11-23 19:11   ` David Sterba
  2023-11-02  5:33 ` [PATCH 2/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Qu Wenruo @ 2023-11-02  5:33 UTC (permalink / raw)
  To: linux-btrfs

The function strdup() can return NULL if the system is out of memory,
thus we need to hanle the rare but possible -ENOMEM case.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 cmds/subvolume.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/cmds/subvolume.c b/cmds/subvolume.c
index 8504c380c9ee..bccc4968dad3 100644
--- a/cmds/subvolume.c
+++ b/cmds/subvolume.c
@@ -194,8 +194,17 @@ static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **a
 	}
 
 	dupname = strdup(dst);
+	if (!dupname) {
+		error("out of memory when duplicating %s", dst);
+		goto out;
+	}
 	newname = basename(dupname);
+
 	dupdir = strdup(dst);
+	if (!dupdir) {
+		error("out of memory when duplicating %s", dst);
+		goto out;
+	}
 	dstdir = dirname(dupdir);
 
 	if (!test_issubvolname(newname)) {
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] btrfs-progs: subvolume create: accept multiple arguments
  2023-11-02  5:33 [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
  2023-11-02  5:33 ` [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Qu Wenruo
@ 2023-11-02  5:33 ` Qu Wenruo
  2023-11-02  5:33 ` [PATCH 3/3] btrfs-progs: cli-tests: add test case for subvolume create " Qu Wenruo
  2023-11-23 19:22 ` [PATCH 0/3] btrfs-progs: subvolume create: accept " David Sterba
  3 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2023-11-02  5:33 UTC (permalink / raw)
  To: linux-btrfs

This patch would make "btrfs subvolume create" to accept multiple
arguments, just like "mkdir".

The existing options like "-i <qgroupid>" and "-p" would all be applied
to all subvolume(s).

If one destination failed, the command would return 1, while still retry
the remaining destinations.

Issue: #695
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 Documentation/btrfs-subvolume.rst |  11 ++-
 cmds/subvolume.c                  | 150 +++++++++++++++++-------------
 2 files changed, 92 insertions(+), 69 deletions(-)

diff --git a/Documentation/btrfs-subvolume.rst b/Documentation/btrfs-subvolume.rst
index 6da00be8dc86..8b434475337b 100644
--- a/Documentation/btrfs-subvolume.rst
+++ b/Documentation/btrfs-subvolume.rst
@@ -49,12 +49,19 @@ do not affect the files in the original subvolume.
 SUBCOMMAND
 -----------
 
-create [options] [<dest>/]<name>
-        Create a subvolume *name* in *dest*.
+create [options] [<dest>/]<name> [[<dest2>/]<name2>] ...
+        Create subvolume(s) at the destination(s).
 
         If *dest* is not given, subvolume *name* will be created in the current
         directory.
 
+	If multiple desinations are given, then the options are applied to all
+	subvolumes.
+
+	If failure happened for any of the destinations, the command would
+	still retry the remaining destinations, but would return 1 to indicate
+	the failure.
+
         ``Options``
 
         -i <qgroupid>
diff --git a/cmds/subvolume.c b/cmds/subvolume.c
index bccc4968dad3..7decaa1eb828 100644
--- a/cmds/subvolume.c
+++ b/cmds/subvolume.c
@@ -114,81 +114,38 @@ static const char * const subvolume_cmd_group_usage[] = {
 };
 
 static const char * const cmd_subvolume_create_usage[] = {
-	"btrfs subvolume create [options] [<dest>/]<name>",
-	"Create a subvolume",
-	"Create a subvolume <name> in <dest>.  If <dest> is not given",
+	"btrfs subvolume create [options] [<dest>/]<name> [[<dest2>/]<name2>] ...",
+	"Create subvolume(s)",
+	"Create subvolume(s) at specified destination.  If <dest> is not given",
 	"subvolume <name> will be created in the current directory.",
 	"",
-	OPTLINE("-i <qgroupid>", "add the newly created subvolume to a qgroup. This option can be given multiple times."),
+	OPTLINE("-i <qgroupid>", "add the newly created subvolume(s) to a qgroup. This option can be given multiple times."),
 	OPTLINE("-p|--parents", "create any missing parent directories for each argument (like mkdir -p)"),
 	HELPINFO_INSERT_GLOBALS,
 	HELPINFO_INSERT_QUIET,
 	NULL
 };
 
-static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **argv)
+static int create_one_subvolume(const char *dst,
+				struct btrfs_qgroup_inherit *inherit,
+				bool create_parents)
 {
-	int	retval, res, len;
+	int	ret;
+	int	len;
 	int	fddst = -1;
 	char	*dupname = NULL;
 	char	*dupdir = NULL;
 	char	*newname;
 	char	*dstdir;
-	char	*dst;
-	struct btrfs_qgroup_inherit *inherit = NULL;
 	DIR	*dirstream = NULL;
-	bool create_parents = false;
 
-	optind = 0;
-	while (1) {
-		int c;
-		static const struct option long_options[] = {
-			{ "parents", no_argument, NULL, 'p' },
-			{ NULL, 0, NULL, 0 }
-		};
-
-		c = getopt_long(argc, argv, "i:p", long_options, NULL);
-		if (c < 0)
-			break;
-
-		switch (c) {
-		case 'c':
-			res = btrfs_qgroup_inherit_add_copy(&inherit, optarg, 0);
-			if (res) {
-				retval = res;
-				goto out;
-			}
-			break;
-		case 'i':
-			res = btrfs_qgroup_inherit_add_group(&inherit, optarg);
-			if (res) {
-				retval = res;
-				goto out;
-			}
-			break;
-		case 'p':
-			create_parents = true;
-			break;
-		default:
-			usage_unknown_option(cmd, argv);
-		}
-	}
-
-	if (check_argc_exact(argc - optind, 1)) {
-		retval = 1;
-		goto out;
-	}
-
-	dst = argv[optind];
-
-	retval = 1;	/* failure */
-	res = path_is_dir(dst);
-	if (res < 0 && res != -ENOENT) {
-		errno = -res;
+	ret = path_is_dir(dst);
+	if (ret < 0 && ret != -ENOENT) {
+		errno = -ret;
 		error("cannot access %s: %m", dst);
 		goto out;
 	}
-	if (res >= 0) {
+	if (ret >= 0) {
 		error("target path already exists: %s", dst);
 		goto out;
 	}
@@ -230,15 +187,15 @@ static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **a
 		token = strtok(dstdir_dup, "/");
 		while (token) {
 			strcat(p, token);
-			res = path_is_dir(p);
-			if (res == -ENOENT) {
-				res = mkdir(p, 0777);
-				if (res < 0) {
+			ret = path_is_dir(p);
+			if (ret == -ENOENT) {
+				ret = mkdir(p, 0777);
+				if (ret < 0) {
 					error("failed to create directory %s: %m", p);
 					goto out;
 				}
-			} else if (res <= 0) {
-				errno = res;
+			} else if (ret <= 0) {
+				errno = ret ;
 				error("failed to check directory %s before creation: %m", p);
 				goto out;
 			}
@@ -261,28 +218,87 @@ static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **a
 		args.size = btrfs_qgroup_inherit_size(inherit);
 		args.qgroup_inherit = inherit;
 
-		res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
+		ret = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
 	} else {
 		struct btrfs_ioctl_vol_args	args;
 
 		memset(&args, 0, sizeof(args));
 		strncpy_null(args.name, newname);
 
-		res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
+		ret = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
 	}
 
-	if (res < 0) {
+	if (ret < 0) {
 		error("cannot create subvolume: %m");
 		goto out;
 	}
 
-	retval = 0;	/* success */
 out:
 	close_file_or_dir(fddst, dirstream);
-	free(inherit);
 	free(dupname);
 	free(dupdir);
 
+	return ret;
+}
+static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **argv)
+{
+	int	retval, res;
+	struct btrfs_qgroup_inherit *inherit = NULL;
+	bool has_error = false;
+	bool create_parents = false;
+
+	optind = 0;
+	while (1) {
+		int c;
+		static const struct option long_options[] = {
+			{ "parents", no_argument, NULL, 'p' },
+			{ NULL, 0, NULL, 0 }
+		};
+
+		c = getopt_long(argc, argv, "i:p", long_options, NULL);
+		if (c < 0)
+			break;
+
+		switch (c) {
+		case 'c':
+			res = btrfs_qgroup_inherit_add_copy(&inherit, optarg, 0);
+			if (res) {
+				retval = res;
+				goto out;
+			}
+			break;
+		case 'i':
+			res = btrfs_qgroup_inherit_add_group(&inherit, optarg);
+			if (res) {
+				retval = res;
+				goto out;
+			}
+			break;
+		case 'p':
+			create_parents = true;
+			break;
+		default:
+			usage_unknown_option(cmd, argv);
+		}
+	}
+
+	if (check_argc_min(argc - optind, 1)) {
+		retval = 1;
+		goto out;
+	}
+
+	retval = 1;
+
+	for (int i = optind; i < argc; i++) {
+		res = create_one_subvolume(argv[i], inherit, create_parents);
+		if (res < 0)
+			has_error = true;
+	}
+	if (!has_error)
+		retval = 0;
+out:
+	free(inherit);
+
 	return retval;
 }
 static DEFINE_SIMPLE_COMMAND(subvolume_create, "create");
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] btrfs-progs: cli-tests: add test case for subvolume create multiple arguments
  2023-11-02  5:33 [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
  2023-11-02  5:33 ` [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Qu Wenruo
  2023-11-02  5:33 ` [PATCH 2/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
@ 2023-11-02  5:33 ` Qu Wenruo
  2023-11-23 19:22 ` [PATCH 0/3] btrfs-progs: subvolume create: accept " David Sterba
  3 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2023-11-02  5:33 UTC (permalink / raw)
  To: linux-btrfs

The test case would verify the following behaviors:

- Partial failure
  Should return 1, but the remaining valid destinations would still be
  created.

- All success
  That's as usual.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 .../021-subvolume-multiple-arguments/test.sh  | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100755 tests/cli-tests/021-subvolume-multiple-arguments/test.sh

diff --git a/tests/cli-tests/021-subvolume-multiple-arguments/test.sh b/tests/cli-tests/021-subvolume-multiple-arguments/test.sh
new file mode 100755
index 000000000000..f86763829d31
--- /dev/null
+++ b/tests/cli-tests/021-subvolume-multiple-arguments/test.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Create subvolume with multiple destinations
+
+source "$TEST_TOP/common" || exit
+
+setup_root_helper
+prepare_test_dev
+
+run_check_mkfs_test_dev
+run_check_mount_test_dev
+
+# Create one invalid subvolume with 2 valid ones.
+# The command should return 1 but the 2 valid ones should be created.
+run_mustfail "should report error for any failed subvolume creation" \
+	$SUDO_HELPER "$TOP/btrfs" subvolume create \
+	"$TEST_MNT/non-exist-dir/subv0" \
+	"$TEST_MNT/subv1" \
+	"$TEST_MNT/subv2"
+
+run_check $SUDO_HELPER stat "$TEST_MNT/subv1"
+run_check $SUDO_HELPER stat "$TEST_MNT/subv2"
+
+# Create multiple subvolumes with parent
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume create -p \
+	"$TEST_MNT/non-exist-dir/subv0" \
+	"$TEST_MNT/subv1/subv3" \
+	"$TEST_MNT/subv4" \
+
+run_check $SUDO_HELPER stat "$TEST_MNT/non-exist-dir/subv0"
+run_check $SUDO_HELPER stat "$TEST_MNT/subv1/subv3"
+run_check $SUDO_HELPER stat "$TEST_MNT/subv4"
+
+run_check $SUDO_HELPER "$TOP/btrfs" subvolume create -p "$TEST_MNT/dir3/dir1/./..//.///subv3//////"
+run_check $SUDO_HELPER stat "$TEST_MNT/dir3/dir1"
+run_check $SUDO_HELPER stat "$TEST_MNT/dir3/subv3"
+run_check find "$TEST_MNT" -ls
+run_check_umount_test_dev
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup()
  2023-11-02  5:33 ` [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Qu Wenruo
@ 2023-11-23 19:11   ` David Sterba
  0 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2023-11-23 19:11 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

On Thu, Nov 02, 2023 at 04:03:48PM +1030, Qu Wenruo wrote:
> The function strdup() can return NULL if the system is out of memory,
> thus we need to hanle the rare but possible -ENOMEM case.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  cmds/subvolume.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/cmds/subvolume.c b/cmds/subvolume.c
> index 8504c380c9ee..bccc4968dad3 100644
> --- a/cmds/subvolume.c
> +++ b/cmds/subvolume.c
> @@ -194,8 +194,17 @@ static int cmd_subvolume_create(const struct cmd_struct *cmd, int argc, char **a
>  	}
>  
>  	dupname = strdup(dst);
> +	if (!dupname) {
> +		error("out of memory when duplicating %s", dst);

There are message templats for the most common errors, so this is now

error_msg(ERROR_MSG_MEMORY, "duplicating %s", dst);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments
  2023-11-02  5:33 [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
                   ` (2 preceding siblings ...)
  2023-11-02  5:33 ` [PATCH 3/3] btrfs-progs: cli-tests: add test case for subvolume create " Qu Wenruo
@ 2023-11-23 19:22 ` David Sterba
  3 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2023-11-23 19:22 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

On Thu, Nov 02, 2023 at 04:03:47PM +1030, Qu Wenruo wrote:
> This patchset adds the ability to accept multiple arguments for "btrfs
> subvolume create" command, just like "mkdir".
> 
> And also we follow the error reporting part of "mkdir", any failure
> would make the command to return 1 for error.
> 
> [PATCHSET STRUCTURE]
> During the development, I found two missing error handling for strdup(),
> thus here comes the first patch to fix them.
> 
> Then the 2nd patch implements the main part.
> 
> Finally the last patch is add the new test case for the error handling
> part.
> 
> Qu Wenruo (3):
>   btrfs-progs: subvolume create: handle failure for strdup()
>   btrfs-progs: subvolume create: accept multiple arguments
>   btrfs-progs: cli-tests: add test case for subvolume create multiple
>     arguments

Added to devel, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-11-23 19:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-02  5:33 [PATCH 0/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
2023-11-02  5:33 ` [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Qu Wenruo
2023-11-23 19:11   ` David Sterba
2023-11-02  5:33 ` [PATCH 2/3] btrfs-progs: subvolume create: accept multiple arguments Qu Wenruo
2023-11-02  5:33 ` [PATCH 3/3] btrfs-progs: cli-tests: add test case for subvolume create " Qu Wenruo
2023-11-23 19:22 ` [PATCH 0/3] btrfs-progs: subvolume create: accept " David Sterba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox