linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] add crtime to the snapshot list
@ 2012-08-01 12:01 Anand jain
  2012-08-01 12:01 ` [PATCH] Btrfs-progs: show crtime in " Anand jain
                   ` (3 more replies)
  0 siblings, 4 replies; 18+ messages in thread
From: Anand jain @ 2012-08-01 12:01 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand

From: Anand <anand.jain@oracle.com>

 This patch adds creation-time to the snapshot list display,
 which would help user to better manage the snapshots when
 number of snapshots grow substantially. This patch is developed
 and on top of the send/receive btrfs and btrfs-progs repo at 
  git://github.com/ablock84/linux-btrfs.git (send-v2)
  git://github.com/ablock84/btrfs-progs.git (send-v2)
 respectively.

 Further this patch has the dependency on the following patches
  Liu Bo:
   [PATCH 2/3 RESEND] Btrfs-progs: show generation in command btrfs subvol list
   [PATCH 3/3] Btrfs-progs: list snapshots by generation

 Eg output:
   #btrfs su list -s 1 /btrfs
   ID 258 gen 39 cgen 6 top level 5 crtime 2012-07-27 17:43:55 path ss1
   ID 260 gen 8 cgen 8 top level 5 crtime 2012-07-27 17:47:51 path ss2
   ID 263 gen 16 cgen 16 top level 5 crtime 2012-07-29 00:50:19 path ss3
   ID 264 gen 25 cgen 25 top level 5 crtime 2012-07-30 09:56:50 path sv1/.snap

Anand Jain (1):
  Btrfs-progs: show crtime in the snapshot list

 btrfs-list.c |   45 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 36 insertions(+), 9 deletions(-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] Btrfs-progs: show crtime in the snapshot list
  2012-08-01 12:01 [PATCH] add crtime to the snapshot list Anand jain
@ 2012-08-01 12:01 ` Anand jain
  2012-08-01 12:14 ` [PATCH] add crtime to " Alexander Block
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-01 12:01 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>


Signed-off-by: Anand <anand.jain@oracle.com>
---
 btrfs-list.c |   45 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index c6bfb1e..2102d00 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -60,6 +60,9 @@ struct root_info {
 	/* generation when the root is created or last updated */
 	u64 gen;
 
+	/* creation time of this root in sec*/
+	time_t otime;
+
 	/* path from the subvol we live in to this root, including the
 	 * root's name.  This is null until we do the extra lookup ioctl.
 	 */
@@ -185,7 +188,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, u64 *gen)
+		    int name_len, u64 *gen, time_t ot)
 {
 	struct root_info *ri;
 	struct rb_node *ret;
@@ -205,6 +208,7 @@ static int add_root(struct root_lookup *root_lookup,
 		ri->name[name_len] = 0;
 	if (gen)
 		ri->gen = *gen;
+	ri->otime = ot;
 
 	ret = tree_insert(&root_lookup->root, root_id, ref_tree, gen,
 			  &ri->rb_node);
@@ -215,7 +219,8 @@ static int add_root(struct root_lookup *root_lookup,
 	return 0;
 }
 
-static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen)
+static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen,
+			time_t ot)
 {
 	struct root_info *ri;
 
@@ -225,6 +230,7 @@ static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen)
 		return -ENOENT;
 	}
 	ri->gen = gen;
+	ri->otime = ot;
 	return 0;
 }
 
@@ -658,6 +664,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	u64 gen = 0;
 	int i;
 	int get_gen = 0;
+	time_t	t;
 
 	root_lookup_init(root_lookup);
 	memset(&args, 0, sizeof(args));
@@ -711,12 +718,16 @@ again:
 				dir_id = btrfs_stack_root_ref_dirid(ref);
 
 				add_root(root_lookup, sh->objectid, sh->offset,
-					 dir_id, name, name_len, NULL);
+					 dir_id, name, name_len, NULL, 0);
 			} else if (get_gen && sh->type == BTRFS_ROOT_ITEM_KEY) {
 				ri = (struct btrfs_root_item *)(args.buf + off);
 				gen = btrfs_root_generation(ri);
+				if(ri->generation == ri->generation_v2)
+					t = ri->otime.sec;
+				else
+					t = 0;
 
-				update_root(root_lookup, sh->objectid, gen);
+				update_root(root_lookup, sh->objectid, gen, t);
 			}
 
 			off += sh->len;
@@ -805,14 +816,21 @@ static int __list_snapshot_search(int fd, struct root_lookup *root_lookup)
 		 * read the root_ref item it contains
 		 */
 		for (i = 0; i < sk->nr_items; i++) {
+			struct btrfs_root_item *item;
+			time_t	t;
 			sh = (struct btrfs_ioctl_search_header *)(args.buf +
 								  off);
 			off += sizeof(*sh);
 			if (sh->type == BTRFS_ROOT_ITEM_KEY && sh->offset) {
+				item = (struct btrfs_root_item *)(args.buf + off);
+				if(item->generation == item->generation_v2)
+					t = item->otime.sec;
+				else
+					t = 0;
 				gen = sh->offset;
 
 				add_root(root_lookup, sh->objectid, 0,
-					 0, NULL, 0, &gen);
+					 0, NULL, 0, &gen, t);
 			}
 			off += sh->len;
 
@@ -981,24 +999,33 @@ int list_snapshots(int fd, int print_parent, int order)
 		u64 level;
 		u64 parent_id;
 		char *path;
+		time_t t;
+		char tstr[256];
 
 		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);
+		t = entry->otime;
+		if(t)
+			strftime(tstr,256,"%Y-%m-%d %X",localtime(&t));
+		else
+			strcpy(tstr,"-");
 		if (print_parent) {
-			printf("ID %llu gen %llu cgen %llu parent %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu cgen %llu parent %llu top level %llu "
+				"crtime %s 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);
+				(unsigned long long)level, tstr, path);
 		} else {
-			printf("ID %llu gen %llu cgen %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu cgen %llu top level %llu "
+				"crtime %s 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);
+				(unsigned long long)level, tstr, path);
 		}
 
 		free(path);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] add crtime to the snapshot list
  2012-08-01 12:01 [PATCH] add crtime to the snapshot list Anand jain
  2012-08-01 12:01 ` [PATCH] Btrfs-progs: show crtime in " Anand jain
@ 2012-08-01 12:14 ` Alexander Block
  2012-08-01 15:56   ` anand jain
  2012-08-01 12:43 ` Liu Bo
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
  3 siblings, 1 reply; 18+ messages in thread
From: Alexander Block @ 2012-08-01 12:14 UTC (permalink / raw)
  To: Anand jain; +Cc: linux-btrfs

On Wed, Aug 1, 2012 at 2:01 PM, Anand jain <Anand.Jain@oracle.com> wrote:
> From: Anand <anand.jain@oracle.com>
>
>  This patch adds creation-time to the snapshot list display,
>  which would help user to better manage the snapshots when
>  number of snapshots grow substantially. This patch is developed
>  and on top of the send/receive btrfs and btrfs-progs repo at
>   git://github.com/ablock84/linux-btrfs.git (send-v2)
>   git://github.com/ablock84/btrfs-progs.git (send-v2)
>  respectively.
>
Cool, that would helpful.
>  Further this patch has the dependency on the following patches
>   Liu Bo:
>    [PATCH 2/3 RESEND] Btrfs-progs: show generation in command btrfs subvol list
>    [PATCH 3/3] Btrfs-progs: list snapshots by generation
>
>  Eg output:
>    #btrfs su list -s 1 /btrfs
>    ID 258 gen 39 cgen 6 top level 5 crtime 2012-07-27 17:43:55 path ss1
>    ID 260 gen 8 cgen 8 top level 5 crtime 2012-07-27 17:47:51 path ss2
>    ID 263 gen 16 cgen 16 top level 5 crtime 2012-07-29 00:50:19 path ss3
>    ID 264 gen 25 cgen 25 top level 5 crtime 2012-07-30 09:56:50 path sv1/.snap
Is it possible to rename crtime to otime? I used otime to refer
creation time all the time. Using crtime could be confusing, as ctime
is the change time and rtime is the receive time.
>
> Anand Jain (1):
>   Btrfs-progs: show crtime in the snapshot list
>
>  btrfs-list.c |   45 ++++++++++++++++++++++++++++++++++++---------
>  1 files changed, 36 insertions(+), 9 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] add crtime to the snapshot list
  2012-08-01 12:01 [PATCH] add crtime to the snapshot list Anand jain
  2012-08-01 12:01 ` [PATCH] Btrfs-progs: show crtime in " Anand jain
  2012-08-01 12:14 ` [PATCH] add crtime to " Alexander Block
