1 diff --git a/Makefile b/Makefile
2 index 8097b5a..6e6f6c6 100644
5 @@ -4,7 +4,7 @@ CFLAGS = -g -Werror -Os
6 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
7 root-tree.o dir-item.o file-item.o inode-item.o \
8 inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
10 + volumes.o utils.o btrfs-list.o
13 CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
14 @@ -16,7 +16,9 @@ prefix ?= /usr/local
15 bindir = $(prefix)/bin
18 -progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck
19 +progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
23 # make C=1 to enable sparse
25 @@ -35,6 +37,10 @@ all: version $(progs) manpages
29 +btrfs: $(objects) btrfs.o btrfs_cmds.o
30 + gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \
31 + $(objects) $(LDFLAGS) $(LIBS)
33 btrfsctl: $(objects) btrfsctl.o
34 gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
36 @@ -53,9 +59,15 @@ mkfs.btrfs: $(objects) mkfs.o
37 btrfs-debug-tree: $(objects) debug-tree.o
38 gcc $(CFLAGS) -o btrfs-debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS)
40 +btrfs-zero-log: $(objects) btrfs-zero-log.o
41 + gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS)
43 btrfstune: $(objects) btrfstune.o
44 gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
46 +btrfs-map-logical: $(objects) btrfs-map-logical.o
47 + gcc $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS)
49 btrfs-image: $(objects) btrfs-image.o
50 gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS)
52 @@ -66,7 +78,10 @@ quick-test: $(objects) quick-test.o
53 gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS)
55 convert: $(objects) convert.o
56 - gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs $(LDFLAGS) $(LIBS)
57 + gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS)
59 +ioctl-test: $(objects) ioctl-test.o
60 + gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
64 diff --git a/btrfs-defrag.c b/btrfs-defrag.c
66 index 0000000..8f1525a
71 + * Copyright (C) 2010 Oracle. All rights reserved.
73 + * This program is free software; you can redistribute it and/or
74 + * modify it under the terms of the GNU General Public
75 + * License v2 as published by the Free Software Foundation.
77 + * This program is distributed in the hope that it will be useful,
78 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
80 + * General Public License for more details.
82 + * You should have received a copy of the GNU General Public
83 + * License along with this program; if not, write to the
84 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
85 + * Boston, MA 021110-1307, USA.
89 +#include <sys/ioctl.h>
90 +#include <sys/mount.h>
95 +#include <sys/types.h>
96 +#include <sys/stat.h>
103 +#include "kerncompat.h"
105 +#include "transaction.h"
107 +#include "version.h"
109 diff --git a/btrfs-list.c b/btrfs-list.c
111 index 0000000..93766a8
116 + * Copyright (C) 2010 Oracle. All rights reserved.
118 + * This program is free software; you can redistribute it and/or
119 + * modify it under the terms of the GNU General Public
120 + * License v2 as published by the Free Software Foundation.
122 + * This program is distributed in the hope that it will be useful,
123 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
124 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
125 + * General Public License for more details.
127 + * You should have received a copy of the GNU General Public
128 + * License along with this program; if not, write to the
129 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
130 + * Boston, MA 021110-1307, USA.
135 +#include <sys/ioctl.h>
136 +#include <sys/mount.h>
141 +#include <sys/types.h>
142 +#include <sys/stat.h>
147 +#include "kerncompat.h"
149 +#include "transaction.h"
151 +#include "version.h"
153 +/* we store all the roots we find in an rbtree so that we can
154 + * search for them later.
156 +struct root_lookup {
157 + struct rb_root root;
161 + * one of these for each root we find.
164 + struct rb_node rb_node;
166 + /* this root's id */
169 + /* the id of the root that references this one */
172 + /* the dir id we're in from ref_tree */
175 + /* path from the subvol we live in to this root, including the
176 + * root's name. This is null until we do the extra lookup ioctl.
180 + /* the name of this root in the directory it lives in */
184 +static void root_lookup_init(struct root_lookup *tree)
186 + tree->root.rb_node = NULL;
189 +static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
191 + if (entry->root_id > root_id)
193 + if (entry->root_id < root_id)
195 + if (entry->ref_tree > ref_tree)
197 + if (entry->ref_tree < ref_tree)
203 + * insert a new root into the tree. returns the existing root entry
204 + * if one is already there. Both root_id and ref_tree are used
207 +static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
208 + u64 ref_tree, struct rb_node *node)
210 + struct rb_node ** p = &root->rb_node;
211 + struct rb_node * parent = NULL;
212 + struct root_info *entry;
217 + entry = rb_entry(parent, struct root_info, rb_node);
219 + comp = comp_entry(entry, root_id, ref_tree);
222 + p = &(*p)->rb_left;
224 + p = &(*p)->rb_right;
229 + entry = rb_entry(parent, struct root_info, rb_node);
230 + rb_link_node(node, parent, p);
231 + rb_insert_color(node, root);
236 + * find a given root id in the tree. We return the smallest one,
237 + * rb_next can be used to move forward looking for more if required
239 +static struct root_info *tree_search(struct rb_root *root, u64 root_id)
241 + struct rb_node * n = root->rb_node;
242 + struct root_info *entry;
245 + entry = rb_entry(n, struct root_info, rb_node);
247 + if (entry->root_id < root_id)
249 + else if (entry->root_id > root_id)
252 + struct root_info *prev;
253 + struct rb_node *prev_n;
255 + prev_n = rb_prev(n);
258 + prev = rb_entry(prev_n, struct root_info,
260 + if (prev->root_id != root_id)
272 + * this allocates a new root in the lookup tree.
274 + * root_id should be the object id of the root
276 + * ref_tree is the objectid of the referring root.
278 + * dir_id is the directory in ref_tree where this root_id can be found.
280 + * name is the name of root_id in that directory
282 + * name_len is the length of name
284 +static int add_root(struct root_lookup *root_lookup,
285 + u64 root_id, u64 ref_tree, u64 dir_id, char *name,
288 + struct root_info *ri;
289 + struct rb_node *ret;
290 + ri = malloc(sizeof(*ri) + name_len + 1);
292 + printf("memory allocation failed\n");
295 + memset(ri, 0, sizeof(*ri) + name_len + 1);
297 + ri->dir_id = dir_id;
298 + ri->root_id = root_id;
299 + ri->ref_tree = ref_tree;
300 + strncpy(ri->name, name, name_len);
302 + ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
304 + printf("failed to insert tree %llu\n", (unsigned long long)root_id);
311 + * for a given root_info, search through the root_lookup tree to construct
312 + * the full path name to it.
314 + * This can't be called until all the root_info->path fields are filled
315 + * in by lookup_ino_path
317 +static int resolve_root(struct root_lookup *rl, struct root_info *ri)
320 + char *full_path = NULL;
322 + struct root_info *found;
325 + * we go backwards from the root_info object and add pathnames
326 + * from parent directories as we go.
332 + int add_len = strlen(found->path);
334 + /* room for / and for null */
335 + tmp = malloc(add_len + 2 + len);
337 + memcpy(tmp + add_len + 1, full_path, len);
338 + tmp[add_len] = '/';
339 + memcpy(tmp, found->path, add_len);
340 + tmp [add_len + len + 1] = '\0';
343 + len += add_len + 1;
345 + full_path = strdup(found->path);
349 + next = found->ref_tree;
350 + /* if the ref_tree refers to ourselves, we're at the top */
351 + if (next == found->root_id) {
357 + * if the ref_tree wasn't in our tree of roots, we're
360 + found = tree_search(&rl->root, next);
366 + printf("ID %llu top level %llu path %s\n", ri->root_id, top_id,
373 + * for a single root_info, ask the kernel to give us a path name
374 + * inside it's ref_root for the dir_id where it lives.
376 + * This fills in root_info->path with the path to the directory and and
377 + * appends this root's name.
379 +static int lookup_ino_path(int fd, struct root_info *ri)
381 + struct btrfs_ioctl_ino_lookup_args args;
387 + memset(&args, 0, sizeof(args));
388 + args.treeid = ri->ref_tree;
389 + args.objectid = ri->dir_id;
391 + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
393 + fprintf(stderr, "ERROR: Failed to lookup path for root %llu\n",
394 + (unsigned long long)ri->ref_tree);
398 + if (args.name[0]) {
400 + * we're in a subdirectory of ref_tree, the kernel ioctl
401 + * puts a / in there for us
403 + ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
405 + perror("malloc failed");
408 + strcpy(ri->path, args.name);
409 + strcat(ri->path, ri->name);
411 + /* we're at the root of ref_tree */
412 + ri->path = strdup(ri->name);
414 + perror("strdup failed");
421 +/* finding the generation for a given path is a two step process.
422 + * First we use the inode loookup routine to find out the root id
424 + * Then we use the tree search ioctl to scan all the root items for a
425 + * given root id and spit out the latest generation we can find
427 +static u64 find_root_gen(int fd)
429 + struct btrfs_ioctl_ino_lookup_args ino_args;
431 + struct btrfs_ioctl_search_args args;
432 + struct btrfs_ioctl_search_key *sk = &args.key;
433 + struct btrfs_ioctl_search_header *sh;
434 + unsigned long off = 0;
438 + memset(&ino_args, 0, sizeof(ino_args));
439 + ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
441 + /* this ioctl fills in ino_args->treeid */
442 + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
444 + fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
445 + (unsigned long long)BTRFS_FIRST_FREE_OBJECTID);
449 + memset(&args, 0, sizeof(args));
454 + * there may be more than one ROOT_ITEM key if there are
455 + * snapshots pending deletion, we have to loop through
458 + sk->min_objectid = ino_args.treeid;
459 + sk->max_objectid = ino_args.treeid;
460 + sk->max_type = BTRFS_ROOT_ITEM_KEY;
461 + sk->min_type = BTRFS_ROOT_ITEM_KEY;
462 + sk->max_offset = (u64)-1;
463 + sk->max_transid = (u64)-1;
464 + sk->nr_items = 4096;
467 + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
469 + fprintf(stderr, "ERROR: can't perform the search\n");
472 + /* the ioctl returns the number of item it found in nr_items */
473 + if (sk->nr_items == 0)
477 + for (i = 0; i < sk->nr_items; i++) {
478 + struct btrfs_root_item *item;
479 + sh = (struct btrfs_ioctl_search_header *)(args.buf +
482 + off += sizeof(*sh);
483 + item = (struct btrfs_root_item *)(args.buf + off);
486 + sk->min_objectid = sh->objectid;
487 + sk->min_type = sh->type;
488 + sk->min_offset = sh->offset;
490 + if (sh->objectid > ino_args.treeid)
493 + if (sh->objectid == ino_args.treeid &&
494 + sh->type == BTRFS_ROOT_ITEM_KEY) {
495 + max_found = max(max_found,
496 + btrfs_root_generation(item));
499 + if (sk->min_offset < (u64)-1)
504 + if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
506 + if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
512 +/* pass in a directory id and this will return
513 + * the full path of the parent directory inside its
516 + * It may return NULL if it is in the root, or an ERR_PTR if things
519 +static char *__ino_resolve(int fd, u64 dirid)
521 + struct btrfs_ioctl_ino_lookup_args args;
525 + memset(&args, 0, sizeof(args));
526 + args.objectid = dirid;
528 + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
530 + fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
531 + (unsigned long long)dirid);
532 + return ERR_PTR(ret);
535 + if (args.name[0]) {
537 + * we're in a subdirectory of ref_tree, the kernel ioctl
538 + * puts a / in there for us
540 + full = strdup(args.name);
542 + perror("malloc failed");
543 + return ERR_PTR(-ENOMEM);
546 + /* we're at the root of ref_tree */
553 + * simple string builder, returning a new string with both
556 +char *build_name(char *dirid, char *name)
560 + return strdup(name);
562 + full = malloc(strlen(dirid) + strlen(name) + 1);
565 + strcpy(full, dirid);
566 + strcat(full, name);
571 + * given an inode number, this returns the full path name inside the subvolume
572 + * to that file/directory. cache_dirid and cache_name are used to
573 + * cache the results so we can avoid tree searches if a later call goes
574 + * to the same directory or file name
576 +static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
584 + struct btrfs_ioctl_search_args args;
585 + struct btrfs_ioctl_search_key *sk = &args.key;
586 + struct btrfs_ioctl_search_header *sh;
587 + unsigned long off = 0;
590 + memset(&args, 0, sizeof(args));
595 + * step one, we search for the inode back ref. We just use the first
598 + sk->min_objectid = ino;
599 + sk->max_objectid = ino;
600 + sk->max_type = BTRFS_INODE_REF_KEY;
601 + sk->max_offset = (u64)-1;
602 + sk->min_type = BTRFS_INODE_REF_KEY;
603 + sk->max_transid = (u64)-1;
606 + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
608 + fprintf(stderr, "ERROR: can't perform the search\n");
611 + /* the ioctl returns the number of item it found in nr_items */
612 + if (sk->nr_items == 0)
616 + sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
618 + if (sh->type == BTRFS_INODE_REF_KEY) {
619 + struct btrfs_inode_ref *ref;
620 + dirid = sh->offset;
622 + ref = (struct btrfs_inode_ref *)(sh + 1);
623 + namelen = btrfs_stack_inode_ref_name_len(ref);
625 + name = (char *)(ref + 1);
626 + name = strndup(name, namelen);
628 + /* use our cached value */
629 + if (dirid == *cache_dirid && *cache_name) {
630 + dirname = *cache_name;
637 + * the inode backref gives us the file name and the parent directory id.
638 + * From here we use __ino_resolve to get the path to the parent
640 + dirname = __ino_resolve(fd, dirid);
642 + full = build_name(dirname, name);
643 + if (*cache_name && dirname != *cache_name)
646 + *cache_name = dirname;
647 + *cache_dirid = dirid;
653 +int list_subvols(int fd)
655 + struct root_lookup root_lookup;
658 + struct btrfs_ioctl_search_args args;
659 + struct btrfs_ioctl_search_key *sk = &args.key;
660 + struct btrfs_ioctl_search_header *sh;
661 + struct btrfs_root_ref *ref;
662 + unsigned long off = 0;
668 + root_lookup_init(&root_lookup);
670 + memset(&args, 0, sizeof(args));
672 + /* search in the tree of tree roots */
676 + * set the min and max to backref keys. The search will
677 + * only send back this type of key now.
679 + sk->max_type = BTRFS_ROOT_BACKREF_KEY;
680 + sk->min_type = BTRFS_ROOT_BACKREF_KEY;
683 + * set all the other params to the max, we'll take any objectid
686 + sk->max_objectid = (u64)-1;
687 + sk->max_offset = (u64)-1;
688 + sk->max_transid = (u64)-1;
690 + /* just a big number, doesn't matter much */
691 + sk->nr_items = 4096;
694 + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
696 + fprintf(stderr, "ERROR: can't perform the search\n");
699 + /* the ioctl returns the number of item it found in nr_items */
700 + if (sk->nr_items == 0)
706 + * for each item, pull the key out of the header and then
707 + * read the root_ref item it contains
709 + for (i = 0; i < sk->nr_items; i++) {
710 + sh = (struct btrfs_ioctl_search_header *)(args.buf +
712 + off += sizeof(*sh);
713 + if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
714 + ref = (struct btrfs_root_ref *)(args.buf + off);
715 + name_len = btrfs_stack_root_ref_name_len(ref);
716 + name = (char *)(ref + 1);
717 + dir_id = btrfs_stack_root_ref_dirid(ref);
719 + add_root(&root_lookup, sh->objectid, sh->offset,
720 + dir_id, name, name_len);
726 + * record the mins in sk so we can make sure the
727 + * next search doesn't repeat this root
729 + sk->min_objectid = sh->objectid;
730 + sk->min_type = sh->type;
731 + sk->min_offset = sh->offset;
733 + sk->nr_items = 4096;
734 + /* this iteration is done, step forward one root for the next
737 + if (sk->min_objectid < (u64)-1) {
738 + sk->min_objectid++;
739 + sk->min_type = BTRFS_ROOT_BACKREF_KEY;
740 + sk->min_offset = 0;
745 + * now we have an rbtree full of root_info objects, but we need to fill
746 + * in their path names within the subvol that is referencing each one.
748 + n = rb_first(&root_lookup.root);
750 + struct root_info *entry;
752 + entry = rb_entry(n, struct root_info, rb_node);
753 + ret = lookup_ino_path(fd, entry);
759 + /* now that we have all the subvol-relative paths filled in,
760 + * we have to string the subvols together so that we can get
761 + * a path all the way back to the FS root
763 + n = rb_last(&root_lookup.root);
765 + struct root_info *entry;
766 + entry = rb_entry(n, struct root_info, rb_node);
767 + resolve_root(&root_lookup, entry);
774 +static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
775 + struct btrfs_file_extent_item *item,
776 + u64 found_gen, u64 *cache_dirid,
777 + char **cache_dir_name, u64 *cache_ino,
778 + char **cache_full_name)
781 + u64 disk_start = 0;
782 + u64 disk_offset = 0;
784 + int compressed = 0;
788 + if (sh->objectid == *cache_ino) {
789 + name = *cache_full_name;
790 + } else if (*cache_full_name) {
791 + free(*cache_full_name);
792 + *cache_full_name = NULL;
795 + name = ino_resolve(fd, sh->objectid, cache_dirid,
797 + *cache_full_name = name;
798 + *cache_ino = sh->objectid;
803 + type = btrfs_stack_file_extent_type(item);
804 + compressed = btrfs_stack_file_extent_compression(item);
806 + if (type == BTRFS_FILE_EXTENT_REG ||
807 + type == BTRFS_FILE_EXTENT_PREALLOC) {
808 + disk_start = btrfs_stack_file_extent_disk_bytenr(item);
809 + disk_offset = btrfs_stack_file_extent_offset(item);
810 + len = btrfs_stack_file_extent_num_bytes(item);
811 + } else if (type == BTRFS_FILE_EXTENT_INLINE) {
814 + len = btrfs_stack_file_extent_ram_bytes(item);
816 + printf("unhandled extent type %d for inode %llu "
817 + "file offset %llu gen %llu\n",
819 + (unsigned long long)sh->objectid,
820 + (unsigned long long)sh->offset,
821 + (unsigned long long)found_gen);
825 + printf("inode %llu file offset %llu len %llu disk start %llu "
826 + "offset %llu gen %llu flags ",
827 + (unsigned long long)sh->objectid,
828 + (unsigned long long)sh->offset,
829 + (unsigned long long)len,
830 + (unsigned long long)disk_start,
831 + (unsigned long long)disk_offset,
832 + (unsigned long long)found_gen);
835 + printf("COMPRESS");
838 + if (type == BTRFS_FILE_EXTENT_PREALLOC) {
839 + printf("%sPREALLOC", flags ? "|" : "");
842 + if (type == BTRFS_FILE_EXTENT_INLINE) {
843 + printf("%sINLINE", flags ? "|" : "");
849 + printf(" %s\n", name);
853 +int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
856 + struct btrfs_ioctl_search_args args;
857 + struct btrfs_ioctl_search_key *sk = &args.key;
858 + struct btrfs_ioctl_search_header *sh;
859 + struct btrfs_file_extent_item *item;
860 + unsigned long off = 0;
864 + u64 cache_dirid = 0;
866 + char *cache_dir_name = NULL;
867 + char *cache_full_name = NULL;
868 + struct btrfs_file_extent_item backup;
870 + memset(&backup, 0, sizeof(backup));
871 + memset(&args, 0, sizeof(args));
873 + sk->tree_id = root_id;
876 + * set all the other params to the max, we'll take any objectid
879 + sk->max_objectid = (u64)-1;
880 + sk->max_offset = (u64)-1;
881 + sk->max_transid = (u64)-1;
882 + sk->max_type = BTRFS_EXTENT_DATA_KEY;
883 + sk->min_transid = oldest_gen;
884 + /* just a big number, doesn't matter much */
885 + sk->nr_items = 4096;
887 + max_found = find_root_gen(fd);
889 + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
891 + fprintf(stderr, "ERROR: can't perform the search\n");
894 + /* the ioctl returns the number of item it found in nr_items */
895 + if (sk->nr_items == 0)
901 + * for each item, pull the key out of the header and then
902 + * read the root_ref item it contains
904 + for (i = 0; i < sk->nr_items; i++) {
905 + sh = (struct btrfs_ioctl_search_header *)(args.buf +
907 + off += sizeof(*sh);
910 + * just in case the item was too big, pass something other
916 + item = (struct btrfs_file_extent_item *)(args.buf +
918 + found_gen = btrfs_stack_file_extent_generation(item);
919 + if (sh->type == BTRFS_EXTENT_DATA_KEY &&
920 + found_gen >= oldest_gen) {
921 + print_one_extent(fd, sh, item, found_gen,
922 + &cache_dirid, &cache_dir_name,
923 + &cache_ino, &cache_full_name);
928 + * record the mins in sk so we can make sure the
929 + * next search doesn't repeat this root
931 + sk->min_objectid = sh->objectid;
932 + sk->min_offset = sh->offset;
933 + sk->min_type = sh->type;
935 + sk->nr_items = 4096;
936 + if (sk->min_offset < (u64)-1)
938 + else if (sk->min_objectid < (u64)-1) {
939 + sk->min_objectid++;
940 + sk->min_offset = 0;
945 + free(cache_dir_name);
946 + free(cache_full_name);
947 + printf("transid marker was %llu\n", (unsigned long long)max_found);
950 diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
952 index 0000000..a109c6a
954 +++ b/btrfs-map-logical.c
957 + * Copyright (C) 2009 Oracle. All rights reserved.
959 + * This program is free software; you can redistribute it and/or
960 + * modify it under the terms of the GNU General Public
961 + * License v2 as published by the Free Software Foundation.
963 + * This program is distributed in the hope that it will be useful,
964 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
965 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
966 + * General Public License for more details.
968 + * You should have received a copy of the GNU General Public
969 + * License along with this program; if not, write to the
970 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
971 + * Boston, MA 021110-1307, USA.
974 +#define _XOPEN_SOURCE 500
975 +#define _GNU_SOURCE 1
981 +#include "kerncompat.h"
983 +#include "volumes.h"
984 +#include "disk-io.h"
985 +#include "print-tree.h"
986 +#include "transaction.h"
988 +#include "version.h"
990 +/* we write the mirror info to stdout unless they are dumping the data
993 +static FILE *info_file;
995 +struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
996 + u32 blocksize, int copy)
1000 + struct extent_buffer *eb;
1002 + struct btrfs_multi_bio *multi = NULL;
1003 + struct btrfs_device *device;
1005 + int mirror_num = 1;
1007 + eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
1012 + length = blocksize;
1014 + ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
1015 + eb->start, &length, &multi, mirror_num);
1017 + device = multi->stripes[0].dev;
1018 + eb->fd = device->fd;
1019 + device->total_ios++;
1020 + eb->dev_bytenr = multi->stripes[0].physical;
1022 + fprintf(info_file, "mirror %d logical %Lu physical %Lu "
1023 + "device %s\n", mirror_num, bytenr, eb->dev_bytenr,
1027 + if (!copy || mirror_num == copy)
1028 + ret = read_extent_from_disk(eb);
1030 + num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
1031 + eb->start, eb->len);
1032 + if (num_copies == 1)
1036 + if (mirror_num > num_copies)
1042 +static void print_usage(void)
1044 + fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n");
1045 + fprintf(stderr, "\t-l Logical extent to map\n");
1046 + fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n");
1047 + fprintf(stderr, "\t-o Output file to hold the extent\n");
1048 + fprintf(stderr, "\t-s Number of bytes to read\n");
1052 +static struct option long_options[] = {
1053 + /* { "byte-count", 1, NULL, 'b' }, */
1054 + { "logical", 1, NULL, 'l' },
1055 + { "copy", 1, NULL, 'c' },
1056 + { "output", 1, NULL, 'c' },
1057 + { "bytes", 1, NULL, 'b' },
1061 +int main(int ac, char **av)
1063 + struct cache_tree root_cache;
1064 + struct btrfs_root *root;
1065 + struct extent_buffer *eb;
1067 + char *output_file = NULL;
1070 + int option_index = 0;
1078 + c = getopt_long(ac, av, "l:c:o:b:", long_options,
1084 + logical = atoll(optarg);
1085 + if (logical == 0) {
1087 + "invalid extent number\n");
1092 + copy = atoi(optarg);
1095 + "invalid copy number\n");
1100 + bytes = atoll(optarg);
1103 + "invalid byte count\n");
1108 + output_file = strdup(optarg);
1124 + radix_tree_init();
1125 + cache_tree_init(&root_cache);
1127 + root = open_ctree(dev, 0, 0);
1129 + fprintf(stderr, "Open ctree failed\n");
1133 + if (output_file) {
1134 + if (strcmp(output_file, "-") == 0) {
1136 + info_file = stderr;
1138 + out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
1141 + err = ftruncate(out_fd, 0);
1146 + info_file = stdout;
1151 + bytes = root->sectorsize;
1153 + bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
1154 + bytes *= root->sectorsize;
1156 + while (bytes > 0) {
1157 + eb = debug_read_block(root, logical, root->sectorsize, copy);
1158 + if (eb && output_file) {
1159 + err = write(out_fd, eb->data, eb->len);
1160 + if (err < 0 || err != eb->len) {
1161 + fprintf(stderr, "output file write failed\n");
1162 + goto out_close_fd;
1165 + free_extent_buffer(eb);
1166 + logical += root->sectorsize;
1167 + bytes -= root->sectorsize;
1171 + if (output_file && out_fd != 1)
1174 + close_ctree(root);
1177 diff --git a/btrfs-vol.c b/btrfs-vol.c
1178 index 8069778..4ed799d 100644
1181 @@ -108,10 +108,24 @@ int main(int ac, char **av)
1182 if (device && strcmp(device, "missing") == 0 &&
1183 cmd == BTRFS_IOC_RM_DEV) {
1184 fprintf(stderr, "removing missing devices from %s\n", mnt);
1185 - } else if (device) {
1186 + } else if (cmd != BTRFS_IOC_BALANCE) {
1187 + if (cmd == BTRFS_IOC_ADD_DEV) {
1188 + ret = check_mounted(device);
1191 + "error checking %s mount status\n",
1196 + fprintf(stderr, "%s is mounted\n", device);
1200 devfd = open(device, O_RDWR);
1203 fprintf(stderr, "Unable to open device %s\n", device);
1206 ret = fstat(devfd, &st);
1208 diff --git a/btrfs-zero-log.c b/btrfs-zero-log.c
1209 new file mode 100644
1210 index 0000000..f10438b
1212 +++ b/btrfs-zero-log.c
1215 + * Copyright (C) 2007 Oracle. All rights reserved.
1217 + * This program is free software; you can redistribute it and/or
1218 + * modify it under the terms of the GNU General Public
1219 + * License v2 as published by the Free Software Foundation.
1221 + * This program is distributed in the hope that it will be useful,
1222 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1223 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1224 + * General Public License for more details.
1226 + * You should have received a copy of the GNU General Public
1227 + * License along with this program; if not, write to the
1228 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1229 + * Boston, MA 021110-1307, USA.
1232 +#define _XOPEN_SOURCE 500
1233 +#define _GNU_SOURCE 1
1235 +#include <stdlib.h>
1236 +#include <unistd.h>
1238 +#include <sys/stat.h>
1239 +#include "kerncompat.h"
1241 +#include "disk-io.h"
1242 +#include "print-tree.h"
1243 +#include "transaction.h"
1245 +#include "version.h"
1248 +static void print_usage(void)
1250 + fprintf(stderr, "usage: btrfs-zero-log dev\n");
1251 + fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
1255 +int main(int ac, char **av)
1257 + struct btrfs_root *root;
1263 + radix_tree_init();
1265 + if((ret = check_mounted(av[1])) < 0) {
1266 + fprintf(stderr, "Could not check mount status: %s\n", strerror(ret));
1269 + fprintf(stderr, "%s is currently mounted. Aborting.\n", av[1]);
1273 + root = open_ctree(av[1], 0, 1);
1278 + btrfs_set_super_log_root(&root->fs_info->super_copy, 0);
1279 + btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0);
1280 + close_ctree(root);
1283 diff --git a/btrfs.c b/btrfs.c
1284 new file mode 100644
1285 index 0000000..46314cf
1290 + * This program is free software; you can redistribute it and/or
1291 + * modify it under the terms of the GNU General Public
1292 + * License v2 as published by the Free Software Foundation.
1294 + * This program is distributed in the hope that it will be useful,
1295 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1296 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1297 + * General Public License for more details.
1299 + * You should have received a copy of the GNU General Public
1300 + * License along with this program; if not, write to the
1301 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1302 + * Boston, MA 021110-1307, USA.
1305 +#define _GNU_SOURCE
1307 +#include <stdlib.h>
1308 +#include <string.h>
1310 +#include "kerncompat.h"
1311 +#include "btrfs_cmds.h"
1312 +#include "version.h"
1314 +typedef int (*CommandFunction)(int argc, char **argv);
1317 + CommandFunction func; /* function which implements the command */
1318 + int nargs; /* if == 999, any number of arguments
1319 + if >= 0, number of arguments,
1320 + if < 0, _minimum_ number of arguments */
1321 + char *verb; /* verb */
1322 + char *help; /* help lines; form the 2nd onward they are
1325 + /* the following fields are run-time filled by the program */
1326 + char **cmds; /* array of subcommands */
1327 + int ncmds; /* number of subcommand */
1330 +static struct Command commands[] = {
1333 + avoid short commands different for the case only
1336 + "subvolume snapshot", "<source> [<dest>/]<name>\n"
1337 + "Create a writable snapshot of the subvolume <source> with\n"
1338 + "the name <name> in the <dest> directory."
1340 + { do_delete_subvolume, 1,
1341 + "subvolume delete", "<subvolume>\n"
1342 + "Delete the subvolume <subvolume>."
1344 + { do_create_subvol, 1,
1345 + "subvolume create", "[<dest>/]<name>\n"
1346 + "Create a subvolume in <dest> (or the current directory if\n"
1349 + { do_subvol_list, 1, "subvolume list", "<path>\n"
1350 + "List the snapshot/subvolume of a filesystem."
1352 + { do_find_newer, 2, "subvolume find-new", "<path> <last_gen>\n"
1353 + "List the recently modified files in a filesystem."
1356 + "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] <file>|<dir> [<file>|<dir>...]\n"
1357 + "Defragment a file or a directory."
1359 + { do_set_default_subvol, 2,
1360 + "subvolume set-default", "<id> <path>\n"
1361 + "Set the subvolume of the filesystem <path> which will be mounted\n"
1365 + "filesystem sync", "<path>\n"
1366 + "Force a sync on the filesystem <path>."
1369 + "filesystem resize", "[+/-]<newsize>[gkm]|max <filesystem>\n"
1370 + "Resize the file system. If 'max' is passed, the filesystem\n"
1371 + "will occupe all available space on the device."
1373 + { do_show_filesystem, 999,
1374 + "filesystem show", "[<uuid>|<label>]\n"
1375 + "Show the info of a btrfs filesystem. If no <uuid> or <label>\n"
1376 + "is passed, info of all the btrfs filesystem are shown."
1378 + { do_df_filesystem, 1,
1379 + "filesystem df", "<path>\n"
1380 + "Show space usage information for a mount point\n."
1383 + "filesystem balance", "<path>\n"
1384 + "Balance the chunks across the device."
1387 + 999, "device scan", "[<device> [<device>..]\n"
1388 + "Scan all device for or the passed device for a btrfs\n"
1391 + { do_add_volume, -2,
1392 + "device add", "<dev> [<dev>..] <path>\n"
1393 + "Add a device to a filesystem."
1395 + { do_remove_volume, -2,
1396 + "device delete", "<dev> [<dev>..] <path>\n"
1397 + "Remove a device from a filesystem."
1400 + { 2, "filesystem label", "<label> <path>\n"
1401 + "Set the label of a filesystem"
1407 +static char *get_prgname(char *programname)
1410 + np = strrchr(programname,'/');
1419 +static void print_help(char *programname, struct Command *cmd)
1423 + printf("\t%s %s ", programname, cmd->verb );
1425 + for(pc = cmd->help; *pc; pc++){
1433 +static void help(char *np)
1435 + struct Command *cp;
1437 + printf("Usage:\n");
1438 + for( cp = commands; cp->verb; cp++ )
1439 + print_help(np, cp);
1441 + printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np);
1442 + printf("\n%s\n", BTRFS_BUILD_VERSION);
1445 +static int split_command(char *cmd, char ***commands)
1450 + for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){
1451 + if ( *p && *p != ' ' )
1454 + /* c + 2 so that we have room for the null */
1455 + (*commands) = realloc( (*commands), sizeof(char *)*(c + 2));
1456 + (*commands)[c] = strndup(s, l);
1463 + (*commands)[c] = 0;
1468 + This function checks if the passed command is ambiguous
1470 +static int check_ambiguity(struct Command *cmd, char **argv){
1472 + struct Command *cp;
1473 + /* check for ambiguity */
1474 + for( i = 0 ; i < cmd->ncmds ; i++ ){
1476 + for( match = 0, cp = commands; cp->verb; cp++ ){
1480 + if( cp->ncmds < i )
1483 + for( skip = 0, j = 0 ; j < i ; j++ )
1484 + if( strcmp(cmd->cmds[j], cp->cmds[j])){
1491 + if( !strcmp(cmd->cmds[i], cp->cmds[i]))
1493 + for(s2 = cp->cmds[i], s1 = argv[i+1];
1494 + *s1 == *s2 && *s1; s1++, s2++ ) ;
1500 + fprintf(stderr, "ERROR: in command '");
1501 + for( j = 0 ; j <= i ; j++ )
1502 + fprintf(stderr, "%s%s",j?" ":"", argv[j+1]);
1503 + fprintf(stderr, "', '%s' is ambiguous\n",argv[j]);
1511 + * This function, compacts the program name and the command in the first
1512 + * element of the '*av' array
1514 +static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){
1520 + ret = (char **)malloc(sizeof(char*)*(*ac+1));
1521 + newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2);
1522 + if( !ret || !newname ){
1529 + for(i=0; i < *ac ; i++ )
1530 + ret[i+1] = (*av)[i];
1532 + strcpy(newname, prgname);
1533 + strcat(newname, " ");
1534 + strcat(newname, cmd->verb);
1547 + This function perform the following jobs:
1548 + - show the help if '--help' or 'help' or '-h' are passed
1549 + - verify that a command is not ambiguous, otherwise show which
1550 + part of the command is ambiguous
1551 + - if after a (even partial) command there is '--help' show the help
1552 + for all the matching commands
1553 + - if the command doesn't' match show an error
1554 + - finally, if a command match, they return which command is matched and
1557 + The function return 0 in case of help is requested; <0 in case
1558 + of uncorrect command; >0 in case of matching commands
1559 + argc, argv are the arg-counter and arg-vector (input)
1560 + *nargs_ is the number of the arguments after the command (output)
1561 + **cmd_ is the invoked command (output)
1562 + ***args_ are the arguments after the command
1565 +static int parse_args(int argc, char **argv,
1566 + CommandFunction *func_,
1567 + int *nargs_, char **cmd_, char ***args_ )
1569 + struct Command *cp;
1570 + struct Command *matchcmd=0;
1571 + char *prgname = get_prgname(argv[0]);
1572 + int i=0, helprequested=0;
1574 + if( argc < 2 || !strcmp(argv[1], "help") ||
1575 + !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
1580 + for( cp = commands; cp->verb; cp++ )
1582 + cp->ncmds = split_command(cp->verb, &(cp->cmds));
1584 + for( cp = commands; cp->verb; cp++ ){
1587 + if( argc-1 < cp->ncmds )
1589 + for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){
1594 + for(s2 = cp->cmds[i], s1 = argv[i+1];
1595 + *s1 == *s2 && *s1;
1603 + /* If you understand why this code works ...
1604 + you are a genious !! */
1605 + if(argc>i+1 && !strcmp(argv[i+1],"--help")){
1606 + if(!helprequested)
1607 + printf("Usage:\n");
1608 + print_help(prgname, cp);
1617 + *nargs_ = argc-matchcmd->ncmds-1;
1618 + *cmd_ = matchcmd->verb;
1619 + *args_ = argv+matchcmd->ncmds+1;
1620 + *func_ = cp->func;
1625 + if(helprequested){
1626 + printf("\n%s\n", BTRFS_BUILD_VERSION);
1631 + fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]);
1636 + if(check_ambiguity(matchcmd, argv))
1639 + /* check the number of argument */
1640 + if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){
1641 + fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n",
1642 + matchcmd->verb, -matchcmd->nargs);
1645 + if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){
1646 + fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n",
1647 + matchcmd->verb, matchcmd->nargs);
1651 + if (prepare_args( nargs_, args_, prgname, matchcmd )){
1652 + fprintf(stderr, "ERROR: not enough memory\\n");
1659 +int main(int ac, char **av )
1662 + char *cmd=0, **args=0;
1664 + CommandFunction func=0;
1666 + r = parse_args(ac, av, &func, &nargs, &cmd, &args);
1668 + /* error or no command to parse*/
1672 + exit(func(nargs, args));
1676 diff --git a/btrfs_cmds.c b/btrfs_cmds.c
1677 new file mode 100644
1678 index 0000000..8031c58
1683 + * This program is free software; you can redistribute it and/or
1684 + * modify it under the terms of the GNU General Public
1685 + * License v2 as published by the Free Software Foundation.
1687 + * This program is distributed in the hope that it will be useful,
1688 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1689 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1690 + * General Public License for more details.
1692 + * You should have received a copy of the GNU General Public
1693 + * License along with this program; if not, write to the
1694 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1695 + * Boston, MA 021110-1307, USA.
1700 +#include <stdlib.h>
1701 +#include <string.h>
1702 +#include <sys/ioctl.h>
1703 +#include <sys/types.h>
1704 +#include <dirent.h>
1705 +#include <sys/stat.h>
1706 +#include <unistd.h>
1708 +#include <libgen.h>
1709 +#include <limits.h>
1710 +#include <uuid/uuid.h>
1715 +#include "kerncompat.h"
1717 +#include "transaction.h"
1719 +#include "version.h"
1721 +#include "volumes.h"
1723 +#include "btrfs_cmds.h"
1726 +#define BLKGETSIZE64 0
1727 +#define BTRFS_IOC_SNAP_CREATE 0
1728 +#define BTRFS_VOL_NAME_MAX 255
1729 +struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; };
1730 +static inline int ioctl(int fd, int define, void *arg) { return 0; }
1734 + * test if path is a subvolume:
1735 + * this function return
1736 + * 0-> path exists but it is not a subvolume
1737 + * 1-> path exists and it is a subvolume
1738 + * -1 -> path is unaccessible
1740 +static int test_issubvolume(char *path)
1746 + res = stat(path, &st);
1750 + return (st.st_ino == 256) && S_ISDIR(st.st_mode);
1755 + * test if path is a directory
1756 + * this function return
1757 + * 0-> path exists but it is not a directory
1758 + * 1-> path exists and it is a directory
1759 + * -1 -> path is unaccessible
1761 +static int test_isdir(char *path)
1766 + res = stat(path, &st);
1770 + return S_ISDIR(st.st_mode);
1774 +static int open_file_or_dir(const char *fname)
1781 + ret = stat(fname, &st);
1785 + if (S_ISDIR(st.st_mode)) {
1786 + dirstream = opendir(fname);
1790 + fd = dirfd(dirstream);
1792 + fd = open(fname, O_RDWR);
1800 +static u64 parse_size(char *s)
1802 + int len = strlen(s);
1806 + if (!isdigit(s[len - 1])) {
1807 + c = tolower(s[len - 1]);
1818 + fprintf(stderr, "Unknown size descriptor %c\n", c);
1821 + s[len - 1] = '\0';
1823 + return atoll(s) * mult;
1826 +int do_defrag(int ac, char **av)
1832 + u64 len = (u64)-1;
1838 + int fancy_ioctl = 0;
1839 + struct btrfs_ioctl_defrag_range_args range;
1843 + int c = getopt(ac, av, "vcfs:l:t:");
1859 + start = parse_size(optarg);
1863 + len = parse_size(optarg);
1867 + thresh = parse_size(optarg);
1871 + fprintf(stderr, "Invalid arguments for defragment\n");
1876 + if (ac - optind == 0) {
1877 + fprintf(stderr, "Invalid arguments for defragment\n");
1882 + memset(&range, 0, sizeof(range));
1883 + range.start = start;
1885 + range.extent_thresh = thresh;
1887 + range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1889 + range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1891 + for (i = optind; i < ac; i++) {
1893 + printf("%s\n", av[i]);
1894 + fd = open_file_or_dir(av[i]);
1896 + fprintf(stderr, "failed to open %s\n", av[i]);
1901 + if (!fancy_ioctl) {
1902 + ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
1904 + ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
1905 + if (ret && errno == ENOTTY) {
1906 + fprintf(stderr, "defrag range ioctl not "
1907 + "supported in this kernel, please try "
1908 + "without any options.\n");
1914 + fprintf(stderr, "ioctl failed on %s ret %d errno %d\n",
1915 + av[i], ret, errno);
1921 + printf("%s\n", BTRFS_BUILD_VERSION);
1923 + fprintf(stderr, "total %d failures\n", errors);
1928 + return errors + 20;
1931 +int do_find_newer(int argc, char **argv)
1939 + last_gen = atoll(argv[2]);
1941 + ret = test_issubvolume(subvol);
1943 + fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1947 + fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1951 + fd = open_file_or_dir(subvol);
1953 + fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1956 + ret = find_updated_files(fd, 0, last_gen);
1962 +int do_subvol_list(int argc, char **argv)
1970 + ret = test_issubvolume(subvol);
1972 + fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1976 + fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1980 + fd = open_file_or_dir(subvol);
1982 + fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1985 + ret = list_subvols(fd);
1991 +int do_clone(int argc, char **argv)
1993 + char *subvol, *dst;
1994 + int res, fd, fddst, len;
2000 + struct btrfs_ioctl_vol_args args;
2002 + res = test_issubvolume(subvol);
2004 + fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
2008 + fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
2012 + res = test_isdir(dst);
2014 + fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
2019 + newname = strdup(subvol);
2020 + newname = basename(newname);
2023 + newname = strdup(dst);
2024 + newname = basename(newname);
2025 + dstdir = strdup(dst);
2026 + dstdir = dirname(dstdir);
2029 + if( !strcmp(newname,".") || !strcmp(newname,"..") ||
2030 + strchr(newname, '/') ){
2031 + fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
2036 + len = strlen(newname);
2037 + if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2038 + fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
2043 + fddst = open_file_or_dir(dstdir);
2045 + fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2049 + fd = open_file_or_dir(subvol);
2052 + fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2056 + printf("Create a snapshot of '%s' in '%s/%s'\n",
2057 + subvol, dstdir, newname);
2059 + strcpy(args.name, newname);
2060 + res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args);
2066 + fprintf( stderr, "ERROR: cannot snapshot '%s'\n",subvol);
2074 +int do_delete_subvolume(int argc, char **argv)
2077 + struct btrfs_ioctl_vol_args args;
2078 + char *dname, *vname, *cpath;
2079 + char *path = argv[1];
2081 + res = test_issubvolume(path);
2083 + fprintf(stderr, "ERROR: error accessing '%s'\n", path);
2087 + fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
2091 + cpath = realpath(path, 0);
2092 + dname = strdup(cpath);
2093 + dname = dirname(dname);
2094 + vname = strdup(cpath);
2095 + vname = basename(vname);
2098 + if( !strcmp(vname,".") || !strcmp(vname,"..") ||
2099 + strchr(vname, '/') ){
2100 + fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
2105 + len = strlen(vname);
2106 + if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2107 + fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
2112 + fd = open_file_or_dir(dname);
2115 + fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
2119 + printf("Delete subvolume '%s/%s'\n", dname, vname);
2120 + strcpy(args.name, vname);
2121 + res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
2126 + fprintf( stderr, "ERROR: cannot delete '%s/%s'\n",dname, vname);
2134 +int do_create_subvol(int argc, char **argv)
2136 + int res, fddst, len;
2139 + struct btrfs_ioctl_vol_args args;
2140 + char *dst = argv[1];
2142 + res = test_isdir(dst);
2144 + fprintf(stderr, "ERROR: '%s' exists\n", dst);
2148 + newname = strdup(dst);
2149 + newname = basename(newname);
2150 + dstdir = strdup(dst);
2151 + dstdir = dirname(dstdir);
2153 + if( !strcmp(newname,".") || !strcmp(newname,"..") ||
2154 + strchr(newname, '/') ){
2155 + fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
2160 + len = strlen(newname);
2161 + if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2162 + fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
2167 + fddst = open_file_or_dir(dstdir);
2169 + fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2173 + printf("Create subvolume '%s/%s'\n", dstdir, newname);
2174 + strcpy(args.name, newname);
2175 + res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
2180 + fprintf( stderr, "ERROR: cannot create subvolume\n");
2188 +int do_fssync(int argc, char **argv)
2191 + char *path = argv[1];
2193 + fd = open_file_or_dir(path);
2195 + fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2199 + printf("FSSync '%s'\n", path);
2200 + res = ioctl(fd, BTRFS_IOC_SYNC);
2203 + fprintf(stderr, "ERROR: unable to fs-syncing '%s'\n", path);
2210 +int do_scan(int argc, char **argv)
2216 + printf("Scanning for Btrfs filesystems\n");
2217 + ret = btrfs_scan_one_dir("/dev", 1);
2219 + fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2225 + fd = open("/dev/btrfs-control", O_RDWR);
2227 + perror("failed to open /dev/btrfs-control");
2231 + for( i = 1 ; i < argc ; i++ ){
2232 + struct btrfs_ioctl_vol_args args;
2235 + printf("Scanning for Btrfs filesystems in '%s'\n", argv[i]);
2237 + strcpy(args.name, argv[i]);
2239 + * FIXME: which are the error code returned by this ioctl ?
2240 + * it seems that is impossible to understand if there no is
2241 + * a btrfs filesystem from an I/O error !!!
2243 + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
2247 + fprintf(stderr, "ERROR: unable to scan the device '%s'\n", argv[i]);
2257 +int do_resize(int argc, char **argv)
2260 + struct btrfs_ioctl_vol_args args;
2262 + char *amount=argv[1], *path=argv[2];
2264 + fd = open_file_or_dir(path);
2266 + fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2269 + len = strlen(amount);
2270 + if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2271 + fprintf(stderr, "ERROR: size value too long ('%s)\n",
2276 + printf("Resize '%s' of '%s'\n", path, amount);
2277 + strcpy(args.name, amount);
2278 + res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
2281 + fprintf(stderr, "ERROR: unable to resize '%s'\n", path);
2287 +static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
2289 + struct list_head *cur;
2290 + struct btrfs_device *device;
2292 + list_for_each(cur, &fs_devices->devices) {
2293 + device = list_entry(cur, struct btrfs_device, dev_list);
2294 + if ((device->label && strcmp(device->label, search) == 0) ||
2295 + strcmp(device->name, search) == 0)
2301 +static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
2304 + struct list_head *cur;
2305 + struct btrfs_device *device;
2306 + char *super_bytes_used;
2307 + u64 devs_found = 0;
2310 + uuid_unparse(fs_devices->fsid, uuidbuf);
2311 + device = list_entry(fs_devices->devices.next, struct btrfs_device,
2313 + if (device->label && device->label[0])
2314 + printf("Label: '%s' ", device->label);
2316 + printf("Label: none ");
2318 + super_bytes_used = pretty_sizes(device->super_bytes_used);
2320 + total = device->total_devs;
2321 + printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
2322 + (unsigned long long)total, super_bytes_used);
2324 + free(super_bytes_used);
2326 + list_for_each(cur, &fs_devices->devices) {
2327 + char *total_bytes;
2329 + device = list_entry(cur, struct btrfs_device, dev_list);
2330 + total_bytes = pretty_sizes(device->total_bytes);
2331 + bytes_used = pretty_sizes(device->bytes_used);
2332 + printf("\tdevid %4llu size %s used %s path %s\n",
2333 + (unsigned long long)device->devid,
2334 + total_bytes, bytes_used, device->name);
2335 + free(total_bytes);
2339 + if (devs_found < total) {
2340 + printf("\t*** Some devices missing\n");
2345 +int do_show_filesystem(int argc, char **argv)
2347 + struct list_head *all_uuids;
2348 + struct btrfs_fs_devices *fs_devices;
2349 + struct list_head *cur_uuid;
2350 + char *search = argv[1];
2353 + ret = btrfs_scan_one_dir("/dev", 0);
2355 + fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2359 + all_uuids = btrfs_scanned_uuids();
2360 + list_for_each(cur_uuid, all_uuids) {
2361 + fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
2363 + if (search && uuid_search(fs_devices, search) == 0)
2365 + print_one_uuid(fs_devices);
2367 + printf("%s\n", BTRFS_BUILD_VERSION);
2371 +int do_add_volume(int nargs, char **args)
2374 + char *mntpnt = args[nargs-1];
2375 + int i, fdmnt, ret=0;
2378 + fdmnt = open_file_or_dir(mntpnt);
2380 + fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2384 + for(i=1 ; i < (nargs-1) ; i++ ){
2385 + struct btrfs_ioctl_vol_args ioctl_args;
2387 + u64 dev_block_count = 0;
2390 + devfd = open(args[i], O_RDWR);
2392 + fprintf(stderr, "ERROR: Unable to open device '%s'\n", args[i]);
2397 + ret = fstat(devfd, &st);
2399 + fprintf(stderr, "ERROR: Unable to stat '%s'\n", args[i]);
2404 + if (!S_ISBLK(st.st_mode)) {
2405 + fprintf(stderr, "ERROR: '%s' is not a block device\n", args[i]);
2411 + res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count);
2413 + fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]);
2420 + strcpy(ioctl_args.name, args[i]);
2421 + res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
2423 + fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]);
2437 +int do_balance(int argc, char **argv)
2441 + struct btrfs_ioctl_vol_args args;
2442 + char *path = argv[1];
2444 + fdmnt = open_file_or_dir(path);
2446 + fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2450 + memset(&args, 0, sizeof(args));
2451 + ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args);
2454 + fprintf(stderr, "ERROR: balancing '%s'\n", path);
2460 +int do_remove_volume(int nargs, char **args)
2463 + char *mntpnt = args[nargs-1];
2464 + int i, fdmnt, ret=0;
2466 + fdmnt = open_file_or_dir(mntpnt);
2468 + fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2472 + for(i=1 ; i < (nargs-1) ; i++ ){
2473 + struct btrfs_ioctl_vol_args arg;
2476 + strcpy(arg.name, args[i]);
2477 + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
2479 + fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]);
2491 +int do_set_default_subvol(int nargs, char **argv)
2495 + char *path = argv[2];
2496 + char *subvolid = argv[1];
2498 + fd = open_file_or_dir(path);
2500 + fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2504 + objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
2505 + if (errno == ERANGE) {
2506 + fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
2509 + ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
2512 + fprintf(stderr, "ERROR: unable to set a new default subvolume\n");
2518 +int do_df_filesystem(int nargs, char **argv)
2520 + struct btrfs_ioctl_space_args *sargs;
2524 + char *path = argv[1];
2526 + fd = open_file_or_dir(path);
2528 + fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2532 + sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
2536 + sargs->space_slots = 0;
2537 + sargs->total_spaces = 0;
2539 + ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2544 + if (!sargs->total_spaces)
2547 + count = sargs->total_spaces;
2549 + sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
2550 + (count * sizeof(struct btrfs_ioctl_space_info)));
2554 + sargs->space_slots = count;
2555 + sargs->total_spaces = 0;
2557 + ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2563 + for (i = 0; i < sargs->total_spaces; i++) {
2564 + char description[80];
2565 + char *total_bytes;
2568 + u64 flags = sargs->spaces[i].flags;
2570 + memset(description, 0, 80);
2572 + if (flags & BTRFS_BLOCK_GROUP_DATA) {
2573 + snprintf(description, 5, "%s", "Data");
2575 + } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
2576 + snprintf(description, 7, "%s", "System");
2578 + } else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
2579 + snprintf(description, 9, "%s", "Metadata");
2583 + if (flags & BTRFS_BLOCK_GROUP_RAID0) {
2584 + snprintf(description+written, 8, "%s", ", RAID0");
2586 + } else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
2587 + snprintf(description+written, 8, "%s", ", RAID1");
2589 + } else if (flags & BTRFS_BLOCK_GROUP_DUP) {
2590 + snprintf(description+written, 6, "%s", ", DUP");
2592 + } else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
2593 + snprintf(description+written, 9, "%s", ", RAID10");
2597 + total_bytes = pretty_sizes(sargs->spaces[i].total_bytes);
2598 + used_bytes = pretty_sizes(sargs->spaces[i].used_bytes);
2599 + printf("%s: total=%s, used=%s\n", description, total_bytes,
2606 diff --git a/btrfs_cmds.h b/btrfs_cmds.h
2607 new file mode 100644
2608 index 0000000..7bde191
2613 + * This program is free software; you can redistribute it and/or
2614 + * modify it under the terms of the GNU General Public
2615 + * License v2 as published by the Free Software Foundation.
2617 + * This program is distributed in the hope that it will be useful,
2618 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2619 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2620 + * General Public License for more details.
2622 + * You should have received a copy of the GNU General Public
2623 + * License along with this program; if not, write to the
2624 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2625 + * Boston, MA 021110-1307, USA.
2629 +int do_clone(int nargs, char **argv);
2630 +int do_delete_subvolume(int nargs, char **argv);
2631 +int do_create_subvol(int nargs, char **argv);
2632 +int do_fssync(int nargs, char **argv);
2633 +int do_defrag(int argc, char **argv);
2634 +int do_show_filesystem(int nargs, char **argv);
2635 +int do_add_volume(int nargs, char **args);
2636 +int do_balance(int nargs, char **argv);
2637 +int do_remove_volume(int nargs, char **args);
2638 +int do_scan(int nargs, char **argv);
2639 +int do_resize(int nargs, char **argv);
2640 +int do_subvol_list(int nargs, char **argv);
2641 +int do_set_default_subvol(int nargs, char **argv);
2642 +int list_subvols(int fd);
2643 +int do_df_filesystem(int nargs, char **argv);
2644 +int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
2645 +int do_find_newer(int argc, char **argv);
2646 diff --git a/btrfsck.c b/btrfsck.c
2647 index 40c90f8..63e44d1 100644
2651 #define _GNU_SOURCE 1
2654 +#include <unistd.h>
2656 +#include <sys/stat.h>
2657 #include "kerncompat.h"
2659 #include "disk-io.h"
2661 #include "transaction.h"
2663 #include "version.h"
2666 static u64 bytes_used = 0;
2667 static u64 total_csum_bytes = 0;
2668 @@ -36,7 +39,7 @@ static u64 total_fs_tree_bytes = 0;
2669 static u64 btree_space_waste = 0;
2670 static u64 data_bytes_allocated = 0;
2671 static u64 data_bytes_referenced = 0;
2672 -int found_old_backref = 0;
2673 +static int found_old_backref = 0;
2675 struct extent_backref {
2676 struct list_head list;
2677 @@ -100,7 +103,11 @@ struct inode_backref {
2678 #define REF_ERR_DUP_INODE_REF (1 << 5)
2679 #define REF_ERR_INDEX_UNMATCH (1 << 6)
2680 #define REF_ERR_FILETYPE_UNMATCH (1 << 7)
2681 -#define REF_ERR_NAME_TOO_LONG (1 << 8)
2682 +#define REF_ERR_NAME_TOO_LONG (1 << 8) // 100
2683 +#define REF_ERR_NO_ROOT_REF (1 << 9)
2684 +#define REF_ERR_NO_ROOT_BACKREF (1 << 10)
2685 +#define REF_ERR_DUP_ROOT_REF (1 << 11)
2686 +#define REF_ERR_DUP_ROOT_BACKREF (1 << 12)
2688 struct inode_record {
2689 struct list_head backrefs;
2690 @@ -144,6 +151,29 @@ struct inode_record {
2691 #define I_ERR_SOME_CSUM_MISSING (1 << 12)
2692 #define I_ERR_LINK_COUNT_WRONG (1 << 13)
2694 +struct root_backref {
2695 + struct list_head list;
2696 + unsigned int found_dir_item:1;
2697 + unsigned int found_dir_index:1;
2698 + unsigned int found_back_ref:1;
2699 + unsigned int found_forward_ref:1;
2700 + unsigned int reachable:1;
2709 +struct root_record {
2710 + struct list_head backrefs;
2711 + struct cache_extent cache;
2712 + unsigned int found_root_item:1;
2718 struct cache_extent cache;
2720 @@ -151,6 +181,7 @@ struct ptr_node {
2722 struct shared_node {
2723 struct cache_extent cache;
2724 + struct cache_tree root_cache;
2725 struct cache_tree inode_cache;
2726 struct inode_record *current;
2728 @@ -258,6 +289,14 @@ static void free_inode_rec(struct inode_record *rec)
2732 +static int can_free_inode_rec(struct inode_record *rec)
2734 + if (!rec->errors && rec->checked && rec->found_inode_item &&
2735 + rec->nlink == rec->found_link && list_empty(&rec->backrefs))
2740 static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2741 struct inode_record *rec)
2743 @@ -309,8 +348,7 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2746 BUG_ON(rec->refs != 1);
2747 - if (!rec->errors && rec->nlink == rec->found_link &&
2748 - list_empty(&rec->backrefs)) {
2749 + if (can_free_inode_rec(rec)) {
2750 cache = find_cache_extent(inode_cache, rec->ino, 1);
2751 node = container_of(cache, struct ptr_node, cache);
2752 BUG_ON(node->data != rec);
2753 @@ -338,14 +376,12 @@ static int check_orphan_item(struct btrfs_root *root, u64 ino)
2757 -static int process_inode_item(struct btrfs_root *root,
2758 - struct extent_buffer *eb,
2759 +static int process_inode_item(struct extent_buffer *eb,
2760 int slot, struct btrfs_key *key,
2761 struct shared_node *active_node)
2763 struct inode_record *rec;
2764 struct btrfs_inode_item *item;
2767 rec = active_node->current;
2768 BUG_ON(rec->ino != key->objectid || rec->refs > 1);
2769 @@ -361,11 +397,8 @@ static int process_inode_item(struct btrfs_root *root,
2770 if (btrfs_inode_flags(eb, item) & BTRFS_INODE_NODATASUM)
2772 rec->found_inode_item = 1;
2773 - if (rec->nlink == 0) {
2774 - ret = check_orphan_item(root, rec->ino);
2775 - if (ret == -ENOENT)
2776 - rec->errors |= I_ERR_NO_ORPHAN_ITEM;
2778 + if (rec->nlink == 0)
2779 + rec->errors |= I_ERR_NO_ORPHAN_ITEM;
2780 maybe_free_inode_rec(&active_node->inode_cache, rec);
2783 @@ -391,7 +424,6 @@ static struct inode_backref *get_inode_backref(struct inode_record *rec,
2784 memcpy(backref->name, name, namelen);
2785 backref->name[namelen] = '\0';
2786 list_add_tail(&backref->list, &rec->backrefs);
2787 - rec->found_link++;
2791 @@ -419,6 +451,7 @@ static int add_inode_backref(struct cache_tree *inode_cache,
2792 backref->filetype = filetype;
2793 backref->found_dir_index = 1;
2794 } else if (itemtype == BTRFS_DIR_ITEM_KEY) {
2795 + rec->found_link++;
2796 if (backref->found_dir_item)
2797 backref->errors |= REF_ERR_DUP_DIR_ITEM;
2798 if (backref->found_dir_index && backref->filetype != filetype)
2799 @@ -443,10 +476,10 @@ static int add_inode_backref(struct cache_tree *inode_cache,
2802 static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2803 - struct shared_node *dst_node)
2804 + struct cache_tree *dst_cache)
2806 struct inode_backref *backref;
2807 - struct cache_tree *dst_cache = &dst_node->inode_cache;
2808 + u32 dir_count = 0;
2811 list_for_each_entry(backref, &src->backrefs, list) {
2812 @@ -457,6 +490,7 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2813 BTRFS_DIR_INDEX_KEY, backref->errors);
2815 if (backref->found_dir_item) {
2817 add_inode_backref(dst_cache, dst->ino,
2818 backref->dir, 0, backref->name,
2819 backref->namelen, backref->filetype,
2820 @@ -481,6 +515,8 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2821 if (dst->first_extent_gap > src->first_extent_gap)
2822 dst->first_extent_gap = src->first_extent_gap;
2824 + BUG_ON(src->found_link < dir_count);
2825 + dst->found_link += src->found_link - dir_count;
2826 dst->found_size += src->found_size;
2827 if (src->extent_start != (u64)-1) {
2828 if (dst->extent_start == (u64)-1) {
2829 @@ -510,14 +546,8 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2830 dst->errors |= I_ERR_DUP_INODE_ITEM;
2834 - if (src->checked) {
2836 - if (dst_node->current == dst)
2837 - dst_node->current = NULL;
2840 - maybe_free_inode_rec(dst_cache, dst);
2845 @@ -537,8 +567,9 @@ static int splice_shared_node(struct shared_node *src_node,
2846 if (src_node->current)
2847 current_ino = src_node->current->ino;
2849 - src = &src_node->inode_cache;
2850 - dst = &dst_node->inode_cache;
2851 + src = &src_node->root_cache;
2852 + dst = &dst_node->root_cache;
2854 cache = find_first_cache_extent(src, 0);
2856 node = container_of(cache, struct ptr_node, cache);
2857 @@ -558,13 +589,26 @@ static int splice_shared_node(struct shared_node *src_node,
2858 ret = insert_existing_cache_extent(dst, &ins->cache);
2859 if (ret == -EEXIST) {
2860 conflict = get_inode_rec(dst, rec->ino, 1);
2861 - merge_inode_recs(rec, conflict, dst_node);
2862 + merge_inode_recs(rec, conflict, dst);
2863 + if (rec->checked) {
2864 + conflict->checked = 1;
2865 + if (dst_node->current == conflict)
2866 + dst_node->current = NULL;
2868 + maybe_free_inode_rec(dst, conflict);
2869 free_inode_rec(rec);
2876 + if (src == &src_node->root_cache) {
2877 + src = &src_node->inode_cache;
2878 + dst = &dst_node->inode_cache;
2882 if (current_ino > 0 && (!dst_node->current ||
2883 current_ino > dst_node->current->ino)) {
2884 if (dst_node->current) {
2885 @@ -616,6 +660,7 @@ static int add_shared_node(struct cache_tree *shared, u64 bytenr, u32 refs)
2886 node = calloc(1, sizeof(*node));
2887 node->cache.start = bytenr;
2888 node->cache.size = 1;
2889 + cache_tree_init(&node->root_cache);
2890 cache_tree_init(&node->inode_cache);
2893 @@ -646,6 +691,7 @@ static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs,
2894 if (wc->root_level == wc->active_node &&
2895 btrfs_root_refs(&root->root_item) == 0) {
2896 if (--node->refs == 0) {
2897 + free_inode_recs(&node->root_cache);
2898 free_inode_recs(&node->inode_cache);
2899 remove_cache_extent(&wc->shared, &node->cache);
2901 @@ -708,10 +754,12 @@ static int process_dir_item(struct extent_buffer *eb,
2903 struct btrfs_dir_item *di;
2904 struct inode_record *rec;
2905 + struct cache_tree *root_cache;
2906 struct cache_tree *inode_cache;
2907 struct btrfs_key location;
2908 char namebuf[BTRFS_NAME_LEN];
2910 + root_cache = &active_node->root_cache;
2911 inode_cache = &active_node->inode_cache;
2912 rec = active_node->current;
2913 rec->found_dir_item = 1;
2914 @@ -740,7 +788,9 @@ static int process_dir_item(struct extent_buffer *eb,
2915 key->objectid, key->offset, namebuf,
2916 len, filetype, key->type, error);
2917 } else if (location.type == BTRFS_ROOT_ITEM_KEY) {
2918 - /* fixme: check root back & forward references */
2919 + add_inode_backref(root_cache, location.objectid,
2920 + key->objectid, key->offset, namebuf,
2921 + len, filetype, key->type, error);
2923 fprintf(stderr, "warning line %d\n", __LINE__);
2925 @@ -977,8 +1027,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
2926 ret = process_inode_ref(eb, i, &key, active_node);
2928 case BTRFS_INODE_ITEM_KEY:
2929 - ret = process_inode_item(root, eb, i, &key,
2931 + ret = process_inode_item(eb, i, &key, active_node);
2933 case BTRFS_EXTENT_DATA_KEY:
2934 ret = process_file_extent(root, eb, i, &key,
2935 @@ -1120,7 +1169,7 @@ static int check_root_dir(struct inode_record *rec)
2937 if (!rec->found_inode_item || rec->errors)
2939 - if (rec->nlink != 1 || rec->found_link != 1)
2940 + if (rec->nlink != 1 || rec->found_link != 0)
2942 if (list_empty(&rec->backrefs))
2944 @@ -1176,13 +1225,23 @@ static int check_inode_recs(struct btrfs_root *root,
2945 node = container_of(cache, struct ptr_node, cache);
2947 remove_cache_extent(inode_cache, &node->cache);
2949 if (rec->ino == root_dirid ||
2950 rec->ino == BTRFS_ORPHAN_OBJECTID) {
2952 free_inode_rec(rec);
2956 + if (rec->errors & I_ERR_NO_ORPHAN_ITEM) {
2957 + ret = check_orphan_item(root, rec->ino);
2959 + rec->errors &= ~I_ERR_NO_ORPHAN_ITEM;
2960 + if (can_free_inode_rec(rec)) {
2961 + free_inode_rec(rec);
2967 if (!rec->found_inode_item)
2968 rec->errors |= I_ERR_NO_INODE_ITEM;
2969 @@ -1205,13 +1264,314 @@ static int check_inode_recs(struct btrfs_root *root,
2970 backref->namelen, backref->name,
2971 backref->filetype, backref->errors);
2974 free_inode_rec(rec);
2976 return (error > 0) ? -1 : 0;
2979 +static struct root_record *get_root_rec(struct cache_tree *root_cache,
2982 + struct cache_extent *cache;
2983 + struct root_record *rec = NULL;
2986 + cache = find_cache_extent(root_cache, objectid, 1);
2988 + rec = container_of(cache, struct root_record, cache);
2990 + rec = calloc(1, sizeof(*rec));
2991 + rec->objectid = objectid;
2992 + INIT_LIST_HEAD(&rec->backrefs);
2993 + rec->cache.start = objectid;
2994 + rec->cache.size = 1;
2996 + ret = insert_existing_cache_extent(root_cache, &rec->cache);
3002 +static struct root_backref *get_root_backref(struct root_record *rec,
3003 + u64 ref_root, u64 dir, u64 index,
3004 + const char *name, int namelen)
3006 + struct root_backref *backref;
3008 + list_for_each_entry(backref, &rec->backrefs, list) {
3009 + if (backref->ref_root != ref_root || backref->dir != dir ||
3010 + backref->namelen != namelen)
3012 + if (memcmp(name, backref->name, namelen))
3017 + backref = malloc(sizeof(*backref) + namelen + 1);
3018 + memset(backref, 0, sizeof(*backref));
3019 + backref->ref_root = ref_root;
3020 + backref->dir = dir;
3021 + backref->index = index;
3022 + backref->namelen = namelen;
3023 + memcpy(backref->name, name, namelen);
3024 + backref->name[namelen] = '\0';
3025 + list_add_tail(&backref->list, &rec->backrefs);
3029 +static void free_root_recs(struct cache_tree *root_cache)
3031 + struct cache_extent *cache;
3032 + struct root_record *rec;
3033 + struct root_backref *backref;
3036 + cache = find_first_cache_extent(root_cache, 0);
3039 + rec = container_of(cache, struct root_record, cache);
3040 + remove_cache_extent(root_cache, &rec->cache);
3042 + while (!list_empty(&rec->backrefs)) {
3043 + backref = list_entry(rec->backrefs.next,
3044 + struct root_backref, list);
3045 + list_del(&backref->list);
3052 +static int add_root_backref(struct cache_tree *root_cache,
3053 + u64 root_id, u64 ref_root, u64 dir, u64 index,
3054 + const char *name, int namelen,
3055 + int item_type, int errors)
3057 + struct root_record *rec;
3058 + struct root_backref *backref;
3060 + rec = get_root_rec(root_cache, root_id);
3061 + backref = get_root_backref(rec, ref_root, dir, index, name, namelen);
3063 + backref->errors |= errors;
3065 + if (item_type != BTRFS_DIR_ITEM_KEY) {
3066 + if (backref->found_dir_index || backref->found_back_ref ||
3067 + backref->found_forward_ref) {
3068 + if (backref->index != index)
3069 + backref->errors |= REF_ERR_INDEX_UNMATCH;
3071 + backref->index = index;
3075 + if (item_type == BTRFS_DIR_ITEM_KEY) {
3076 + backref->found_dir_item = 1;
3077 + backref->reachable = 1;
3079 + } else if (item_type == BTRFS_DIR_INDEX_KEY) {
3080 + backref->found_dir_index = 1;
3081 + } else if (item_type == BTRFS_ROOT_REF_KEY) {
3082 + if (backref->found_forward_ref)
3083 + backref->errors |= REF_ERR_DUP_ROOT_REF;
3084 + backref->found_forward_ref = 1;
3085 + } else if (item_type == BTRFS_ROOT_BACKREF_KEY) {
3086 + if (backref->found_back_ref)
3087 + backref->errors |= REF_ERR_DUP_ROOT_BACKREF;
3088 + backref->found_back_ref = 1;
3096 +static int merge_root_recs(struct btrfs_root *root,
3097 + struct cache_tree *src_cache,
3098 + struct cache_tree *dst_cache)
3100 + struct cache_extent *cache;
3101 + struct ptr_node *node;
3102 + struct inode_record *rec;
3103 + struct inode_backref *backref;
3105 + if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
3106 + free_inode_recs(src_cache);
3111 + cache = find_first_cache_extent(src_cache, 0);
3114 + node = container_of(cache, struct ptr_node, cache);
3116 + remove_cache_extent(src_cache, &node->cache);
3119 + list_for_each_entry(backref, &rec->backrefs, list) {
3120 + BUG_ON(backref->found_inode_ref);
3121 + if (backref->found_dir_item)
3122 + add_root_backref(dst_cache, rec->ino,
3123 + root->root_key.objectid, backref->dir,
3124 + backref->index, backref->name,
3125 + backref->namelen, BTRFS_DIR_ITEM_KEY,
3127 + if (backref->found_dir_index)
3128 + add_root_backref(dst_cache, rec->ino,
3129 + root->root_key.objectid, backref->dir,
3130 + backref->index, backref->name,
3131 + backref->namelen, BTRFS_DIR_INDEX_KEY,
3134 + free_inode_rec(rec);
3139 +static int check_root_refs(struct btrfs_root *root,
3140 + struct cache_tree *root_cache)
3142 + struct root_record *rec;
3143 + struct root_record *ref_root;
3144 + struct root_backref *backref;
3145 + struct cache_extent *cache;
3151 + rec = get_root_rec(root_cache, BTRFS_FS_TREE_OBJECTID);
3152 + rec->found_ref = 1;
3154 + /* fixme: this can not detect circular references */
3157 + cache = find_first_cache_extent(root_cache, 0);
3161 + rec = container_of(cache, struct root_record, cache);
3162 + cache = next_cache_extent(cache);
3164 + if (rec->found_ref == 0)
3167 + list_for_each_entry(backref, &rec->backrefs, list) {
3168 + if (!backref->reachable)
3171 + ref_root = get_root_rec(root_cache,
3172 + backref->ref_root);
3173 + if (ref_root->found_ref > 0)
3176 + backref->reachable = 0;
3178 + if (rec->found_ref == 0)
3184 + cache = find_first_cache_extent(root_cache, 0);
3188 + rec = container_of(cache, struct root_record, cache);
3189 + cache = next_cache_extent(cache);
3191 + if (rec->found_ref == 0 &&
3192 + rec->objectid >= BTRFS_FIRST_FREE_OBJECTID &&
3193 + rec->objectid <= BTRFS_LAST_FREE_OBJECTID) {
3194 + ret = check_orphan_item(root->fs_info->tree_root,
3199 + fprintf(stderr, "fs tree %llu not referenced\n",
3200 + (unsigned long long)rec->objectid);
3204 + if (rec->found_ref > 0 && !rec->found_root_item)
3206 + list_for_each_entry(backref, &rec->backrefs, list) {
3207 + if (!backref->found_dir_item)
3208 + backref->errors |= REF_ERR_NO_DIR_ITEM;
3209 + if (!backref->found_dir_index)
3210 + backref->errors |= REF_ERR_NO_DIR_INDEX;
3211 + if (!backref->found_back_ref)
3212 + backref->errors |= REF_ERR_NO_ROOT_BACKREF;
3213 + if (!backref->found_forward_ref)
3214 + backref->errors |= REF_ERR_NO_ROOT_REF;
3215 + if (backref->reachable && backref->errors)
3222 + fprintf(stderr, "fs tree %llu refs %u %s\n",
3223 + (unsigned long long)rec->objectid, rec->found_ref,
3224 + rec->found_root_item ? "" : "not found");
3226 + list_for_each_entry(backref, &rec->backrefs, list) {
3227 + if (!backref->reachable)
3229 + if (!backref->errors && rec->found_root_item)
3231 + fprintf(stderr, "\tunresolved ref root %llu dir %llu"
3232 + " index %llu namelen %u name %s error %x\n",
3233 + (unsigned long long)backref->ref_root,
3234 + (unsigned long long)backref->dir,
3235 + (unsigned long long)backref->index,
3236 + backref->namelen, backref->name,
3240 + return errors > 0 ? 1 : 0;
3243 +static int process_root_ref(struct extent_buffer *eb, int slot,
3244 + struct btrfs_key *key,
3245 + struct cache_tree *root_cache)
3251 + struct btrfs_root_ref *ref;
3252 + char namebuf[BTRFS_NAME_LEN];
3255 + ref = btrfs_item_ptr(eb, slot, struct btrfs_root_ref);
3257 + dirid = btrfs_root_ref_dirid(eb, ref);
3258 + index = btrfs_root_ref_sequence(eb, ref);
3259 + name_len = btrfs_root_ref_name_len(eb, ref);
3261 + if (name_len <= BTRFS_NAME_LEN) {
3265 + len = BTRFS_NAME_LEN;
3266 + error = REF_ERR_NAME_TOO_LONG;
3268 + read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
3270 + if (key->type == BTRFS_ROOT_REF_KEY) {
3271 + add_root_backref(root_cache, key->offset, key->objectid, dirid,
3272 + index, namebuf, len, key->type, error);
3274 + add_root_backref(root_cache, key->objectid, key->offset, dirid,
3275 + index, namebuf, len, key->type, error);
3280 static int check_fs_root(struct btrfs_root *root,
3281 + struct cache_tree *root_cache,
3282 struct walk_control *wc)
3285 @@ -1219,10 +1579,18 @@ static int check_fs_root(struct btrfs_root *root,
3287 struct btrfs_path path;
3288 struct shared_node root_node;
3289 + struct root_record *rec;
3290 struct btrfs_root_item *root_item = &root->root_item;
3292 + if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
3293 + rec = get_root_rec(root_cache, root->root_key.objectid);
3294 + if (btrfs_root_refs(root_item) > 0)
3295 + rec->found_root_item = 1;
3298 btrfs_init_path(&path);
3299 memset(&root_node, 0, sizeof(root_node));
3300 + cache_tree_init(&root_node.root_cache);
3301 cache_tree_init(&root_node.inode_cache);
3303 level = btrfs_header_level(root->node);
3304 @@ -1266,6 +1634,8 @@ static int check_fs_root(struct btrfs_root *root,
3306 btrfs_release_path(root, &path);
3308 + merge_root_recs(root, &root_node.root_cache, root_cache);
3310 if (root_node.current) {
3311 root_node.current->checked = 1;
3312 maybe_free_inode_rec(&root_node.inode_cache,
3313 @@ -1280,13 +1650,15 @@ static int fs_root_objectid(u64 objectid)
3315 if (objectid == BTRFS_FS_TREE_OBJECTID ||
3316 objectid == BTRFS_TREE_RELOC_OBJECTID ||
3317 + objectid == BTRFS_DATA_RELOC_TREE_OBJECTID ||
3318 (objectid >= BTRFS_FIRST_FREE_OBJECTID &&
3319 - objectid < BTRFS_LAST_FREE_OBJECTID))
3320 + objectid <= BTRFS_LAST_FREE_OBJECTID))
3325 -static int check_fs_roots(struct btrfs_root *root)
3326 +static int check_fs_roots(struct btrfs_root *root,
3327 + struct cache_tree *root_cache)
3329 struct btrfs_path path;
3330 struct btrfs_key key;
3331 @@ -1319,10 +1691,14 @@ static int check_fs_roots(struct btrfs_root *root)
3332 fs_root_objectid(key.objectid)) {
3333 tmp_root = btrfs_read_fs_root_no_cache(root->fs_info,
3335 - ret = check_fs_root(tmp_root, &wc);
3336 + ret = check_fs_root(tmp_root, root_cache, &wc);
3339 btrfs_free_fs_root(root->fs_info, tmp_root);
3340 + } else if (key.type == BTRFS_ROOT_REF_KEY ||
3341 + key.type == BTRFS_ROOT_BACKREF_KEY) {
3342 + process_root_ref(leaf, path.slots[0], &key,
3347 @@ -1895,7 +2271,6 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
3352 static int add_pending(struct cache_tree *pending,
3353 struct cache_tree *seen, u64 bytenr, u32 size)
3355 @@ -2443,14 +2818,45 @@ static void print_usage(void)
3357 int main(int ac, char **av)
3359 + struct cache_tree root_cache;
3360 struct btrfs_root *root;
3368 + c = getopt(ac, av, "s:");
3373 + num = atol(optarg);
3374 + bytenr = btrfs_sb_offset(num);
3375 + printf("using SB copy %d, bytenr %llu\n", num,
3376 + (unsigned long long)bytenr);
3388 - root = open_ctree(av[1], 0, 0);
3389 + cache_tree_init(&root_cache);
3391 + if((ret = check_mounted(av[optind])) < 0) {
3392 + fprintf(stderr, "Could not check mount status: %s\n", strerror(ret));
3395 + fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]);
3399 + root = open_ctree(av[optind], bytenr, 0);
3403 @@ -2458,10 +2864,15 @@ int main(int ac, char **av)
3404 ret = check_extents(root);
3407 - ret = check_fs_roots(root);
3408 + ret = check_fs_roots(root, &root_cache);
3412 + ret = check_root_refs(root, &root_cache);
3414 + free_root_recs(&root_cache);
3417 if (found_old_backref) {
3419 * there was a disk format change when mixed
3420 diff --git a/btrfsctl.c b/btrfsctl.c
3421 index b323818..92bdf39 100644
3428 +#include <stdlib.h>
3429 #include "kerncompat.h"
3431 #include "transaction.h"
3432 @@ -46,7 +47,7 @@ static inline int ioctl(int fd, int define, void *arg) { return 0; }
3433 static void print_usage(void)
3435 printf("usage: btrfsctl [ -d file|dir] [ -s snap_name subvol|tree ]\n");
3436 - printf(" [-r size] [-A device] [-a] [-c]\n");
3437 + printf(" [-r size] [-A device] [-a] [-c] [-D dir .]\n");
3438 printf("\t-d filename: defragments one file\n");
3439 printf("\t-d directory: defragments the entire Btree\n");
3440 printf("\t-s snap_name dir: creates a new snapshot of dir\n");
3441 @@ -55,6 +56,9 @@ static void print_usage(void)
3442 printf("\t-A device: scans the device file for a Btrfs filesystem\n");
3443 printf("\t-a: scans all devices for Btrfs filesystems\n");
3444 printf("\t-c: forces a single FS sync\n");
3445 + printf("\t-D: delete snapshot\n");
3446 + printf("\t-m [tree id] directory: set the default mounted subvolume"
3447 + " to the [tree id] or the directory\n");
3448 printf("%s\n", BTRFS_BUILD_VERSION);
3451 @@ -99,7 +103,9 @@ int main(int ac, char **av)
3453 unsigned long command = 0;
3459 if (ac == 2 && strcmp(av[1], "-a") == 0) {
3460 fprintf(stderr, "Scanning for Btrfs filesystems\n");
3461 @@ -158,6 +164,28 @@ int main(int ac, char **av)
3464 command = BTRFS_IOC_DEFRAG;
3465 + } else if (strcmp(av[i], "-D") == 0) {
3466 + if (i >= ac - 1) {
3467 + fprintf(stderr, "-D requires an arg\n");
3470 + command = BTRFS_IOC_SNAP_DESTROY;
3472 + len = strlen(name);
3473 + pos = strchr(name, '/');
3475 + if (*(pos + 1) == '\0')
3479 + "error: / not allowed in names\n");
3483 + if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
3484 + fprintf(stderr, "-D size too long\n");
3487 } else if (strcmp(av[i], "-A") == 0) {
3489 fprintf(stderr, "-A requires an arg\n");
3490 @@ -178,6 +206,16 @@ int main(int ac, char **av)
3491 command = BTRFS_IOC_RESIZE;
3492 } else if (strcmp(av[i], "-c") == 0) {
3493 command = BTRFS_IOC_SYNC;
3494 + } else if (strcmp(av[i], "-m") == 0) {
3495 + command = BTRFS_IOC_DEFAULT_SUBVOL;
3496 + if (i == ac - 3) {
3497 + objectid = (unsigned long long)
3498 + strtoll(av[i + 1], NULL, 0);
3499 + if (errno == ERANGE) {
3500 + fprintf(stderr, "invalid tree id\n");
3507 @@ -206,6 +244,9 @@ int main(int ac, char **av)
3508 if (command == BTRFS_IOC_SNAP_CREATE) {
3510 ret = ioctl(snap_fd, command, &args);
3511 + } else if (command == BTRFS_IOC_DEFAULT_SUBVOL) {
3512 + printf("objectid is %llu\n", objectid);
3513 + ret = ioctl(fd, command, &objectid);
3515 ret = ioctl(fd, command, &args);
3517 @@ -219,8 +260,8 @@ int main(int ac, char **av)
3519 printf("%s\n", BTRFS_BUILD_VERSION);
3528 diff --git a/convert.c b/convert.c
3529 index d2c9efa..d037c98 100644
3532 @@ -370,7 +370,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3533 struct btrfs_extent_item *ei;
3534 u32 blocksize = root->sectorsize;
3538 if (disk_bytenr == 0) {
3539 ret = btrfs_insert_file_extent(trans, root, objectid,
3540 @@ -432,9 +431,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3541 nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
3542 btrfs_set_stack_inode_nbytes(inode, nbytes);
3544 - bytes_used = btrfs_root_used(&root->root_item);
3545 - btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
3547 btrfs_release_path(root, &path);
3549 ins_key.objectid = disk_bytenr;
3550 @@ -454,9 +450,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3552 btrfs_mark_buffer_dirty(leaf);
3554 - bytes_used = btrfs_super_bytes_used(&info->super_copy);
3555 - btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
3557 ret = btrfs_update_block_group(trans, root, disk_bytenr,
3560 diff --git a/ctree.h b/ctree.h
3561 index a9062ea..b79e238 100644
3564 @@ -350,11 +350,13 @@ struct btrfs_super_block {
3565 * ones specified below then we will fail to mount
3567 #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
3568 +#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0)
3570 #define BTRFS_FEATURE_COMPAT_SUPP 0ULL
3571 #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
3572 #define BTRFS_FEATURE_INCOMPAT_SUPP \
3573 - BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF
3574 + (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
3575 + BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)
3578 * A leaf is full of items. offset and size tell us where to find
3579 @@ -1047,6 +1049,7 @@ BTRFS_SETGET_STACK_FUNCS(block_group_flags,
3581 /* struct btrfs_inode_ref */
3582 BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
3583 +BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
3584 BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
3586 /* struct btrfs_inode_item */
3587 @@ -1325,6 +1328,10 @@ BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
3588 BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
3589 BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
3591 +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
3592 +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
3593 +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
3595 /* struct btrfs_dir_item */
3596 BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
3597 BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
3598 @@ -1572,6 +1579,7 @@ static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
3600 /* struct btrfs_file_extent_item */
3601 BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
3602 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, type, 8);
3604 static inline unsigned long btrfs_file_extent_inline_start(struct
3605 btrfs_file_extent_item *e)
3606 @@ -1588,18 +1596,30 @@ static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
3608 BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
3610 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item,
3612 BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
3614 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item,
3616 BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
3617 disk_num_bytes, 64);
3618 BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
3620 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item,
3622 BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
3624 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item,
3626 BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
3628 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item,
3630 BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
3632 +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item,
3634 BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
3636 BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
3637 diff --git a/debug-tree.c b/debug-tree.c
3638 index 1d47519..0525354 100644
3641 @@ -116,19 +116,27 @@ int main(int ac, char **av)
3644 int extent_only = 0;
3645 + int device_only = 0;
3646 + u64 block_only = 0;
3647 struct btrfs_root *tree_root_scan;
3653 - c = getopt(ac, av, "e");
3654 + c = getopt(ac, av, "deb:");
3665 + block_only = atoll(optarg);
3670 @@ -142,14 +150,37 @@ int main(int ac, char **av)
3671 fprintf(stderr, "unable to open %s\n", av[optind]);
3675 + leaf = read_tree_block(root,
3677 + root->leafsize, 0);
3679 + if (leaf && btrfs_header_level(leaf) != 0) {
3680 + free_extent_buffer(leaf);
3685 + leaf = read_tree_block(root,
3687 + root->nodesize, 0);
3690 + fprintf(stderr, "failed to read %llu\n", block_only);
3693 + btrfs_print_tree(root, leaf, 0);
3698 printf("root tree\n");
3699 btrfs_print_tree(root->fs_info->tree_root,
3700 - root->fs_info->tree_root->node);
3701 + root->fs_info->tree_root->node, 1);
3703 printf("chunk tree\n");
3704 btrfs_print_tree(root->fs_info->chunk_root,
3705 - root->fs_info->chunk_root->node);
3706 + root->fs_info->chunk_root->node, 1);
3708 tree_root_scan = root->fs_info->tree_root;
3710 @@ -175,7 +206,7 @@ again:
3711 if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
3712 unsigned long offset;
3713 struct extent_buffer *buf;
3714 - int skip = extent_only;
3715 + int skip = extent_only | device_only;
3717 offset = btrfs_item_ptr_offset(leaf, slot);
3718 read_extent_buffer(leaf, &ri, offset, sizeof(ri));
3719 @@ -188,8 +219,9 @@ again:
3722 case BTRFS_EXTENT_TREE_OBJECTID:
3727 + if (!extent_only && !device_only)
3730 case BTRFS_CHUNK_TREE_OBJECTID:
3731 @@ -198,9 +230,8 @@ again:
3734 case BTRFS_DEV_TREE_OBJECTID:
3741 case BTRFS_FS_TREE_OBJECTID:
3743 @@ -208,9 +239,8 @@ again:
3746 case BTRFS_ROOT_TREE_DIR_OBJECTID:
3748 - printf("directory");
3751 + printf("directory");
3753 case BTRFS_CSUM_TREE_OBJECTID:
3755 @@ -256,13 +286,13 @@ again:
3759 - if (!skip && !extent_only) {
3760 + if (extent_only && !skip) {
3761 + print_extents(tree_root_scan, buf);
3762 + } else if (!skip) {
3764 btrfs_print_key(&disk_key);
3766 - btrfs_print_tree(tree_root_scan, buf);
3767 - } else if (extent_only && !skip) {
3768 - print_extents(tree_root_scan, buf);
3769 + btrfs_print_tree(tree_root_scan, buf, 1);
3773 @@ -275,7 +305,7 @@ again:
3778 + if (extent_only || device_only)
3781 printf("total bytes %llu\n",
3782 diff --git a/dir-test.c b/dir-test.c
3783 index 44f2758..3ae9c68 100644
3786 @@ -485,7 +485,7 @@ int main(int ac, char **av)
3788 fprintf(stderr, "op %d failed %d:%d\n",
3790 - btrfs_print_tree(root, root->node);
3791 + btrfs_print_tree(root, root->node, 1);
3792 fprintf(stderr, "op %d failed %d:%d\n",
3795 diff --git a/disk-io.c b/disk-io.c
3796 index addebe1..a6e1000 100644
3799 @@ -86,7 +86,7 @@ int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size,
3800 if (memcmp_extent_buffer(buf, result, 0, csum_size)) {
3801 printk("checksum verify failed on %llu wanted %X "
3802 "found %X\n", (unsigned long long)buf->start,
3803 - *((int *)result), *((int *)buf));
3804 + *((int *)result), *((char *)buf->data));
3808 @@ -970,13 +970,13 @@ int close_ctree(struct btrfs_root *root)
3809 if (fs_info->csum_root->node)
3810 free_extent_buffer(fs_info->csum_root->node);
3812 - if (root->fs_info->log_root_tree) {
3813 - if (root->fs_info->log_root_tree->node)
3814 - free_extent_buffer(root->fs_info->log_root_tree->node);
3815 - free(root->fs_info->log_root_tree);
3816 + if (fs_info->log_root_tree) {
3817 + if (fs_info->log_root_tree->node)
3818 + free_extent_buffer(fs_info->log_root_tree->node);
3819 + free(fs_info->log_root_tree);
3822 - close_all_devices(root->fs_info);
3823 + close_all_devices(fs_info);
3824 extent_io_tree_cleanup(&fs_info->extent_cache);
3825 extent_io_tree_cleanup(&fs_info->free_space_cache);
3826 extent_io_tree_cleanup(&fs_info->block_group_cache);
3827 diff --git a/ioctl-test.c b/ioctl-test.c
3828 new file mode 100644
3829 index 0000000..7cf3bc2
3834 +#include <stdlib.h>
3835 +#include "kerncompat.h"
3838 +unsigned long ioctls[] = {
3839 + BTRFS_IOC_SNAP_CREATE,
3842 + BTRFS_IOC_SCAN_DEV,
3843 + BTRFS_IOC_TRANS_START,
3844 + BTRFS_IOC_TRANS_END,
3847 + BTRFS_IOC_ADD_DEV,
3849 + BTRFS_IOC_BALANCE,
3850 + BTRFS_IOC_SUBVOL_CREATE,
3851 + BTRFS_IOC_SNAP_DESTROY,
3852 + BTRFS_IOC_DEFRAG_RANGE,
3853 + BTRFS_IOC_TREE_SEARCH,
3854 + BTRFS_IOC_INO_LOOKUP,
3855 + BTRFS_IOC_DEFAULT_SUBVOL,
3856 + BTRFS_IOC_SPACE_INFO,
3859 +int main(int ac, char **av)
3862 + while(ioctls[i]) {
3863 + printf("%lu\n" ,ioctls[i]);
3869 diff --git a/ioctl.h b/ioctl.h
3870 index a084f33..776d7a9 100644
3873 @@ -30,6 +30,108 @@ struct btrfs_ioctl_vol_args {
3874 char name[BTRFS_PATH_NAME_MAX + 1];
3877 +struct btrfs_ioctl_search_key {
3878 + /* which root are we searching. 0 is the tree of tree roots */
3881 + /* keys returned will be >= min and <= max */
3882 + __u64 min_objectid;
3883 + __u64 max_objectid;
3885 + /* keys returned will be >= min and <= max */
3889 + /* max and min transids to search for */
3890 + __u64 min_transid;
3891 + __u64 max_transid;
3893 + /* keys returned will be >= min and <= max */
3898 + * how many items did userland ask for, and how many are we
3903 + /* align to 64 bits */
3906 + /* some extra for later */
3913 +struct btrfs_ioctl_search_header {
3919 +} __attribute__((may_alias));
3921 +#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
3923 + * the buf is an array of search headers where
3924 + * each header is followed by the actual item
3925 + * the type field is expanded to 32 bits for alignment
3927 +struct btrfs_ioctl_search_args {
3928 + struct btrfs_ioctl_search_key key;
3929 + char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
3932 +#define BTRFS_INO_LOOKUP_PATH_MAX 4080
3933 +struct btrfs_ioctl_ino_lookup_args {
3936 + char name[BTRFS_INO_LOOKUP_PATH_MAX];
3939 +/* flags for the defrag range ioctl */
3940 +#define BTRFS_DEFRAG_RANGE_COMPRESS 1
3941 +#define BTRFS_DEFRAG_RANGE_START_IO 2
3943 +struct btrfs_ioctl_defrag_range_args {
3944 + /* start of the defrag operation */
3947 + /* number of bytes to defrag, use (u64)-1 to say all */
3951 + * flags for the operation, which can include turning
3952 + * on compression for this one defrag
3957 + * any extent bigger than this will be considered
3958 + * already defragged. Use 0 to take the kernel default
3959 + * Use 1 to say every single extent must be rewritten
3961 + __u32 extent_thresh;
3963 + /* spare for later */
3967 +struct btrfs_ioctl_space_info {
3969 + __u64 total_bytes;
3973 +struct btrfs_ioctl_space_args {
3974 + __u64 space_slots;
3975 + __u64 total_spaces;
3976 + struct btrfs_ioctl_space_info spaces[0];
3979 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
3980 struct btrfs_ioctl_vol_args)
3981 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
3982 @@ -56,4 +158,15 @@ struct btrfs_ioctl_vol_args {
3983 /* 13 is for CLONE_RANGE */
3984 #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
3985 struct btrfs_ioctl_vol_args)
3986 +#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
3987 + struct btrfs_ioctl_vol_args)
3988 +#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
3989 + struct btrfs_ioctl_defrag_range_args)
3990 +#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
3991 + struct btrfs_ioctl_search_args)
3992 +#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
3993 + struct btrfs_ioctl_ino_lookup_args)
3994 +#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
3995 +#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
3996 + struct btrfs_ioctl_space_args)
3998 diff --git a/kerncompat.h b/kerncompat.h
3999 index e4c8ce0..46236cd 100644
4004 #define __read_mostly
4005 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
4008 #define ULONG_MAX (~0UL)
4011 #define BUG() abort()
4013 #define __force __attribute__((force))
4014 diff --git a/man/Makefile b/man/Makefile
4015 index 4e8893b..4a90b75 100644
4018 @@ -7,13 +7,16 @@ mandir = $(prefix)/man
4019 man8dir = $(mandir)/man8
4021 MANPAGES = mkfs.btrfs.8.gz btrfsctl.8.gz btrfsck.8.gz btrfs-image.8.gz \
4023 + btrfs-show.8.gz btrfs.8.gz
4027 mkfs.btrfs.8.gz: mkfs.btrfs.8.in
4028 $(GZIP) -n -c mkfs.btrfs.8.in > mkfs.btrfs.8.gz
4030 +btrfs.8.gz: btrfs.8.in
4031 + $(GZIP) -n -c btrfs.8.in > btrfs.8.gz
4033 btrfsctl.8.gz: btrfsctl.8.in
4034 $(GZIP) -n -c btrfsctl.8.in > btrfsctl.8.gz
4036 diff --git a/man/btrfs.8.in b/man/btrfs.8.in
4037 new file mode 100644
4038 index 0000000..26ef982
4040 +++ b/man/btrfs.8.in
4042 +.TH BTRFS 8 "" "btrfs" "btrfs"
4044 +.\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
4047 +btrfs \- control a btrfs filesystem
4049 +\fBbtrfs\fP \fBsubvolume snapshot\fP\fI <source> [<dest>/]<name>\fP
4051 +\fBbtrfs\fP \fBsubvolume delete\fP\fI <subvolume>\fP
4053 +\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
4055 +\fBbtrfs\fP \fBsubvolume list\fP\fI <path>\fP
4057 +\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
4059 +\fBbtrfs\fP \fBfilesystem defrag\fP\fI <file>|<dir> [<file>|<dir>...]\fP
4061 +\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
4063 +\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
4065 +\fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
4067 +\fBbtrfs\fP \fBdevice show\fP\fI <dev>|<label> [<dev>|<label>...]\fP
4069 +\fBbtrfs\fP \fBdevice balance\fP\fI <path> \fP
4071 +\fBbtrfs\fP \fBdevice add\fP\fI <dev> [<dev>..] <path> \fP
4073 +\fBbtrfs\fP \fBdevice delete\fP\fI <dev> [<dev>..] <path> \fP]
4076 +\fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
4080 +is used to control the filesystem and the files and directories stored. It is
4081 +the tool to create or destroy a snapshot or a subvolume for the
4082 +filesystem, to defrag a file or a directory, flush the data to the disk,
4083 +to resize the filesystem, to scan the device.
4085 +It is possible to abbreviate the commands unless the commands are ambiguous.
4086 +For example: it is possible to run
4089 +.I btrfs subvolume snapshot.
4092 +is not allowed, because
4094 +may be interpreted both as
4102 +If a command is terminated by
4104 +, the relevant help is showed. If the passed command matches more commands,
4105 +the help of all the matched commands are showed. For example
4106 +.I btrfs dev --help
4107 +shows the help of all
4114 +\fBsubvolume snapshot\fR\fI <source> [<dest>/]<name>\fR
4115 +Create a writable snapshot of the subvolume \fI<source>\fR with the name
4116 +\fI<name>\fR in the \fI<dest>\fR directory. If \fI<source>\fR is not a
4117 +subvolume, \fBbtrfs\fR returns an error.
4120 +\fBsubvolume delete\fR\fI <subvolume>\fR
4121 +Delete the subvolume \fI<subvolume>\fR. If \fI<subvolume>\fR is not a
4122 +subvolume, \fBbtrfs\fR returns an error.
4125 +\fBsubvolume create\fR\fI [<dest>/]<name>\fR
4126 +Create a subvolume in \fI<dest>\fR (or in the current directory if
4127 +\fI<dest>\fR is omitted).
4130 +\fBsubvolume list\fR\fI <path>\fR
4131 +List the subvolumes present in the filesystem \fI<path>\fR. For every
4132 +subvolume is showed the subvolume ID (second column),
4133 +the ID of the \fItop level\fR
4134 +subvolume (fifth column), and the path (seventh column) relative to the
4135 +\fItop level\fR subvolume.
4136 +These <ID> may be used by the \fBsubvolume set-default\fR command, or at
4137 +mount time via the \fIsubvol=\fR option.
4140 +\fBsubvolume set-default\fR\fI <id> <path>\fR
4141 +Set the subvolume of the filesystem \fI<path>\fR which is mounted as
4142 +\fIdefault\fR. The subvolume is identified by \fB<id>\fR, which
4143 +is returned by the \fBsubvolume list\fR command.
4146 +\fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fR
4147 +Defragment files and/or directories.
4150 +\fBdevice scan\fR \fI[<device> [<device>..]]\fR
4151 +Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR scans
4152 +all the block devices.
4155 +\fBfilesystem sync\fR\fI <path> \fR
4156 +Force a sync for the filesystem identified by \fI<path>\fR.
4160 +.\" Some wording are extracted by the resize2fs man page
4163 +\fBfilesystem resize\fR\fI [+/\-]<size>[gkm]|max <path>\fR
4164 +Resize a filesystem identified by \fI<path>\fR.
4165 +The \fI<size>\fR parameter specifies the new size of the filesystem.
4166 +If the prefix \fI+\fR or \fI\-\fR is present the size is increased or decreased
4167 +by the quantity \fI<size>\fR.
4168 +If no units are specified, the unit of the \fI<size>\fR parameter defaults to
4169 +bytes. Optionally, the size parameter may be suffixed by one of the following
4170 +the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
4173 +If 'max' is passed, the filesystem will occupy all available space on the
4176 +The \fBresize\fR command \fBdoes not\fR manipulate the size of underlying
4177 +partition. If you wish to enlarge/reduce a filesystem, you must make sure you
4178 +can expand the partition before enlarging the filesystem and shrink the
4179 +partition after reducing the size of the filesystem.
4182 +\fBfilesystem show\fR [<uuid>|<label>]\fR
4183 +Show the btrfs filesystem with some additional info. If no UUID or label is
4184 +passed, \fBbtrfs\fR show info of all the btrfs filesystem.
4187 +\fBdevice balance\fR \fI<path>\fR
4188 +Balance the chunks of the filesystem identified by \fI<path>\fR
4189 +across the devices.
4192 +\fBdevice add\fR\fI <dev> [<dev>..] <path>\fR
4193 +Add device(s) to the filesystem identified by \fI<path>\fR.
4196 +\fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
4197 +Remove device(s) from a filesystem identified by \fI<path>\fR.
4201 +\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
4206 +is part of btrfs-progs. Btrfs filesystem is currently under heavy development,
4207 +and not suitable for any uses other than benchmarking and review.
4208 +Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
4212 diff --git a/print-tree.c b/print-tree.c
4213 index 59f4358..ac575d5 100644
4216 @@ -413,8 +413,11 @@ static void print_objectid(unsigned long long objectid, u8 type)
4219 case BTRFS_FIRST_CHUNK_TREE_OBJECTID:
4220 - printf("FIRST_CHUNK_TREE");
4222 + if (type == BTRFS_CHUNK_ITEM_KEY) {
4223 + printf("FIRST_CHUNK_TREE");
4228 printf("%llu", objectid);
4230 @@ -607,7 +610,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
4234 -void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb)
4235 +void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow)
4239 @@ -643,6 +646,9 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb)
4240 (unsigned long long)btrfs_node_ptr_generation(eb, i));
4246 for (i = 0; i < nr; i++) {
4247 struct extent_buffer *next = read_tree_block(root,
4248 btrfs_node_blockptr(eb, i),
4249 @@ -660,8 +666,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb)
4250 if (btrfs_header_level(next) !=
4251 btrfs_header_level(eb) - 1)
4253 - btrfs_print_tree(root, next);
4254 + btrfs_print_tree(root, next, 1);
4255 free_extent_buffer(next);
4259 diff --git a/print-tree.h b/print-tree.h
4260 index 4d1a01a..495b81a 100644
4264 #ifndef __PRINT_TREE_
4265 #define __PRINT_TREE_
4266 void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l);
4267 -void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *t);
4268 +void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *t, int follow);
4269 void btrfs_print_key(struct btrfs_disk_key *disk_key);
4271 diff --git a/quick-test.c b/quick-test.c
4272 index 351c706..fa6fd83 100644
4275 @@ -85,7 +85,7 @@ int main(int ac, char **av) {
4276 fprintf(stderr, "search %d:%d\n", num, i);
4277 ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
4279 - btrfs_print_tree(root, root->node);
4280 + btrfs_print_tree(root, root->node, 1);
4281 printf("unable to find %d\n", num);
4284 @@ -148,7 +148,7 @@ int main(int ac, char **av) {
4285 fprintf(stderr, "search %d:%d\n", num, i);
4286 ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
4288 - btrfs_print_tree(root, root->node);
4289 + btrfs_print_tree(root, root->node, 1);
4290 printf("unable to find %d\n", num);
4293 @@ -196,7 +196,7 @@ int main(int ac, char **av) {
4294 btrfs_commit_transaction(trans, root);
4295 printf("tree size is now %d\n", tree_size);
4296 printf("root %p commit root %p\n", root->node, root->commit_root);
4297 - btrfs_print_tree(root, root->node);
4298 + btrfs_print_tree(root, root->node, 1);
4302 diff --git a/random-test.c b/random-test.c
4303 index 571735d..0003236 100644
4306 @@ -404,7 +404,7 @@ int main(int ac, char **av)
4308 fprintf(stderr, "op %d failed %d:%d\n",
4310 - btrfs_print_tree(root, root->node);
4311 + btrfs_print_tree(root, root->node, 1);
4312 fprintf(stderr, "op %d failed %d:%d\n",
4315 diff --git a/utils.c b/utils.c
4316 index 2f4c6e1..fd894f3 100644
4323 +#include <linux/loop.h>
4324 +#include <linux/major.h>
4325 +#include <linux/kdev_t.h>
4326 +#include <limits.h>
4327 #include "kerncompat.h"
4328 #include "radix-tree.h"
4330 @@ -586,55 +590,224 @@ error:
4334 +/* checks if a device is a loop device */
4335 +int is_loop_device (const char* device) {
4336 + struct stat statbuf;
4338 + if(stat(device, &statbuf) < 0)
4341 + return (S_ISBLK(statbuf.st_mode) &&
4342 + MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
4346 +/* Takes a loop device path (e.g. /dev/loop0) and returns
4347 + * the associated file (e.g. /images/my_btrfs.img) */
4348 +int resolve_loop_device(const char* loop_dev, char* loop_file, int max_len)
4352 + struct loop_info loopinfo;
4354 + if ((loop_fd = open(loop_dev, O_RDONLY)) < 0)
4357 + ret_ioctl = ioctl(loop_fd, LOOP_GET_STATUS, &loopinfo);
4360 + if (ret_ioctl == 0)
4361 + strncpy(loop_file, loopinfo.lo_name, max_len);
4368 +/* Checks whether a and b are identical or device
4369 + * files associated with the same block device
4371 +int is_same_blk_file(const char* a, const char* b)
4373 + struct stat st_buf_a, st_buf_b;
4374 + char real_a[PATH_MAX];
4375 + char real_b[PATH_MAX];
4377 + if(!realpath(a, real_a) ||
4378 + !realpath(b, real_b))
4383 + /* Identical path? */
4384 + if(strcmp(real_a, real_b) == 0)
4387 + if(stat(a, &st_buf_a) < 0 ||
4388 + stat(b, &st_buf_b) < 0)
4393 + /* Same blockdevice? */
4394 + if(S_ISBLK(st_buf_a.st_mode) &&
4395 + S_ISBLK(st_buf_b.st_mode) &&
4396 + st_buf_a.st_rdev == st_buf_b.st_rdev)
4402 + if (st_buf_a.st_dev == st_buf_b.st_dev &&
4403 + st_buf_a.st_ino == st_buf_b.st_ino)
4411 +/* checks if a and b are identical or device
4412 + * files associated with the same block device or
4413 + * if one file is a loop device that uses the other
4416 +int is_same_loop_file(const char* a, const char* b)
4418 + char res_a[PATH_MAX];
4419 + char res_b[PATH_MAX];
4420 + const char* final_a;
4421 + const char* final_b;
4424 + /* Resolve a if it is a loop device */
4425 + if((ret = is_loop_device(a)) < 0) {
4428 + if((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
4436 + /* Resolve b if it is a loop device */
4437 + if((ret = is_loop_device(b)) < 0) {
4440 + if((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0)
4448 + return is_same_blk_file(final_a, final_b);
4451 +/* Checks if a file exists and is a block or regular file*/
4452 +int is_existing_blk_or_reg_file(const char* filename)
4454 + struct stat st_buf;
4456 + if(stat(filename, &st_buf) < 0) {
4457 + if(errno == ENOENT)
4463 + return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode));
4466 +/* Checks if a file is used (directly or indirectly via a loop device)
4467 + * by a device in fs_devices
4469 +int blk_file_in_dev_list(struct btrfs_fs_devices* fs_devices, const char* file)
4472 + struct list_head *head;
4473 + struct list_head *cur;
4474 + struct btrfs_device *device;
4476 + head = &fs_devices->devices;
4477 + list_for_each(cur, head) {
4478 + device = list_entry(cur, struct btrfs_device, dev_list);
4480 + if((ret = is_same_loop_file(device->name, file)))
4488 * returns 1 if the device was mounted, < 0 on error or 0 if everything
4489 - * is safe to continue. TODO, this should also scan multi-device filesystems
4490 + * is safe to continue.
4492 -int check_mounted(char *file)
4493 +int check_mounted(const char* file)
4495 - struct mntent *mnt;
4496 - struct stat st_buf;
4497 - dev_t file_dev = 0;
4498 - dev_t file_rdev = 0;
4499 - ino_t file_ino = 0;
4502 + u64 total_devs = 1;
4504 + struct btrfs_fs_devices* fs_devices_mnt = NULL;
4507 + struct mntent *mnt;
4509 - if ((f = setmntent ("/proc/mounts", "r")) == NULL)
4510 + fd = open(file, O_RDONLY);
4512 + fprintf (stderr, "check_mounted(): Could not open %s\n", file);
4516 - if (stat(file, &st_buf) < 0) {
4519 - if (S_ISBLK(st_buf.st_mode)) {
4520 - file_rdev = st_buf.st_rdev;
4522 - file_dev = st_buf.st_dev;
4523 - file_ino = st_buf.st_ino;
4525 + /* scan the initial device */
4526 + ret = btrfs_scan_one_device(fd, file, &fs_devices_mnt,
4527 + &total_devs, BTRFS_SUPER_INFO_OFFSET);
4528 + is_btrfs = (ret >= 0);
4531 + /* scan other devices */
4532 + if (is_btrfs && total_devs > 1) {
4533 + if((ret = btrfs_scan_for_fsid(fs_devices_mnt, total_devs, 1)))
4537 + /* iterate over the list of currently mountes filesystems */
4538 + if ((f = setmntent ("/proc/mounts", "r")) == NULL)
4541 while ((mnt = getmntent (f)) != NULL) {
4542 - if (strcmp(file, mnt->mnt_fsname) == 0)
4545 + if(strcmp(mnt->mnt_type, "btrfs") != 0)
4548 - if (stat(mnt->mnt_fsname, &st_buf) == 0) {
4549 - if (S_ISBLK(st_buf.st_mode)) {
4550 - if (file_rdev && (file_rdev == st_buf.st_rdev))
4552 - } else if (file_dev && ((file_dev == st_buf.st_dev) &&
4553 - (file_ino == st_buf.st_ino))) {
4556 + ret = blk_file_in_dev_list(fs_devices_mnt, mnt->mnt_fsname);
4558 + /* ignore entries in the mount table that are not
4559 + associated with a file*/
4560 + if((ret = is_existing_blk_or_reg_file(mnt->mnt_fsname)) < 0)
4561 + goto out_mntloop_err;
4565 + ret = is_same_loop_file(file, mnt->mnt_fsname);
4570 - /* found an entry in mnt table */
4573 + goto out_mntloop_err;
4578 + /* Did we find an entry in mnt table? */
4579 + ret = (mnt != NULL);
4587 diff --git a/utils.h b/utils.h
4588 index 7ff542b..9dce5b0 100644
4591 @@ -36,7 +36,7 @@ int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
4593 void btrfs_register_one_device(char *fname);
4594 int btrfs_scan_one_dir(char *dirname, int run_ioctl);
4595 -int check_mounted(char *devicename);
4596 +int check_mounted(const char *devicename);
4597 int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
4599 char *pretty_sizes(u64 size);