All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Nicol <davidnicol@gmail.com>
To: BTRFS MAILING LIST <linux-btrfs@vger.kernel.org>
Subject: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
Date: Wed, 6 Oct 2010 16:00:55 -0500	[thread overview]
Message-ID: <AANLkTim0NC5QRs_z=tA8R5R4J07aQ7LS-Ls17t2Qvd7p@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 391 bytes --]

the ISO 8601 duration support is very loose, but I believe it is
accurate for valid
input. Without any non-numeric designators, the timeout is interpreted
as seconds,
so
    btrfs fi reclaim 10.3321 /my_btrfs_mount ||  echo timed out
will wait 10332 ms before echoing, if the pending subvolume deletions
take longer than that.

Timeout defaults to 0, and path defaults to current directory.

[-- Attachment #2: progs_patch_8601.diff --]
[-- Type: text/x-diff, Size: 12980 bytes --]

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..3928961 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
@@ -77,6 +79,11 @@ static struct Command commands[] = {
 	  "filesystem sync", "<path>\n"
 		"Force a sync on the filesystem <path>."
 	},
+	{ do_wait4clean, 1002, /* require at most two args */
+	  "filesystem reclaim", "<path> [timeout]\n"
+		"Wait for cleanup of deleted subvolumes in the filesystem <path>.\n"
+		"Optional timeout in whole or partial seconds, or ISO8601 string.\n"
+	},
 	{ do_resize, 2,
 	  "filesystem resize", "[+/-]<newsize>[gkm]|max <filesystem>\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 <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, "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 <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
 \fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
@@ -115,6 +117,15 @@ all the block devices.
 Force a sync for the filesystem identified by \fI<path>\fR.
 .TP
 
+\fBfilesystem reclaim\fR\fI <path> [timeout] \fR
+Wait for recovery of space from deleted
+subvolumes on the filesystem containing \fI<path>\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,

             reply	other threads:[~2010-10-06 21:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-06 21:00 David Nicol [this message]
2010-10-07  6:10 ` IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support Goffredo Baroncelli
2010-10-07 13:50   ` David Nicol
2010-10-07 14:25     ` David Nicol
2010-10-07 15:50       ` David Nicol
2010-10-07 17:38   ` David Nicol

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='AANLkTim0NC5QRs_z=tA8R5R4J07aQ7LS-Ls17t2Qvd7p@mail.gmail.com' \
    --to=davidnicol@gmail.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.