@ 2012-08-01 12:43 ` Liu Bo
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
  3 siblings, 0 replies; 18+ messages in thread
From: Liu Bo @ 2012-08-01 12:43 UTC (permalink / raw)
  To: Anand jain; +Cc: linux-btrfs

On 08/01/2012 08:01 PM, Anand jain wrote:
> From: Anand <anand.jain@oracle.com>
> 
>  This patch adds creation-time to the snapshot list display,
>  which would help user to better manage the snapshots when
>  number of snapshots grow substantially. This patch is developed
>  and on top of the send/receive btrfs and btrfs-progs repo at 
>   git://github.com/ablock84/linux-btrfs.git (send-v2)
>   git://github.com/ablock84/btrfs-progs.git (send-v2)
>  respectively.
> 

Hi Arand,

Can you please also post the patch itself here?

thanks,
liubo

>  Further this patch has the dependency on the following patches
>   Liu Bo:
>    [PATCH 2/3 RESEND] Btrfs-progs: show generation in command btrfs subvol list
>    [PATCH 3/3] Btrfs-progs: list snapshots by generation
> 
>  Eg output:
>    #btrfs su list -s 1 /btrfs
>    ID 258 gen 39 cgen 6 top level 5 crtime 2012-07-27 17:43:55 path ss1
>    ID 260 gen 8 cgen 8 top level 5 crtime 2012-07-27 17:47:51 path ss2
>    ID 263 gen 16 cgen 16 top level 5 crtime 2012-07-29 00:50:19 path ss3
>    ID 264 gen 25 cgen 25 top level 5 crtime 2012-07-30 09:56:50 path sv1/.snap
> 
> Anand Jain (1):
>   Btrfs-progs: show crtime in the snapshot list
> 
>  btrfs-list.c |   45 ++++++++++++++++++++++++++++++++++++---------
>  1 files changed, 36 insertions(+), 9 deletions(-)
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] add crtime to the snapshot list
  2012-08-01 12:14 ` [PATCH] add crtime to " Alexander Block
@ 2012-08-01 15:56   ` anand jain
  0 siblings, 0 replies; 18+ messages in thread
From: anand jain @ 2012-08-01 15:56 UTC (permalink / raw)
  To: Alexander Block; +Cc: linux-btrfs


>>   Eg output:
>>     #btrfs su list -s 1 /btrfs
>>     ID 258 gen 39 cgen 6 top level 5 crtime 2012-07-27 17:43:55 path ss1
>>     ID 260 gen 8 cgen 8 top level 5 crtime 2012-07-27 17:47:51 path ss2
>>     ID 263 gen 16 cgen 16 top level 5 crtime 2012-07-29 00:50:19 path ss3
>>     ID 264 gen 25 cgen 25 top level 5 crtime 2012-07-30 09:56:50 path sv1/.snap
> Is it possible to rename crtime to otime? I used otime to refer
> creation time all the time. Using crtime could be confusing, as ctime
> is the change time and rtime is the receive time.

  Yeah.  Will rename it to otime

  just to mention the choices were..
      Birth-time (as in stat output), crtime and otime.

Thanks, Anand

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 0/9 V2] Include otime in the snapshot list
  2012-08-01 12:01 [PATCH] add crtime to the snapshot list Anand jain
                   ` (2 preceding siblings ...)
  2012-08-01 12:43 ` Liu Bo
@ 2012-08-03  9:48 ` Anand jain
  2012-08-03  9:48   ` [PATCH] Btrfs: introduce subvol uuids and times Anand jain
                     ` (10 more replies)
  3 siblings, 11 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>

 Thanks to Alexander Block and Liu Bo for the review.
 Changes from V1 -> V2:
   . renamed crtime to otime
   . included the dependent btrfs-progs and btrfs kernel
      patches as below and in email following this respectively
   . fix bug in the btrfs su list 

 btrfs kernel dependency:
  otime is added by the kernel patch:
    [RFC PATCH 4/7] Btrfs: introduce subvol uuids and times
  this btrfs-progs patch has been unit-tested to work fine
  for both the cases that is snapshots created with and
  without the otime/above-kerne-patch, this patch will
  print the otime and/or "-" in the respective scenarios.

 Eg:
  # btrfs su list -s 1 /btrfs2
  ID 259 gen 8 cgen 8 top level 5 otime - path sv-old-gen1/.snapshot/ss1-old-gen1
  ID 261 gen 13 cgen 13 top level 5 otime - path sv-old-gen1/.snapshot/ss2
  ID 262 gen 18 cgen 18 top level 5 otime 2012-08-03 16:08:59 path sv-old-gen1/.snapshot/ss3-on-new

Alexander Block (1):
  Update ctree.h and ioctl.h for the new uuid+times for subvolumes.

Anand Jain (2):
  Btrfs-progs: add otime to the snapshot list
  Btrfs-progs: fix the btrfs subvol list path last char

Ilya Dryomov (3):
  Btrfs-progs: refactor resolve_root() function a bit
  Btrfs-progs: nuke redundant zeroing in __list_subvol_search()
  Btrfs-progs: bring 'subvol get-default' back in

Liu Bo (3):
  Btrfs-progs: search subvolumes with proper objectid
  Btrfs-progs: show generation in command btrfs subvol list
  Btrfs-progs: list snapshots by generation

 btrfs-list.c     |  378 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 cmds-subvolume.c |   19 ++-
 ctree.h          |   42 ++++++-
 ioctl.h          |   12 ++
 print-tree.c     |   79 +++++++++---
 5 files changed, 476 insertions(+), 54 deletions(-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] Btrfs: introduce subvol uuids and times
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 1/9] Update ctree.h and ioctl.h for the new uuid+times for subvolumes Anand jain
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Alexander Block

From: Alexander Block <ablock84@googlemail.com>

This patch introduces uuids for subvolumes. Each
subvolume has it's own uuid. In case it was snapshotted,
it also contains parent_uuid. In case it was received,
it also contains received_uuid.

It also introduces subvolume ctime/otime/stime/rtime. The
first two are comparable to the times found in inodes. otime
is the origin/creation time and ctime is the change time.
stime/rtime are only valid on received subvolumes.
stime is the time of the subvolume when it was
sent. rtime is the time of the subvolume when it was
received.

Additionally to the times, we have a transid for each
time. They are updated at the same place as the times.

btrfs receive uses stransid and rtransid to find out
if a received subvolume changed in the meantime.

If an older kernel mounts a filesystem with the
extented fields, all fields become invalid. The next
mount with a new kernel will detect this and reset the
fields.

Signed-off-by: Alexander Block <ablock84@googlemail.com>
---
 fs/btrfs/ctree.h       |   43 +++++++++++++++++++++
 fs/btrfs/disk-io.c     |    2 +
 fs/btrfs/inode.c       |    4 ++
 fs/btrfs/ioctl.c       |   96 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/btrfs/ioctl.h       |   13 ++++++
 fs/btrfs/root-tree.c   |   92 +++++++++++++++++++++++++++++++++++++++++++---
 fs/btrfs/transaction.c |   17 ++++++++
 7 files changed, 258 insertions(+), 9 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fa5c45b..982815b 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -709,6 +709,35 @@ struct btrfs_root_item {
 	struct btrfs_disk_key drop_progress;
 	u8 drop_level;
 	u8 level;
+
+	/*
+	 * The following fields appear after subvol_uuids+subvol_times
+	 * were introduced.
+	 */
+
+	/*
+	 * This generation number is used to test if the new fields are valid
+	 * and up to date while reading the root item. Everytime the root item
+	 * is written out, the "generation" field is copied into this field. If
+	 * anyone ever mounted the fs with an older kernel, we will have
+	 * mismatching generation values here and thus must invalidate the
+	 * new fields. See btrfs_update_root and btrfs_find_last_root for
+	 * details.
+	 * the offset of generation_v2 is also used as the start for the memset
+	 * when invalidating the fields.
+	 */
+	__le64 generation_v2;
+	u8 uuid[BTRFS_UUID_SIZE];
+	u8 parent_uuid[BTRFS_UUID_SIZE];
+	u8 received_uuid[BTRFS_UUID_SIZE];
+	__le64 ctransid; /* updated when an inode changes */
+	__le64 otransid; /* trans when created */
+	__le64 stransid; /* trans when sent. non-zero for received subvol */
+	__le64 rtransid; /* trans when received. non-zero for received subvol */
+	struct btrfs_timespec ctime;
+	struct btrfs_timespec otime;
+	struct btrfs_timespec stime;
+	struct btrfs_timespec rtime;
 } __attribute__ ((__packed__));
 
 /*
@@ -1416,6 +1445,8 @@ struct btrfs_root {
 	dev_t anon_dev;
 
 	int force_cow;
+
+	spinlock_t root_times_lock;
 };
 
 struct btrfs_ioctl_defrag_range_args {
@@ -2189,6 +2220,16 @@ BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
 BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
 BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
 			 last_snapshot, 64);
+BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
+			 generation_v2, 64);
+BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,
+			 ctransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,
+			 otransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
+			 stransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
+			 rtransid, 64);
 
 static inline bool btrfs_root_readonly(struct btrfs_root *root)
 {
@@ -2826,6 +2867,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
 void btrfs_set_root_node(struct btrfs_root_item *item,
 			 struct extent_buffer *node);
 void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
+void btrfs_update_root_times(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root);
 
 /* dir-item.c */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2936ca4..62aa391 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
 	root->defrag_running = 0;
 	root->root_key.objectid = objectid;
 	root->anon_dev = 0;
