From patchwork Tue Mar 25 13:37:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Mahoney X-Patchwork-Id: 3887891 X-Patchwork-Delegate: dave@jikos.cz Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 5D9DCBF540 for ; Tue, 25 Mar 2014 13:37:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2948F20179 for ; Tue, 25 Mar 2014 13:37:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B209220138 for ; Tue, 25 Mar 2014 13:37:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752700AbaCYNhT (ORCPT ); Tue, 25 Mar 2014 09:37:19 -0400 Received: from cantor2.suse.de ([195.135.220.15]:53150 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751906AbaCYNhR (ORCPT ); Tue, 25 Mar 2014 09:37:17 -0400 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 976E0AC86 for ; Tue, 25 Mar 2014 13:37:16 +0000 (UTC) Message-ID: <53318689.8030605@suse.com> Date: Tue, 25 Mar 2014 09:37:13 -0400 From: Jeff Mahoney User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: linux-btrfs CC: Arvin Schnell , David Sterba Subject: [PATCH v2] btrfs-progs: allow use of subvolume id to create snapshots References: <5330C6AA.7010508@suse.com> In-Reply-To: <5330C6AA.7010508@suse.com> X-Enigmail-Version: 1.6 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch uses the new BTRFS_SUBVOL_CREATE_SUBVOLID flag to create snapshots by subvolume ID. usage: btrfs subvolume snapshot [-r] [-q ] -s / Since we don't have a name for the source snapshot, the complete path to the destination must be specified. A previous version of this patch missed an error printing case and would print (null) instead of the subvolume id on error. Signed-off-by: Jeff Mahoney --- cmds-subvolume.c | 105 +++++++++++++++++++++++++++++++++++++++++-------------- ioctl.h | 6 ++- man/btrfs.8.in | 31 ++++++++++++++-- 3 files changed, 112 insertions(+), 30 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -14,6 +14,7 @@ * Boston, MA 021110-1307, USA. */ +#define _GNU_SOURCE #include #include #include @@ -576,6 +577,7 @@ out: static const char * const cmd_snapshot_usage[] = { "btrfs subvolume snapshot [-r] |[/]", "btrfs subvolume snapshot [-r] [-i ] |[/]", + "btrfs subvolume snapshot [-r] [-i ] -s /", "Create a snapshot of the subvolume", "Create a writable/readonly snapshot of the subvolume with", "the name in the directory. If only is given,", @@ -584,12 +586,27 @@ static const char * const cmd_snapshot_u "-r create a readonly snapshot", "-i add the newly created snapshot to a qgroup. This", " option can be given multiple times.", + "-s create a snapshot using the subvolume id. This", + " is useful for snapshotting subvolumes outside", + " of the mounted namespace.", NULL }; +static int get_subvolid(const char *str, u64 *subvolid) +{ + char *p; + errno = 0; + *subvolid = strtoull(optarg, &p, 10); + if (errno || *p != '\0') { + fprintf(stderr, "ERROR: invalid subvolume id '%s'\n", optarg); + return -EINVAL; + } + return 0; +} + static int cmd_snapshot(int argc, char **argv) { - char *subvol, *dst; + char *subvol = NULL, *dst; int res, retval; int fd = -1, fddst = -1; int len, readonly = 0; @@ -597,6 +614,9 @@ static int cmd_snapshot(int argc, char * char *dupdir = NULL; char *newname; char *dstdir; + u64 subvolid = 0; + char *subvol_descr = NULL; + int nargs = 2; struct btrfs_ioctl_vol_args_v2 args; struct btrfs_qgroup_inherit *inherit = NULL; DIR *dirstream1 = NULL, *dirstream2 = NULL; @@ -604,7 +624,7 @@ static int cmd_snapshot(int argc, char * optind = 1; memset(&args, 0, sizeof(args)); while (1) { - int c = getopt(argc, argv, "c:i:r"); + int c = getopt(argc, argv, "c:i:rs:"); if (c < 0) break; @@ -633,27 +653,39 @@ static int cmd_snapshot(int argc, char * goto out; } break; + case 's': + res = get_subvolid(optarg, &subvolid); + if (res) { + retval = res; + goto out; + } + nargs = 1; + break; default: usage(cmd_snapshot_usage); } } - if (check_argc_exact(argc - optind, 2)) + if (check_argc_exact(argc - optind, nargs)) usage(cmd_snapshot_usage); - subvol = argv[optind]; - dst = argv[optind + 1]; + if (nargs == 2) { + subvol = argv[optind]; + dst = argv[optind + 1]; - retval = 1; /* failure */ - res = test_issubvolume(subvol); - if (res < 0) { - fprintf(stderr, "ERROR: error accessing '%s'\n", subvol); - goto out; - } - if (!res) { - fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol); - goto out; - } + retval = 1; /* failure */ + res = test_issubvolume(subvol); + if (res < 0) { + fprintf(stderr, "ERROR: error accessing '%s'\n", subvol); + goto out; + } + if (!res) { + fprintf(stderr, "ERROR: '%s' is not a subvolume\n", + subvol); + goto out; + } + } else + dst = argv[optind]; res = test_isdir(dst); if (res == 0) { @@ -662,6 +694,13 @@ static int cmd_snapshot(int argc, char * } if (res > 0) { + if (!subvol) { + retval = 1; + fprintf(stderr, + "ERROR: '%s' exists and must not when snapshotting by specifying subvolid.\n", + dst); + goto out; + } dupname = strdup(subvol); newname = basename(dupname); dstdir = dst; @@ -692,22 +731,34 @@ static int cmd_snapshot(int argc, char * goto out; } - fd = open_file_or_dir(subvol, &dirstream2); - if (fd < 0) { - fprintf(stderr, "ERROR: can't access '%s'\n", dstdir); + if (subvol) { + fd = open_file_or_dir(subvol, &dirstream2); + if (fd < 0) { + fprintf(stderr, "ERROR: can't access '%s'\n", dstdir); + goto out; + } + args.fd = fd; + res = asprintf(&subvol_descr, "'%s'", subvol); + } else { + args.subvolid = subvolid; + args.flags |= BTRFS_SUBVOL_CREATE_SUBVOLID; + res = asprintf(&subvol_descr, "subvolume id %llu", subvolid); + } + if (res < 0) { + fprintf(stderr, "ERROR: can't allocate memory\n"); + retval = 1; goto out; } if (readonly) { args.flags |= BTRFS_SUBVOL_RDONLY; - printf("Create a readonly snapshot of '%s' in '%s/%s'\n", - subvol, dstdir, newname); + printf("Create a readonly snapshot of %s in '%s/%s'\n", + subvol_descr, dstdir, newname); } else { - printf("Create a snapshot of '%s' in '%s/%s'\n", - subvol, dstdir, newname); + printf("Create a snapshot of %s in '%s/%s'\n", + subvol_descr, dstdir, newname); } - args.fd = fd; if (inherit) { args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT; args.size = qgroup_inherit_size(inherit); @@ -718,8 +769,8 @@ static int cmd_snapshot(int argc, char * res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args); if (res < 0) { - fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n", - subvol, strerror(errno)); + fprintf( stderr, "ERROR: cannot snapshot %s - %s\n", + subvol_descr, strerror(errno)); goto out; } @@ -727,7 +778,9 @@ static int cmd_snapshot(int argc, char * out: close_file_or_dir(fddst, dirstream1); - close_file_or_dir(fd, dirstream2); + if (subvol) + close_file_or_dir(fd, dirstream2); + free(subvol_descr); free(inherit); free(dupname); free(dupdir); --- a/ioctl.h +++ b/ioctl.h @@ -41,6 +41,7 @@ struct btrfs_ioctl_vol_args { #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) #define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) +#define BTRFS_SUBVOL_CREATE_SUBVOLID (1ULL << 3) #define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0) @@ -69,7 +70,10 @@ struct btrfs_ioctl_qgroup_limit_args { #define BTRFS_SUBVOL_NAME_MAX 4039 struct btrfs_ioctl_vol_args_v2 { - __s64 fd; + union { + __s64 fd; + __u64 subvolid; + }; __u64 transid; __u64 flags; union { --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -12,7 +12,9 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBsubvolume list\fP [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI\fP .PP -\fBbtrfs\fP \fBsubvolume snapshot\fP [-r] \fI\fP \fI\fP|[\fI\fP/]\fI\fP +\fBbtrfs\fP \fBsubvolume snapshot\fP [-r] [-i qgroupid] \fI\fP \fI\fP|[\fI\fP/]\fI\fP +.PP +\fBbtrfs\fP \fBsubvolume snapshot\fP [-r] [-i qgroupid] \fI-s \fP \fI/\fP .PP \fBbtrfs\fP \fBsubvolume get-default\fP\fI \fP .PP @@ -242,12 +244,35 @@ for \fB--sort\fP you can combine some it .RE .TP -\fBsubvolume snapshot\fP [-r] \fI\fP \fI\fP|[\fI\fP/]\fI\fP +\fBsubvolume snapshot\fP [-r] [-i qgroupid] \fI\fP \fI\fP|[\fI\fP/]\fI\fP Create a writable/readonly snapshot of the subvolume \fI\fR with the name \fI\fR in the \fI\fR directory. If only \fI\fR is given, the subvolume will be named the basename of \fI\fR. If \fI\fR is not a subvolume, \fBbtrfs\fR returns an error. -If \fI-r\fR is given, the snapshot will be readonly. +.RS + +\fIOptions\fP +.IP \fB-r\fP 5 +The newly created snapshot will be readonly. +.IP "\fB-i\fP \fI\fR" 5 +Add the newly created subvolume to a qgroup. This option can be given multiple +times. +.RE +.TP + +\fBsubvolume snapshot\fP [-r] [-i qgroupid] \fI-s \fP \fI\fP/\fI\fP +Create a writable/readonly snapshot of the subvolume \fI\fR with the +name \fI\fR in the \fI\fR directory. +If \fI\fR does not refer to a subvolume, \fBbtrfs\fR returns an error. +.RS + +\fIOptions\fP +.IP \fB-r\fP 5 +The newly created snapshot will be readonly. +.IP "\fB-i\fP \fI\fR" 5 +Add the newly created subvolume to a qgroup. This option can be given multiple +times. +.RE .TP \fBsubvolume get-default\fR\fI \fR