From patchwork Thu Nov 28 16:59:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Sterba X-Patchwork-Id: 3255201 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 10DBCC045B for ; Thu, 28 Nov 2013 17:00:07 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B198620660 for ; Thu, 28 Nov 2013 17:00:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 956052065B for ; Thu, 28 Nov 2013 17:00:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759294Ab3K1Q75 (ORCPT ); Thu, 28 Nov 2013 11:59:57 -0500 Received: from cantor2.suse.de ([195.135.220.15]:59636 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752789Ab3K1Q7z (ORCPT ); Thu, 28 Nov 2013 11:59:55 -0500 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 3C627A7DA0; Thu, 28 Nov 2013 17:59:54 +0100 (CET) Received: by ds.suse.cz (Postfix, from userid 10065) id 92436DAA1A; Thu, 28 Nov 2013 17:59:52 +0100 (CET) From: David Sterba To: linux-btrfs@vger.kernel.org Cc: clm@fb.com, David Sterba , Alex Lyakas Subject: [PATCH] btrfs-progs: add options to sync filesystem after subvol delete Date: Thu, 28 Nov 2013 17:59:07 +0100 Message-Id: <1385657947-26145-1-git-send-email-dsterba@suse.cz> X-Mailer: git-send-email 1.8.4.3 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-6.9 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 Subvolume deletion does not do a full transaction commit. This can lead to an unexpected result when the system crashes between deletion and commit, the subvolume directory will appear again. Add options to request filesystem sync after each deleted subvolume or after the last one. If the command with sync option finishes succesfully, the subvolume(s) deletion status is safely stored on the media. Userspace approach is more flexible than in-kernel. Related discussions: http://www.spinics.net/lists/linux-btrfs/msg22088.html http://www.spinics.net/lists/linux-btrfs/msg27240.html CC: Alex Lyakas Signed-off-by: David Sterba --- The option names may not be ideal, feel free to suggest better. cmds-subvolume.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++----- man/btrfs.8.in | 23 ++++++++++++++--- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/cmds-subvolume.c b/cmds-subvolume.c index c6a5284a02a4..c124c3185252 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -202,24 +202,67 @@ int test_issubvolume(char *path) } static const char * const cmd_subvol_delete_usage[] = { - "btrfs subvolume delete [...]", + "btrfs subvolume delete [options] [...]", "Delete subvolume(s)", + "Delete subvolumes from the filesystem. The corresponding directory", + "is removed instantly but the data blocks are removed later.", + "The deletion does not involve full commit by default due to", + "performance reasons (as a consequence, the subvolume may appear again", + "after a crash). Use one of the --sync options to sync the filesystem", + "via a btrfs specific ioctl.", + "", + "-s|--sync-after call sync at the end of the operation", + "-S|--sync-each sync the filesystem after deleting each subvolume", NULL }; static int cmd_subvol_delete(int argc, char **argv) { - int res, fd, len, e, cnt = 1, ret = 0; + int res, len, e, ret = 0; + int cnt; + int fd = -1; struct btrfs_ioctl_vol_args args; char *dname, *vname, *cpath; char *dupdname = NULL; char *dupvname = NULL; char *path; DIR *dirstream = NULL; + int sync_mode = 0; + struct option long_options[] = { + {"sync-after", no_argument, NULL, 's'}, /* sync mode 1 */ + {"sync-each", no_argument, NULL, 'S'}, /* sync mode 2 */ + {NULL, 0, NULL, 0} + }; - if (argc < 2) + optind = 1; + while (1) { + int c; + + c = getopt_long(argc, argv, "sS", long_options, NULL); + if (c < 0) + break; + + switch(c) { + case 's': + sync_mode = 1; + break; + case 'S': + sync_mode = 2; + break; + default: + usage(cmd_subvol_delete_usage); + } + } + + if (check_argc_min(argc - optind, 1)) usage(cmd_subvol_delete_usage); + printf("Sync filesystem mode: %s\n", + !sync_mode ? "none (default)" : + sync_mode == 1 ? "at the end" : "after each"); + + cnt = optind; + again: path = argv[cnt]; @@ -276,8 +319,6 @@ again: res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); e = errno; - close_file_or_dir(fd, dirstream); - if(res < 0 ){ fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n", dname, vname, strerror(e)); @@ -285,14 +326,38 @@ again: goto out; } + if (sync_mode == 1) { + res = ioctl(fd, BTRFS_IOC_SYNC); + if (res < 0) { + fprintf(stderr, + "ERROR: unable to sync after '%s': %s\n", + path, strerror(e)); + ret = 1; + } + } + out: free(dupdname); free(dupvname); dupdname = NULL; dupvname = NULL; cnt++; - if (cnt < argc) + if (cnt < argc) { + close_file_or_dir(fd, dirstream); goto again; + } + + if (sync_mode == 2 && fd != -1) { + res = ioctl(fd, BTRFS_IOC_SYNC); + e = errno; + if (res < 0) { + fprintf(stderr, + "ERROR: unable to do final sync: %s\n", + strerror(e)); + ret = 1; + } + } + close_file_or_dir(fd, dirstream); return ret; } diff --git a/man/btrfs.8.in b/man/btrfs.8.in index b6203483296e..2d5c12e08640 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -8,7 +8,7 @@ btrfs \- control a btrfs filesystem .SH SYNOPSIS \fBbtrfs\fP \fBsubvolume create\fP [-i \fI\fP] [\fI\fP/]\fI\fP .PP -\fBbtrfs\fP \fBsubvolume delete\fP \fI\fP [\fI...\fP] +\fBbtrfs\fP \fBsubvolume delete\fP [\fIoptions\fP] \fI\fP [\fI...\fP] .PP \fBbtrfs\fP \fBsubvolume list\fP [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI\fP .PP @@ -168,9 +168,24 @@ times. .RE .TP -\fBsubvolume delete\fR\fI \fP[\fI...\fP]\fR -Delete the subvolume \fI\fR. If \fI\fR is not a -subvolume, \fBbtrfs\fR returns an error. +\fBsubvolume delete\fR [\fIoptions\fP] \fI\fP [\fI...\fP]\fR +Delete the subvolume(s) from the filesystem. If \fI\fR is not a +subvolume, \fBbtrfs\fR returns an error but continues if there are more arguments +to process. + +The corresponding directory is removed instantly but the data blocks are +removed later. The deletion does not involve full commit by default due to +performance reasons (as a consequence, the subvolume may appear again after a +crash). Use one of the --sync options to sync the filesystem via a btrfs +specific ioctl. +.RS + +\fIOptions\fP +.IP "\fB-s|--sync-after\fP" 5 +call sync at the end of the operation +.IP "\fB-S|--sync-each\fP" 5 +sync the filesystem after deleting each subvolume +.RE .TP \fBsubvolume list\fR [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI\fR