+
+	spin_lock_init(&root->root_times_lock);
 }
 
 static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a7d1921..4ffc873 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2734,6 +2734,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
 	 */
 	if (!btrfs_is_free_space_inode(root, inode)
 	    && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
+		btrfs_update_root_times(trans, root);
+
 		ret = btrfs_delayed_update_inode(trans, root, inode);
 		if (!ret)
 			btrfs_set_inode_last_trans(trans, inode);
@@ -4723,6 +4725,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	trace_btrfs_inode_new(inode);
 	btrfs_set_inode_last_trans(trans, inode);
 
+	btrfs_update_root_times(trans, root);
+
 	return inode;
 fail:
 	if (dir)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 0e92e57..db2bbc7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -41,6 +41,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
+#include <linux/uuid.h>
 #include "compat.h"
 #include "ctree.h"
 #include "disk-io.h"
@@ -346,11 +347,13 @@ static noinline int create_subvol(struct btrfs_root *root,
 	struct btrfs_root *new_root;
 	struct dentry *parent = dentry->d_parent;
 	struct inode *dir;
+	struct timespec cur_time = CURRENT_TIME;
 	int ret;
 	int err;
 	u64 objectid;
 	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
 	u64 index = 0;
+	uuid_le new_uuid;
 
 	ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
 	if (ret)
@@ -389,8 +392,9 @@ static noinline int create_subvol(struct btrfs_root *root,
 			    BTRFS_UUID_SIZE);
 	btrfs_mark_buffer_dirty(leaf);
 
+	memset(&root_item, 0, sizeof(root_item));
+
 	inode_item = &root_item.inode;
-	memset(inode_item, 0, sizeof(*inode_item));
 	inode_item->generation = cpu_to_le64(1);
 	inode_item->size = cpu_to_le64(3);
 	inode_item->nlink = cpu_to_le32(1);
@@ -408,8 +412,15 @@ static noinline int create_subvol(struct btrfs_root *root,
 	btrfs_set_root_used(&root_item, leaf->len);
 	btrfs_set_root_last_snapshot(&root_item, 0);
 
-	memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
-	root_item.drop_level = 0;
+	btrfs_set_root_generation_v2(&root_item,
+			btrfs_root_generation(&root_item));
+	uuid_le_gen(&new_uuid);
+	memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE);
+	root_item.otime.sec = cpu_to_le64(cur_time.tv_sec);
+	root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec);
+	root_item.ctime = root_item.otime;
+	btrfs_set_root_ctransid(&root_item, trans->transid);
+	btrfs_set_root_otransid(&root_item, trans->transid);
 
 	btrfs_tree_unlock(leaf);
 	free_extent_buffer(leaf);
@@ -3390,6 +3401,83 @@ out:
 	return ret;
 }
 
+static long btrfs_ioctl_set_received_subvol(struct file *file,
+					    void __user *arg)
+{
+	struct btrfs_ioctl_received_subvol_args *sa = NULL;
+	struct inode *inode = fdentry(file)->d_inode;
+	struct btrfs_root *root = BTRFS_I(inode)->root;
+	struct btrfs_root_item *root_item = &root->root_item;
+	struct btrfs_trans_handle *trans;
+	int ret = 0;
+
+	ret = mnt_want_write_file(file);
+	if (ret < 0)
+		return ret;
+
+	down_write(&root->fs_info->subvol_sem);
+
+	if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (btrfs_root_readonly(root)) {
+		ret = -EROFS;
+		goto out;
+	}
+
+	if (!inode_owner_or_capable(inode)) {
+		ret = -EACCES;
+		goto out;
+	}
+
+	sa = memdup_user(arg, sizeof(*sa));
+	if (IS_ERR(sa)) {
+		ret = PTR_ERR(sa);
+		sa = NULL;
+		goto out;
+	}
+
+	trans = btrfs_start_transaction(root, 1);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		trans = NULL;
+		goto out;
+	}
+
+	sa->rtransid = trans->transid;
+	sa->rtime = CURRENT_TIME;
+
+	memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
+	btrfs_set_root_stransid(root_item, sa->stransid);
+	btrfs_set_root_rtransid(root_item, sa->rtransid);
+	root_item->stime.sec = cpu_to_le64(sa->stime.tv_sec);
+	root_item->stime.nsec = cpu_to_le64(sa->stime.tv_nsec);
+	root_item->rtime.sec = cpu_to_le64(sa->rtime.tv_sec);
+	root_item->rtime.nsec = cpu_to_le64(sa->rtime.tv_nsec);
+
+	ret = btrfs_update_root(trans, root->fs_info->tree_root,
+				&root->root_key, &root->root_item);
+	if (ret < 0) {
+		goto out;
+	} else {
+		ret = btrfs_commit_transaction(trans, root);
+		if (ret < 0)
+			goto out;
+	}
+
+	ret = copy_to_user(arg, sa, sizeof(*sa));
+	if (ret)
+		ret = -EFAULT;
+
+out:
+	kfree(sa);
+	up_write(&root->fs_info->subvol_sem);
+	mnt_drop_write_file(file);
+	return ret;
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
 		cmd, unsigned long arg)
 {
@@ -3472,6 +3560,8 @@ long btrfs_ioctl(struct file *file, unsigned int
 		return btrfs_ioctl_balance_ctl(root, arg);
 	case BTRFS_IOC_BALANCE_PROGRESS:
 		return btrfs_ioctl_balance_progress(root, argp);
+	case BTRFS_IOC_SET_RECEIVED_SUBVOL:
+		return btrfs_ioctl_set_received_subvol(file, argp);
 	case BTRFS_IOC_GET_DEV_STATS:
 		return btrfs_ioctl_get_dev_stats(root, argp, 0);
 	case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index e440aa6..c9e3fac 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -295,6 +295,15 @@ struct btrfs_ioctl_get_dev_stats {
 	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
 };
 
+struct btrfs_ioctl_received_subvol_args {
+	char	uuid[BTRFS_UUID_SIZE];	/* in */
+	__u64	stransid;		/* in */
+	__u64	rtransid;		/* out */
+	struct timespec stime;		/* in */
+	struct timespec rtime;		/* out */
+	__u64	reserved[16];
+};
+
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
 				   struct btrfs_ioctl_vol_args)
 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -359,6 +368,10 @@ struct btrfs_ioctl_get_dev_stats {
 					struct btrfs_ioctl_ino_path_args)
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
 					struct btrfs_ioctl_ino_path_args)
+
+#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
+				struct btrfs_ioctl_received_subvol_args)
+
 #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
 				      struct btrfs_ioctl_get_dev_stats)
 #define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 24fb8ce..17d638e 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -16,6 +16,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#include <linux/uuid.h>
 #include "ctree.h"
 #include "transaction.h"
 #include "disk-io.h"
@@ -25,6 +26,9 @@
  * lookup the root with the highest offset for a given objectid.  The key we do
  * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
  * on error.
+ * We also check if the root was once mounted with an older kernel. If we detect
+ * this, the new fields coming after 'level' get overwritten with zeros so to
+ * invalidate the fields.
  */
 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
 			struct btrfs_root_item *item, struct btrfs_key *key)
@@ -35,6 +39,9 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
 	struct extent_buffer *l;
 	int ret;
 	int slot;
+	int len;
+	int need_reset = 0;
+	uuid_le uuid;
 
 	search_key.objectid = objectid;
 	search_key.type = BTRFS_ROOT_ITEM_KEY;
@@ -60,11 +67,36 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
 		ret = 1;
 		goto out;
 	}
-	if (item)
+	if (item) {
+		len = btrfs_item_size_nr(l, slot);
 		read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
-				   sizeof(*item));
+				min_t(int, len, (int)sizeof(*item)));
+		if (len < sizeof(*item))
+			need_reset = 1;
+		if (!need_reset && btrfs_root_generation(item)
+			!= btrfs_root_generation_v2(item)) {
+			if (btrfs_root_generation_v2(item) != 0) {
+				printk(KERN_WARNING "btrfs: mismatching "
+						"generation and generation_v2 "
+						"found in root item. This root "
+						"was probably mounted with an "
+						"older kernel. Resetting all "
+						"new fields.\n");
+			}
+			need_reset = 1;
+		}
+		if (need_reset) {
+			memset(&item->generation_v2, 0,
+				sizeof(*item) - offsetof(struct btrfs_root_item,
+						generation_v2));
+
+			uuid_le_gen(&uuid);
+			memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE);
+		}
+	}
 	if (key)
 		memcpy(key, &found_key, sizeof(found_key));
+
 	ret = 0;
 out:
 	btrfs_free_path(path);
@@ -91,16 +123,15 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 	int ret;
 	int slot;
 	unsigned long ptr;
+	int old_len;
 
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
 
 	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
