David Nicol
2010-Oct-13 14:37 UTC
PATCH: IOCTL#21 progs, including -dq OPTIONS FOR btrfs fi sy
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 <sys/ioctl.h> #include <sys/mount.h> @@ -34,6 +35,7 @@ #include "transaction.h" #include "utils.h" #include "version.h" +#include <string.h> /* 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..47ce5c2 100644 --- a/btrfs.c +++ b/btrfs.c @@ -15,6 +15,7 @@ */ +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -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 @@ -73,14 +75,19 @@ static struct Command commands[] = { "Set the subvolume of the filesystem <path> which will be mounted\n" "as default." }, - { do_fssync, 1, - "filesystem sync", "<path>\n" - "Force a sync on the filesystem <path>." + { do_fssync, 1002, + "filesystem sync", "[-dq] <path>\n" + "Force a sync on the filesystem <path>, defaulting to ''.''." + }, + { do_wait4clean, 1002, /* require at most two args */ + "filesystem reclaim", "[path [timeout]] \n" + "Wait for cleanup of deleted subvolumes. Path defaults to .\n" + "Timeout in seconds, or add m for minutes.\n" }, { do_resize, 2, "filesystem resize", "[+/-]<newsize>[gkm]|max <filesystem>\n" "Resize the file system. If ''max'' is passed, the filesystem\n" - "will occupe all available space on the device." + "will occupy all available space on the device." }, { do_show_filesystem, 999, "filesystem show", "[<uuid>|<label>]\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..d2b81ba 100644 --- a/btrfs_cmds.c +++ b/btrfs_cmds.c @@ -507,22 +507,87 @@ int do_create_subvol(int argc, char **argv) int do_fssync(int argc, char **argv) { int fd, res; - char *path = argv[1]; - + int cleanup=1, quiet=0; + char *path = ".", *p; /* [-dq] [<path>] */ + struct btrfs_ioctl_cleaner_wait_args w4c_arg; + + if (argc > 1){ + if (argv[1][0] == ''-''){ + for (p=&argv[1][1]; *p; p++) switch (*p){ + case ''q'': quiet++; break; + case ''d'': cleanup++; break; + default: + fprintf(stderr, + "ERROR: unknown flag ''%c'' in ''%s''\n", *p,argv[1]); + return 12; + }; + if (argc > 2) + path = argv[2]; + + }else{ + path = argv[1]; + + }; + + }; + while (cleanup--){ /* cleanup starts at 1 */ fd = open_file_or_dir(path); if (fd < 0) { fprintf(stderr, "ERROR: can''t access to ''%s''\n", path); return 12; } - printf("FSSync ''%s''\n", path); + if (!quiet) printf("FSSync ''%s''\n", path); res = ioctl(fd, BTRFS_IOC_SYNC); - close(fd); if( res < 0 ){ fprintf(stderr, "ERROR: unable to fs-syncing ''%s''\n", path); return 16; } + if (cleanup){ + w4c_arg.ms = 0UL; + fd = open_file_or_dir(path); + if (!quiet) printf("reclaim: ''%s''\n", path); + 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; +} + +#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; } 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..13dddd5 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..f982d34 --- /dev/null +++ b/iso8601toms.c @@ -0,0 +1,114 @@ +/* + * 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 + + always treats "m" as minutes + + 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 halts and catches fire on: + + P or p appearing somewhere besides the beginning of the string + + Attempts to use Years or Months + + unrecognized characters + + +***********/ + +#include <stdlib.h> +#include <stdio.h> + +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, "non-initial P " + "in duration string %s\n", P); + exit (-1); + case ''Y'': /* year */ case ''y'': + fprintf(stderr, "Years are not supported " + "in duration string %s\n", P); + exit (-1); + 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 */ + if (M_min == 0 ){ + fprintf(stderr, "Months are not supported " + "in duration string %s\n" + "use ''m'' instead or prefix a ''T''\n" + , P); + exit (-1); + }; + case ''m'': /* minute */ + component *= 60; + case ''S'': /* second */ case ''s'': + case ''\0'': /* default to second */ + component *= 1000; + ms += component; + break; + + default: + fprintf(stderr, + "unexpected char [%c] in duration string %s\n" + "valid designators are [WwDdHhMmSs] with implied trailing S.\n", + *endptr, P + ); + exit (-1); + }; + 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..a62f02b 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -17,7 +17,9 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBfilesystem defrag\fP\fI <file>|<dir> [<file>|<dir>...]\fP .PP -\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP +\fBbtrfs\fP \fBfilesystem sync\fP\fI [-dq] [<path>] \fP +.PP +\fBbtrfs\fP \fBfilesystem reclaim\fP\fI [path [timeout]] \fP .PP \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP .PP @@ -111,8 +113,22 @@ Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR scans all the block devices. .TP -\fBfilesystem sync\fR\fI <path> \fR -Force a sync for the filesystem identified by \fI<path>\fR. +\fBfilesystem sync\fR \fI[-dq] [<path>]\fR +Force a sync for the filesystem identified by \fI<path>\fR, which defaults +to the current directory. Use the \fI-d\fR switch to wait for the deleted +subvolume cleaner thread to finish, and the \fI-q\fR switch to suppress +informational output. +.TP + +\fBfilesystem reclaim\fR\fI [path [timeout]] \fR +Wait for recovery of space from deleted +subvolumes on the filesystem containing \fIpath\fR, +which defaults to the current working directory, to complete. +The optional timeout parameter is a series of number[.number][letter] +components where the letter is one of wdhms for weeks, days, hours, minutes, +seconds, defaulting to seconds. The default timeout is zero which means +no timeout. 90, 1.5m, and PT1.5M all mean ninety seconds. + .TP .\" diff --git a/man/btrfsctl.8.in b/man/btrfsctl.8.in index c2d4488..890c625 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 seconds[.subseconds], or append "m" +for minutes[.subminutes]. "90", "90.000s", "T1.5M", and "1m30" all mean +the same thing. The default timeout is zero, which means do not time out. +The optional directory parameter defaults to the current directory. .SH AVAILABILITY .B btrfsctl is part of btrfs-progs. Btrfs is currently under heavy development, -- l''égalité des droits pour les ambidextres -- 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
David Nicol
2010-Oct-13 15:04 UTC
Re: PATCH: IOCTL#21 progs, including -dq OPTIONS FOR btrfs fi sy
Drat, I left in a file descriptor leak. Is anyone trying this stuff? On Wed, Oct 13, 2010 at 9:37 AM, David Nicol <davidnicol@gmail.com> wrote:> > res = ioctl(fd, BTRFS_IOC_SYNC); > - close(fd); > if( res < 0 ){-- 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