summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.cz>2015-04-08 00:28:48 +0200
committerDavid Sterba <dsterba@suse.cz>2015-06-09 18:18:19 +0200
commitc9f885ec8963be55983caeeb63ff6cd71ded3f52 (patch)
tree18d674d942ed3aeeaf1186a3e54a8311a0e2356b
parentff36fbae4d4e6a18c43c0693fb16f0abfc411e32 (diff)
btrfs-progs: subvol: let sync check only current deletions
So far the subvol sync command takes a shortcut and looks if there are any deleted subvols at all. It does not print the deleted subvolumes as they get cleaned. Arguably this is what the user would like to see and has to do $ btrfs subvol sync /path $(btrfs subvol list -d /path | "extract the ids") to see the progress. Make it look for all currently deleted subvolumes automatically and print the progress as if the ids were listed manually. This is a slight change in the semantics of the command. Previously, any new subvol deletion would prevent subvol sync to return. To simulate the old behaviour, run 'subvol sync' in a loop until it returns 0. Signed-off-by: David Sterba <dsterba@suse.cz>
-rw-r--r--Documentation/btrfs-subvolume.asciidoc6
-rw-r--r--cmds-subvolume.c168
2 files changed, 126 insertions, 48 deletions
diff --git a/Documentation/btrfs-subvolume.asciidoc b/Documentation/btrfs-subvolume.asciidoc
index 3dd5289b..c187fd86 100644
--- a/Documentation/btrfs-subvolume.asciidoc
+++ b/Documentation/btrfs-subvolume.asciidoc
@@ -155,9 +155,9 @@ If '-r' is given, the snapshot will be readonly.
*sync* <path> [subvolid...]::
Wait until given subvolume(s) are completely removed from the filesystem
-after deletion. If no subvolume id is given, wait until all ongoing deletion
-requests are complete. This may take long if new deleted subvolumes appear
-during the sleep interval.
+after deletion. If no subvolume id is given, wait until all current deletion
+requests are completed, but do not wait for subvolumes deleted meanwhile.
+The status of subvolume ids is checked periodically.
+
`Options`
+
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index c69cb3c2..5591e452 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -1028,9 +1028,9 @@ static const char * const cmd_subvol_sync_usage[] = {
"Wait until given subvolume(s) are completely removed from the filesystem.",
"Wait until given subvolume(s) are completely removed from the filesystem",
"after deletion.",
- "If no subvolume id is given, wait until all ongoing deletion requests",
- "are complete. This may take long if new deleted subvolumes appear during",
- "the sleep interval.",
+ "If no subvolume id is given, wait until all current deletion requests",
+ "are completed, but do not wait for subvolumes deleted meanwhile.",
+ "The status of subvolume ids is checked periodically.",
"",
"-s <N> sleep N seconds between checks (default: 1)",
NULL
@@ -1063,6 +1063,7 @@ static int is_subvolume_cleaned(int fd, u64 subvolid)
return 0;
}
+#if 0
/*
* If we're looking for any dead subvolume, take a shortcut and look
* for any ORPHAN_ITEMs in the tree root
@@ -1126,6 +1127,82 @@ again:
return 1;
}
+#endif
+
+#define SUBVOL_ID_BATCH 1024
+
+/*
+ * Enumerate all dead subvolumes that exist in the filesystem.
+ * Fill @ids and reallocate to bigger size if needed.
+ */
+static int enumerate_dead_subvols(int fd, int count, u64 **ids)
+{
+ int ret;
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+ int idx = 0;
+
+ memset(&args, 0, sizeof(args));
+
+ sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+ sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
+ sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
+ sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
+ sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
+ sk->min_offset = 0;
+ sk->max_offset = (u64)-1;
+ sk->min_transid = 0;
+ sk->max_transid = (u64)-1;
+ sk->nr_items = 4096;
+
+ while (1) {
+ struct btrfs_ioctl_search_header *sh;
+ unsigned long off;
+ int i;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return -errno;
+
+ if (!sk->nr_items)
+ return idx;
+
+ off = 0;
+ for (i = 0; i < sk->nr_items; i++) {
+ sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
+ off += sizeof(*sh);
+
+ if (sh->type == BTRFS_ORPHAN_ITEM_KEY) {
+ *ids[idx] = sh->offset;
+ idx++;
+ if (idx >= count) {
+ u64 *newids;
+
+ count += SUBVOL_ID_BATCH;
+ newids = (u64*)realloc(*ids, count);
+ if (!newids)
+ return -ENOMEM;
+ *ids = newids;
+ }
+ }
+ off += sh->len;
+
+ sk->min_objectid = sh->objectid;
+ sk->min_type = sh->type;
+ sk->min_offset = sh->offset;
+ }
+ if (sk->min_offset < (u64)-1)
+ sk->min_offset++;
+ else
+ break;
+ if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
+ break;
+ if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
+ break;
+ }
+
+ return idx;
+}
static int cmd_subvol_sync(int argc, char **argv)
{
@@ -1173,56 +1250,57 @@ static int cmd_subvol_sync(int argc, char **argv)
optind++;
id_count = argc - optind;
-
- /*
- * Wait for all
- */
if (!id_count) {
- while (1) {
- ret = fs_has_dead_subvolumes(fd);
- if (ret < 0) {
- fprintf(stderr, "ERROR: can't perform the search - %s\n",
- strerror(-ret));
- ret = 1;
- goto out;
- }
- if (!ret)
- goto out;
- sleep(sleep_interval);
+ id_count = SUBVOL_ID_BATCH;
+ ids = (u64*)malloc(id_count * sizeof(u64));
+ if (!ids) {
+ fprintf(stderr, "ERROR: not enough memory\n");
+ ret = 1;
+ goto out;
}
- }
-
- /*
- * Wait only for the requested ones
- */
- ids = (u64*)malloc(sizeof(u64) * id_count);
-
- if (!ids) {
- fprintf(stderr, "ERROR: not enough memory\n");
- ret = 1;
- goto out;
- }
-
- for (i = 0; i < id_count; i++) {
- u64 id;
- const char *arg;
-
- arg = argv[optind + i];
- errno = 0;
- id = strtoull(arg, NULL, 10);
- if (errno < 0) {
- fprintf(stderr, "ERROR: unrecognized subvolume id %s\n",
- arg);
+ id_count = enumerate_dead_subvols(fd, id_count, &ids);
+ if (id_count < 0) {
+ fprintf(stderr, "ERROR: can't enumerate dead subvolumes: %s\n",
+ strerror(-id_count));
ret = 1;
goto out;
}
- if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) {
- fprintf(stderr, "ERROR: subvolume id %s out of range\n",
- arg);
+ if (id_count == 0) {
+ ret = 0;
+ goto out;
+ }
+ } else {
+ ids = (u64*)malloc(id_count * sizeof(u64));
+ if (!ids) {
+ fprintf(stderr, "ERROR: not enough memory\n");
ret = 1;
goto out;
}
- ids[i] = id;
+
+ for (i = 0; i < id_count; i++) {
+ u64 id;
+ const char *arg;
+
+ arg = argv[optind + i];
+ errno = 0;
+ id = strtoull(arg, NULL, 10);
+ if (errno < 0) {
+ fprintf(stderr,
+ "ERROR: unrecognized subvolume id %s\n",
+ arg);
+ ret = 1;
+ goto out;
+ }
+ if (id < BTRFS_FIRST_FREE_OBJECTID
+ || id > BTRFS_LAST_FREE_OBJECTID) {
+ fprintf(stderr,
+ "ERROR: subvolume id %s out of range\n",
+ arg);
+ ret = 1;
+ goto out;
+ }
+ ids[i] = id;
+ }
}
remaining = id_count;