-	if (ret < 0) {
-		btrfs_abort_transaction(trans, root, ret);
-		goto out;
-	}
+	if (ret < 0)
+		goto out_abort;
 
 	if (ret != 0) {
 		btrfs_print_leaf(root, path->nodes[0]);
@@ -113,11 +144,47 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 	l = path->nodes[0];
 	slot = path->slots[0];
 	ptr = btrfs_item_ptr_offset(l, slot);
+	old_len = btrfs_item_size_nr(l, slot);
+
+	/*
+	 * If this is the first time we update the root item which originated
+	 * from an older kernel, we need to enlarge the item size to make room
+	 * for the added fields.
+	 */
+	if (old_len < sizeof(*item)) {
+		btrfs_release_path(path);
+		ret = btrfs_search_slot(trans, root, key, path,
+				-1, 1);
+		if (ret < 0)
+			goto out_abort;
+		ret = btrfs_del_item(trans, root, path);
+		if (ret < 0)
+			goto out_abort;
+		btrfs_release_path(path);
+		ret = btrfs_insert_empty_item(trans, root, path,
+				key, sizeof(*item));
+		if (ret < 0)
+			goto out_abort;
+		l = path->nodes[0];
+		slot = path->slots[0];
+		ptr = btrfs_item_ptr_offset(l, slot);
+	}
+
+	/*
+	 * Update generation_v2 so at the next mount we know the new root
+	 * fields are valid.
+	 */
+	btrfs_set_root_generation_v2(item, btrfs_root_generation(item));
+
 	write_extent_buffer(l, item, ptr, sizeof(*item));
 	btrfs_mark_buffer_dirty(path->nodes[0]);
 out:
 	btrfs_free_path(path);
 	return ret;
+
+out_abort:
+	btrfs_abort_transaction(trans, root, ret);
+	goto out;
 }
 
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -454,3 +521,16 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item)
 		root_item->byte_limit = 0;
 	}
 }
+
+void btrfs_update_root_times(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root)
+{
+	struct btrfs_root_item *item = &root->root_item;
+	struct timespec ct = CURRENT_TIME;
+
+	spin_lock(&root->root_times_lock);
+	item->ctransid = trans->transid;
+	item->ctime.sec = cpu_to_le64(ct.tv_sec);
+	item->ctime.nsec = cpu_to_le64(ct.tv_nsec);
+	spin_unlock(&root->root_times_lock);
+}
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index b72b068..a21f308 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -22,6 +22,7 @@
 #include <linux/writeback.h>
 #include <linux/pagemap.h>
 #include <linux/blkdev.h>
+#include <linux/uuid.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -926,11 +927,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 	struct dentry *dentry;
 	struct extent_buffer *tmp;
 	struct extent_buffer *old;
+	struct timespec cur_time = CURRENT_TIME;
 	int ret;
 	u64 to_reserve = 0;
 	u64 index = 0;
 	u64 objectid;
 	u64 root_flags;
+	uuid_le new_uuid;
 
 	rsv = trans->block_rsv;
 
@@ -1016,6 +1019,20 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 		root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY;
 	btrfs_set_root_flags(new_root_item, root_flags);
 
