2 * Copyright (C) 2010 Oracle. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
27 #include <sys/types.h>
33 #include "kerncompat.h"
35 #include "transaction.h"
37 #include <uuid/uuid.h>
38 #include "btrfs-list.h"
40 /* we store all the roots we find in an rbtree so that we can
41 * search for them later.
48 * one of these for each root we find.
51 struct rb_node rb_node;
56 /* the id of the root that references this one */
59 /* the dir id we're in from ref_tree */
62 /* generation when the root is created or last updated */
65 /* creation time of this root in sec*/
68 u8 uuid[BTRFS_UUID_SIZE];
70 /* path from the subvol we live in to this root, including the
71 * root's name. This is null until we do the extra lookup ioctl.
75 /* the name of this root in the directory it lives in */
79 static void root_lookup_init(struct root_lookup *tree)
81 tree->root.rb_node = NULL;
84 static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
86 if (entry->root_id > root_id)
88 if (entry->root_id < root_id)
90 if (entry->ref_tree > ref_tree)
92 if (entry->ref_tree < ref_tree)
97 static int comp_entry_with_gen(struct root_info *entry, u64 root_id,
98 u64 ref_tree, u64 gen)
100 if (entry->gen < gen)
102 if (entry->gen > gen)
104 return comp_entry(entry, root_id, ref_tree);
108 * insert a new root into the tree. returns the existing root entry
109 * if one is already there. Both root_id and ref_tree are used
112 static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
113 u64 ref_tree, u64 *gen, struct rb_node *node)
115 struct rb_node ** p = &root->rb_node;
116 struct rb_node * parent = NULL;
117 struct root_info *entry;
122 entry = rb_entry(parent, struct root_info, rb_node);
125 comp = comp_entry(entry, root_id, ref_tree);
127 comp = comp_entry_with_gen(entry, root_id, ref_tree,
138 entry = rb_entry(parent, struct root_info, rb_node);
139 rb_link_node(node, parent, p);
140 rb_insert_color(node, root);
145 * find a given root id in the tree. We return the smallest one,
146 * rb_next can be used to move forward looking for more if required
148 static struct root_info *tree_search(struct rb_root *root, u64 root_id)
150 struct rb_node * n = root->rb_node;
151 struct root_info *entry;
154 entry = rb_entry(n, struct root_info, rb_node);
156 if (entry->root_id < root_id)
158 else if (entry->root_id > root_id)
161 struct root_info *prev;
162 struct rb_node *prev_n;
167 prev = rb_entry(prev_n, struct root_info,
169 if (prev->root_id != root_id)
181 * this allocates a new root in the lookup tree.
183 * root_id should be the object id of the root
185 * ref_tree is the objectid of the referring root.
187 * dir_id is the directory in ref_tree where this root_id can be found.
189 * name is the name of root_id in that directory
191 * name_len is the length of name
193 static int add_root(struct root_lookup *root_lookup,
194 u64 root_id, u64 ref_tree, u64 dir_id, char *name,
195 int name_len, u64 *gen, time_t ot, void *uuid)
197 struct root_info *ri;
199 ri = malloc(sizeof(*ri) + name_len + 1);
201 printf("memory allocation failed\n");
204 memset(ri, 0, sizeof(*ri) + name_len + 1);
207 ri->root_id = root_id;
208 ri->ref_tree = ref_tree;
210 strncpy(ri->name, name, name_len);
212 ri->name[name_len] = 0;
218 memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
220 memset(&ri->uuid, 0, BTRFS_UUID_SIZE);
222 ret = tree_insert(&root_lookup->root, root_id, ref_tree, gen,
225 printf("failed to insert tree %llu\n", (unsigned long long)root_id);
231 static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 gen,
232 time_t ot, void *uuid)
234 struct root_info *ri;
236 ri = tree_search(&root_lookup->root, root_id);
237 if (!ri || ri->root_id != root_id) {
238 fprintf(stderr, "could not find subvol %llu\n", root_id);
244 memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE);
246 memset(&ri->uuid, 0, BTRFS_UUID_SIZE);
252 * for a given root_info, search through the root_lookup tree to construct
253 * the full path name to it.
255 * This can't be called until all the root_info->path fields are filled
256 * in by lookup_ino_path
258 static int resolve_root(struct root_lookup *rl, struct root_info *ri,
259 u64 *parent_id, u64 *top_id, char **path)
261 char *full_path = NULL;
263 struct root_info *found;
266 * we go backwards from the root_info object and add pathnames
267 * from parent directories as we go.
274 int add_len = strlen(found->path);
276 /* room for / and for null */
277 tmp = malloc(add_len + 2 + len);
279 memcpy(tmp + add_len + 1, full_path, len);
281 memcpy(tmp, found->path, add_len);
282 tmp [add_len + len + 1] = '\0';
287 full_path = strdup(found->path);
291 next = found->ref_tree;
292 /* record the first parent */
296 /* if the ref_tree refers to ourselves, we're at the top */
297 if (next == found->root_id) {
303 * if the ref_tree wasn't in our tree of roots, we're
306 found = tree_search(&rl->root, next);
319 * for a single root_info, ask the kernel to give us a path name
320 * inside it's ref_root for the dir_id where it lives.
322 * This fills in root_info->path with the path to the directory and and
323 * appends this root's name.
325 static int lookup_ino_path(int fd, struct root_info *ri)
327 struct btrfs_ioctl_ino_lookup_args args;
333 memset(&args, 0, sizeof(args));
334 args.treeid = ri->ref_tree;
335 args.objectid = ri->dir_id;
337 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
340 fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n",
341 (unsigned long long)ri->ref_tree,
348 * we're in a subdirectory of ref_tree, the kernel ioctl
349 * puts a / in there for us
351 ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
353 perror("malloc failed");
356 strcpy(ri->path, args.name);
357 strcat(ri->path, ri->name);
359 /* we're at the root of ref_tree */
360 ri->path = strdup(ri->name);
362 perror("strdup failed");
369 /* finding the generation for a given path is a two step process.
370 * First we use the inode loookup routine to find out the root id
372 * Then we use the tree search ioctl to scan all the root items for a
373 * given root id and spit out the latest generation we can find
375 static u64 find_root_gen(int fd)
377 struct btrfs_ioctl_ino_lookup_args ino_args;
379 struct btrfs_ioctl_search_args args;
380 struct btrfs_ioctl_search_key *sk = &args.key;
381 struct btrfs_ioctl_search_header *sh;
382 unsigned long off = 0;
387 memset(&ino_args, 0, sizeof(ino_args));
388 ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
390 /* this ioctl fills in ino_args->treeid */
391 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
394 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
395 (unsigned long long)BTRFS_FIRST_FREE_OBJECTID,
400 memset(&args, 0, sizeof(args));
405 * there may be more than one ROOT_ITEM key if there are
406 * snapshots pending deletion, we have to loop through
409 sk->min_objectid = ino_args.treeid;
410 sk->max_objectid = ino_args.treeid;
411 sk->max_type = BTRFS_ROOT_ITEM_KEY;
412 sk->min_type = BTRFS_ROOT_ITEM_KEY;
413 sk->max_offset = (u64)-1;
414 sk->max_transid = (u64)-1;
418 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
421 fprintf(stderr, "ERROR: can't perform the search - %s\n",
425 /* the ioctl returns the number of item it found in nr_items */
426 if (sk->nr_items == 0)
430 for (i = 0; i < sk->nr_items; i++) {
431 struct btrfs_root_item *item;
432 sh = (struct btrfs_ioctl_search_header *)(args.buf +
436 item = (struct btrfs_root_item *)(args.buf + off);
439 sk->min_objectid = sh->objectid;
440 sk->min_type = sh->type;
441 sk->min_offset = sh->offset;
443 if (sh->objectid > ino_args.treeid)
446 if (sh->objectid == ino_args.treeid &&
447 sh->type == BTRFS_ROOT_ITEM_KEY) {
448 max_found = max(max_found,
449 btrfs_root_generation(item));
452 if (sk->min_offset < (u64)-1)
457 if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
459 if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
465 /* pass in a directory id and this will return
466 * the full path of the parent directory inside its
469 * It may return NULL if it is in the root, or an ERR_PTR if things
472 static char *__ino_resolve(int fd, u64 dirid)
474 struct btrfs_ioctl_ino_lookup_args args;
479 memset(&args, 0, sizeof(args));
480 args.objectid = dirid;
482 ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
485 fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n",
486 (unsigned long long)dirid, strerror(e) );
492 * we're in a subdirectory of ref_tree, the kernel ioctl
493 * puts a / in there for us
495 full = strdup(args.name);
497 perror("malloc failed");
498 return ERR_PTR(-ENOMEM);
501 /* we're at the root of ref_tree */
508 * simple string builder, returning a new string with both
511 char *build_name(char *dirid, char *name)
517 full = malloc(strlen(dirid) + strlen(name) + 1);
526 * given an inode number, this returns the full path name inside the subvolume
527 * to that file/directory. cache_dirid and cache_name are used to
528 * cache the results so we can avoid tree searches if a later call goes
529 * to the same directory or file name
531 static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
539 struct btrfs_ioctl_search_args args;
540 struct btrfs_ioctl_search_key *sk = &args.key;
541 struct btrfs_ioctl_search_header *sh;
542 unsigned long off = 0;
546 memset(&args, 0, sizeof(args));
551 * step one, we search for the inode back ref. We just use the first
554 sk->min_objectid = ino;
555 sk->max_objectid = ino;
556 sk->max_type = BTRFS_INODE_REF_KEY;
557 sk->max_offset = (u64)-1;
558 sk->min_type = BTRFS_INODE_REF_KEY;
559 sk->max_transid = (u64)-1;
562 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
565 fprintf(stderr, "ERROR: can't perform the search - %s\n",
569 /* the ioctl returns the number of item it found in nr_items */
570 if (sk->nr_items == 0)
574 sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
576 if (sh->type == BTRFS_INODE_REF_KEY) {
577 struct btrfs_inode_ref *ref;
580 ref = (struct btrfs_inode_ref *)(sh + 1);
581 namelen = btrfs_stack_inode_ref_name_len(ref);
583 name = (char *)(ref + 1);
584 name = strndup(name, namelen);
586 /* use our cached value */
587 if (dirid == *cache_dirid && *cache_name) {
588 dirname = *cache_name;
595 * the inode backref gives us the file name and the parent directory id.
596 * From here we use __ino_resolve to get the path to the parent
598 dirname = __ino_resolve(fd, dirid);
600 full = build_name(dirname, name);
601 if (*cache_name && dirname != *cache_name)
604 *cache_name = dirname;
605 *cache_dirid = dirid;
611 static int get_default_subvolid(int fd, u64 *default_id)
613 struct btrfs_ioctl_search_args args;
614 struct btrfs_ioctl_search_key *sk = &args.key;
615 struct btrfs_ioctl_search_header *sh;
619 memset(&args, 0, sizeof(args));
622 * search for a dir item with a name 'default' in the tree of
623 * tree roots, it should point us to a default root
627 /* don't worry about ancient format and request only one item */
630 sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
631 sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
632 sk->max_type = BTRFS_DIR_ITEM_KEY;
633 sk->min_type = BTRFS_DIR_ITEM_KEY;
634 sk->max_offset = (u64)-1;
635 sk->max_transid = (u64)-1;
637 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
641 /* the ioctl returns the number of items it found in nr_items */
642 if (sk->nr_items == 0)
645 sh = (struct btrfs_ioctl_search_header *)args.buf;
647 if (sh->type == BTRFS_DIR_ITEM_KEY) {
648 struct btrfs_dir_item *di;
652 di = (struct btrfs_dir_item *)(sh + 1);
653 name_len = btrfs_stack_dir_name_len(di);
654 name = (char *)(di + 1);
656 if (!strncmp("default", name, name_len))
657 found = btrfs_disk_key_objectid(&di->location);
665 static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
668 struct btrfs_ioctl_search_args args;
669 struct btrfs_ioctl_search_key *sk = &args.key;
670 struct btrfs_ioctl_search_header *sh;
671 struct btrfs_root_ref *ref;
672 struct btrfs_root_item *ri;
673 unsigned long off = 0;
682 u8 uuid[BTRFS_UUID_SIZE];
684 root_lookup_init(root_lookup);
685 memset(&args, 0, sizeof(args));
687 /* search in the tree of tree roots */
691 * set the min and max to backref keys. The search will
692 * only send back this type of key now.
694 sk->max_type = BTRFS_ROOT_BACKREF_KEY;
695 sk->min_type = BTRFS_ROOT_BACKREF_KEY;
697 sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
700 * set all the other params to the max, we'll take any objectid
703 sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
704 sk->max_offset = (u64)-1;
705 sk->max_transid = (u64)-1;
708 /* just a big number, doesn't matter much */
712 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
715 /* the ioctl returns the number of item it found in nr_items */
716 if (sk->nr_items == 0)
722 * for each item, pull the key out of the header and then
723 * read the root_ref item it contains
725 for (i = 0; i < sk->nr_items; i++) {
726 sh = (struct btrfs_ioctl_search_header *)(args.buf +
729 if (!get_gen && sh->type == BTRFS_ROOT_BACKREF_KEY) {
730 ref = (struct btrfs_root_ref *)(args.buf + off);
731 name_len = btrfs_stack_root_ref_name_len(ref);
732 name = (char *)(ref + 1);
733 dir_id = btrfs_stack_root_ref_dirid(ref);
735 add_root(root_lookup, sh->objectid, sh->offset,
736 dir_id, name, name_len, NULL, 0, NULL);
737 } else if (get_gen && sh->type == BTRFS_ROOT_ITEM_KEY) {
738 ri = (struct btrfs_root_item *)(args.buf + off);
739 gen = btrfs_root_generation(ri);
740 if(ri->generation == ri->generation_v2) {
742 memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE);
745 memset(uuid, 0, BTRFS_UUID_SIZE);
748 update_root(root_lookup, sh->objectid, gen, t,
755 * record the mins in sk so we can make sure the
756 * next search doesn't repeat this root
758 sk->min_objectid = sh->objectid;
759 sk->min_type = sh->type;
760 sk->min_offset = sh->offset;
763 /* this iteration is done, step forward one root for the next
767 type = BTRFS_ROOT_ITEM_KEY;
769 type = BTRFS_ROOT_BACKREF_KEY;
771 if (sk->min_type < type) {
774 } else if (sk->min_objectid < BTRFS_LAST_FREE_OBJECTID) {
783 memset(&args, 0, sizeof(args));
786 sk->max_type = BTRFS_ROOT_ITEM_KEY;
787 sk->min_type = BTRFS_ROOT_ITEM_KEY;
789 sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
791 sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
792 sk->max_offset = (u64)-1;
793 sk->max_transid = (u64)-1;
801 static int __list_snapshot_search(int fd, struct root_lookup *root_lookup)
804 struct btrfs_ioctl_search_args args;
805 struct btrfs_ioctl_search_key *sk = &args.key;
806 struct btrfs_ioctl_search_header *sh;
807 unsigned long off = 0;
811 root_lookup_init(root_lookup);
812 memset(&args, 0, sizeof(args));
815 sk->max_type = BTRFS_ROOT_ITEM_KEY;
816 sk->min_type = BTRFS_ROOT_ITEM_KEY;
817 sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID;
818 sk->max_objectid = BTRFS_LAST_FREE_OBJECTID;
819 sk->max_offset = (u64)-1;
820 sk->max_transid = (u64)-1;
824 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
827 /* the ioctl returns the number of item it found in nr_items */
828 if (sk->nr_items == 0)
834 * for each item, pull the key out of the header and then
835 * read the root_ref item it contains
837 for (i = 0; i < sk->nr_items; i++) {
838 struct btrfs_root_item *item;
840 u8 uuid[BTRFS_UUID_SIZE];
842 sh = (struct btrfs_ioctl_search_header *)(args.buf +
845 if (sh->type == BTRFS_ROOT_ITEM_KEY && sh->offset) {
846 item = (struct btrfs_root_item *)(args.buf + off);
847 if(item->generation == item->generation_v2) {
849 memcpy(uuid, item->uuid, BTRFS_UUID_SIZE);
852 memset(uuid, 0, BTRFS_UUID_SIZE);
856 add_root(root_lookup, sh->objectid, 0,
857 0, NULL, 0, &gen, t, uuid);
862 * record the mins in sk so we can make sure the
863 * next search doesn't repeat this root
865 sk->min_objectid = sh->objectid;
866 sk->min_type = sh->type;
867 sk->min_offset = sh->offset;
870 /* this iteration is done, step forward one root for the next
873 if (sk->min_type < BTRFS_ROOT_ITEM_KEY) {
874 sk->min_type = BTRFS_ROOT_ITEM_KEY;
876 } else if (sk->min_objectid < BTRFS_LAST_FREE_OBJECTID) {
878 sk->min_type = BTRFS_ROOT_ITEM_KEY;
886 static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup)
890 n = rb_first(&root_lookup->root);
892 struct root_info *entry;
894 entry = rb_entry(n, struct root_info, rb_node);
895 ret = lookup_ino_path(fd, entry);
904 int list_subvols(int fd, int print_parent, int get_default, int print_uuid)
906 struct root_lookup root_lookup;
913 ret = get_default_subvolid(fd, &default_id);
915 fprintf(stderr, "ERROR: can't perform the search - %s\n",
919 if (default_id == 0) {
920 fprintf(stderr, "ERROR: 'default' dir item not found\n");
924 /* no need to resolve roots if FS_TREE is default */
925 if (default_id == BTRFS_FS_TREE_OBJECTID) {
926 printf("ID 5 (FS_TREE)\n");
931 ret = __list_subvol_search(fd, &root_lookup);
933 fprintf(stderr, "ERROR: can't perform the search - %s\n",
939 * now we have an rbtree full of root_info objects, but we need to fill
940 * in their path names within the subvol that is referencing each one.
942 ret = __list_subvol_fill_paths(fd, &root_lookup);
946 /* now that we have all the subvol-relative paths filled in,
947 * we have to string the subvols together so that we can get
948 * a path all the way back to the FS root
950 n = rb_last(&root_lookup.root);
952 struct root_info *entry;
957 entry = rb_entry(n, struct root_info, rb_node);
958 if (get_default && entry->root_id != default_id) {
963 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
966 if (uuid_is_null(entry->uuid))
967 strcpy(uuidparse, "-");
969 uuid_unparse(entry->uuid, uuidparse);
970 printf("ID %llu gen %llu parent %llu top level %llu"
971 " uuid %s path %s\n",
972 (unsigned long long)entry->root_id,
973 (unsigned long long)entry->gen,
974 (unsigned long long)parent_id,
975 (unsigned long long)level,
978 printf("ID %llu gen %llu parent %llu top level"
980 (unsigned long long)entry->root_id,
981 (unsigned long long)entry->gen,
982 (unsigned long long)parent_id,
983 (unsigned long long)level, path);
987 if (uuid_is_null(entry->uuid))
988 strcpy(uuidparse, "-");
990 uuid_unparse(entry->uuid, uuidparse);
991 printf("ID %llu gen %llu top level %llu"
992 " uuid %s path %s\n",
993 (unsigned long long)entry->root_id,
994 (unsigned long long)entry->gen,
995 (unsigned long long)level,
998 printf("ID %llu gen %llu top level %llu path %s\n",
999 (unsigned long long)entry->root_id,
1000 (unsigned long long)entry->gen,
1001 (unsigned long long)level, path);
1012 int list_snapshots(int fd, int print_parent, int order, int print_uuid)
1014 struct root_lookup root_lookup;
1015 struct root_lookup root_lookup_snap;
1019 ret = __list_snapshot_search(fd, &root_lookup_snap);
1021 fprintf(stderr, "ERROR: can't perform the search - %s\n",
1026 ret = __list_subvol_search(fd, &root_lookup);
1028 fprintf(stderr, "ERROR: can't perform the search - %s\n",
1034 * now we have an rbtree full of root_info objects, but we need to fill
1035 * in their path names within the subvol that is referencing each one.
1037 ret = __list_subvol_fill_paths(fd, &root_lookup);
1041 /* now that we have all the subvol-relative paths filled in,
1042 * we have to string the subvols together so that we can get
1043 * a path all the way back to the FS root
1046 n = rb_last(&root_lookup_snap.root);
1048 n = rb_first(&root_lookup_snap.root);
1050 struct root_info *entry_snap;
1051 struct root_info *entry;
1059 entry_snap = rb_entry(n, struct root_info, rb_node);
1060 entry = tree_search(&root_lookup.root, entry_snap->root_id);
1062 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
1065 strftime(tstr,256,"%Y-%m-%d %X",localtime(&t));
1070 if (uuid_is_null(entry->uuid))
1071 strcpy(uuidparse, "-");
1073 uuid_unparse(entry->uuid, uuidparse);
1074 printf("ID %llu gen %llu cgen %llu parent %llu"
1075 " top level %llu otime %s uuid %s path %s\n",
1076 (unsigned long long)entry->root_id,
1077 (unsigned long long)entry->gen,
1078 (unsigned long long)entry_snap->gen,
1079 (unsigned long long)parent_id,
1080 (unsigned long long)level,
1081 tstr, uuidparse, path);
1083 printf("ID %llu gen %llu cgen %llu parent %llu"
1084 " top level %llu otime %s path %s\n",
1085 (unsigned long long)entry->root_id,
1086 (unsigned long long)entry->gen,
1087 (unsigned long long)entry_snap->gen,
1088 (unsigned long long)parent_id,
1089 (unsigned long long)level, tstr, path);
1093 if (uuid_is_null(entry->uuid))
1094 strcpy(uuidparse, "-");
1096 uuid_unparse(entry->uuid, uuidparse);
1097 printf("ID %llu gen %llu cgen %llu top level %llu "
1098 "otime %s uuid %s path %s\n",
1099 (unsigned long long)entry->root_id,
1100 (unsigned long long)entry->gen,
1101 (unsigned long long)entry_snap->gen,
1102 (unsigned long long)level,
1103 tstr, uuidparse, path);
1105 printf("ID %llu gen %llu cgen %llu top level %llu "
1106 "otime %s path %s\n",
1107 (unsigned long long)entry->root_id,
1108 (unsigned long long)entry->gen,
1109 (unsigned long long)entry_snap->gen,
1110 (unsigned long long)level, tstr, path);
1124 static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
1125 struct btrfs_file_extent_item *item,
1126 u64 found_gen, u64 *cache_dirid,
1127 char **cache_dir_name, u64 *cache_ino,
1128 char **cache_full_name)
1132 u64 disk_offset = 0;
1138 if (sh->objectid == *cache_ino) {
1139 name = *cache_full_name;
1140 } else if (*cache_full_name) {
1141 free(*cache_full_name);
1142 *cache_full_name = NULL;
1145 name = ino_resolve(fd, sh->objectid, cache_dirid,
1147 *cache_full_name = name;
1148 *cache_ino = sh->objectid;
1153 type = btrfs_stack_file_extent_type(item);
1154 compressed = btrfs_stack_file_extent_compression(item);
1156 if (type == BTRFS_FILE_EXTENT_REG ||
1157 type == BTRFS_FILE_EXTENT_PREALLOC) {
1158 disk_start = btrfs_stack_file_extent_disk_bytenr(item);
1159 disk_offset = btrfs_stack_file_extent_offset(item);
1160 len = btrfs_stack_file_extent_num_bytes(item);
1161 } else if (type == BTRFS_FILE_EXTENT_INLINE) {
1164 len = btrfs_stack_file_extent_ram_bytes(item);
1166 printf("unhandled extent type %d for inode %llu "
1167 "file offset %llu gen %llu\n",
1169 (unsigned long long)sh->objectid,
1170 (unsigned long long)sh->offset,
1171 (unsigned long long)found_gen);
1175 printf("inode %llu file offset %llu len %llu disk start %llu "
1176 "offset %llu gen %llu flags ",
1177 (unsigned long long)sh->objectid,
1178 (unsigned long long)sh->offset,
1179 (unsigned long long)len,
1180 (unsigned long long)disk_start,
1181 (unsigned long long)disk_offset,
1182 (unsigned long long)found_gen);
1188 if (type == BTRFS_FILE_EXTENT_PREALLOC) {
1189 printf("%sPREALLOC", flags ? "|" : "");
1192 if (type == BTRFS_FILE_EXTENT_INLINE) {
1193 printf("%sINLINE", flags ? "|" : "");
1199 printf(" %s\n", name);
1203 int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
1206 struct btrfs_ioctl_search_args args;
1207 struct btrfs_ioctl_search_key *sk = &args.key;
1208 struct btrfs_ioctl_search_header *sh;
1209 struct btrfs_file_extent_item *item;
1210 unsigned long off = 0;
1215 u64 cache_dirid = 0;
1217 char *cache_dir_name = NULL;
1218 char *cache_full_name = NULL;
1219 struct btrfs_file_extent_item backup;
1221 memset(&backup, 0, sizeof(backup));
1222 memset(&args, 0, sizeof(args));
1224 sk->tree_id = root_id;
1227 * set all the other params to the max, we'll take any objectid
1230 sk->max_objectid = (u64)-1;
1231 sk->max_offset = (u64)-1;
1232 sk->max_transid = (u64)-1;
1233 sk->max_type = BTRFS_EXTENT_DATA_KEY;
1234 sk->min_transid = oldest_gen;
1235 /* just a big number, doesn't matter much */
1236 sk->nr_items = 4096;
1238 max_found = find_root_gen(fd);
1240 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1243 fprintf(stderr, "ERROR: can't perform the search- %s\n",
1247 /* the ioctl returns the number of item it found in nr_items */
1248 if (sk->nr_items == 0)
1254 * for each item, pull the key out of the header and then
1255 * read the root_ref item it contains
1257 for (i = 0; i < sk->nr_items; i++) {
1258 sh = (struct btrfs_ioctl_search_header *)(args.buf +
1263 * just in case the item was too big, pass something other
1269 item = (struct btrfs_file_extent_item *)(args.buf +
1271 found_gen = btrfs_stack_file_extent_generation(item);
1272 if (sh->type == BTRFS_EXTENT_DATA_KEY &&
1273 found_gen >= oldest_gen) {
1274 print_one_extent(fd, sh, item, found_gen,
1275 &cache_dirid, &cache_dir_name,
1276 &cache_ino, &cache_full_name);
1281 * record the mins in sk so we can make sure the
1282 * next search doesn't repeat this root
1284 sk->min_objectid = sh->objectid;
1285 sk->min_offset = sh->offset;
1286 sk->min_type = sh->type;
1288 sk->nr_items = 4096;
1289 if (sk->min_offset < (u64)-1)
1291 else if (sk->min_objectid < (u64)-1) {
1298 free(cache_dir_name);
1299 free(cache_full_name);
1300 printf("transid marker was %llu\n", (unsigned long long)max_found);
1304 char *path_for_root(int fd, u64 root)
1306 struct root_lookup root_lookup;
1308 char *ret_path = NULL;
1311 ret = __list_subvol_search(fd, &root_lookup);
1313 return ERR_PTR(ret);
1315 ret = __list_subvol_fill_paths(fd, &root_lookup);
1317 return ERR_PTR(ret);
1319 n = rb_last(&root_lookup.root);
1321 struct root_info *entry;
1326 entry = rb_entry(n, struct root_info, rb_node);
1327 resolve_root(&root_lookup, entry, &parent_id, &level, &path);
1328 if (entry->root_id == root)