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>
34 #include "transaction.h"
36 #include <uuid/uuid.h>
37 #include "btrfs-list.h"
39 #define BTRFS_LIST_NFILTERS_INCREASE (2 * BTRFS_LIST_FILTER_MAX)
40 #define BTRFS_LIST_NCOMPS_INCREASE (2 * BTRFS_LIST_COMP_MAX)
42 /* we store all the roots we find in an rbtree so that we can
43 * search for them later.
50 * one of these for each root we find.
53 struct rb_node rb_node
;
54 struct rb_node sort_node
;
59 /* equal the offset of the root's key */
62 /* flags of the root */
65 /* the id of the root that references this one */
68 /* the dir id we're in from ref_tree */
73 /* generation when the root is created or last updated */
76 /* creation generation of this root in sec*/
79 /* creation time of this root in sec*/
82 u8 uuid
[BTRFS_UUID_SIZE
];
84 /* path from the subvol we live in to this root, including the
85 * root's name. This is null until we do the extra lookup ioctl.
89 /* the name of this root in the directory it lives in */
99 } btrfs_list_columns
[] = {
107 .column_name
= "Gen",
112 .column_name
= "CGen",
117 .column_name
= "Parent",
122 .column_name
= "Top Level",
127 .column_name
= "OTime",
132 .column_name
= "UUID",
137 .column_name
= "Path",
147 static btrfs_list_filter_func all_filter_funcs
[];
148 static btrfs_list_comp_func all_comp_funcs
[];
150 void btrfs_list_setup_print_column(enum btrfs_list_column_enum column
)
154 BUG_ON(column
< 0 || column
> BTRFS_LIST_ALL
);
156 if (column
< BTRFS_LIST_ALL
) {
157 btrfs_list_columns
[column
].need_print
= 1;
161 for (i
= 0; i
< BTRFS_LIST_ALL
; i
++)
162 btrfs_list_columns
[i
].need_print
= 1;
165 static void root_lookup_init(struct root_lookup
*tree
)
167 tree
->root
.rb_node
= NULL
;
170 static int comp_entry_with_rootid(struct root_info
*entry1
,
171 struct root_info
*entry2
,
176 if (entry1
->root_id
> entry2
->root_id
)
178 else if (entry1
->root_id
< entry2
->root_id
)
183 return is_descending
? -ret
: ret
;
186 static int comp_entry_with_gen(struct root_info
*entry1
,
187 struct root_info
*entry2
,
192 if (entry1
->gen
> entry2
->gen
)
194 else if (entry1
->gen
< entry2
->gen
)
199 return is_descending
? -ret
: ret
;
202 static int comp_entry_with_ogen(struct root_info
*entry1
,
203 struct root_info
*entry2
,
208 if (entry1
->ogen
> entry2
->ogen
)
210 else if (entry1
->ogen
< entry2
->ogen
)
215 return is_descending
? -ret
: ret
;
218 static int comp_entry_with_path(struct root_info
*entry1
,
219 struct root_info
*entry2
,
224 if (strcmp(entry1
->full_path
, entry2
->full_path
) > 0)
226 else if (strcmp(entry1
->full_path
, entry2
->full_path
) < 0)
231 return is_descending
? -ret
: ret
;
234 static btrfs_list_comp_func all_comp_funcs
[] = {
235 [BTRFS_LIST_COMP_ROOTID
] = comp_entry_with_rootid
,
236 [BTRFS_LIST_COMP_OGEN
] = comp_entry_with_ogen
,
237 [BTRFS_LIST_COMP_GEN
] = comp_entry_with_gen
,
238 [BTRFS_LIST_COMP_PATH
] = comp_entry_with_path
,
241 static char *all_sort_items
[] = {
242 [BTRFS_LIST_COMP_ROOTID
] = "rootid",
243 [BTRFS_LIST_COMP_OGEN
] = "ogen",
244 [BTRFS_LIST_COMP_GEN
] = "gen",
245 [BTRFS_LIST_COMP_PATH
] = "path",
246 [BTRFS_LIST_COMP_MAX
] = NULL
,
249 static int btrfs_list_get_sort_item(char *sort_name
)
253 for (i
= 0; i
< BTRFS_LIST_COMP_MAX
; i
++) {
254 if (strcmp(sort_name
, all_sort_items
[i
]) == 0)
260 struct btrfs_list_comparer_set
*btrfs_list_alloc_comparer_set(void)
262 struct btrfs_list_comparer_set
*set
;
265 size
= sizeof(struct btrfs_list_comparer_set
) +
266 BTRFS_LIST_NCOMPS_INCREASE
* sizeof(struct btrfs_list_comparer
);
269 fprintf(stderr
, "memory allocation failed\n");
273 memset(set
, 0, size
);
274 set
->total
= BTRFS_LIST_NCOMPS_INCREASE
;
279 void btrfs_list_free_comparer_set(struct btrfs_list_comparer_set
*comp_set
)
284 int btrfs_list_setup_comparer(struct btrfs_list_comparer_set
**comp_set
,
285 enum btrfs_list_comp_enum comparer
,
288 struct btrfs_list_comparer_set
*set
= *comp_set
;
292 BUG_ON(comparer
>= BTRFS_LIST_COMP_MAX
);
293 BUG_ON(set
->ncomps
> set
->total
);
295 if (set
->ncomps
== set
->total
) {
296 size
= set
->total
+ BTRFS_LIST_NCOMPS_INCREASE
;
297 size
= sizeof(*set
) + size
* sizeof(struct btrfs_list_comparer
);
298 set
= realloc(set
, size
);
300 fprintf(stderr
, "memory allocation failed\n");
304 memset(&set
->comps
[set
->total
], 0,
305 BTRFS_LIST_NCOMPS_INCREASE
*
306 sizeof(struct btrfs_list_comparer
));
307 set
->total
+= BTRFS_LIST_NCOMPS_INCREASE
;
311 BUG_ON(set
->comps
[set
->ncomps
].comp_func
);
313 set
->comps
[set
->ncomps
].comp_func
= all_comp_funcs
[comparer
];
314 set
->comps
[set
->ncomps
].is_descending
= is_descending
;
319 static int sort_comp(struct root_info
*entry1
, struct root_info
*entry2
,
320 struct btrfs_list_comparer_set
*set
)
322 int rootid_compared
= 0;
325 if (!set
|| !set
->ncomps
)
328 for (i
= 0; i
< set
->ncomps
; i
++) {
329 if (!set
->comps
[i
].comp_func
)
332 ret
= set
->comps
[i
].comp_func(entry1
, entry2
,
333 set
->comps
[i
].is_descending
);
337 if (set
->comps
[i
].comp_func
== comp_entry_with_rootid
)
341 if (!rootid_compared
) {
343 ret
= comp_entry_with_rootid(entry1
, entry2
, 0);
349 static int sort_tree_insert(struct root_lookup
*sort_tree
,
350 struct root_info
*ins
,
351 struct btrfs_list_comparer_set
*comp_set
)
353 struct rb_node
**p
= &sort_tree
->root
.rb_node
;
354 struct rb_node
*parent
= NULL
;
355 struct root_info
*curr
;
360 curr
= rb_entry(parent
, struct root_info
, sort_node
);
362 ret
= sort_comp(ins
, curr
, comp_set
);
371 rb_link_node(&ins
->sort_node
, parent
, p
);
372 rb_insert_color(&ins
->sort_node
, &sort_tree
->root
);
377 * insert a new root into the tree. returns the existing root entry
378 * if one is already there. Both root_id and ref_tree are used
381 static int root_tree_insert(struct root_lookup
*root_tree
,
382 struct root_info
*ins
)
384 struct rb_node
**p
= &root_tree
->root
.rb_node
;
385 struct rb_node
* parent
= NULL
;
386 struct root_info
*curr
;
391 curr
= rb_entry(parent
, struct root_info
, rb_node
);
393 ret
= comp_entry_with_rootid(ins
, curr
, 0);
402 rb_link_node(&ins
->rb_node
, parent
, p
);
403 rb_insert_color(&ins
->rb_node
, &root_tree
->root
);
408 * find a given root id in the tree. We return the smallest one,
409 * rb_next can be used to move forward looking for more if required
411 static struct root_info
*root_tree_search(struct root_lookup
*root_tree
,
414 struct rb_node
*n
= root_tree
->root
.rb_node
;
415 struct root_info
*entry
;
416 struct root_info tmp
;
419 tmp
.root_id
= root_id
;
422 entry
= rb_entry(n
, struct root_info
, rb_node
);
424 ret
= comp_entry_with_rootid(&tmp
, entry
, 0);
435 static int update_root(struct root_lookup
*root_lookup
,
436 u64 root_id
, u64 ref_tree
, u64 root_offset
, u64 flags
,
437 u64 dir_id
, char *name
, int name_len
, u64 ogen
, u64 gen
,
438 time_t ot
, void *uuid
)
440 struct root_info
*ri
;
442 ri
= root_tree_search(root_lookup
, root_id
);
443 if (!ri
|| ri
->root_id
!= root_id
)
445 if (name
&& name_len
> 0) {
449 ri
->name
= malloc(name_len
+ 1);
451 fprintf(stderr
, "memory allocation failed\n");
454 strncpy(ri
->name
, name
, name_len
);
455 ri
->name
[name_len
] = 0;
458 ri
->ref_tree
= ref_tree
;
460 ri
->root_offset
= root_offset
;
469 if (!ri
->ogen
&& root_offset
)
470 ri
->ogen
= root_offset
;
474 memcpy(&ri
->uuid
, uuid
, BTRFS_UUID_SIZE
);
480 * add_root - update the existed root, or allocate a new root and insert it
481 * into the lookup tree.
482 * root_id: object id of the root
483 * ref_tree: object id of the referring root.
484 * root_offset: offset value of the root'key
485 * dir_id: inode id of the directory in ref_tree where this root can be found.
486 * name: the name of root_id in that directory
487 * name_len: the length of name
488 * ogen: the original generation of the root
489 * gen: the current generation of the root
490 * ot: the original time(create time) of the root
491 * uuid: uuid of the root
493 static int add_root(struct root_lookup
*root_lookup
,
494 u64 root_id
, u64 ref_tree
, u64 root_offset
, u64 flags
,
495 u64 dir_id
, char *name
, int name_len
, u64 ogen
, u64 gen
,
496 time_t ot
, void *uuid
)
498 struct root_info
*ri
;
501 ret
= update_root(root_lookup
, root_id
, ref_tree
, root_offset
, flags
,
502 dir_id
, name
, name_len
, ogen
, gen
, ot
, uuid
);
506 ri
= malloc(sizeof(*ri
));
508 printf("memory allocation failed\n");
511 memset(ri
, 0, sizeof(*ri
));
512 ri
->root_id
= root_id
;
514 if (name
&& name_len
> 0) {
515 ri
->name
= malloc(name_len
+ 1);
517 fprintf(stderr
, "memory allocation failed\n");
520 strncpy(ri
->name
, name
, name_len
);
521 ri
->name
[name_len
] = 0;
524 ri
->ref_tree
= ref_tree
;
528 ri
->root_offset
= root_offset
;
535 if (!ri
->ogen
&& root_offset
)
536 ri
->ogen
= root_offset
;
541 memcpy(&ri
->uuid
, uuid
, BTRFS_UUID_SIZE
);
543 ret
= root_tree_insert(root_lookup
, ri
);
545 printf("failed to insert tree %llu\n", (unsigned long long)root_id
);
551 void __free_root_info(struct root_info
*ri
)
565 void __free_all_subvolumn(struct root_lookup
*root_tree
)
567 struct root_info
*entry
;
570 n
= rb_first(&root_tree
->root
);
572 entry
= rb_entry(n
, struct root_info
, rb_node
);
573 rb_erase(n
, &root_tree
->root
);
574 __free_root_info(entry
);
576 n
= rb_first(&root_tree
->root
);
581 * for a given root_info, search through the root_lookup tree to construct
582 * the full path name to it.
584 * This can't be called until all the root_info->path fields are filled
585 * in by lookup_ino_path
587 static int resolve_root(struct root_lookup
*rl
, struct root_info
*ri
,
590 char *full_path
= NULL
;
592 struct root_info
*found
;
595 * we go backwards from the root_info object and add pathnames
596 * from parent directories as we go.
602 int add_len
= strlen(found
->path
);
604 /* room for / and for null */
605 tmp
= malloc(add_len
+ 2 + len
);
607 perror("malloc failed");
611 memcpy(tmp
+ add_len
+ 1, full_path
, len
);
613 memcpy(tmp
, found
->path
, add_len
);
614 tmp
[add_len
+ len
+ 1] = '\0';
619 full_path
= strdup(found
->path
);
623 next
= found
->ref_tree
;
625 if (next
== top_id
) {
630 if (next
== BTRFS_FS_TREE_OBJECTID
) {
631 char p
[] = "<FS_TREE>";
633 len
= strlen(full_path
);
634 tmp
= malloc(len
+ add_len
+ 2);
635 memcpy(tmp
+ add_len
+ 1, full_path
, len
);
637 memcpy(tmp
, p
, add_len
);
645 * if the ref_tree wasn't in our tree of roots, we're
648 found
= root_tree_search(rl
, next
);
655 ri
->full_path
= full_path
;
661 * for a single root_info, ask the kernel to give us a path name
662 * inside it's ref_root for the dir_id where it lives.
664 * This fills in root_info->path with the path to the directory and and
665 * appends this root's name.
667 static int lookup_ino_path(int fd
, struct root_info
*ri
)
669 struct btrfs_ioctl_ino_lookup_args args
;
675 memset(&args
, 0, sizeof(args
));
676 args
.treeid
= ri
->ref_tree
;
677 args
.objectid
= ri
->dir_id
;
679 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
682 fprintf(stderr
, "ERROR: Failed to lookup path for root %llu - %s\n",
683 (unsigned long long)ri
->ref_tree
,
690 * we're in a subdirectory of ref_tree, the kernel ioctl
691 * puts a / in there for us
693 ri
->path
= malloc(strlen(ri
->name
) + strlen(args
.name
) + 1);
695 perror("malloc failed");
698 strcpy(ri
->path
, args
.name
);
699 strcat(ri
->path
, ri
->name
);
701 /* we're at the root of ref_tree */
702 ri
->path
= strdup(ri
->name
);
704 perror("strdup failed");
711 /* finding the generation for a given path is a two step process.
712 * First we use the inode loookup routine to find out the root id
714 * Then we use the tree search ioctl to scan all the root items for a
715 * given root id and spit out the latest generation we can find
717 static u64
find_root_gen(int fd
)
719 struct btrfs_ioctl_ino_lookup_args ino_args
;
721 struct btrfs_ioctl_search_args args
;
722 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
723 struct btrfs_ioctl_search_header
*sh
;
724 unsigned long off
= 0;
729 memset(&ino_args
, 0, sizeof(ino_args
));
730 ino_args
.objectid
= BTRFS_FIRST_FREE_OBJECTID
;
732 /* this ioctl fills in ino_args->treeid */
733 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &ino_args
);
736 fprintf(stderr
, "ERROR: Failed to lookup path for dirid %llu - %s\n",
737 (unsigned long long)BTRFS_FIRST_FREE_OBJECTID
,
742 memset(&args
, 0, sizeof(args
));
747 * there may be more than one ROOT_ITEM key if there are
748 * snapshots pending deletion, we have to loop through
751 sk
->min_objectid
= ino_args
.treeid
;
752 sk
->max_objectid
= ino_args
.treeid
;
753 sk
->max_type
= BTRFS_ROOT_ITEM_KEY
;
754 sk
->min_type
= BTRFS_ROOT_ITEM_KEY
;
755 sk
->max_offset
= (u64
)-1;
756 sk
->max_transid
= (u64
)-1;
760 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
763 fprintf(stderr
, "ERROR: can't perform the search - %s\n",
767 /* the ioctl returns the number of item it found in nr_items */
768 if (sk
->nr_items
== 0)
772 for (i
= 0; i
< sk
->nr_items
; i
++) {
773 struct btrfs_root_item
*item
;
774 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
778 item
= (struct btrfs_root_item
*)(args
.buf
+ off
);
781 sk
->min_objectid
= sh
->objectid
;
782 sk
->min_type
= sh
->type
;
783 sk
->min_offset
= sh
->offset
;
785 if (sh
->objectid
> ino_args
.treeid
)
788 if (sh
->objectid
== ino_args
.treeid
&&
789 sh
->type
== BTRFS_ROOT_ITEM_KEY
) {
790 max_found
= max(max_found
,
791 btrfs_root_generation(item
));
794 if (sk
->min_offset
< (u64
)-1)
799 if (sk
->min_type
!= BTRFS_ROOT_ITEM_KEY
)
801 if (sk
->min_objectid
!= BTRFS_ROOT_ITEM_KEY
)
807 /* pass in a directory id and this will return
808 * the full path of the parent directory inside its
811 * It may return NULL if it is in the root, or an ERR_PTR if things
814 static char *__ino_resolve(int fd
, u64 dirid
)
816 struct btrfs_ioctl_ino_lookup_args args
;
821 memset(&args
, 0, sizeof(args
));
822 args
.objectid
= dirid
;
824 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
827 fprintf(stderr
, "ERROR: Failed to lookup path for dirid %llu - %s\n",
828 (unsigned long long)dirid
, strerror(e
) );
834 * we're in a subdirectory of ref_tree, the kernel ioctl
835 * puts a / in there for us
837 full
= strdup(args
.name
);
839 perror("malloc failed");
840 return ERR_PTR(-ENOMEM
);
843 /* we're at the root of ref_tree */
850 * simple string builder, returning a new string with both
853 char *build_name(char *dirid
, char *name
)
859 full
= malloc(strlen(dirid
) + strlen(name
) + 1);
868 * given an inode number, this returns the full path name inside the subvolume
869 * to that file/directory. cache_dirid and cache_name are used to
870 * cache the results so we can avoid tree searches if a later call goes
871 * to the same directory or file name
873 static char *ino_resolve(int fd
, u64 ino
, u64
*cache_dirid
, char **cache_name
)
881 struct btrfs_ioctl_search_args args
;
882 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
883 struct btrfs_ioctl_search_header
*sh
;
884 unsigned long off
= 0;
888 memset(&args
, 0, sizeof(args
));
893 * step one, we search for the inode back ref. We just use the first
896 sk
->min_objectid
= ino
;
897 sk
->max_objectid
= ino
;
898 sk
->max_type
= BTRFS_INODE_REF_KEY
;
899 sk
->max_offset
= (u64
)-1;
900 sk
->min_type
= BTRFS_INODE_REF_KEY
;
901 sk
->max_transid
= (u64
)-1;
904 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
907 fprintf(stderr
, "ERROR: can't perform the search - %s\n",
911 /* the ioctl returns the number of item it found in nr_items */
912 if (sk
->nr_items
== 0)
916 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+ off
);
918 if (sh
->type
== BTRFS_INODE_REF_KEY
) {
919 struct btrfs_inode_ref
*ref
;
922 ref
= (struct btrfs_inode_ref
*)(sh
+ 1);
923 namelen
= btrfs_stack_inode_ref_name_len(ref
);
925 name
= (char *)(ref
+ 1);
926 name
= strndup(name
, namelen
);
928 /* use our cached value */
929 if (dirid
== *cache_dirid
&& *cache_name
) {
930 dirname
= *cache_name
;
937 * the inode backref gives us the file name and the parent directory id.
938 * From here we use __ino_resolve to get the path to the parent
940 dirname
= __ino_resolve(fd
, dirid
);
942 full
= build_name(dirname
, name
);
943 if (*cache_name
&& dirname
!= *cache_name
)
946 *cache_name
= dirname
;
947 *cache_dirid
= dirid
;
953 int btrfs_list_get_default_subvolume(int fd
, u64
*default_id
)
955 struct btrfs_ioctl_search_args args
;
956 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
957 struct btrfs_ioctl_search_header
*sh
;
961 memset(&args
, 0, sizeof(args
));
964 * search for a dir item with a name 'default' in the tree of
965 * tree roots, it should point us to a default root
969 /* don't worry about ancient format and request only one item */
972 sk
->max_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
973 sk
->min_objectid
= BTRFS_ROOT_TREE_DIR_OBJECTID
;
974 sk
->max_type
= BTRFS_DIR_ITEM_KEY
;
975 sk
->min_type
= BTRFS_DIR_ITEM_KEY
;
976 sk
->max_offset
= (u64
)-1;
977 sk
->max_transid
= (u64
)-1;
979 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
983 /* the ioctl returns the number of items it found in nr_items */
984 if (sk
->nr_items
== 0)
987 sh
= (struct btrfs_ioctl_search_header
*)args
.buf
;
989 if (sh
->type
== BTRFS_DIR_ITEM_KEY
) {
990 struct btrfs_dir_item
*di
;
994 di
= (struct btrfs_dir_item
*)(sh
+ 1);
995 name_len
= btrfs_stack_dir_name_len(di
);
996 name
= (char *)(di
+ 1);
998 if (!strncmp("default", name
, name_len
))
999 found
= btrfs_disk_key_objectid(&di
->location
);
1003 *default_id
= found
;
1007 static int __list_subvol_search(int fd
, struct root_lookup
*root_lookup
)
1010 struct btrfs_ioctl_search_args args
;
1011 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
1012 struct btrfs_ioctl_search_header
*sh
;
1013 struct btrfs_root_ref
*ref
;
1014 struct btrfs_root_item
*ri
;
1015 unsigned long off
= 0;
1024 u8 uuid
[BTRFS_UUID_SIZE
];
1026 root_lookup_init(root_lookup
);
1027 memset(&args
, 0, sizeof(args
));
1029 /* search in the tree of tree roots */
1033 * set the min and max to backref keys. The search will
1034 * only send back this type of key now.
1036 sk
->max_type
= BTRFS_ROOT_BACKREF_KEY
;
1037 sk
->min_type
= BTRFS_ROOT_ITEM_KEY
;
1039 sk
->min_objectid
= BTRFS_FIRST_FREE_OBJECTID
;
1042 * set all the other params to the max, we'll take any objectid
1045 sk
->max_objectid
= BTRFS_LAST_FREE_OBJECTID
;
1046 sk
->max_offset
= (u64
)-1;
1047 sk
->max_transid
= (u64
)-1;
1049 /* just a big number, doesn't matter much */
1050 sk
->nr_items
= 4096;
1053 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
1056 /* the ioctl returns the number of item it found in nr_items */
1057 if (sk
->nr_items
== 0)
1063 * for each item, pull the key out of the header and then
1064 * read the root_ref item it contains
1066 for (i
= 0; i
< sk
->nr_items
; i
++) {
1067 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
1070 if (sh
->type
== BTRFS_ROOT_BACKREF_KEY
) {
1071 ref
= (struct btrfs_root_ref
*)(args
.buf
+ off
);
1072 name_len
= btrfs_stack_root_ref_name_len(ref
);
1073 name
= (char *)(ref
+ 1);
1074 dir_id
= btrfs_stack_root_ref_dirid(ref
);
1076 add_root(root_lookup
, sh
->objectid
, sh
->offset
,
1077 0, 0, dir_id
, name
, name_len
, 0, 0, 0,
1079 } else if (sh
->type
== BTRFS_ROOT_ITEM_KEY
) {
1080 ri
= (struct btrfs_root_item
*)(args
.buf
+ off
);
1081 gen
= btrfs_root_generation(ri
);
1082 flags
= btrfs_root_flags(ri
);
1084 sizeof(struct btrfs_root_item_v0
)) {
1086 ogen
= btrfs_root_otransid(ri
);
1087 memcpy(uuid
, ri
->uuid
, BTRFS_UUID_SIZE
);
1091 memset(uuid
, 0, BTRFS_UUID_SIZE
);
1094 add_root(root_lookup
, sh
->objectid
, 0,
1095 sh
->offset
, flags
, 0, NULL
, 0, ogen
,
1102 * record the mins in sk so we can make sure the
1103 * next search doesn't repeat this root
1105 sk
->min_objectid
= sh
->objectid
;
1106 sk
->min_type
= sh
->type
;
1107 sk
->min_offset
= sh
->offset
;
1109 sk
->nr_items
= 4096;
1111 if (!sk
->min_offset
) /* overflow */
1116 if (sk
->min_type
> BTRFS_ROOT_BACKREF_KEY
) {
1117 sk
->min_type
= BTRFS_ROOT_ITEM_KEY
;
1122 if (sk
->min_objectid
> sk
->max_objectid
)
1129 static int filter_by_rootid(struct root_info
*ri
, u64 data
)
1131 return ri
->root_id
== data
;
1134 static int filter_snapshot(struct root_info
*ri
, u64 data
)
1136 return !!ri
->root_offset
;
1139 static int filter_flags(struct root_info
*ri
, u64 flags
)
1141 return ri
->flags
& flags
;
1144 static int filter_gen_more(struct root_info
*ri
, u64 data
)
1146 return ri
->gen
>= data
;
1149 static int filter_gen_less(struct root_info
*ri
, u64 data
)
1151 return ri
->gen
<= data
;
1154 static int filter_gen_equal(struct root_info
*ri
, u64 data
)
1156 return ri
->gen
== data
;
1159 static int filter_cgen_more(struct root_info
*ri
, u64 data
)
1161 return ri
->ogen
>= data
;
1164 static int filter_cgen_less(struct root_info
*ri
, u64 data
)
1166 return ri
->ogen
<= data
;
1169 static int filter_cgen_equal(struct root_info
*ri
, u64 data
)
1171 return ri
->ogen
== data
;
1174 static int filter_topid_equal(struct root_info
*ri
, u64 data
)
1176 return ri
->top_id
== data
;
1179 static btrfs_list_filter_func all_filter_funcs
[] = {
1180 [BTRFS_LIST_FILTER_ROOTID
] = filter_by_rootid
,
1181 [BTRFS_LIST_FILTER_SNAPSHOT_ONLY
] = filter_snapshot
,
1182 [BTRFS_LIST_FILTER_FLAGS
] = filter_flags
,
1183 [BTRFS_LIST_FILTER_GEN_MORE
] = filter_gen_more
,
1184 [BTRFS_LIST_FILTER_GEN_LESS
] = filter_gen_less
,
1185 [BTRFS_LIST_FILTER_GEN_EQUAL
] = filter_gen_equal
,
1186 [BTRFS_LIST_FILTER_CGEN_MORE
] = filter_cgen_more
,
1187 [BTRFS_LIST_FILTER_CGEN_LESS
] = filter_cgen_less
,
1188 [BTRFS_LIST_FILTER_CGEN_EQUAL
] = filter_cgen_equal
,
1189 [BTRFS_LIST_FILTER_TOPID_EQUAL
] = filter_topid_equal
,
1192 struct btrfs_list_filter_set
*btrfs_list_alloc_filter_set(void)
1194 struct btrfs_list_filter_set
*set
;
1197 size
= sizeof(struct btrfs_list_filter_set
) +
1198 BTRFS_LIST_NFILTERS_INCREASE
* sizeof(struct btrfs_list_filter
);
1201 fprintf(stderr
, "memory allocation failed\n");
1205 memset(set
, 0, size
);
1206 set
->total
= BTRFS_LIST_NFILTERS_INCREASE
;
1211 void btrfs_list_free_filter_set(struct btrfs_list_filter_set
*filter_set
)
1216 int btrfs_list_setup_filter(struct btrfs_list_filter_set
**filter_set
,
1217 enum btrfs_list_filter_enum filter
, u64 data
)
1219 struct btrfs_list_filter_set
*set
= *filter_set
;
1223 BUG_ON(filter
>= BTRFS_LIST_FILTER_MAX
);
1224 BUG_ON(set
->nfilters
> set
->total
);
1226 if (set
->nfilters
== set
->total
) {
1227 size
= set
->total
+ BTRFS_LIST_NFILTERS_INCREASE
;
1228 size
= sizeof(*set
) + size
* sizeof(struct btrfs_list_filter
);
1229 set
= realloc(set
, size
);
1231 fprintf(stderr
, "memory allocation failed\n");
1235 memset(&set
->filters
[set
->total
], 0,
1236 BTRFS_LIST_NFILTERS_INCREASE
*
1237 sizeof(struct btrfs_list_filter
));
1238 set
->total
+= BTRFS_LIST_NFILTERS_INCREASE
;
1242 BUG_ON(set
->filters
[set
->nfilters
].filter_func
);
1244 set
->filters
[set
->nfilters
].filter_func
= all_filter_funcs
[filter
];
1245 set
->filters
[set
->nfilters
].data
= data
;
1250 static int filter_root(struct root_info
*ri
,
1251 struct btrfs_list_filter_set
*set
)
1255 if (!set
|| !set
->nfilters
)
1258 for (i
= 0; i
< set
->nfilters
; i
++) {
1259 if (!set
->filters
[i
].filter_func
)
1261 ret
= set
->filters
[i
].filter_func(ri
, set
->filters
[i
].data
);
1268 static void __filter_and_sort_subvol(struct root_lookup
*all_subvols
,
1269 struct root_lookup
*sort_tree
,
1270 struct btrfs_list_filter_set
*filter_set
,
1271 struct btrfs_list_comparer_set
*comp_set
,
1275 struct root_info
*entry
;
1277 u64 top_id
= btrfs_list_get_path_rootid(fd
);
1279 root_lookup_init(sort_tree
);
1281 n
= rb_last(&all_subvols
->root
);
1283 entry
= rb_entry(n
, struct root_info
, rb_node
);
1285 resolve_root(all_subvols
, entry
, top_id
);
1286 ret
= filter_root(entry
, filter_set
);
1288 sort_tree_insert(sort_tree
, entry
, comp_set
);
1293 static int __list_subvol_fill_paths(int fd
, struct root_lookup
*root_lookup
)
1297 n
= rb_first(&root_lookup
->root
);
1299 struct root_info
*entry
;
1301 entry
= rb_entry(n
, struct root_info
, rb_node
);
1302 ret
= lookup_ino_path(fd
, entry
);
1311 static void print_subvolume_column(struct root_info
*subv
,
1312 enum btrfs_list_column_enum column
)
1317 BUG_ON(column
>= BTRFS_LIST_ALL
|| column
< 0);
1320 case BTRFS_LIST_OBJECTID
:
1321 printf("%llu", subv
->root_id
);
1323 case BTRFS_LIST_GENERATION
:
1324 printf("%llu", subv
->gen
);
1326 case BTRFS_LIST_OGENERATION
:
1327 printf("%llu", subv
->ogen
);
1329 case BTRFS_LIST_PARENT
:
1330 printf("%llu", subv
->ref_tree
);
1332 case BTRFS_LIST_TOP_LEVEL
:
1333 printf("%llu", subv
->top_id
);
1335 case BTRFS_LIST_OTIME
:
1337 strftime(tstr
, 256, "%Y-%m-%d %X",
1338 localtime(&subv
->otime
));
1343 case BTRFS_LIST_UUID
:
1344 if (uuid_is_null(subv
->uuid
))
1345 strcpy(uuidparse
, "-");
1347 uuid_unparse(subv
->uuid
, uuidparse
);
1348 printf("%s", uuidparse
);
1350 case BTRFS_LIST_PATH
:
1351 BUG_ON(!subv
->full_path
);
1352 printf("%s", subv
->full_path
);
1359 static void print_single_volume_info_table(struct root_info
*subv
)
1363 for (i
= 0; i
< BTRFS_LIST_ALL
; i
++) {
1364 if (!btrfs_list_columns
[i
].need_print
)
1367 print_subvolume_column(subv
, i
);
1369 if (i
!= BTRFS_LIST_PATH
)
1372 if (i
== BTRFS_LIST_TOP_LEVEL
)
1378 static void print_single_volume_info_default(struct root_info
*subv
)
1382 for (i
= 0; i
< BTRFS_LIST_ALL
; i
++) {
1383 if (!btrfs_list_columns
[i
].need_print
)
1386 printf("%s ", btrfs_list_columns
[i
].name
);
1387 print_subvolume_column(subv
, i
);
1389 if (i
!= BTRFS_LIST_PATH
)
1395 static void print_all_volume_info_tab_head()
1401 for (i
= 0; i
< BTRFS_LIST_ALL
; i
++) {
1402 if (btrfs_list_columns
[i
].need_print
)
1403 printf("%s\t", btrfs_list_columns
[i
].name
);
1405 if (i
== BTRFS_LIST_ALL
-1)
1409 for (i
= 0; i
< BTRFS_LIST_ALL
; i
++) {
1410 memset(barrier
, 0, sizeof(barrier
));
1412 if (btrfs_list_columns
[i
].need_print
) {
1413 len
= strlen(btrfs_list_columns
[i
].name
);
1415 strcat(barrier
, "-");
1417 printf("%s\t", barrier
);
1419 if (i
== BTRFS_LIST_ALL
-1)
1424 static void print_all_volume_info(struct root_lookup
*sorted_tree
,
1428 struct root_info
*entry
;
1431 print_all_volume_info_tab_head();
1433 n
= rb_first(&sorted_tree
->root
);
1435 entry
= rb_entry(n
, struct root_info
, sort_node
);
1437 print_single_volume_info_table(entry
);
1439 print_single_volume_info_default(entry
);
1444 int btrfs_list_subvols(int fd
, struct btrfs_list_filter_set
*filter_set
,
1445 struct btrfs_list_comparer_set
*comp_set
,
1448 struct root_lookup root_lookup
;
1449 struct root_lookup root_sort
;
1452 ret
= __list_subvol_search(fd
, &root_lookup
);
1454 fprintf(stderr
, "ERROR: can't perform the search - %s\n",
1460 * now we have an rbtree full of root_info objects, but we need to fill
1461 * in their path names within the subvol that is referencing each one.
1463 ret
= __list_subvol_fill_paths(fd
, &root_lookup
);
1467 __filter_and_sort_subvol(&root_lookup
, &root_sort
, filter_set
,
1470 print_all_volume_info(&root_sort
, is_tab_result
);
1471 __free_all_subvolumn(&root_lookup
);
1475 static int print_one_extent(int fd
, struct btrfs_ioctl_search_header
*sh
,
1476 struct btrfs_file_extent_item
*item
,
1477 u64 found_gen
, u64
*cache_dirid
,
1478 char **cache_dir_name
, u64
*cache_ino
,
1479 char **cache_full_name
)
1483 u64 disk_offset
= 0;
1489 if (sh
->objectid
== *cache_ino
) {
1490 name
= *cache_full_name
;
1491 } else if (*cache_full_name
) {
1492 free(*cache_full_name
);
1493 *cache_full_name
= NULL
;
1496 name
= ino_resolve(fd
, sh
->objectid
, cache_dirid
,
1498 *cache_full_name
= name
;
1499 *cache_ino
= sh
->objectid
;
1504 type
= btrfs_stack_file_extent_type(item
);
1505 compressed
= btrfs_stack_file_extent_compression(item
);
1507 if (type
== BTRFS_FILE_EXTENT_REG
||
1508 type
== BTRFS_FILE_EXTENT_PREALLOC
) {
1509 disk_start
= btrfs_stack_file_extent_disk_bytenr(item
);
1510 disk_offset
= btrfs_stack_file_extent_offset(item
);
1511 len
= btrfs_stack_file_extent_num_bytes(item
);
1512 } else if (type
== BTRFS_FILE_EXTENT_INLINE
) {
1515 len
= btrfs_stack_file_extent_ram_bytes(item
);
1517 printf("unhandled extent type %d for inode %llu "
1518 "file offset %llu gen %llu\n",
1520 (unsigned long long)sh
->objectid
,
1521 (unsigned long long)sh
->offset
,
1522 (unsigned long long)found_gen
);
1526 printf("inode %llu file offset %llu len %llu disk start %llu "
1527 "offset %llu gen %llu flags ",
1528 (unsigned long long)sh
->objectid
,
1529 (unsigned long long)sh
->offset
,
1530 (unsigned long long)len
,
1531 (unsigned long long)disk_start
,
1532 (unsigned long long)disk_offset
,
1533 (unsigned long long)found_gen
);
1539 if (type
== BTRFS_FILE_EXTENT_PREALLOC
) {
1540 printf("%sPREALLOC", flags
? "|" : "");
1543 if (type
== BTRFS_FILE_EXTENT_INLINE
) {
1544 printf("%sINLINE", flags
? "|" : "");
1550 printf(" %s\n", name
);
1554 int btrfs_list_find_updated_files(int fd
, u64 root_id
, u64 oldest_gen
)
1557 struct btrfs_ioctl_search_args args
;
1558 struct btrfs_ioctl_search_key
*sk
= &args
.key
;
1559 struct btrfs_ioctl_search_header
*sh
;
1560 struct btrfs_file_extent_item
*item
;
1561 unsigned long off
= 0;
1566 u64 cache_dirid
= 0;
1568 char *cache_dir_name
= NULL
;
1569 char *cache_full_name
= NULL
;
1570 struct btrfs_file_extent_item backup
;
1572 memset(&backup
, 0, sizeof(backup
));
1573 memset(&args
, 0, sizeof(args
));
1575 sk
->tree_id
= root_id
;
1578 * set all the other params to the max, we'll take any objectid
1581 sk
->max_objectid
= (u64
)-1;
1582 sk
->max_offset
= (u64
)-1;
1583 sk
->max_transid
= (u64
)-1;
1584 sk
->max_type
= BTRFS_EXTENT_DATA_KEY
;
1585 sk
->min_transid
= oldest_gen
;
1586 /* just a big number, doesn't matter much */
1587 sk
->nr_items
= 4096;
1589 max_found
= find_root_gen(fd
);
1591 ret
= ioctl(fd
, BTRFS_IOC_TREE_SEARCH
, &args
);
1594 fprintf(stderr
, "ERROR: can't perform the search- %s\n",
1598 /* the ioctl returns the number of item it found in nr_items */
1599 if (sk
->nr_items
== 0)
1605 * for each item, pull the key out of the header and then
1606 * read the root_ref item it contains
1608 for (i
= 0; i
< sk
->nr_items
; i
++) {
1609 sh
= (struct btrfs_ioctl_search_header
*)(args
.buf
+
1614 * just in case the item was too big, pass something other
1620 item
= (struct btrfs_file_extent_item
*)(args
.buf
+
1622 found_gen
= btrfs_stack_file_extent_generation(item
);
1623 if (sh
->type
== BTRFS_EXTENT_DATA_KEY
&&
1624 found_gen
>= oldest_gen
) {
1625 print_one_extent(fd
, sh
, item
, found_gen
,
1626 &cache_dirid
, &cache_dir_name
,
1627 &cache_ino
, &cache_full_name
);
1632 * record the mins in sk so we can make sure the
1633 * next search doesn't repeat this root
1635 sk
->min_objectid
= sh
->objectid
;
1636 sk
->min_offset
= sh
->offset
;
1637 sk
->min_type
= sh
->type
;
1639 sk
->nr_items
= 4096;
1640 if (sk
->min_offset
< (u64
)-1)
1642 else if (sk
->min_objectid
< (u64
)-1) {
1649 free(cache_dir_name
);
1650 free(cache_full_name
);
1651 printf("transid marker was %llu\n", (unsigned long long)max_found
);
1655 char *btrfs_list_path_for_root(int fd
, u64 root
)
1657 struct root_lookup root_lookup
;
1659 char *ret_path
= NULL
;
1661 u64 top_id
= btrfs_list_get_path_rootid(fd
);
1663 ret
= __list_subvol_search(fd
, &root_lookup
);
1665 return ERR_PTR(ret
);
1667 ret
= __list_subvol_fill_paths(fd
, &root_lookup
);
1669 return ERR_PTR(ret
);
1671 n
= rb_last(&root_lookup
.root
);
1673 struct root_info
*entry
;
1675 entry
= rb_entry(n
, struct root_info
, rb_node
);
1676 resolve_root(&root_lookup
, entry
, top_id
);
1677 if (entry
->root_id
== root
) {
1678 ret_path
= entry
->full_path
;
1679 entry
->full_path
= NULL
;
1684 __free_all_subvolumn(&root_lookup
);
1689 int btrfs_list_parse_sort_string(char *optarg
,
1690 struct btrfs_list_comparer_set
**comps
)
1698 while ((p
= strtok(optarg
, ",")) != NULL
) {
1700 ptr_argv
= all_sort_items
;
1703 if (strcmp(*ptr_argv
, p
) == 0) {
1708 if (strcmp(*ptr_argv
, p
) == 0) {
1725 } else if (*p
== '-') {
1731 what_to_sort
= btrfs_list_get_sort_item(p
);
1732 btrfs_list_setup_comparer(comps
, what_to_sort
, order
);
1741 * This function is used to parse the argument of filter condition.
1743 * type is the filter object.
1745 int btrfs_list_parse_filter_string(char *optarg
,
1746 struct btrfs_list_filter_set
**filters
,
1747 enum btrfs_list_filter_enum type
)
1751 char *ptr_parse_end
= NULL
;
1752 char *ptr_optarg_end
= optarg
+ strlen(optarg
);
1754 switch (*(optarg
++)) {
1756 arg
= (u64
)strtol(optarg
, &ptr_parse_end
, 10);
1758 if (ptr_parse_end
!= ptr_optarg_end
)
1761 btrfs_list_setup_filter(filters
, type
, arg
);
1764 arg
= (u64
)strtoll(optarg
, &ptr_parse_end
, 10);
1766 if (ptr_parse_end
!= ptr_optarg_end
)
1769 btrfs_list_setup_filter(filters
, type
, arg
);
1773 arg
= (u64
)strtoll(optarg
, &ptr_parse_end
, 10);
1775 if (ptr_parse_end
!= ptr_optarg_end
)
1777 btrfs_list_setup_filter(filters
, type
, arg
);
1784 u64
btrfs_list_get_path_rootid(int fd
)
1787 struct btrfs_ioctl_ino_lookup_args args
;
1789 memset(&args
, 0, sizeof(args
));
1790 args
.objectid
= BTRFS_FIRST_FREE_OBJECTID
;
1792 ret
= ioctl(fd
, BTRFS_IOC_INO_LOOKUP
, &args
);
1795 "ERROR: can't perform the search -%s\n",