From patchwork Wed Oct 6 21:00:55 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Nicol X-Patchwork-Id: 237071 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o96L1ofP011189 for ; Wed, 6 Oct 2010 21:01:50 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933110Ab0JFVB2 (ORCPT ); Wed, 6 Oct 2010 17:01:28 -0400 Received: from mail-iw0-f174.google.com ([209.85.214.174]:52361 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933107Ab0JFVB0 (ORCPT ); Wed, 6 Oct 2010 17:01:26 -0400 Received: by iwn5 with SMTP id 5so2085iwn.19 for ; Wed, 06 Oct 2010 14:01:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:mime-version:received:from:date :message-id:subject:to:content-type; bh=nWA1XluKiZc/1ZF5V1tix4wa2d9MwCu/SquVaRfu8eo=; b=SqdLo8rtcjVeqaECreUWaEAmuz7HTFowQ2WxZzR7UbmfApGHCWxC2aZFqxt9+V6DS8 n9jwnfsoHY8tjIO85plPly2GpoFGodh8VSAWizrZD+5UEkxzJ4150eYaIV1Hp4n2Zo66 idpnFpn8Tie5B2iAWnMWeFIXVh20HUPy59gOU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; b=ipqvgIpOeZedl5fEntgccTIxQ5LghveM1U8G7kqZOaof95UIQst6ZMMlbSfLcmuXmq ywYR67ZcOT6nDGK8ajcGZbV6MCZwfaW2x65BY0VvxBndncPto1rSUJ7TvAKCC80nRQyP 5Xug7/pl/w21ZdJ5a8j6eGnS1xPA0GGIsectw= Received: by 10.231.14.8 with SMTP id e8mr14622969iba.16.1286398881573; Wed, 06 Oct 2010 14:01:21 -0700 (PDT) MIME-Version: 1.0 Received: by 10.231.152.1 with HTTP; Wed, 6 Oct 2010 14:00:55 -0700 (PDT) From: David Nicol Date: Wed, 6 Oct 2010 16:00:55 -0500 Message-ID: Subject: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support To: BTRFS MAILING LIST Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Wed, 06 Oct 2010 21:01:50 +0000 (UTC) diff --git a/Makefile b/Makefile index 525676e..7442e14 100644 --- a/Makefile +++ b/Makefile @@ -37,12 +37,13 @@ all: version $(progs) manpages version: bash version.sh -btrfs: $(objects) btrfs.o btrfs_cmds.o - gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \ +btrfs: $(objects) btrfs.o btrfs_cmds.o iso8601toms.o + gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o iso8601toms.o \ $(objects) $(LDFLAGS) $(LIBS) -btrfsctl: $(objects) btrfsctl.o - gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) +btrfsctl: $(objects) btrfsctl.o iso8601toms.o + gcc $(CFLAGS) -o btrfsctl btrfsctl.o iso8601toms.o \ + $(objects) $(LDFLAGS) $(LIBS) btrfs-vol: $(objects) btrfs-vol.o gcc $(CFLAGS) -o btrfs-vol btrfs-vol.o $(objects) $(LDFLAGS) $(LIBS) diff --git a/btrfs-list.c b/btrfs-list.c index 7741705..7b92bc0 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -16,6 +16,7 @@ * Boston, MA 021110-1307, USA. */ +#define _GNU_SOURCE #ifndef __CHECKER__ #include #include @@ -34,6 +35,7 @@ #include "transaction.h" #include "utils.h" #include "version.h" +#include /* we store all the roots we find in an rbtree so that we can * search for them later. diff --git a/btrfs.c b/btrfs.c index ab5e57f..3928961 100644 --- a/btrfs.c +++ b/btrfs.c @@ -15,6 +15,7 @@ */ +#define _GNU_SOURCE #include #include #include @@ -29,6 +30,7 @@ struct Command { CommandFunction func; /* function which implements the command */ int nargs; /* if == 999, any number of arguments if >= 0, number of arguments, + if > 1000, 1000 more than the _maximum_ number of arguments, if < 0, _minimum_ number of arguments */ char *verb; /* verb */ char *help; /* help lines; form the 2nd onward they are @@ -77,6 +79,11 @@ static struct Command commands[] = { "filesystem sync", "\n" "Force a sync on the filesystem ." }, + { do_wait4clean, 1002, /* require at most two args */ + "filesystem reclaim", " [timeout]\n" + "Wait for cleanup of deleted subvolumes in the filesystem .\n" + "Optional timeout in whole or partial seconds, or ISO8601 string.\n" + }, { do_resize, 2, "filesystem resize", "[+/-][gkm]|max \n" "Resize the file system. If 'max' is passed, the filesystem\n" @@ -349,17 +356,26 @@ static int parse_args(int argc, char **argv, return -2; /* check the number of argument */ - if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){ + + if(matchcmd->nargs > 1000 ){ + if ( matchcmd->nargs < (1000 + *nargs_)){ + fprintf(stderr, "ERROR: '%s' requires only %d or fewer arg(s)\n", + matchcmd->verb, matchcmd->nargs - 1000 ); + return -2; + } + } else { + + if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){ fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n", matchcmd->verb, -matchcmd->nargs); return -2; - } - if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){ + } + if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){ fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n", matchcmd->verb, matchcmd->nargs); return -2; - } - + } + } if (prepare_args( nargs_, args_, prgname, matchcmd )){ fprintf(stderr, "ERROR: not enough memory\\n"); return -20; diff --git a/btrfs_cmds.c b/btrfs_cmds.c index 8031c58..855c950 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -526,6 +526,37 @@ int do_fssync(int argc, char **argv) return 0; } +#include "iso8601toms.h" + +int do_wait4clean(int argc, char **argv) +{ + int fd, res; + struct btrfs_ioctl_cleaner_wait_args w4c_arg; + + char *path = "."; + w4c_arg.ms = 0UL; + + if (argc > 1) + path = argv[1]; + if (argc > 2) + w4c_arg.ms = iso8601toms(argv[2]); + + fd = open_file_or_dir(path); + if (fd < 0) { + fprintf(stderr, "ERROR: can't open file or dir '%s'\n", path); + return 12; + } + res = ioctl(fd, BTRFS_IOC_CLEANER_WAIT, &w4c_arg); + close(fd); + if( res != 0 ){ + fprintf(stderr, "%s:error #%i:%s\n", + path, res,strerror(res)); + return -res; + } + + return 0; +} + int do_scan(int argc, char **argv) { int i, fd; diff --git a/btrfs_cmds.h b/btrfs_cmds.h index 7bde191..c958338 100644 --- a/btrfs_cmds.h +++ b/btrfs_cmds.h @@ -19,6 +19,7 @@ int do_clone(int nargs, char **argv); int do_delete_subvolume(int nargs, char **argv); int do_create_subvol(int nargs, char **argv); int do_fssync(int nargs, char **argv); +int do_wait4clean(int nargs, char **argv); int do_defrag(int argc, char **argv); int do_show_filesystem(int nargs, char **argv); int do_add_volume(int nargs, char **args); diff --git a/btrfsctl.c b/btrfsctl.c index be6bf25..307ec53 100644 --- a/btrfsctl.c +++ b/btrfsctl.c @@ -34,6 +34,7 @@ #include "ctree.h" #include "transaction.h" #include "utils.h" +#include "iso8601toms.h" #include "version.h" #ifdef __CHECKER__ @@ -57,6 +58,7 @@ static void print_usage(void) printf("\t-a: scans all devices for Btrfs filesystems\n"); printf("\t-c: forces a single FS sync\n"); printf("\t-D: delete snapshot\n"); + printf("\t-C [timeout] [directory]: wait for snapshot space recovery\n"); printf("\t-m [tree id] directory: set the default mounted subvolume" " to the [tree id] or the directory\n"); printf("%s\n", BTRFS_BUILD_VERSION); @@ -96,7 +98,7 @@ int main(int ac, char **av) char *fname = NULL; char *snap_location = NULL; int snap_fd = 0; - int fd; + int fd = -999; /* silence a warning */ int ret; struct btrfs_ioctl_vol_args args; char *name = NULL; @@ -105,6 +107,7 @@ int main(int ac, char **av) int len; char *fullpath; u64 objectid = 0; + struct btrfs_ioctl_cleaner_wait_args CWargs; if (ac == 2 && strcmp(av[1], "-a") == 0) { fprintf(stderr, "Scanning for Btrfs filesystems\n"); @@ -175,6 +178,10 @@ int main(int ac, char **av) fprintf(stderr, "-D size too long\n"); exit(1); } + } else if (strcmp(av[i], "-C") == 0) { + command = BTRFS_IOC_CLEANER_WAIT; + CWargs.ms = ( ac > (i+1) ? iso8601toms(av[i+1]) : 0UL ); + name = ( ac > ( i+2 ) ? av[i + 2] : "." ); } else if (strcmp(av[i], "-A") == 0) { if (i >= ac - 1) { fprintf(stderr, "-A requires an arg\n"); @@ -221,9 +228,9 @@ int main(int ac, char **av) exit(1); } name = fname; - } else { + } else if (command != BTRFS_IOC_CLEANER_WAIT) { fd = open_file_or_dir(fname); - } + } if (name) strcpy(args.name, name); @@ -236,6 +243,9 @@ int main(int ac, char **av) } else if (command == BTRFS_IOC_DEFAULT_SUBVOL) { printf("objectid is %llu\n", objectid); ret = ioctl(fd, command, &objectid); + } else if (command == BTRFS_IOC_CLEANER_WAIT) { + fd = open_file_or_dir(name); + ret = ioctl(fd, command, &CWargs); } else ret = ioctl(fd, command, &args); if (ret < 0) { diff --git a/ioctl.h b/ioctl.h index 776d7a9..27df596 100644 --- a/ioctl.h +++ b/ioctl.h @@ -169,4 +169,11 @@ struct btrfs_ioctl_space_args { #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64) #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ struct btrfs_ioctl_space_args) +struct btrfs_ioctl_cleaner_wait_args{ + unsigned long ms; + unsigned long flags; /* for future use */ +}; +#define BTRFS_IOC_CLEANER_WAIT _IOW(BTRFS_IOCTL_MAGIC, 21, \ + struct btrfs_ioctl_cleaner_wait_args) #endif + diff --git a/iso8601toms.c b/iso8601toms.c new file mode 100644 index 0000000..a1ee9bd --- /dev/null +++ b/iso8601toms.c @@ -0,0 +1,109 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +/*********** + + the following will correctly parse valid duration strings, + also it will accept a lot of invalid ones. + + it does: + + know all the ISO8601 letters + + accept a non-integer as the last numeric component + + it silently accepts: + + out of order duration type letters + + strings missing the leading P character + + lowercase duration type letters + + non-integers in any position + + it warns on: + + P or p appearing somewhere besides the beginning of the string + + unrecognized characters + + +***********/ + +#include +#include + +unsigned long iso8601toms(char *P){ + unsigned long ms; + double component; + char *ptr; + char *endptr; + short M_min = 0; + + ms = 0UL; + ptr = P; + for(;;){ + component=strtod(ptr, &endptr); + switch (*endptr) + { + case 'P': /* anchor */ case 'p': + if (ptr > P) + fprintf(stderr, "ignoring non-initial P " + "in ISO8601 duration string %s\n", P); + break; + case 'Y': /* years */ case 'y': + component *= 12; + BIGM: + /* average days in a gregorian month */ + component *= (365.2425 / 12.0); + /* ms in a day */ + component *= ( 24 * 3600 * 1000 ); + ms += component; + break; + case 'T': /* Time (not date) anchor */ case 't': + M_min = 1; + break; + case 'W': /* week */ case 'w': + component *= 7; + case 'D': /* day */ case 'd': + component *= 24 ; + case 'H': /* hour */ case 'h': + component *= 60; + M_min = 1; + case 'M': /* month, or minute */ case 'm': + if (!M_min++) + goto BIGM; + component *= 60; + case 'S': /* second */ case 's': + case '\0': /* default to second */ + component *= 1000; + ms += component; + break; + + default: + fprintf(stderr, + "ignoring unexpected char [%c] " + "in iso8601 duration string %s\n", + *endptr, P + ); + }; + if (!*endptr) + return (ms); + ptr = 1+endptr; + }; +} + diff --git a/iso8601toms.h b/iso8601toms.h new file mode 100644 index 0000000..8f7ca83 --- /dev/null +++ b/iso8601toms.h @@ -0,0 +1,3 @@ + +unsigned long iso8601toms(char *P); + diff --git a/man/btrfs.8.in b/man/btrfs.8.in index 26ef982..5f1155e 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -19,6 +19,8 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBfilesystem sync\fP\fI \fP .PP +\fBbtrfs\fP \fBfilesystem reclaim\fP\fI [timeout] \fP +.PP \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-][gkm]|max \fP .PP \fBbtrfs\fP \fBdevice scan\fP\fI [ [..]]\fP @@ -115,6 +117,15 @@ all the block devices. Force a sync for the filesystem identified by \fI\fR. .TP +\fBfilesystem reclaim\fR\fI [timeout] \fR +Wait for recovery of space from deleted +subvolumes on the filesystem containing \fI\fR to complete. +The optional timeout is in seconds, which can be fractional, or you may use +an ISO8601 duration string, such as PT5M2.5S, which would mean five minutes, +two and a half seconds. The P and T are optional, but without them "M" might +get interpreted as months, which is probably not what you want. +.TP + .\" .\" Some wording are extracted by the resize2fs man page .\" diff --git a/man/btrfsctl.8.in b/man/btrfsctl.8.in index c2d4488..62a1db2 100644 --- a/man/btrfsctl.8.in +++ b/man/btrfsctl.8.in @@ -10,6 +10,7 @@ btrfsctl \- control a btrfs filesystem [ \fB \-A\fP\fI device\fP ] [ \fB \-a\fP ] [ \fB \-c\fP ] +[ \fB \-C\fP\fI [timeout [directory]]\fP ] .SH DESCRIPTION .B btrfsctl is used to control the filesystem and the files and directories stored. It is the tool to create a new snapshot for the filesystem. @@ -35,6 +36,13 @@ Scans all devices present in the system for btrfs filesystem. .TP \fB\-c\fR Forces a filesystem sync. +.TP +\fB\-C\fR \fI[timeout] [directory]\fR +Wait until all the space from all deleted snapshots has been recovered. +The optional timeout parameter is in seconds, or an ISO8601 string, +defaulting to zero, which means do not time out. Fractional seconds +resolve to milliseconds. The optional directory parameter defaults to +the current directory. .SH AVAILABILITY .B btrfsctl is part of btrfs-progs. Btrfs is currently under heavy development,