From patchwork Thu Nov 2 05:33:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13443412 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1599C4167B for ; Thu, 2 Nov 2023 05:34:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348556AbjKBFeU (ORCPT ); Thu, 2 Nov 2023 01:34:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348533AbjKBFeT (ORCPT ); Thu, 2 Nov 2023 01:34:19 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [IPv6:2001:67c:2178:6::1c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 709B812C for ; Wed, 1 Nov 2023 22:34:13 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id BF5FA215EE for ; Thu, 2 Nov 2023 05:34:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1698903250; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=k9MXKkOVGBXEnhTBHXJFuZSDwCpHr5r3pxdIhgYGGlU=; b=IZpFFGVfM2o+Xn4/NLLqPRLMXhxdRKdtThq+EHl4Yc7fZa9eMUh6ljnxHyVTU89bNpmt2C yzvZ/4dL10beCQ7e8lILZZ+KvVRoWJGCYZGDHYz5yIHcD4xYjcgcKufm6NzBaIaJD9074U mB5ou0YqI7zvvrH+PaQYVlinGldPKsg= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id EC23D13460 for ; Thu, 2 Nov 2023 05:34:09 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id IFxVKdE0Q2U/AwAAMHmgww (envelope-from ) for ; Thu, 02 Nov 2023 05:34:09 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 1/3] btrfs-progs: subvolume create: handle failure for strdup() Date: Thu, 2 Nov 2023 16:03:48 +1030 Message-ID: <8c3df11d55b5add76a6abfd7896762697520a136.1698903010.git.wqu@suse.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org 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 --- 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)) { From patchwork Thu Nov 2 05:33:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13443414 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1FABC4167D for ; Thu, 2 Nov 2023 05:34:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348557AbjKBFeW (ORCPT ); Thu, 2 Nov 2023 01:34:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38266 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348560AbjKBFeV (ORCPT ); Thu, 2 Nov 2023 01:34:21 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 60808112 for ; Wed, 1 Nov 2023 22:34:13 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 1CB75219EB for ; Thu, 2 Nov 2023 05:34:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1698903252; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kZG8+05kUznsBYroCuFJkKDlDBYg/QUqMeLa9e5YTpc=; b=iC4dHHEz1MJv7tAvZdAyneOeY8tIRX6s/is16QzSwYEW6m8h994TPexrd74dk3+mtMPy9f q+s7d1fmStp94Iuui5R9m7qMxFGN8BsmuNSNlxN7glWPzwmEfBq/FTEEfw3H1yv974rIfv jby4FC6JGPwLLos25JP3dkWAjzGMHuA= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 4512A13460 for ; Thu, 2 Nov 2023 05:34:11 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id UOCHAdM0Q2U/AwAAMHmgww (envelope-from ) for ; Thu, 02 Nov 2023 05:34:11 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 2/3] btrfs-progs: subvolume create: accept multiple arguments Date: Thu, 2 Nov 2023 16:03:49 +1030 Message-ID: X-Mailer: git-send-email 2.42.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This patch would make "btrfs subvolume create" to accept multiple arguments, just like "mkdir". The existing options like "-i " 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 --- 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] [/] - Create a subvolume *name* in *dest*. +create [options] [/] [[/]] ... + 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 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] [/]", - "Create a subvolume", - "Create a subvolume in . If is not given", + "btrfs subvolume create [options] [/] [[/]] ...", + "Create subvolume(s)", + "Create subvolume(s) at specified destination. If is not given", "subvolume will be created in the current directory.", "", - OPTLINE("-i ", "add the newly created subvolume to a qgroup. This option can be given multiple times."), + OPTLINE("-i ", "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"); From patchwork Thu Nov 2 05:33:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 13443413 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D03C9C41535 for ; Thu, 2 Nov 2023 05:34:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348560AbjKBFeX (ORCPT ); Thu, 2 Nov 2023 01:34:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38280 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348559AbjKBFeV (ORCPT ); Thu, 2 Nov 2023 01:34:21 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A0AE312F for ; Wed, 1 Nov 2023 22:34:14 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 64507219EC for ; Thu, 2 Nov 2023 05:34:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1698903253; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=B/6I3sL4qQRxet9RVKwxSUIU1lq+8IoUhM84A9BvecU=; b=Rnd25G4dcDgbwjKKbSnqQ9aZM7McmKZbn31guxG0ze1toqeM3g/JaDBQ+QGrGtDBvSKOOE M3dBS/wcZypvktsXhPstkBeBY13UIUEZTdqPU/VjnUMcvupqUmW5u6sjpn8PoC9UqJlDlp WSUVF5zW2L+q8Vm86gp3IF43dCg98ak= Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 962F913460 for ; Thu, 2 Nov 2023 05:34:12 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id OMJoFdQ0Q2U/AwAAMHmgww (envelope-from ) for ; Thu, 02 Nov 2023 05:34:12 +0000 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Subject: [PATCH 3/3] btrfs-progs: cli-tests: add test case for subvolume create multiple arguments Date: Thu, 2 Nov 2023 16:03:50 +1030 Message-ID: <453c0e60ff7db7a1af06df230e2847d0f2b62692.1698903010.git.wqu@suse.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org 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 --- .../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