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(-) -- 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
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 -- 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
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/.snapIs 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-- 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
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 >-- 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
>> 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 -- 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
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(-) -- 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
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 1/9] Update ctree.h and ioctl.h for the new uuid+times for subvolumes.
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 2/9] Btrfs-progs: search subvolumes with proper objectid
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 3/9] Btrfs-progs: refactor resolve_root() function a bit
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 4/9] Btrfs-progs: nuke redundant zeroing in __list_subvol_search()
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 5/9] Btrfs-progs: bring ''subvol get-default'' back in
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 6/9] Btrfs-progs: show generation in command btrfs subvol list
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 -- 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
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 -- 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
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 -- 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
Anand jain
2012-Aug-03 09:48 UTC
[PATCH 9/9] Btrfs-progs: fix the btrfs subvol list path last char
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 -- 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
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(-) -- 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
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 -- 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
Reasonably Related Threads
- [PATCH v1 0/2] Btrfs-progs: commands "resolve inode" and "resolve logical"
- [PATCH 1/3] Btrfs-progs: add support to set subvolume/snapshot readonly
- [PATCH] Btrfs-progs: enhance 'btrfs subvolume list'
- [Request for review] [RFC] Add label support for snapshots and subvols
- [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete