From: Anand Jain <Anand.Jain@oracle.com>
To: Liu Bo <liubo2009@cn.fujitsu.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 3/3] Btrfs-progs: list snapshots by generation
Date: Thu, 02 Aug 2012 17:52:44 +0800 [thread overview]
Message-ID: <501A4DEC.2070901@oracle.com> (raw)
In-Reply-To: <1343713776-14232-3-git-send-email-liubo2009@cn.fujitsu.com>
Liu Bo,
I am trying to resolve a conflict with your patch vs Hugo'
integration branch
http://git.darksatanic.net/repo/btrfs-progs-unstable.git
(integration-20120605)
---
> @@ -185,11 +199,15 @@ static int add_root(struct root_lookup *root_lookup,
> ri->dir_id = dir_id;
> ri->root_id = root_id;
> ri->ref_tree = ref_tree;
> - strncpy(ri->name, name, name_len);
> + if (name)
> + strncpy(ri->name, name, name_len);
> if (name_len> 0)
> ri->name[name_len] = 0; <----here
> + if (gen)
> + ri->gen = *gen;
---
Per the original patch
http://permalink.gmane.org/gmane.comp.file-systems.btrfs/16914
it is ri->name[name_len-1] instead.
and I don't see any further patches which made it to be
ri->name[name_len] as in your patch. any idea?
Thanks, Anand
On 31/07/12 13:49, Liu Bo wrote:
> The idea is that we usually use snapshot to backup/restore our data, and the
> common way can be a cron script which makes lots of snapshots, so we can end
> up with spending some time to find the latest snapshot to restore.
>
> This adds a feature for 'btrfs subvolume list' to let it list snapshots by their
> _created_ generation.
>
> What we need to do is just to list them in descending order and get the latest
> snapshot. What's more, we can find the oldest snapshot as well by listing
> snapshots in ascending order.
>
> Signed-off-by: Liu Bo<liubo2009@cn.fujitsu.com>
> ---
> btrfs-list.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
> cmds-subvolume.c | 19 +++++-
> 2 files changed, 185 insertions(+), 10 deletions(-)
>
> diff --git a/btrfs-list.c b/btrfs-list.c
> index 05360dc..0374b41 100644
> --- a/btrfs-list.c
> +++ b/btrfs-list.c
> @@ -87,13 +87,23 @@ static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
> return 0;
> }
>
> +static int comp_entry_with_gen(struct root_info *entry, u64 root_id,
> + u64 ref_tree, u64 gen)
> +{
> + if (entry->gen< gen)
> + return 1;
> + if (entry->gen> gen)
> + return -1;
> + return comp_entry(entry, root_id, ref_tree);
> +}
> +
> /*
> * insert a new root into the tree. returns the existing root entry
> * if one is already there. Both root_id and ref_tree are used
> * as the key
> */
> static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
> - u64 ref_tree, struct rb_node *node)
> + u64 ref_tree, u64 *gen, struct rb_node *node)
> {
> struct rb_node ** p =&root->rb_node;
> struct rb_node * parent = NULL;
> @@ -104,7 +114,11 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
> parent = *p;
> entry = rb_entry(parent, struct root_info, rb_node);
>
> - comp = comp_entry(entry, root_id, ref_tree);
> + if (!gen)
> + comp = comp_entry(entry, root_id, ref_tree);
> + else
> + comp = comp_entry_with_gen(entry, root_id, ref_tree,
> + *gen);
>
> if (comp< 0)
> p =&(*p)->rb_left;
> @@ -171,7 +185,7 @@ static struct root_info *tree_search(struct rb_root *root, u64 root_id)
> */
> static int add_root(struct root_lookup *root_lookup,
> u64 root_id, u64 ref_tree, u64 dir_id, char *name,
> - int name_len)
> + int name_len, u64 *gen)
> {
> struct root_info *ri;
> struct rb_node *ret;
> @@ -185,11 +199,15 @@ static int add_root(struct root_lookup *root_lookup,
> ri->dir_id = dir_id;
> ri->root_id = root_id;
> ri->ref_tree = ref_tree;
> - strncpy(ri->name, name, name_len);
> + if (name)
> + strncpy(ri->name, name, name_len);
> if (name_len> 0)
> ri->name[name_len] = 0;
> + if (gen)
> + ri->gen = *gen;
>
> - ret = tree_insert(&root_lookup->root, root_id, ref_tree,&ri->rb_node);
> + ret = tree_insert(&root_lookup->root, root_id, ref_tree, gen,
> + &ri->rb_node);
> if (ret) {
> printf("failed to insert tree %llu\n", (unsigned long long)root_id);
> exit(1);
> @@ -693,7 +711,7 @@ again:
> dir_id = btrfs_stack_root_ref_dirid(ref);
>
> add_root(root_lookup, sh->objectid, sh->offset,
> - dir_id, name, name_len);
> + dir_id, name, name_len, NULL);
> } else if (get_gen&& sh->type == BTRFS_ROOT_ITEM_KEY) {
> ri = (struct btrfs_root_item *)(args.buf + off);
> gen = btrfs_root_generation(ri);
> @@ -750,6 +768,79 @@ again:
> return 0;
> }
>
> +static int __list_snapshot_search(int fd, struct root_lookup *root_lookup)
> +{
> + int ret;
> + struct btrfs_ioctl_search_args args;
> + struct btrfs_ioctl_search_key *sk =&args.key;
> + struct btrfs_ioctl_search_header *sh;
> + unsigned long off = 0;
> + u64 gen = 0;
> + int i;
> +
> + root_lookup_init(root_lookup);
> + memset(&args, 0, sizeof(args));
> +
> + sk->tree_id = 1;
> + sk->max_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
> + sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
> + sk->max_offset = (u64)-1;
> + sk->max_transid = (u64)-1;
> + sk->nr_items = 4096;
> +
> + while (1) {
> + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH,&args);
> + if (ret< 0)
> + return ret;
> + /* the ioctl returns the number of item it found in nr_items */
> + if (sk->nr_items == 0)
> + break;
> +
> + off = 0;
> +
> + /*
> + * for each item, pull the key out of the header and then
> + * read the root_ref item it contains
> + */
> + for (i = 0; i< sk->nr_items; i++) {
> + sh = (struct btrfs_ioctl_search_header *)(args.buf +
> + off);
> + off += sizeof(*sh);
> + if (sh->type == BTRFS_ROOT_ITEM_KEY&& sh->offset) {
> + gen = sh->offset;
> +
> + add_root(root_lookup, sh->objectid, 0,
> + 0, NULL, 0,&gen);
> + }
> + off += sh->len;
> +
> + /*
> + * record the mins in sk so we can make sure the
> + * next search doesn't repeat this root
> + */
> + sk->min_objectid = sh->objectid;
> + sk->min_type = sh->type;
> + sk->min_offset = sh->offset;
> + }
> + sk->nr_items = 4096;
> + /* this iteration is done, step forward one root for the next
> + * ioctl
> + */
> + if (sk->min_type< BTRFS_ROOT_ITEM_KEY) {
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_offset = 0;
> + } else if (sk->min_objectid< BTRFS_LAST_FREE_OBJECTID) {
> + sk->min_objectid++;
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_offset = 0;
> + } else
> + break;
> + }
> + return 0;
> +}
> +
> static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
> {
> struct rb_node *n;
> @@ -847,6 +938,79 @@ int list_subvols(int fd, int print_parent, int get_default)
> return ret;
> }
>
> +int list_snapshots(int fd, int print_parent, int order)
> +{
> + struct root_lookup root_lookup;
> + struct root_lookup root_lookup_snap;
> + struct rb_node *n;
> + int ret;
> +
> + ret = __list_snapshot_search(fd,&root_lookup_snap);
> + if (ret) {
> + fprintf(stderr, "ERROR: can't perform the search - %s\n",
> + strerror(errno));
> + return ret;
> + }
> +
> + ret = __list_subvol_search(fd,&root_lookup);
> + if (ret) {
> + fprintf(stderr, "ERROR: can't perform the search - %s\n",
> + strerror(errno));
> + return ret;
> + }
> +
> + /*
> + * now we have an rbtree full of root_info objects, but we need to fill
> + * in their path names within the subvol that is referencing each one.
> + */
> + ret = __list_subvol_fill_paths(fd,&root_lookup);
> + if (ret< 0)
> + return ret;
> +
> + /* now that we have all the subvol-relative paths filled in,
> + * we have to string the subvols together so that we can get
> + * a path all the way back to the FS root
> + */
> + if (!order)
> + n = rb_last(&root_lookup_snap.root);
> + else
> + n = rb_first(&root_lookup_snap.root);
> + while (n) {
> + struct root_info *entry_snap;
> + struct root_info *entry;
> + u64 level;
> + u64 parent_id;
> + char *path;
> +
> + entry_snap = rb_entry(n, struct root_info, rb_node);
> + entry = tree_search(&root_lookup.root, entry_snap->root_id);
> +
> + resolve_root(&root_lookup, entry,&parent_id,&level,&path);
> + if (print_parent) {
> + printf("ID %llu gen %llu cgen %llu parent %llu top level %llu path %s\n",
> + (unsigned long long)entry->root_id,
> + (unsigned long long)entry->gen,
> + (unsigned long long)entry_snap->gen,
> + (unsigned long long)parent_id,
> + (unsigned long long)level, path);
> + } else {
> + printf("ID %llu gen %llu cgen %llu top level %llu path %s\n",
> + (unsigned long long)entry->root_id,
> + (unsigned long long)entry->gen,
> + (unsigned long long)entry_snap->gen,
> + (unsigned long long)level, path);
> + }
> +
> + free(path);
> + if (!order)
> + n = rb_prev(n);
> + else
> + n = rb_next(n);
> + }
> +
> + return ret;
> +}
> +
> static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
> struct btrfs_file_extent_item *item,
> u64 found_gen, u64 *cache_dirid,
> diff --git a/cmds-subvolume.c b/cmds-subvolume.c
> index 3508ce6..9c75b47 100644
> --- a/cmds-subvolume.c
> +++ b/cmds-subvolume.c
> @@ -219,10 +219,12 @@ static int cmd_subvol_delete(int argc, char **argv)
> }
>
> static const char * const cmd_subvol_list_usage[] = {
> - "btrfs subvolume list [-p]<path>",
> + "btrfs subvolume list [-ps]<path>",
> "List subvolumes (and snapshots)",
> "",
> - "-p print parent ID",
> + "-p print parent ID",
> + "-s value list snapshots with generation in ascending/descending order",
> + " (1: ascending, 0: descending)",
> NULL
> };
>
> @@ -231,11 +233,13 @@ static int cmd_subvol_list(int argc, char **argv)
> int fd;
> int ret;
> int print_parent = 0;
> + int print_snap_only = 0;
> + int order = 0;
> char *subvol;
>
> optind = 1;
> while(1) {
> - int c = getopt(argc, argv, "p");
> + int c = getopt(argc, argv, "ps:");
> if (c< 0)
> break;
>
> @@ -243,6 +247,10 @@ static int cmd_subvol_list(int argc, char **argv)
> case 'p':
> print_parent = 1;
> break;
> + case 's':
> + print_snap_only = 1;
> + order = atoi(optarg);
> + break;
> default:
> usage(cmd_subvol_list_usage);
> }
> @@ -268,7 +276,10 @@ static int cmd_subvol_list(int argc, char **argv)
> fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
> return 12;
> }
> - ret = list_subvols(fd, print_parent, 0);
> + if (!print_snap_only)
> + ret = list_subvols(fd, print_parent, 0);
> + else
> + ret = list_snapshots(fd, print_parent, order);
> if (ret)
> return 19;
> return 0;
prev parent reply other threads:[~2012-08-02 9:53 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-31 5:49 [PATCH 1/3 RESEND] Btrfs-progs: search subvolumes with proper objectid Liu Bo
2012-07-31 5:49 ` [PATCH 2/3 RESEND] Btrfs-progs: show generation in command btrfs subvol list Liu Bo
2012-07-31 5:49 ` [PATCH 3/3] Btrfs-progs: list snapshots by generation Liu Bo
2012-07-31 21:16 ` Goffredo Baroncelli
2012-08-01 11:28 ` Liu Bo
2012-08-02 9:52 ` Anand Jain [this message]
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=501A4DEC.2070901@oracle.com \
--to=anand.jain@oracle.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=liubo2009@cn.fujitsu.com \
/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 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).