* [PATCH] btrfs-progs: wait until all subvolumes are cleaned
@ 2014-07-23 20:56 David Sterba
2014-07-30 11:22 ` Justus Seifert
2014-07-30 11:55 ` Roman Mamedov
0 siblings, 2 replies; 4+ messages in thread
From: David Sterba @ 2014-07-23 20:56 UTC (permalink / raw)
To: linux-btrfs; +Cc: David Sterba
Enhance the 'subvolume' subcommand to wait until a given list of
subvolumes or all currently scheduled for deletion are cleaned
completely from the filesystem.
Signed-off-by: David Sterba <dsterba@suse.cz>
---
'wait' seemed too generic, 'sync' is not completely accurate but IMHO better,
I'm open to other suggestions
cmds-subvolume.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 231 insertions(+)
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 5e821c712e74..07485acbc1bd 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -1035,6 +1035,236 @@ out:
return !!ret;
}
+static const char * const cmd_subvol_sync_usage[] = {
+ "btrfs subvolume sync <path> [<subvol-id>...]",
+ "Wait until given subvolume(s) are completely cleaned",
+ "Wait until given subvolume(s) are completely cleaned after deletion.",
+ "If no subvolume id is given, wait until there are no more snapshots",
+ "to be cleaned. This may take long if new deleted subvolumes appear",
+ "during the sleep interval.",
+ "",
+ "-s <N> sleep N seconds between checks (default: 1)",
+ NULL
+};
+
+static int is_subvolume_cleaned(int fd, u64 subvolid)
+{
+ int ret;
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+
+ sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+ sk->min_objectid = subvolid;
+ sk->max_objectid = subvolid;
+ sk->min_type = BTRFS_ROOT_ITEM_KEY;
+ sk->max_type = BTRFS_ROOT_ITEM_KEY;
+ sk->min_offset = 0;
+ sk->max_offset = (u64)-1;
+ sk->min_transid = 0;
+ sk->max_transid = (u64)-1;
+ sk->nr_items = 1;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return -errno;
+
+ if (sk->nr_items == 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * If we're looking for any dead subvolume, take a shortcut and look
+ * for any ORPHAN_ITEMs in the tree root
+ */
+static int fs_has_dead_subvolumes(int fd)
+{
+ int ret;
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+ struct btrfs_ioctl_search_header sh;
+ u64 min_subvolid = 0;
+
+again:
+ 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 = min_subvolid;
+ sk->max_offset = (u64)-1;
+ sk->min_transid = 0;
+ sk->max_transid = (u64)-1;
+ sk->nr_items = 1;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return -errno;
+
+ if (!sk->nr_items)
+ return 0;
+
+ memcpy(&sh, args.buf, sizeof(sh));
+ min_subvolid = sh.offset;
+
+ /*
+ * Verify that the root item is really there and we haven't hit
+ * a stale orphan
+ */
+ sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+ sk->min_objectid = min_subvolid;
+ sk->max_objectid = min_subvolid;
+ sk->min_type = BTRFS_ROOT_ITEM_KEY;
+ sk->max_type = BTRFS_ROOT_ITEM_KEY;
+ sk->min_offset = 0;
+ sk->max_offset = (u64)-1;
+ sk->min_transid = 0;
+ sk->max_transid = (u64)-1;
+ sk->nr_items = 1;
+
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0)
+ return -errno;
+
+ /*
+ * Stale orphan, try the next one
+ */
+ if (!sk->nr_items) {
+ min_subvolid++;
+ goto again;
+ }
+
+ return 1;
+}
+
+static int cmd_subvol_sync(int argc, char **argv)
+{
+ int fd = -1;
+ int i;
+ int ret = 1;
+ DIR *dirstream = NULL;
+ u64 *ids = NULL;
+ int id_count;
+ int remaining;
+ int sleep_interval = 1;
+
+ optind = 1;
+ while (1) {
+ int c = getopt(argc, argv, "s:");
+
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 's':
+ sleep_interval = atoi(argv[optind]);
+ if (sleep_interval < 1) {
+ fprintf(stderr,
+ "ERROR: invalid sleep interval %s\n",
+ argv[optind]);
+ ret = 1;
+ goto out;
+ }
+ break;
+ default:
+ usage(cmd_subvol_sync_usage);
+ }
+ }
+
+ if (check_argc_min(argc - optind, 1))
+ usage(cmd_subvol_sync_usage);
+
+ fd = open_file_or_dir(argv[optind], &dirstream);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
+ ret = 1;
+ goto out;
+ }
+ 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);
+ }
+ }
+
+ /*
+ * 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 subovlume id %s\n",
+ arg);
+ ret = 1;
+ goto out;
+ }
+ if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) {
+ fprintf(stderr, "ERROR: subovlume id %s out of range\n",
+ arg);
+ ret = 1;
+ goto out;
+ }
+ ids[i] = id;
+ }
+
+ remaining = id_count;
+ while (1) {
+ for (i = 0; i < id_count; i++) {
+ if (!ids[i])
+ continue;
+ ret = is_subvolume_cleaned(fd, ids[i]);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: can't perform the search - %s\n",
+ strerror(-ret));
+ goto out;
+ }
+ if (ret) {
+ printf("Subvolume id %llu is gone\n", ids[i]);
+ ids[i] = 0;
+ remaining--;
+ }
+ }
+ if (!remaining)
+ break;
+ sleep(sleep_interval);
+ }
+
+out:
+ free(ids);
+ close_file_or_dir(fd, dirstream);
+
+ return !!ret;
+}
+
const struct cmd_group subvolume_cmd_group = {
subvolume_cmd_group_usage, NULL, {
{ "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
@@ -1047,6 +1277,7 @@ const struct cmd_group subvolume_cmd_group = {
cmd_subvol_set_default_usage, NULL, 0 },
{ "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
{ "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
+ { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
NULL_CMD_STRUCT
}
};
--
1.8.4.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs-progs: wait until all subvolumes are cleaned
2014-07-23 20:56 [PATCH] btrfs-progs: wait until all subvolumes are cleaned David Sterba
@ 2014-07-30 11:22 ` Justus Seifert
2014-07-30 11:55 ` Roman Mamedov
1 sibling, 0 replies; 4+ messages in thread
From: Justus Seifert @ 2014-07-30 11:22 UTC (permalink / raw)
To: linux-btrfs
[-- Attachment #1.1: Type: text/plain, Size: 311 bytes --]
On 23.07.2014 22:56, David Sterba wrote:
> Enhance the 'subvolume' subcommand to wait until a given list of
> subvolumes or all currently scheduled for deletion are cleaned[…]
>
> 'wait' seemed too generic, 'sync' is not completely accurate but IMHO better,
> I'm open to other suggestions
'receipt'
[-- Attachment #1.2: justus_seifert.vcf --]
[-- Type: text/x-vcard, Size: 206 bytes --]
begin:vcard
fn:Justus Seifert
n:Seifert;Justus
adr:;;;Dresden;Saxony;;Germany
email;internet:justus.seifert@dergleichrichter.de
tel;cell:+4915730640509
x-mozilla-html:FALSE
version:2.1
end:vcard
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 884 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs-progs: wait until all subvolumes are cleaned
2014-07-23 20:56 [PATCH] btrfs-progs: wait until all subvolumes are cleaned David Sterba
2014-07-30 11:22 ` Justus Seifert
@ 2014-07-30 11:55 ` Roman Mamedov
2014-07-30 17:55 ` David Sterba
1 sibling, 1 reply; 4+ messages in thread
From: Roman Mamedov @ 2014-07-30 11:55 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs
[-- Attachment #1: Type: text/plain, Size: 7539 bytes --]
On Wed, 23 Jul 2014 22:56:13 +0200
David Sterba <dsterba@suse.cz> wrote:
> Enhance the 'subvolume' subcommand to wait until a given list of
> subvolumes or all currently scheduled for deletion are cleaned
> completely from the filesystem.
>
> Signed-off-by: David Sterba <dsterba@suse.cz>
> ---
>
> 'wait' seemed too generic, 'sync' is not completely accurate but IMHO better,
> I'm open to other suggestions
>
> cmds-subvolume.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 231 insertions(+)
>
> diff --git a/cmds-subvolume.c b/cmds-subvolume.c
> index 5e821c712e74..07485acbc1bd 100644
> --- a/cmds-subvolume.c
> +++ b/cmds-subvolume.c
> @@ -1035,6 +1035,236 @@ out:
> return !!ret;
> }
>
> +static const char * const cmd_subvol_sync_usage[] = {
> + "btrfs subvolume sync <path> [<subvol-id>...]",
> + "Wait until given subvolume(s) are completely cleaned",
> + "Wait until given subvolume(s) are completely cleaned after deletion.",
I find "cleaned" to be confusing here. "OK, this subvolume is now clean"? At
the very least this gives an impression that the desired condition is that
subvolume *still exists*, but is empty.
How about "Wait until given subvolume(s) are completely removed from the
filesystem. Does not return until all ongoing deletion requests (if any) on
given subvolume(s) are complete". And yeah, 'sync' sounds good and intuitive
enough.
> + "If no subvolume id is given, wait until there are no more snapshots",
Please don't intermix "subvolume" and "snapshot" like that. Better to use
"subvolume" in all cases to avoid confusion.
> + "to be cleaned. This may take long if new deleted subvolumes appear",
> + "during the sleep interval.",
> + "",
> + "-s <N> sleep N seconds between checks (default: 1)",
> + NULL
> +};
> +
> +static int is_subvolume_cleaned(int fd, u64 subvolid)
> +{
> + int ret;
> + struct btrfs_ioctl_search_args args;
> + struct btrfs_ioctl_search_key *sk = &args.key;
> +
> + sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
> + sk->min_objectid = subvolid;
> + sk->max_objectid = subvolid;
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->max_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_offset = 0;
> + sk->max_offset = (u64)-1;
> + sk->min_transid = 0;
> + sk->max_transid = (u64)-1;
> + sk->nr_items = 1;
> +
> + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
> + if (ret < 0)
> + return -errno;
> +
> + if (sk->nr_items == 0)
> + return 1;
> +
> + return 0;
> +}
> +
> +/*
> + * If we're looking for any dead subvolume, take a shortcut and look
> + * for any ORPHAN_ITEMs in the tree root
> + */
> +static int fs_has_dead_subvolumes(int fd)
> +{
> + int ret;
> + struct btrfs_ioctl_search_args args;
> + struct btrfs_ioctl_search_key *sk = &args.key;
> + struct btrfs_ioctl_search_header sh;
> + u64 min_subvolid = 0;
> +
> +again:
> + 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 = min_subvolid;
> + sk->max_offset = (u64)-1;
> + sk->min_transid = 0;
> + sk->max_transid = (u64)-1;
> + sk->nr_items = 1;
> +
> + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
> + if (ret < 0)
> + return -errno;
> +
> + if (!sk->nr_items)
> + return 0;
> +
> + memcpy(&sh, args.buf, sizeof(sh));
> + min_subvolid = sh.offset;
> +
> + /*
> + * Verify that the root item is really there and we haven't hit
> + * a stale orphan
> + */
> + sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
> + sk->min_objectid = min_subvolid;
> + sk->max_objectid = min_subvolid;
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->max_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_offset = 0;
> + sk->max_offset = (u64)-1;
> + sk->min_transid = 0;
> + sk->max_transid = (u64)-1;
> + sk->nr_items = 1;
> +
> + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
> + if (ret < 0)
> + return -errno;
> +
> + /*
> + * Stale orphan, try the next one
> + */
> + if (!sk->nr_items) {
> + min_subvolid++;
> + goto again;
> + }
> +
> + return 1;
> +}
> +
> +static int cmd_subvol_sync(int argc, char **argv)
> +{
> + int fd = -1;
> + int i;
> + int ret = 1;
> + DIR *dirstream = NULL;
> + u64 *ids = NULL;
> + int id_count;
> + int remaining;
> + int sleep_interval = 1;
> +
> + optind = 1;
> + while (1) {
> + int c = getopt(argc, argv, "s:");
> +
> + if (c < 0)
> + break;
> +
> + switch (c) {
> + case 's':
> + sleep_interval = atoi(argv[optind]);
> + if (sleep_interval < 1) {
> + fprintf(stderr,
> + "ERROR: invalid sleep interval %s\n",
> + argv[optind]);
> + ret = 1;
> + goto out;
> + }
> + break;
> + default:
> + usage(cmd_subvol_sync_usage);
> + }
> + }
> +
> + if (check_argc_min(argc - optind, 1))
> + usage(cmd_subvol_sync_usage);
> +
> + fd = open_file_or_dir(argv[optind], &dirstream);
> + if (fd < 0) {
> + fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
> + ret = 1;
> + goto out;
> + }
> + 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);
> + }
> + }
> +
> + /*
> + * 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 subovlume id %s\n",
Typo.
> + arg);
> + ret = 1;
> + goto out;
> + }
> + if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) {
> + fprintf(stderr, "ERROR: subovlume id %s out of range\n",
And here.
> + arg);
> + ret = 1;
> + goto out;
> + }
> + ids[i] = id;
> + }
> +
> + remaining = id_count;
> + while (1) {
> + for (i = 0; i < id_count; i++) {
> + if (!ids[i])
> + continue;
> + ret = is_subvolume_cleaned(fd, ids[i]);
> + if (ret < 0) {
> + fprintf(stderr, "ERROR: can't perform the search - %s\n",
> + strerror(-ret));
> + goto out;
> + }
> + if (ret) {
> + printf("Subvolume id %llu is gone\n", ids[i]);
> + ids[i] = 0;
> + remaining--;
> + }
> + }
> + if (!remaining)
> + break;
> + sleep(sleep_interval);
> + }
> +
> +out:
> + free(ids);
> + close_file_or_dir(fd, dirstream);
> +
> + return !!ret;
> +}
> +
> const struct cmd_group subvolume_cmd_group = {
> subvolume_cmd_group_usage, NULL, {
> { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
> @@ -1047,6 +1277,7 @@ const struct cmd_group subvolume_cmd_group = {
> cmd_subvol_set_default_usage, NULL, 0 },
> { "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
> { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
> + { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
> NULL_CMD_STRUCT
> }
> };
--
With respect,
Roman
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] btrfs-progs: wait until all subvolumes are cleaned
2014-07-30 11:55 ` Roman Mamedov
@ 2014-07-30 17:55 ` David Sterba
0 siblings, 0 replies; 4+ messages in thread
From: David Sterba @ 2014-07-30 17:55 UTC (permalink / raw)
To: Roman Mamedov; +Cc: linux-btrfs
Thanks for the feedback, appreciated.
On Wed, Jul 30, 2014 at 05:55:19PM +0600, Roman Mamedov wrote:
> > +static const char * const cmd_subvol_sync_usage[] = {
> > + "btrfs subvolume sync <path> [<subvol-id>...]",
> > + "Wait until given subvolume(s) are completely cleaned",
> > + "Wait until given subvolume(s) are completely cleaned after deletion.",
>
> I find "cleaned" to be confusing here. "OK, this subvolume is now clean"? At
> the very least this gives an impression that the desired condition is that
> subvolume *still exists*, but is empty.
>
> How about "Wait until given subvolume(s) are completely removed from the
> filesystem. Does not return until all ongoing deletion requests (if any) on
> given subvolume(s) are complete".
Sounds good, I'll use the text in the next version.
> > + "If no subvolume id is given, wait until there are no more snapshots",
>
> Please don't intermix "subvolume" and "snapshot" like that. Better to use
> "subvolume" in all cases to avoid confusion.
Good point, will fix it and the typos.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-07-30 17:55 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-23 20:56 [PATCH] btrfs-progs: wait until all subvolumes are cleaned David Sterba
2014-07-30 11:22 ` Justus Seifert
2014-07-30 11:55 ` Roman Mamedov
2014-07-30 17:55 ` David Sterba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).