+	btrfs_set_root_generation_v2(new_root_item,
+			trans->transid);
+	uuid_le_gen(&new_uuid);
+	memcpy(new_root_item->uuid, new_uuid.b, BTRFS_UUID_SIZE);
+	memcpy(new_root_item->parent_uuid, root->root_item.uuid,
+			BTRFS_UUID_SIZE);
+	new_root_item->otime.sec = cpu_to_le64(cur_time.tv_sec);
+	new_root_item->otime.nsec = cpu_to_le64(cur_time.tv_nsec);
+	btrfs_set_root_otransid(new_root_item, trans->transid);
+	memset(&new_root_item->stime, 0, sizeof(new_root_item->stime));
+	memset(&new_root_item->rtime, 0, sizeof(new_root_item->rtime));
+	btrfs_set_root_stransid(new_root_item, 0);
+	btrfs_set_root_rtransid(new_root_item, 0);
+
 	old = btrfs_lock_root_node(root);
 	ret = btrfs_cow_block(trans, root, old, NULL, 0, &old);
 	if (ret) {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 1/9] Update ctree.h and ioctl.h for the new uuid+times for subvolumes.
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
  2012-08-03  9:48   ` [PATCH] Btrfs: introduce subvol uuids and times Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 2/9] Btrfs-progs: search subvolumes with proper objectid Anand jain
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Alexander Block

From: Alexander Block <ablock84@googlemail.com>


Signed-off-by: Alexander Block <ablock84@googlemail.com>
---
 ctree.h      |   40 ++++++++++++++++++++++++++++-
 ioctl.h      |   12 +++++++++
 print-tree.c |   79 ++++++++++++++++++++++++++++++++++++++++++++-------------
 3 files changed, 112 insertions(+), 19 deletions(-)

diff --git a/ctree.h b/ctree.h
index 254fb0b..07691c7 100644
--- a/ctree.h
+++ b/ctree.h
@@ -642,6 +642,35 @@ struct btrfs_root_item {
 	struct btrfs_disk_key drop_progress;
 	u8 drop_level;
 	u8 level;
+
+	/*
+	 * The following fields appear after subvol_uuids+subvol_times
+	 * were introduced.
+	 */
+
+	/*
+	 * This generation number is used to test if the new fields are valid
+	 * and up to date while reading the root item. Everytime the root item
+	 * is written out, the "generation" field is copied into this field. If
+	 * anyone ever mounted the fs with an older kernel, we will have
+	 * mismatching generation values here and thus must invalidate the
+	 * new fields. See btrfs_update_root and btrfs_find_last_root for
+	 * details.
+	 * the offset of generation_v2 is also used as the start for the memset
+	 * when invalidating the fields.
+	 */
+	__le64 generation_v2;
+	u8 uuid[BTRFS_UUID_SIZE];
+	u8 parent_uuid[BTRFS_UUID_SIZE];
+	u8 received_uuid[BTRFS_UUID_SIZE];
+	__le64 ctransid; /* updated when an inode changes */
+	__le64 otransid; /* trans when created */
+	__le64 stransid; /* trans when sent. non-zero for received subvol */
+	__le64 rtransid; /* trans when received. non-zero for received subvol */
+	struct btrfs_timespec ctime;
+	struct btrfs_timespec otime;
+	struct btrfs_timespec stime;
+	struct btrfs_timespec rtime;
 } __attribute__ ((__packed__));
 
 /*
@@ -1607,7 +1636,16 @@ BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
 BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
 BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
 			 last_snapshot, 64);
-
+BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
+			 generation_v2, 64);
+BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,
+			 ctransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,
+			 otransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
+			 stransid, 64);
+BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
+			 rtransid, 64);
 
 /* struct btrfs_root_backup */
 BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
diff --git a/ioctl.h b/ioctl.h
index f2e5d8d..6b9a49c 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -20,6 +20,7 @@
 #define __IOCTL_
 #include <asm/types.h>
 #include <linux/ioctl.h>
+#include <time.h>
 
 #define BTRFS_IOCTL_MAGIC 0x94
 #define BTRFS_VOL_NAME_MAX 255
@@ -272,6 +273,15 @@ struct btrfs_ioctl_logical_ino_args {
 	__u64				inodes;
 };
 
+struct btrfs_ioctl_received_subvol_args {
+	char	uuid[BTRFS_UUID_SIZE];	/* in */
+	__u64	stransid;		/* in */
+	__u64	rtransid;		/* out */
+	struct timespec stime;		/* in */
+	struct timespec rtime;		/* out */
+	__u64	reserved[16];
+};
+
 /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
 				   struct btrfs_ioctl_vol_args)
@@ -331,4 +341,6 @@ struct btrfs_ioctl_logical_ino_args {
 #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
 					struct btrfs_ioctl_ino_path_args)
 
+#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
+				struct btrfs_ioctl_received_subvol_args)
 #endif
diff --git a/print-tree.c b/print-tree.c
index fc134c0..67c8982 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -276,6 +276,66 @@ static void print_root_ref(struct extent_buffer *leaf, int slot, char *tag)
 	       namelen, namebuf);
 }
 
+static int count_bytes(void *buf, int len, char b)
+{
+	int cnt = 0;
+	int i;
+	for (i = 0; i < len; i++) {
+		if (((char*)buf)[i] == b)
+			cnt++;
+	}
+	return cnt;
+}
+
+static void print_root(struct extent_buffer *leaf, int slot)
+{
+	struct btrfs_root_item *ri;
+	struct btrfs_root_item root_item;
+	int len;
+	char uuid_str[128];
+
+	ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
+	len = btrfs_item_size_nr(leaf, slot);
+
+	memset(&root_item, 0, sizeof(root_item));
+	read_extent_buffer(leaf, &root_item, (unsigned long)ri, len);
+
+	printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n",
+		(unsigned long long)btrfs_root_bytenr(&root_item),
+		btrfs_root_level(&root_item),
+		(unsigned long long)btrfs_root_dirid(&root_item),
+		btrfs_root_refs(&root_item),
+		(unsigned long long)btrfs_root_generation(&root_item));
+
+	if (root_item.generation == root_item.generation_v2) {
+		uuid_unparse(root_item.uuid, uuid_str);
+		printf("\t\tuuid %s\n", uuid_str);
+		if (count_bytes(root_item.parent_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) {
+			uuid_unparse(root_item.parent_uuid, uuid_str);
+			printf("\t\tparent_uuid %s\n", uuid_str);
+		}
+		if (count_bytes(root_item.received_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) {
+			uuid_unparse(root_item.received_uuid, uuid_str);
+			printf("\t\treceived_uuid %s\n", uuid_str);
+		}
+		if (root_item.ctransid) {
+			printf("\t\tctransid %llu otransid %llu stransid %llu rtransid %llu\n",
+				btrfs_root_ctransid(&root_item),
+				btrfs_root_otransid(&root_item),
+				btrfs_root_stransid(&root_item),
+				btrfs_root_rtransid(&root_item));
+		}
+	}
+	if (btrfs_root_refs(&root_item) == 0) {
+		struct btrfs_key drop_key;
+		btrfs_disk_key_to_cpu(&drop_key,
+				      &root_item.drop_progress);
+		printf("\t\tdrop ");
+		btrfs_print_key(&root_item.drop_progress);
+		printf(" level %d\n", root_item.drop_level);
+	}
+}
+
 static void print_key_type(u8 type)
 {
 	switch (type) {
@@ -446,7 +506,6 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 	int i;
 	char *str;
 	struct btrfs_item *item;
-	struct btrfs_root_item *ri;
 	struct btrfs_dir_item *di;
 	struct btrfs_inode_item *ii;
 	struct btrfs_file_extent_item *fi;
@@ -456,7 +515,6 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 	struct btrfs_inode_ref *iref;
 	struct btrfs_dev_extent *dev_extent;
 	struct btrfs_disk_key disk_key;
-	struct btrfs_root_item root_item;
 	struct btrfs_block_group_item bg_item;
 	struct btrfs_dir_log_item *dlog;
 	u32 nr = btrfs_header_nritems(l);
@@ -508,22 +566,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 			printf("\t\torphan item\n");
 			break;
 		case BTRFS_ROOT_ITEM_KEY:
-			ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
-			read_extent_buffer(l, &root_item, (unsigned long)ri, sizeof(root_item));
-			printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n",
-				(unsigned long long)btrfs_root_bytenr(&root_item),
-				btrfs_root_level(&root_item),
-				(unsigned long long)btrfs_root_dirid(&root_item),
-				btrfs_root_refs(&root_item),
-				(unsigned long long)btrfs_root_generation(&root_item));
-			if (btrfs_root_refs(&root_item) == 0) {
-				struct btrfs_key drop_key;
-				btrfs_disk_key_to_cpu(&drop_key,
-						      &root_item.drop_progress);
-				printf("\t\tdrop ");
-				btrfs_print_key(&root_item.drop_progress);
-				printf(" level %d\n", root_item.drop_level);
-			}
+			print_root(l, i);
 			break;
 		case BTRFS_ROOT_REF_KEY:
 			print_root_ref(l, i, "ref");
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/9] Btrfs-progs: search subvolumes with proper objectid
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
  2012-08-03  9:48   ` [PATCH] Btrfs: introduce subvol uuids and times Anand jain
  2012-08-03  9:48   ` [PATCH 1/9] Update ctree.h and ioctl.h for the new uuid+times for subvolumes Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 3/9] Btrfs-progs: refactor resolve_root() function a bit Anand jain
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Liu Bo

From: Liu Bo <liubo2009@cn.fujitsu.com>

Btrfs's subvolume/snapshot is limited to
[BTRFS_FIRST_FREE_OBJECTID, BTRFS_LAST_FREE_OBJECTID], so just apply the range.

Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
---
 btrfs-list.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 35e6139..680dd03 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -585,11 +585,13 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	sk->max_type = BTRFS_ROOT_BACKREF_KEY;
 	sk->min_type = BTRFS_ROOT_BACKREF_KEY;
 
+	sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
+
 	/*
 	 * set all the other params to the max, we'll take any objectid
 	 * and any trans
 	 */
-	sk->max_objectid = (u64)-1;
+	sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
 	sk->max_offset = (u64)-1;
 	sk->max_transid = (u64)-1;
 
@@ -641,7 +643,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 		if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) {
 			sk->min_type = BTRFS_ROOT_BACKREF_KEY;
 			sk->min_offset = 0;
-		} else  if (sk->min_objectid < (u64)-1) {
+		} else  if (sk->min_objectid < BTRFS_LAST_FREE_OBJECTID) {
 			sk->min_objectid++;
 			sk->min_type = BTRFS_ROOT_BACKREF_KEY;
 			sk->min_offset = 0;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/9] Btrfs-progs: refactor resolve_root() function a bit
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (2 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 2/9] Btrfs-progs: search subvolumes with proper objectid Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 4/9] Btrfs-progs: nuke redundant zeroing in __list_subvol_search() Anand jain
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Ilya Dryomov

From: Ilya Dryomov <idryomov@gmail.com>

Don't pass a pointer to root_id to resolve_root().  It's always the same as
ri->root_id, passing a pointer hints that root_id can somehow change which is
not true.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 btrfs-list.c |   21 ++++++++++-----------
 1 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 680dd03..5c21cac 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -202,7 +202,7 @@ static int add_root(struct root_lookup *root_lookup,
  * in by lookup_ino_path
  */
 static int resolve_root(struct root_lookup *rl, struct root_info *ri,
-			u64 *root_id, u64 *parent_id, u64 *top_id, char **path)
+			u64 *parent_id, u64 *top_id, char **path)
 {
 	char *full_path = NULL;
 	int len = 0;
@@ -256,7 +256,6 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri,
 		}
 	}
 
-	*root_id = ri->root_id;
 	*path = full_path;
 
 	return 0;
@@ -700,23 +699,23 @@ int list_subvols(int fd, int print_parent)
 	n = rb_last(&root_lookup.root);
 	while (n) {
 		struct root_info *entry;
-		u64 root_id;
 		u64 level;
 		u64 parent_id;
 		char *path;
+
 		entry = rb_entry(n, struct root_info, rb_node);
-		resolve_root(&root_lookup, entry, &root_id, &parent_id,
-				&level, &path);
+		resolve_root(&root_lookup, entry, &parent_id, &level, &path);
 		if (print_parent) {
 			printf("ID %llu parent %llu top level %llu path %s\n",
-				(unsigned long long)root_id,
+				(unsigned long long)entry->root_id,
 				(unsigned long long)parent_id,
 				(unsigned long long)level, path);
 		} else {
 			printf("ID %llu top level %llu path %s\n",
-				(unsigned long long)root_id,
+				(unsigned long long)entry->root_id,
 				(unsigned long long)level, path);
 		}
+
 		free(path);
 		n = rb_prev(n);
 	}
@@ -922,17 +921,17 @@ char *path_for_root(int fd, u64 root)
 	n = rb_last(&root_lookup.root);
 	while (n) {
 		struct root_info *entry;
-		u64 root_id;
 		u64 parent_id;
 		u64 level;
 		char *path;
+
 		entry = rb_entry(n, struct root_info, rb_node);
-		resolve_root(&root_lookup, entry, &root_id, &parent_id, &level,
-				&path);
-		if (root_id == root)
+		resolve_root(&root_lookup, entry, &parent_id, &level, &path);
+		if (entry->root_id == root)
 			ret_path = path;
 		else
 			free(path);
+
 		n = rb_prev(n);
 	}
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/9] Btrfs-progs: nuke redundant zeroing in __list_subvol_search()
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (3 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 3/9] Btrfs-progs: refactor resolve_root() function a bit Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 5/9] Btrfs-progs: bring 'subvol get-default' back in Anand jain
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Ilya Dryomov

From: Ilya Dryomov <idryomov@gmail.com>

There's no need to zero out things twice.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 btrfs-list.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 5c21cac..911b238 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -570,10 +570,6 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	root_lookup_init(root_lookup);
 	memset(&args, 0, sizeof(args));
 
-	root_lookup_init(root_lookup);
-
-	memset(&args, 0, sizeof(args));
-
 	/* search in the tree of tree roots */
 	sk->tree_id = 1;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/9] Btrfs-progs: bring 'subvol get-default' back in
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (4 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 4/9] Btrfs-progs: nuke redundant zeroing in __list_subvol_search() Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 6/9] Btrfs-progs: show generation in command btrfs subvol list Anand jain
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Ilya Dryomov

From: Ilya Dryomov <idryomov@gmail.com>

Commit bab2c565 accidentally broke 'subvol get-default' command by
removing almost all of the underlying code.  Bring it back with some
fixes and improvements.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 btrfs-list.c |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ctree.h      |    2 +
 2 files changed, 82 insertions(+), 1 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 911b238..f2a6e19 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -554,6 +554,60 @@ build:
 	return full;
 }
 
+static int get_default_subvolid(int fd, u64 *default_id)
+{
+	struct btrfs_ioctl_search_args args;
+	struct btrfs_ioctl_search_key *sk = &args.key;
+	struct btrfs_ioctl_search_header *sh;
+	u64 found = 0;
+	int ret;
+
+	memset(&args, 0, sizeof(args));
+
+	/*
+	 * search for a dir item with a name 'default' in the tree of
+	 * tree roots, it should point us to a default root
+	 */
+	sk->tree_id = 1;
+
+	/* don't worry about ancient format and request only one item */
+	sk->nr_items = 1;
+
+	sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+	sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+	sk->max_type = BTRFS_DIR_ITEM_KEY;
+	sk->min_type = BTRFS_DIR_ITEM_KEY;
+	sk->max_offset = (u64)-1;
+	sk->max_transid = (u64)-1;
+
+	ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+	if (ret < 0)
+		return ret;
+
+	/* the ioctl returns the number of items it found in nr_items */
+	if (sk->nr_items == 0)
+		goto out;
+
+	sh = (struct btrfs_ioctl_search_header *)args.buf;
+
+	if (sh->type == BTRFS_DIR_ITEM_KEY) {
+		struct btrfs_dir_item *di;
+		int name_len;
+		char *name;
+
+		di = (struct btrfs_dir_item *)(sh + 1);
+		name_len = btrfs_stack_dir_name_len(di);
+		name = (char *)(di + 1);
+
+		if (!strncmp("default", name, name_len))
+			found = btrfs_disk_key_objectid(&di->location);
+	}
+
+out:
+	*default_id = found;
+	return 0;
+}
+
 static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 {
 	int ret;
@@ -667,12 +721,32 @@ static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
 	return 0;
 }
 
-int list_subvols(int fd, int print_parent)
+int list_subvols(int fd, int print_parent, int get_default)
 {
 	struct root_lookup root_lookup;
 	struct rb_node *n;
+	u64 default_id;
 	int ret;
 
+	if (get_default) {
+		ret = get_default_subvolid(fd, &default_id);
+		if (ret) {
+			fprintf(stderr, "ERROR: can't perform the search - %s\n",
+				strerror(errno));
+			return ret;
+		}
+		if (default_id == 0) {
+			fprintf(stderr, "ERROR: 'default' dir item not found\n");
+			return ret;
+		}
+
+		/* no need to resolve roots if FS_TREE is default */
+		if (default_id == BTRFS_FS_TREE_OBJECTID) {
+			printf("ID 5 (FS_TREE)\n");
+			return ret;
+		}
+	}
+
 	ret = __list_subvol_search(fd, &root_lookup);
 	if (ret) {
 		fprintf(stderr, "ERROR: can't perform the search - %s\n",
@@ -700,6 +774,11 @@ int list_subvols(int fd, int print_parent)
 		char *path;
 
 		entry = rb_entry(n, struct root_info, rb_node);
+		if (get_default && entry->root_id != default_id) {
+			n = rb_prev(n);
+			continue;
+		}
+
 		resolve_root(&root_lookup, entry, &parent_id, &level, &path);
 		if (print_parent) {
 			printf("ID %llu parent %llu top level %llu path %s\n",
diff --git a/ctree.h b/ctree.h
index 07691c7..32b591c 100644
--- a/ctree.h
+++ b/ctree.h
@@ -1459,6 +1459,8 @@ BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
 BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
 BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
 
+BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16);
+
 static inline void btrfs_dir_item_key(struct extent_buffer *eb,
 				      struct btrfs_dir_item *item,
 				      struct btrfs_disk_key *key)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 6/9] Btrfs-progs: show generation in command btrfs subvol list
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (5 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 5/9] Btrfs-progs: bring 'subvol get-default' back in Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 7/9] Btrfs-progs: list snapshots by generation Anand jain
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Liu Bo

From: Liu Bo <liubo2009@cn.fujitsu.com>

This adds the ability to show root's modification generation when we use
btrfs subvol list.

NOTE:
Like file's atime and ctime, root's generation also has 'creation generation'
and 'modification generation'.
The generation that we're going to show is 'modification generation', and the
next patch is going to show 'creation generation'.

Signed-off-by: Liu Bo <liubo2009@cn.fujitsu.com>
---
 btrfs-list.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index f2a6e19..0592055 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -57,6 +57,9 @@ struct root_info {
 	/* the dir id we're in from ref_tree */
 	u64 dir_id;
 
+	/* generation when the root is created or last updated */
+	u64 gen;
+
 	/* path from the subvol we live in to this root, including the
 	 * root's name.  This is null until we do the extra lookup ioctl.
 	 */
@@ -194,6 +197,19 @@ static int add_root(struct root_lookup *root_lookup,
 	return 0;
 }
 
+static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen)
+{
+	struct root_info *ri;
+
+	ri = tree_search(&root_lookup->root, root_id);
+	if (!ri || ri->root_id != root_id) {
+		fprintf(stderr, "could not find subvol %llu\n", root_id);
+		return -ENOENT;
+	}
+	ri->gen = gen;
+	return 0;
+}
+
 /*
  * for a given root_info, search through the root_lookup tree to construct
  * the full path name to it.
@@ -615,11 +631,15 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	struct btrfs_ioctl_search_key *sk = &args.key;
 	struct btrfs_ioctl_search_header *sh;
 	struct btrfs_root_ref *ref;
+	struct btrfs_root_item *ri;
 	unsigned long off = 0;
 	int name_len;
 	char *name;
 	u64 dir_id;
+	u8 type;
+	u64 gen = 0;
 	int i;
+	int get_gen = 0;
 
 	root_lookup_init(root_lookup);
 	memset(&args, 0, sizeof(args));
@@ -644,6 +664,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	sk->max_offset = (u64)-1;
 	sk->max_transid = (u64)-1;
 
+again:
 	/* just a big number, doesn't matter much */
 	sk->nr_items = 4096;
 
@@ -665,7 +686,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 			sh = (struct btrfs_ioctl_search_header *)(args.buf +
 								  off);
 			off += sizeof(*sh);
-			if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
+			if (!get_gen && sh->type == BTRFS_ROOT_BACKREF_KEY) {
 				ref = (struct btrfs_root_ref *)(args.buf + off);
 				name_len = btrfs_stack_root_ref_name_len(ref);
 				name = (char *)(ref + 1);
@@ -673,6 +694,11 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 
 				add_root(root_lookup, sh->objectid, sh->offset,
 					 dir_id, name, name_len);
+			} else if (get_gen && sh->type == BTRFS_ROOT_ITEM_KEY) {
+				ri = (struct btrfs_root_item *)(args.buf + off);
+				gen = btrfs_root_generation(ri);
+
+				update_root(root_lookup, sh->objectid, gen);
 			}
 
 			off += sh->len;
@@ -689,17 +715,38 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 		/* this iteration is done, step forward one root for the next
 		 * ioctl
 		 */
-		if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) {
-			sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+		if (get_gen)
+			type = BTRFS_ROOT_ITEM_KEY;
+		else
+			type = BTRFS_ROOT_BACKREF_KEY;
+
+		if (sk->min_type < type) {
+			sk->min_type = type;
 			sk->min_offset = 0;
 		} else  if (sk->min_objectid < BTRFS_LAST_FREE_OBJECTID) {
 			sk->min_objectid++;
-			sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+			sk->min_type = type;
 			sk->min_offset = 0;
 		} else
 			break;
 	}
 
+	if (!get_gen) {
+		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;
+
+		get_gen = 1;
+		goto again;
+	}
 	return 0;
 }
 
@@ -781,13 +828,15 @@ int list_subvols(int fd, int print_parent, int get_default)
 
 		resolve_root(&root_lookup, entry, &parent_id, &level, &path);
 		if (print_parent) {
-			printf("ID %llu parent %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu parent %llu top level %llu path %s\n",
 				(unsigned long long)entry->root_id,
+				(unsigned long long)entry->gen,
 				(unsigned long long)parent_id,
 				(unsigned long long)level, path);
 		} else {
-			printf("ID %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu top level %llu path %s\n",
 				(unsigned long long)entry->root_id,
+				(unsigned long long)entry->gen,
 				(unsigned long long)level, path);
 		}
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 7/9] Btrfs-progs: list snapshots by generation
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (6 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 6/9] Btrfs-progs: show generation in command btrfs subvol list Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 8/9] Btrfs-progs: add otime to the snapshot list Anand jain
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Liu Bo

From: Liu Bo <liubo2009@cn.fujitsu.com>

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 0592055..1db99ae 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-1] = 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;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 8/9] Btrfs-progs: add otime to the snapshot list
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (7 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 7/9] Btrfs-progs: list snapshots by generation Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-03  9:48   ` [PATCH 9/9] Btrfs-progs: fix the btrfs subvol list path last char Anand jain
  2012-08-14  6:04   ` [PATCH] get uuid of subvol and snapshot Anand jain
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>

Reviewed-by: Alexander Block <ablock84@googlemail.com>
Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
 btrfs-list.c |   45 ++++++++++++++++++++++++++++++++++++---------
 1 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 1db99ae..e0cb782 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -60,6 +60,9 @@ struct root_info {
 	/* generation when the root is created or last updated */
 	u64 gen;
 
+	/* creation time of this root in sec*/
+	time_t otime;
+
 	/* path from the subvol we live in to this root, including the
 	 * root's name.  This is null until we do the extra lookup ioctl.
 	 */
@@ -185,7 +188,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, u64 *gen)
+		    int name_len, u64 *gen, time_t ot)
 {
 	struct root_info *ri;
 	struct rb_node *ret;
@@ -205,6 +208,7 @@ static int add_root(struct root_lookup *root_lookup,
 		ri->name[name_len-1] = 0;
 	if (gen)
 		ri->gen = *gen;
+	ri->otime = ot;
 
 	ret = tree_insert(&root_lookup->root, root_id, ref_tree, gen,
 			  &ri->rb_node);
@@ -215,7 +219,8 @@ static int add_root(struct root_lookup *root_lookup,
 	return 0;
 }
 
-static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen)
+static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen,
+			time_t ot)
 {
 	struct root_info *ri;
 
@@ -225,6 +230,7 @@ static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen)
 		return -ENOENT;
 	}
 	ri->gen = gen;
+	ri->otime = ot;
 	return 0;
 }
 
@@ -658,6 +664,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	u64 gen = 0;
 	int i;
 	int get_gen = 0;
+	time_t t;
 
 	root_lookup_init(root_lookup);
 	memset(&args, 0, sizeof(args));
@@ -711,12 +718,16 @@ again:
 				dir_id = btrfs_stack_root_ref_dirid(ref);
 
 				add_root(root_lookup, sh->objectid, sh->offset,
-					 dir_id, name, name_len, NULL);
+					 dir_id, name, name_len, NULL, 0);
 			} else if (get_gen && sh->type == BTRFS_ROOT_ITEM_KEY) {
 				ri = (struct btrfs_root_item *)(args.buf + off);
 				gen = btrfs_root_generation(ri);
+				if(ri->generation == ri->generation_v2)
+					t = ri->otime.sec;
+				else
+					t = 0;
 
-				update_root(root_lookup, sh->objectid, gen);
+				update_root(root_lookup, sh->objectid, gen, t);
 			}
 
 			off += sh->len;
@@ -805,14 +816,21 @@ static int __list_snapshot_search(int fd, struct root_lookup *root_lookup)
 		 * read the root_ref item it contains
 		 */
 		for (i = 0; i < sk->nr_items; i++) {
+			struct btrfs_root_item *item;
+			time_t  t;
 			sh = (struct btrfs_ioctl_search_header *)(args.buf +
 								  off);
 			off += sizeof(*sh);
 			if (sh->type == BTRFS_ROOT_ITEM_KEY && sh->offset) {
+				item = (struct btrfs_root_item *)(args.buf + off);
+				if(item->generation == item->generation_v2)
+					t = item->otime.sec;
+				else
+					t = 0;
 				gen = sh->offset;
 
 				add_root(root_lookup, sh->objectid, 0,
-					 0, NULL, 0, &gen);
+					 0, NULL, 0, &gen, t);
 			}
 			off += sh->len;
 
@@ -981,24 +999,33 @@ int list_snapshots(int fd, int print_parent, int order)
 		u64 level;
 		u64 parent_id;
 		char *path;
+		time_t t;
+		char tstr[256];
 
 		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);
+		t = entry->otime;
+		if(t)
+			strftime(tstr,256,"%Y-%m-%d %X",localtime(&t));
+		else
+			strcpy(tstr,"-");
 		if (print_parent) {
-			printf("ID %llu gen %llu cgen %llu parent %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu cgen %llu parent %llu top level %llu "
+				"otime %s 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);
+				(unsigned long long)level, tstr, path);
 		} else {
-			printf("ID %llu gen %llu cgen %llu top level %llu path %s\n",
+			printf("ID %llu gen %llu cgen %llu top level %llu "
+				"otime %s 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);
+				(unsigned long long)level, tstr, path);
 		}
 
 		free(path);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 9/9] Btrfs-progs: fix the btrfs subvol list path last char
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (8 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 8/9] Btrfs-progs: add otime to the snapshot list Anand jain
@ 2012-08-03  9:48   ` Anand jain
  2012-08-14  6:04   ` [PATCH] get uuid of subvol and snapshot Anand jain
  10 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-03  9:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>


Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
 btrfs-list.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index e0cb782..6e83b31 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -205,7 +205,7 @@ static int add_root(struct root_lookup *root_lookup,
 	if (name)
 		strncpy(ri->name, name, name_len);
 	if (name_len > 0)
-		ri->name[name_len-1] = 0;
+		ri->name[name_len] = '\0';
 	if (gen)
 		ri->gen = *gen;
 	ri->otime = ot;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH] get uuid of subvol and snapshot
  2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
                     ` (9 preceding siblings ...)
  2012-08-03  9:48   ` [PATCH 9/9] Btrfs-progs: fix the btrfs subvol list path last char Anand jain
@ 2012-08-14  6:04   ` Anand jain
  2012-08-14  6:04     ` [PATCH] add -u to show subvol uuid Anand jain
  10 siblings, 1 reply; 18+ messages in thread
From: Anand jain @ 2012-08-14  6:04 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>

 This patch is on top the patch-set titled 
 'Include otime in the snapshot list' sent by me before.

 To show the uuid of the subvol and snapshots.

btrfs su list -u /btrfs1
ID 256 gen 6 top level 5 uuid 4b7188e4-7d48-f247-b956-1a260b721e1d path sv1
ID 259 gen 6 top level 5 uuid 3cf8931a-de31-5545-8ede-435d25fe3c3f path sv1/.snapshot/ss1

Anand Jain (1):
  add -u to show subvol uuid

 btrfs-list.c     |  148 ++++++++++++++++++++++++++++++++++++++++++------------
 cmds-subvolume.c |   14 +++--
 2 files changed, 124 insertions(+), 38 deletions(-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] add -u to show subvol uuid
  2012-08-14  6:04   ` [PATCH] get uuid of subvol and snapshot Anand jain
