summaryrefslogtreecommitdiff
path: root/cmds-subvolume.c
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 /cmds-subvolume.c
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>
Diffstat (limited to 'cmds-subvolume.c')
-rw-r--r--cmds-subvolume.c168
1 files changed, 123 insertions, 45 deletions
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;