@ 2012-08-14  6:04     ` Anand jain
  0 siblings, 0 replies; 18+ messages in thread
From: Anand jain @ 2012-08-14  6:04 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Anand Jain

From: Anand Jain <anand.jain@oracle.com>

Applications would need to know the uuid to manage the configurations
associated with the subvol and snapshots

Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
 btrfs-list.c     |  148 ++++++++++++++++++++++++++++++++++++++++++------------
 cmds-subvolume.c |   14 +++--
 2 files changed, 124 insertions(+), 38 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 6e83b31..d6b22a1 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -34,6 +34,7 @@
 #include "ctree.h"
 #include "transaction.h"
 #include "utils.h"
+#include <uuid/uuid.h>
 
 /* we store all the roots we find in an rbtree so that we can
  * search for them later.
@@ -63,6 +64,8 @@ struct root_info {
 	/* creation time of this root in sec*/
 	time_t otime;
 
+	u8 uuid[BTRFS_UUID_SIZE];
+
 	/* path from the subvol we live in to this root, including the
 	 * root's name.  This is null until we do the extra lookup ioctl.
 	 */
@@ -188,7 +191,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, u64 *gen, time_t ot)
+		    int name_len, u64 *gen, time_t ot, void *uuid)
 {
 	struct root_info *ri;
 	struct rb_node *ret;
@@ -210,6 +213,11 @@ static int add_root(struct root_lookup *root_lookup,
 		ri->gen = *gen;
 	ri->otime = ot;
 
+	if (uuid) 
+		memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
+	else
+		memset(&ri->uuid, 0, BTRFS_UUID_SIZE);
+
 	ret = tree_insert(&root_lookup->root, root_id, ref_tree, gen,
 			  &ri->rb_node);
 	if (ret) {
@@ -220,7 +228,7 @@ static int add_root(struct root_lookup *root_lookup,
 }
 
 static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen,
-			time_t ot)
+			time_t ot, void *uuid)
 {
 	struct root_info *ri;
 
@@ -231,6 +239,11 @@ static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen,
 	}
 	ri->gen = gen;
 	ri->otime = ot;
+	if (uuid)
+		memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
+	else
+		memset(&ri->uuid, 0, BTRFS_UUID_SIZE);
+
 	return 0;
 }
 
@@ -665,6 +678,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	int i;
 	int get_gen = 0;
 	time_t t;
+	u8 uuid[BTRFS_UUID_SIZE];
 
 	root_lookup_init(root_lookup);
 	memset(&args, 0, sizeof(args));
@@ -718,16 +732,20 @@ again:
 				dir_id = btrfs_stack_root_ref_dirid(ref);
 
 				add_root(root_lookup, sh->objectid, sh->offset,
-					 dir_id, name, name_len, NULL, 0);
+					 dir_id, name, name_len, NULL, 0, NULL);
 			} else if (get_gen && sh->type == BTRFS_ROOT_ITEM_KEY) {
 				ri = (struct btrfs_root_item *)(args.buf + off);
 				gen = btrfs_root_generation(ri);
-				if(ri->generation == ri->generation_v2)
+				if(ri->generation == ri->generation_v2) {
 					t = ri->otime.sec;
-				else
+					memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE);
+				} else {
 					t = 0;
+					memset(uuid, 0, BTRFS_UUID_SIZE);
+				}
 
-				update_root(root_lookup, sh->objectid, gen, t);
+				update_root(root_lookup, sh->objectid, gen, t,
+					uuid);
 			}
 
 			off += sh->len;
@@ -818,19 +836,24 @@ static int __list_snapshot_search(int fd, struct root_lookup *root_lookup)
 		for (i = 0; i < sk->nr_items; i++) {
 			struct btrfs_root_item *item;
 			time_t  t;
+			u8 uuid[BTRFS_UUID_SIZE];
+
 			sh = (struct btrfs_ioctl_search_header *)(args.buf +
 								  off);
 			off += sizeof(*sh);
 			if (sh->type == BTRFS_ROOT_ITEM_KEY && sh->offset) {
 				item = (struct btrfs_root_item *)(args.buf + off);
-				if(item->generation == item->generation_v2)
+				if(item->generation == item->generation_v2) {
 					t = item->otime.sec;
-				else
+					memcpy(uuid, item->uuid, BTRFS_UUID_SIZE);
+				} else {
 					t = 0;
+					memset(uuid, 0, BTRFS_UUID_SIZE);
+				}
 				gen = sh->offset;
 
 				add_root(root_lookup, sh->objectid, 0,
-					 0, NULL, 0, &gen, t);
+					 0, NULL, 0, &gen, t, uuid);
 			}
 			off += sh->len;
 
@@ -877,12 +900,13 @@ static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
 	return 0;
 }
 
-int list_subvols(int fd, int print_parent, int get_default)
+int list_subvols(int fd, int print_parent, int get_default, int print_uuid)
 {
 	struct root_lookup root_lookup;
 	struct rb_node *n;
 	u64 default_id;
 	int ret;
+	char uuidparse[37];
 
 	if (get_default) {
 		ret = get_default_subvolid(fd, &default_id);
@@ -937,16 +961,44 @@ int list_subvols(int fd, int print_parent, int get_default)
 
 		resolve_root(&root_lookup, entry, &parent_id, &level, &path);
 		if (print_parent) {
-			printf("ID %llu gen %llu parent %llu top level %llu path %s\n",
-				(unsigned long long)entry->root_id,
-				(unsigned long long)entry->gen,
-				(unsigned long long)parent_id,
-				(unsigned long long)level, path);
+			if (print_uuid) {
+				if (uuid_is_null(entry->uuid))
+					strcpy(uuidparse, "-");
+				else
+					uuid_unparse(entry->uuid, uuidparse);
+				printf("ID %llu gen %llu parent %llu top level %llu"
+					" uuid %s path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)parent_id,
+					(unsigned long long)level,
+					uuidparse, path);
+			} else {
+				printf("ID %llu gen %llu parent %llu top level"
+					" %llu path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)parent_id,
+					(unsigned long long)level, path);
+			}
 		} else {
-			printf("ID %llu gen %llu top level %llu path %s\n",
-				(unsigned long long)entry->root_id,
-				(unsigned long long)entry->gen,
-				(unsigned long long)level, path);
+			if (print_uuid) {
+				if (uuid_is_null(entry->uuid))
+					strcpy(uuidparse, "-");
+				else
+					uuid_unparse(entry->uuid, uuidparse);
+				printf("ID %llu gen %llu top level %llu"
+					" uuid %s path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)level,
+					uuidparse, path);
+			} else {
+				printf("ID %llu gen %llu top level %llu path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)level, path);
+			}
 		}
 
 		free(path);
@@ -956,7 +1008,7 @@ int list_subvols(int fd, int print_parent, int get_default)
 	return ret;
 }
 
-int list_snapshots(int fd, int print_parent, int order)
+int list_snapshots(int fd, int print_parent, int order, int print_uuid)
 {
 	struct root_lookup root_lookup;
 	struct root_lookup root_lookup_snap;
@@ -1001,6 +1053,7 @@ int list_snapshots(int fd, int print_parent, int order)
 		char *path;
 		time_t t;
 		char tstr[256];
+		char uuidparse[37];
 
 		entry_snap = rb_entry(n, struct root_info, rb_node);
 		entry = tree_search(&root_lookup.root, entry_snap->root_id);
@@ -1012,20 +1065,49 @@ int list_snapshots(int fd, int print_parent, int order)
 		else
 			strcpy(tstr,"-");
 		if (print_parent) {
-			printf("ID %llu gen %llu cgen %llu parent %llu top level %llu "
-				"otime %s 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, tstr, path);
+			if (print_uuid) {
+				if (uuid_is_null(entry->uuid))
+					strcpy(uuidparse, "-");
+				else
+					uuid_unparse(entry->uuid, uuidparse);
+				printf("ID %llu gen %llu cgen %llu parent %llu"
+					" top level %llu otime %s uuid %s 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,
+					tstr, uuidparse, path);
+			} else {
+				printf("ID %llu gen %llu cgen %llu parent %llu"
+					" top level %llu otime %s 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, tstr, path);
+			}
 		} else {
-			printf("ID %llu gen %llu cgen %llu top level %llu "
-				"otime %s path %s\n",
-				(unsigned long long)entry->root_id,
-				(unsigned long long)entry->gen,
-				(unsigned long long)entry_snap->gen,
-				(unsigned long long)level, tstr, path);
+			if (print_uuid) {
+				if (uuid_is_null(entry->uuid))
+					strcpy(uuidparse, "-");
+				else
+					uuid_unparse(entry->uuid, uuidparse);
+				printf("ID %llu gen %llu cgen %llu top level %llu "
+					"otime %s uuid %s path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)entry_snap->gen,
+					(unsigned long long)level,
+					tstr, uuidparse, path);
+			} else {
+				printf("ID %llu gen %llu cgen %llu top level %llu "
+					"otime %s path %s\n",
+					(unsigned long long)entry->root_id,
+					(unsigned long long)entry->gen,
+					(unsigned long long)entry_snap->gen,
+					(unsigned long long)level, tstr, path);
+			}
 		}
 
 		free(path);
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 9c75b47..dea8f43 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -30,7 +30,7 @@
 #include "commands.h"
 
 /* btrfs-list.c */
-int list_subvols(int fd, int print_parent, int get_default);
+int list_subvols(int fd, int print_parent, int print_uuid, int get_default);
 int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
 
 static const char * const subvolume_cmd_group_usage[] = {
@@ -236,10 +236,11 @@ static int cmd_subvol_list(int argc, char **argv)
 	int print_snap_only = 0;
 	int order = 0;
 	char *subvol;
+	int print_uuid = 0;
 
 	optind = 1;
 	while(1) {
-		int c = getopt(argc, argv, "ps:");
+		int c = getopt(argc, argv, "ps:u");
 		if (c < 0)
 			break;
 
@@ -251,6 +252,9 @@ static int cmd_subvol_list(int argc, char **argv)
 			print_snap_only = 1;
 			order = atoi(optarg);
 			break;
+		case 'u':
+			print_uuid =1;
+			break;
 		default:
 			usage(cmd_subvol_list_usage);
 		}
@@ -277,9 +281,9 @@ static int cmd_subvol_list(int argc, char **argv)
 		return 12;
 	}
 	if (!print_snap_only)
-		ret = list_subvols(fd, print_parent, 0);
+		ret = list_subvols(fd, print_parent, 0, print_uuid);
 	else
-		ret = list_snapshots(fd, print_parent, order);
+		ret = list_snapshots(fd, print_parent, order, print_uuid);
 	if (ret)
 		return 19;
 	return 0;
@@ -439,7 +443,7 @@ static int cmd_subvol_get_default(int argc, char **argv)
 		fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
 		return 12;
 	}
-	ret = list_subvols(fd, 0, 1);
+	ret = list_subvols(fd, 0, 1, 0);
 	if (ret)
 		return 19;
 	return 0;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-08-14  6:03 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-01 12:01 [PATCH] add crtime to the snapshot list Anand jain
2012-08-01 12:01 ` [PATCH] Btrfs-progs: show crtime in " Anand jain
2012-08-01 12:14 ` [PATCH] add crtime to " Alexander Block
2012-08-01 15:56   ` anand jain
2012-08-01 12:43 ` Liu Bo
2012-08-03  9:48 ` [PATCH 0/9 V2] Include otime in " Anand jain
2012-08-03  9:48   ` [PATCH] Btrfs: introduce subvol uuids and times Anand jain
2012-08-03  9:48   ` [PATCH 1/9] Update ctree.h and ioctl.h for the new uuid+times for subvolumes Anand jain
2012-08-03  9:48   ` [PATCH 2/9] Btrfs-progs: search subvolumes with proper objectid Anand jain
2012-08-03  9:48   ` [PATCH 3/9] Btrfs-progs: refactor resolve_root() function a bit Anand jain
2012-08-03  9:48   ` [PATCH 4/9] Btrfs-progs: nuke redundant zeroing in __list_subvol_search() Anand jain
2012-08-03  9:48   ` [PATCH 5/9] Btrfs-progs: bring 'subvol get-default' back in Anand jain
2012-08-03  9:48   ` [PATCH 6/9] Btrfs-progs: show generation in command btrfs subvol list Anand jain
2012-08-03  9:48   ` [PATCH 7/9] Btrfs-progs: list snapshots by generation Anand jain
2012-08-03  9:48   ` [PATCH 8/9] Btrfs-progs: add otime to the snapshot list Anand jain
2012-08-03  9:48   ` [PATCH 9/9] Btrfs-progs: fix the btrfs subvol list path last char Anand jain
2012-08-14  6:04   ` [PATCH] get uuid of subvol and snapshot Anand jain
2012-08-14  6:04     ` [PATCH] add -u to show subvol uuid Anand jain

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).