]> git.ipfire.org Git - people/amarx/ipfire-3.x.git/blame - btrfs-progs/patches/btrfs-progs-upstream.patch
Merge branch 'master' of ssh://git.ipfire.org/pub/git/ipfire-3.x
[people/amarx/ipfire-3.x.git] / btrfs-progs / patches / btrfs-progs-upstream.patch
CommitLineData
c9b0b55d
MT
1diff --git a/Makefile b/Makefile
2index 8097b5a..6e6f6c6 100644
3--- a/Makefile
4+++ b/Makefile
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 \
9- volumes.o utils.o
10+ volumes.o utils.o btrfs-list.o
11
12 #
13 CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
14@@ -16,7 +16,9 @@ prefix ?= /usr/local
15 bindir = $(prefix)/bin
16 LIBS=-luuid
17
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 \
20+ btrfs \
21+ btrfs-map-logical
22
23 # make C=1 to enable sparse
24 ifdef C
25@@ -35,6 +37,10 @@ all: version $(progs) manpages
26 version:
27 bash version.sh
28
29+btrfs: $(objects) btrfs.o btrfs_cmds.o
30+ gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \
31+ $(objects) $(LDFLAGS) $(LIBS)
32+
33 btrfsctl: $(objects) btrfsctl.o
34 gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
35
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)
39
40+btrfs-zero-log: $(objects) btrfs-zero-log.o
41+ gcc $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS)
42+
43 btrfstune: $(objects) btrfstune.o
44 gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
45
46+btrfs-map-logical: $(objects) btrfs-map-logical.o
47+ gcc $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS)
48+
49 btrfs-image: $(objects) btrfs-image.o
50 gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS)
51
52@@ -66,7 +78,10 @@ quick-test: $(objects) quick-test.o
53 gcc $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS)
54
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)
58+
59+ioctl-test: $(objects) ioctl-test.o
60+ gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
61
62 manpages:
63 cd man; make
64diff --git a/btrfs-defrag.c b/btrfs-defrag.c
65new file mode 100644
66index 0000000..8f1525a
67--- /dev/null
68+++ b/btrfs-defrag.c
69@@ -0,0 +1,39 @@
70+/*
71+ * Copyright (C) 2010 Oracle. All rights reserved.
72+ *
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.
76+ *
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.
81+ *
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.
86+ */
87+
88+#ifndef __CHECKER__
89+#include <sys/ioctl.h>
90+#include <sys/mount.h>
91+#include "ioctl.h"
92+#endif
93+#include <stdio.h>
94+#include <stdlib.h>
95+#include <sys/types.h>
96+#include <sys/stat.h>
97+#include <fcntl.h>
98+#include <ctype.h>
99+#include <unistd.h>
100+#include <dirent.h>
101+#include <libgen.h>
102+#include <getopt.h>
103+#include "kerncompat.h"
104+#include "ctree.h"
105+#include "transaction.h"
106+#include "utils.h"
107+#include "version.h"
108+
109diff --git a/btrfs-list.c b/btrfs-list.c
110new file mode 100644
111index 0000000..93766a8
112--- /dev/null
113+++ b/btrfs-list.c
114@@ -0,0 +1,835 @@
115+/*
116+ * Copyright (C) 2010 Oracle. All rights reserved.
117+ *
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.
121+ *
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.
126+ *
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.
131+ */
132+
133+#define _GNU_SOURCE
134+#ifndef __CHECKER__
135+#include <sys/ioctl.h>
136+#include <sys/mount.h>
137+#include "ioctl.h"
138+#endif
139+#include <stdio.h>
140+#include <stdlib.h>
141+#include <sys/types.h>
142+#include <sys/stat.h>
143+#include <fcntl.h>
144+#include <unistd.h>
145+#include <dirent.h>
146+#include <libgen.h>
147+#include "kerncompat.h"
148+#include "ctree.h"
149+#include "transaction.h"
150+#include "utils.h"
151+#include "version.h"
152+
153+/* we store all the roots we find in an rbtree so that we can
154+ * search for them later.
155+ */
156+struct root_lookup {
157+ struct rb_root root;
158+};
159+
160+/*
161+ * one of these for each root we find.
162+ */
163+struct root_info {
164+ struct rb_node rb_node;
165+
166+ /* this root's id */
167+ u64 root_id;
168+
169+ /* the id of the root that references this one */
170+ u64 ref_tree;
171+
172+ /* the dir id we're in from ref_tree */
173+ u64 dir_id;
174+
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.
177+ */
178+ char *path;
179+
180+ /* the name of this root in the directory it lives in */
181+ char name[];
182+};
183+
184+static void root_lookup_init(struct root_lookup *tree)
185+{
186+ tree->root.rb_node = NULL;
187+}
188+
189+static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
190+{
191+ if (entry->root_id > root_id)
192+ return 1;
193+ if (entry->root_id < root_id)
194+ return -1;
195+ if (entry->ref_tree > ref_tree)
196+ return 1;
197+ if (entry->ref_tree < ref_tree)
198+ return -1;
199+ return 0;
200+}
201+
202+/*
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
205+ * as the key
206+ */
207+static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
208+ u64 ref_tree, struct rb_node *node)
209+{
210+ struct rb_node ** p = &root->rb_node;
211+ struct rb_node * parent = NULL;
212+ struct root_info *entry;
213+ int comp;
214+
215+ while(*p) {
216+ parent = *p;
217+ entry = rb_entry(parent, struct root_info, rb_node);
218+
219+ comp = comp_entry(entry, root_id, ref_tree);
220+
221+ if (comp < 0)
222+ p = &(*p)->rb_left;
223+ else if (comp > 0)
224+ p = &(*p)->rb_right;
225+ else
226+ return parent;
227+ }
228+
229+ entry = rb_entry(parent, struct root_info, rb_node);
230+ rb_link_node(node, parent, p);
231+ rb_insert_color(node, root);
232+ return NULL;
233+}
234+
235+/*
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
238+ */
239+static struct root_info *tree_search(struct rb_root *root, u64 root_id)
240+{
241+ struct rb_node * n = root->rb_node;
242+ struct root_info *entry;
243+
244+ while(n) {
245+ entry = rb_entry(n, struct root_info, rb_node);
246+
247+ if (entry->root_id < root_id)
248+ n = n->rb_left;
249+ else if (entry->root_id > root_id)
250+ n = n->rb_right;
251+ else {
252+ struct root_info *prev;
253+ struct rb_node *prev_n;
254+ while (1) {
255+ prev_n = rb_prev(n);
256+ if (!prev_n)
257+ break;
258+ prev = rb_entry(prev_n, struct root_info,
259+ rb_node);
260+ if (prev->root_id != root_id)
261+ break;
262+ entry = prev;
263+ n = prev_n;
264+ }
265+ return entry;
266+ }
267+ }
268+ return NULL;
269+}
270+
271+/*
272+ * this allocates a new root in the lookup tree.
273+ *
274+ * root_id should be the object id of the root
275+ *
276+ * ref_tree is the objectid of the referring root.
277+ *
278+ * dir_id is the directory in ref_tree where this root_id can be found.
279+ *
280+ * name is the name of root_id in that directory
281+ *
282+ * name_len is the length of name
283+ */
284+static int add_root(struct root_lookup *root_lookup,
285+ u64 root_id, u64 ref_tree, u64 dir_id, char *name,
286+ int name_len)
287+{
288+ struct root_info *ri;
289+ struct rb_node *ret;
290+ ri = malloc(sizeof(*ri) + name_len + 1);
291+ if (!ri) {
292+ printf("memory allocation failed\n");
293+ exit(1);
294+ }
295+ memset(ri, 0, sizeof(*ri) + name_len + 1);
296+ ri->path = NULL;
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);
301+
302+ ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
303+ if (ret) {
304+ printf("failed to insert tree %llu\n", (unsigned long long)root_id);
305+ exit(1);
306+ }
307+ return 0;
308+}
309+
310+/*
311+ * for a given root_info, search through the root_lookup tree to construct
312+ * the full path name to it.
313+ *
314+ * This can't be called until all the root_info->path fields are filled
315+ * in by lookup_ino_path
316+ */
317+static int resolve_root(struct root_lookup *rl, struct root_info *ri)
318+{
319+ u64 top_id;
320+ char *full_path = NULL;
321+ int len = 0;
322+ struct root_info *found;
323+
324+ /*
325+ * we go backwards from the root_info object and add pathnames
326+ * from parent directories as we go.
327+ */
328+ found = ri;
329+ while (1) {
330+ char *tmp;
331+ u64 next;
332+ int add_len = strlen(found->path);
333+
334+ /* room for / and for null */
335+ tmp = malloc(add_len + 2 + len);
336+ if (full_path) {
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';
341+ free(full_path);
342+ full_path = tmp;
343+ len += add_len + 1;
344+ } else {
345+ full_path = strdup(found->path);
346+ len = add_len;
347+ }
348+
349+ next = found->ref_tree;
350+ /* if the ref_tree refers to ourselves, we're at the top */
351+ if (next == found->root_id) {
352+ top_id = next;
353+ break;
354+ }
355+
356+ /*
357+ * if the ref_tree wasn't in our tree of roots, we're
358+ * at the top
359+ */
360+ found = tree_search(&rl->root, next);
361+ if (!found) {
362+ top_id = next;
363+ break;
364+ }
365+ }
366+ printf("ID %llu top level %llu path %s\n", ri->root_id, top_id,
367+ full_path);
368+ free(full_path);
369+ return 0;
370+}
371+
372+/*
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.
375+ *
376+ * This fills in root_info->path with the path to the directory and and
377+ * appends this root's name.
378+ */
379+static int lookup_ino_path(int fd, struct root_info *ri)
380+{
381+ struct btrfs_ioctl_ino_lookup_args args;
382+ int ret;
383+
384+ if (ri->path)
385+ return 0;
386+
387+ memset(&args, 0, sizeof(args));
388+ args.treeid = ri->ref_tree;
389+ args.objectid = ri->dir_id;
390+
391+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
392+ if (ret) {
393+ fprintf(stderr, "ERROR: Failed to lookup path for root %llu\n",
394+ (unsigned long long)ri->ref_tree);
395+ return ret;
396+ }
397+
398+ if (args.name[0]) {
399+ /*
400+ * we're in a subdirectory of ref_tree, the kernel ioctl
401+ * puts a / in there for us
402+ */
403+ ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
404+ if (!ri->path) {
405+ perror("malloc failed");
406+ exit(1);
407+ }
408+ strcpy(ri->path, args.name);
409+ strcat(ri->path, ri->name);
410+ } else {
411+ /* we're at the root of ref_tree */
412+ ri->path = strdup(ri->name);
413+ if (!ri->path) {
414+ perror("strdup failed");
415+ exit(1);
416+ }
417+ }
418+ return 0;
419+}
420+
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
423+ *
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
426+ */
427+static u64 find_root_gen(int fd)
428+{
429+ struct btrfs_ioctl_ino_lookup_args ino_args;
430+ int ret;
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;
435+ u64 max_found = 0;
436+ int i;
437+
438+ memset(&ino_args, 0, sizeof(ino_args));
439+ ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
440+
441+ /* this ioctl fills in ino_args->treeid */
442+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
443+ if (ret) {
444+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
445+ (unsigned long long)BTRFS_FIRST_FREE_OBJECTID);
446+ return 0;
447+ }
448+
449+ memset(&args, 0, sizeof(args));
450+
451+ sk->tree_id = 1;
452+
453+ /*
454+ * there may be more than one ROOT_ITEM key if there are
455+ * snapshots pending deletion, we have to loop through
456+ * them.
457+ */
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;
465+
466+ while (1) {
467+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
468+ if (ret < 0) {
469+ fprintf(stderr, "ERROR: can't perform the search\n");
470+ return 0;
471+ }
472+ /* the ioctl returns the number of item it found in nr_items */
473+ if (sk->nr_items == 0)
474+ break;
475+
476+ off = 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 +
480+ off);
481+
482+ off += sizeof(*sh);
483+ item = (struct btrfs_root_item *)(args.buf + off);
484+ off += sh->len;
485+
486+ sk->min_objectid = sh->objectid;
487+ sk->min_type = sh->type;
488+ sk->min_offset = sh->offset;
489+
490+ if (sh->objectid > ino_args.treeid)
491+ break;
492+
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));
497+ }
498+ }
499+ if (sk->min_offset < (u64)-1)
500+ sk->min_offset++;
501+ else
502+ break;
503+
504+ if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
505+ break;
506+ if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
507+ break;
508+ }
509+ return max_found;
510+}
511+
512+/* pass in a directory id and this will return
513+ * the full path of the parent directory inside its
514+ * subvolume root.
515+ *
516+ * It may return NULL if it is in the root, or an ERR_PTR if things
517+ * go badly.
518+ */
519+static char *__ino_resolve(int fd, u64 dirid)
520+{
521+ struct btrfs_ioctl_ino_lookup_args args;
522+ int ret;
523+ char *full;
524+
525+ memset(&args, 0, sizeof(args));
526+ args.objectid = dirid;
527+
528+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
529+ if (ret) {
530+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
531+ (unsigned long long)dirid);
532+ return ERR_PTR(ret);
533+ }
534+
535+ if (args.name[0]) {
536+ /*
537+ * we're in a subdirectory of ref_tree, the kernel ioctl
538+ * puts a / in there for us
539+ */
540+ full = strdup(args.name);
541+ if (!full) {
542+ perror("malloc failed");
543+ return ERR_PTR(-ENOMEM);
544+ }
545+ } else {
546+ /* we're at the root of ref_tree */
547+ full = NULL;
548+ }
549+ return full;
550+}
551+
552+/*
553+ * simple string builder, returning a new string with both
554+ * dirid and name
555+ */
556+char *build_name(char *dirid, char *name)
557+{
558+ char *full;
559+ if (!dirid)
560+ return strdup(name);
561+
562+ full = malloc(strlen(dirid) + strlen(name) + 1);
563+ if (!full)
564+ return NULL;
565+ strcpy(full, dirid);
566+ strcat(full, name);
567+ return full;
568+}
569+
570+/*
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
575+ */
576+static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
577+
578+{
579+ u64 dirid;
580+ char *dirname;
581+ char *name;
582+ char *full;
583+ int ret;
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;
588+ int namelen;
589+
590+ memset(&args, 0, sizeof(args));
591+
592+ sk->tree_id = 0;
593+
594+ /*
595+ * step one, we search for the inode back ref. We just use the first
596+ * one
597+ */
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;
604+ sk->nr_items = 1;
605+
606+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
607+ if (ret < 0) {
608+ fprintf(stderr, "ERROR: can't perform the search\n");
609+ return NULL;
610+ }
611+ /* the ioctl returns the number of item it found in nr_items */
612+ if (sk->nr_items == 0)
613+ return NULL;
614+
615+ off = 0;
616+ sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
617+
618+ if (sh->type == BTRFS_INODE_REF_KEY) {
619+ struct btrfs_inode_ref *ref;
620+ dirid = sh->offset;
621+
622+ ref = (struct btrfs_inode_ref *)(sh + 1);
623+ namelen = btrfs_stack_inode_ref_name_len(ref);
624+
625+ name = (char *)(ref + 1);
626+ name = strndup(name, namelen);
627+
628+ /* use our cached value */
629+ if (dirid == *cache_dirid && *cache_name) {
630+ dirname = *cache_name;
631+ goto build;
632+ }
633+ } else {
634+ return NULL;
635+ }
636+ /*
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
639+ */
640+ dirname = __ino_resolve(fd, dirid);
641+build:
642+ full = build_name(dirname, name);
643+ if (*cache_name && dirname != *cache_name)
644+ free(*cache_name);
645+
646+ *cache_name = dirname;
647+ *cache_dirid = dirid;
648+ free(name);
649+
650+ return full;
651+}
652+
653+int list_subvols(int fd)
654+{
655+ struct root_lookup root_lookup;
656+ struct rb_node *n;
657+ int ret;
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;
663+ int name_len;
664+ char *name;
665+ u64 dir_id;
666+ int i;
667+
668+ root_lookup_init(&root_lookup);
669+
670+ memset(&args, 0, sizeof(args));
671+
672+ /* search in the tree of tree roots */
673+ sk->tree_id = 1;
674+
675+ /*
676+ * set the min and max to backref keys. The search will
677+ * only send back this type of key now.
678+ */
679+ sk->max_type = BTRFS_ROOT_BACKREF_KEY;
680+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
681+
682+ /*
683+ * set all the other params to the max, we'll take any objectid
684+ * and any trans
685+ */
686+ sk->max_objectid = (u64)-1;
687+ sk->max_offset = (u64)-1;
688+ sk->max_transid = (u64)-1;
689+
690+ /* just a big number, doesn't matter much */
691+ sk->nr_items = 4096;
692+
693+ while(1) {
694+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
695+ if (ret < 0) {
696+ fprintf(stderr, "ERROR: can't perform the search\n");
697+ return ret;
698+ }
699+ /* the ioctl returns the number of item it found in nr_items */
700+ if (sk->nr_items == 0)
701+ break;
702+
703+ off = 0;
704+
705+ /*
706+ * for each item, pull the key out of the header and then
707+ * read the root_ref item it contains
708+ */
709+ for (i = 0; i < sk->nr_items; i++) {
710+ sh = (struct btrfs_ioctl_search_header *)(args.buf +
711+ off);
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);
718+
719+ add_root(&root_lookup, sh->objectid, sh->offset,
720+ dir_id, name, name_len);
721+ }
722+
723+ off += sh->len;
724+
725+ /*
726+ * record the mins in sk so we can make sure the
727+ * next search doesn't repeat this root
728+ */
729+ sk->min_objectid = sh->objectid;
730+ sk->min_type = sh->type;
731+ sk->min_offset = sh->offset;
732+ }
733+ sk->nr_items = 4096;
734+ /* this iteration is done, step forward one root for the next
735+ * ioctl
736+ */
737+ if (sk->min_objectid < (u64)-1) {
738+ sk->min_objectid++;
739+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
740+ sk->min_offset = 0;
741+ } else
742+ break;
743+ }
744+ /*
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.
747+ */
748+ n = rb_first(&root_lookup.root);
749+ while (n) {
750+ struct root_info *entry;
751+ int ret;
752+ entry = rb_entry(n, struct root_info, rb_node);
753+ ret = lookup_ino_path(fd, entry);
754+ if(ret < 0)
755+ return ret;
756+ n = rb_next(n);
757+ }
758+
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
762+ */
763+ n = rb_last(&root_lookup.root);
764+ while (n) {
765+ struct root_info *entry;
766+ entry = rb_entry(n, struct root_info, rb_node);
767+ resolve_root(&root_lookup, entry);
768+ n = rb_prev(n);
769+ }
770+
771+ return ret;
772+}
773+
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)
779+{
780+ u64 len = 0;
781+ u64 disk_start = 0;
782+ u64 disk_offset = 0;
783+ u8 type;
784+ int compressed = 0;
785+ int flags = 0;
786+ char *name = NULL;
787+
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;
793+ }
794+ if (!name) {
795+ name = ino_resolve(fd, sh->objectid, cache_dirid,
796+ cache_dir_name);
797+ *cache_full_name = name;
798+ *cache_ino = sh->objectid;
799+ }
800+ if (!name)
801+ return -EIO;
802+
803+ type = btrfs_stack_file_extent_type(item);
804+ compressed = btrfs_stack_file_extent_compression(item);
805+
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) {
812+ disk_start = 0;
813+ disk_offset = 0;
814+ len = btrfs_stack_file_extent_ram_bytes(item);
815+ } else {
816+ printf("unhandled extent type %d for inode %llu "
817+ "file offset %llu gen %llu\n",
818+ type,
819+ (unsigned long long)sh->objectid,
820+ (unsigned long long)sh->offset,
821+ (unsigned long long)found_gen);
822+
823+ return -EIO;
824+ }
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);
833+
834+ if (compressed) {
835+ printf("COMPRESS");
836+ flags++;
837+ }
838+ if (type == BTRFS_FILE_EXTENT_PREALLOC) {
839+ printf("%sPREALLOC", flags ? "|" : "");
840+ flags++;
841+ }
842+ if (type == BTRFS_FILE_EXTENT_INLINE) {
843+ printf("%sINLINE", flags ? "|" : "");
844+ flags++;
845+ }
846+ if (!flags)
847+ printf("NONE");
848+
849+ printf(" %s\n", name);
850+ return 0;
851+}
852+
853+int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
854+{
855+ int ret;
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;
861+ u64 found_gen;
862+ u64 max_found = 0;
863+ int i;
864+ u64 cache_dirid = 0;
865+ u64 cache_ino = 0;
866+ char *cache_dir_name = NULL;
867+ char *cache_full_name = NULL;
868+ struct btrfs_file_extent_item backup;
869+
870+ memset(&backup, 0, sizeof(backup));
871+ memset(&args, 0, sizeof(args));
872+
873+ sk->tree_id = root_id;
874+
875+ /*
876+ * set all the other params to the max, we'll take any objectid
877+ * and any trans
878+ */
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;
886+
887+ max_found = find_root_gen(fd);
888+ while(1) {
889+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
890+ if (ret < 0) {
891+ fprintf(stderr, "ERROR: can't perform the search\n");
892+ return ret;
893+ }
894+ /* the ioctl returns the number of item it found in nr_items */
895+ if (sk->nr_items == 0)
896+ break;
897+
898+ off = 0;
899+
900+ /*
901+ * for each item, pull the key out of the header and then
902+ * read the root_ref item it contains
903+ */
904+ for (i = 0; i < sk->nr_items; i++) {
905+ sh = (struct btrfs_ioctl_search_header *)(args.buf +
906+ off);
907+ off += sizeof(*sh);
908+
909+ /*
910+ * just in case the item was too big, pass something other
911+ * than garbage
912+ */
913+ if (sh->len == 0)
914+ item = &backup;
915+ else
916+ item = (struct btrfs_file_extent_item *)(args.buf +
917+ off);
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);
924+ }
925+ off += sh->len;
926+
927+ /*
928+ * record the mins in sk so we can make sure the
929+ * next search doesn't repeat this root
930+ */
931+ sk->min_objectid = sh->objectid;
932+ sk->min_offset = sh->offset;
933+ sk->min_type = sh->type;
934+ }
935+ sk->nr_items = 4096;
936+ if (sk->min_offset < (u64)-1)
937+ sk->min_offset++;
938+ else if (sk->min_objectid < (u64)-1) {
939+ sk->min_objectid++;
940+ sk->min_offset = 0;
941+ sk->min_type = 0;
942+ } else
943+ break;
944+ }
945+ free(cache_dir_name);
946+ free(cache_full_name);
947+ printf("transid marker was %llu\n", (unsigned long long)max_found);
948+ return ret;
949+}
950diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
951new file mode 100644
952index 0000000..a109c6a
953--- /dev/null
954+++ b/btrfs-map-logical.c
955@@ -0,0 +1,221 @@
956+/*
957+ * Copyright (C) 2009 Oracle. All rights reserved.
958+ *
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.
962+ *
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.
967+ *
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.
972+ */
973+
974+#define _XOPEN_SOURCE 500
975+#define _GNU_SOURCE 1
976+#include <stdio.h>
977+#include <stdlib.h>
978+#include <fcntl.h>
979+#include <unistd.h>
980+#include <getopt.h>
981+#include "kerncompat.h"
982+#include "ctree.h"
983+#include "volumes.h"
984+#include "disk-io.h"
985+#include "print-tree.h"
986+#include "transaction.h"
987+#include "list.h"
988+#include "version.h"
989+
990+/* we write the mirror info to stdout unless they are dumping the data
991+ * to stdout
992+ * */
993+static FILE *info_file;
994+
995+struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
996+ u32 blocksize, int copy)
997+{
998+ int ret;
999+ int dev_nr;
1000+ struct extent_buffer *eb;
1001+ u64 length;
1002+ struct btrfs_multi_bio *multi = NULL;
1003+ struct btrfs_device *device;
1004+ int num_copies;
1005+ int mirror_num = 1;
1006+
1007+ eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
1008+ if (!eb)
1009+ return NULL;
1010+
1011+ dev_nr = 0;
1012+ length = blocksize;
1013+ while (1) {
1014+ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
1015+ eb->start, &length, &multi, mirror_num);
1016+ BUG_ON(ret);
1017+ device = multi->stripes[0].dev;
1018+ eb->fd = device->fd;
1019+ device->total_ios++;
1020+ eb->dev_bytenr = multi->stripes[0].physical;
1021+
1022+ fprintf(info_file, "mirror %d logical %Lu physical %Lu "
1023+ "device %s\n", mirror_num, bytenr, eb->dev_bytenr,
1024+ device->name);
1025+ kfree(multi);
1026+
1027+ if (!copy || mirror_num == copy)
1028+ ret = read_extent_from_disk(eb);
1029+
1030+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
1031+ eb->start, eb->len);
1032+ if (num_copies == 1)
1033+ break;
1034+
1035+ mirror_num++;
1036+ if (mirror_num > num_copies)
1037+ break;
1038+ }
1039+ return eb;
1040+}
1041+
1042+static void print_usage(void)
1043+{
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");
1049+ exit(1);
1050+}
1051+
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' },
1058+ { 0, 0, 0, 0}
1059+};
1060+
1061+int main(int ac, char **av)
1062+{
1063+ struct cache_tree root_cache;
1064+ struct btrfs_root *root;
1065+ struct extent_buffer *eb;
1066+ char *dev;
1067+ char *output_file = NULL;
1068+ u64 logical = 0;
1069+ int ret = 0;
1070+ int option_index = 0;
1071+ int copy = 0;
1072+ u64 bytes = 0;
1073+ int out_fd = 0;
1074+ int err;
1075+
1076+ while(1) {
1077+ int c;
1078+ c = getopt_long(ac, av, "l:c:o:b:", long_options,
1079+ &option_index);
1080+ if (c < 0)
1081+ break;
1082+ switch(c) {
1083+ case 'l':
1084+ logical = atoll(optarg);
1085+ if (logical == 0) {
1086+ fprintf(stderr,
1087+ "invalid extent number\n");
1088+ print_usage();
1089+ }
1090+ break;
1091+ case 'c':
1092+ copy = atoi(optarg);
1093+ if (copy == 0) {
1094+ fprintf(stderr,
1095+ "invalid copy number\n");
1096+ print_usage();
1097+ }
1098+ break;
1099+ case 'b':
1100+ bytes = atoll(optarg);
1101+ if (bytes == 0) {
1102+ fprintf(stderr,
1103+ "invalid byte count\n");
1104+ print_usage();
1105+ }
1106+ break;
1107+ case 'o':
1108+ output_file = strdup(optarg);
1109+ break;
1110+ default:
1111+ print_usage();
1112+ }
1113+ }
1114+ ac = ac - optind;
1115+ if (ac == 0)
1116+ print_usage();
1117+ if (logical == 0)
1118+ print_usage();
1119+ if (copy < 0)
1120+ print_usage();
1121+
1122+ dev = av[optind];
1123+
1124+ radix_tree_init();
1125+ cache_tree_init(&root_cache);
1126+
1127+ root = open_ctree(dev, 0, 0);
1128+ if (!root) {
1129+ fprintf(stderr, "Open ctree failed\n");
1130+ exit(1);
1131+ }
1132+
1133+ if (output_file) {
1134+ if (strcmp(output_file, "-") == 0) {
1135+ out_fd = 1;
1136+ info_file = stderr;
1137+ } else {
1138+ out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
1139+ if (out_fd < 0)
1140+ goto close;
1141+ err = ftruncate(out_fd, 0);
1142+ if (err) {
1143+ close(out_fd);
1144+ goto close;
1145+ }
1146+ info_file = stdout;
1147+ }
1148+ }
1149+
1150+ if (bytes == 0)
1151+ bytes = root->sectorsize;
1152+
1153+ bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
1154+ bytes *= root->sectorsize;
1155+
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;
1163+ }
1164+ }
1165+ free_extent_buffer(eb);
1166+ logical += root->sectorsize;
1167+ bytes -= root->sectorsize;
1168+ }
1169+
1170+out_close_fd:
1171+ if (output_file && out_fd != 1)
1172+ close(out_fd);
1173+close:
1174+ close_ctree(root);
1175+ return ret;
1176+}
1177diff --git a/btrfs-vol.c b/btrfs-vol.c
1178index 8069778..4ed799d 100644
1179--- a/btrfs-vol.c
1180+++ b/btrfs-vol.c
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);
1189+ if (ret < 0) {
1190+ fprintf(stderr,
1191+ "error checking %s mount status\n",
1192+ device);
1193+ exit(1);
1194+ }
1195+ if (ret == 1) {
1196+ fprintf(stderr, "%s is mounted\n", device);
1197+ exit(1);
1198+ }
1199+ }
1200 devfd = open(device, O_RDWR);
1201- if (!devfd) {
1202+ if (devfd < 0) {
1203 fprintf(stderr, "Unable to open device %s\n", device);
1204+ exit(1);
1205 }
1206 ret = fstat(devfd, &st);
1207 if (ret) {
1208diff --git a/btrfs-zero-log.c b/btrfs-zero-log.c
1209new file mode 100644
1210index 0000000..f10438b
1211--- /dev/null
1212+++ b/btrfs-zero-log.c
1213@@ -0,0 +1,69 @@
1214+/*
1215+ * Copyright (C) 2007 Oracle. All rights reserved.
1216+ *
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.
1220+ *
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.
1225+ *
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.
1230+ */
1231+
1232+#define _XOPEN_SOURCE 500
1233+#define _GNU_SOURCE 1
1234+#include <stdio.h>
1235+#include <stdlib.h>
1236+#include <unistd.h>
1237+#include <fcntl.h>
1238+#include <sys/stat.h>
1239+#include "kerncompat.h"
1240+#include "ctree.h"
1241+#include "disk-io.h"
1242+#include "print-tree.h"
1243+#include "transaction.h"
1244+#include "list.h"
1245+#include "version.h"
1246+#include "utils.h"
1247+
1248+static void print_usage(void)
1249+{
1250+ fprintf(stderr, "usage: btrfs-zero-log dev\n");
1251+ fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
1252+ exit(1);
1253+}
1254+
1255+int main(int ac, char **av)
1256+{
1257+ struct btrfs_root *root;
1258+ int ret;
1259+
1260+ if (ac != 2)
1261+ print_usage();
1262+
1263+ radix_tree_init();
1264+
1265+ if((ret = check_mounted(av[1])) < 0) {
1266+ fprintf(stderr, "Could not check mount status: %s\n", strerror(ret));
1267+ return ret;
1268+ } else if(ret) {
1269+ fprintf(stderr, "%s is currently mounted. Aborting.\n", av[1]);
1270+ return -EBUSY;
1271+ }
1272+
1273+ root = open_ctree(av[1], 0, 1);
1274+
1275+ if (root == NULL)
1276+ return 1;
1277+
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);
1281+ return ret;
1282+}
1283diff --git a/btrfs.c b/btrfs.c
1284new file mode 100644
1285index 0000000..46314cf
1286--- /dev/null
1287+++ b/btrfs.c
1288@@ -0,0 +1,387 @@
1289+/*
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.
1293+ *
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.
1298+ *
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.
1303+ */
1304+
1305+#define _GNU_SOURCE
1306+#include <stdio.h>
1307+#include <stdlib.h>
1308+#include <string.h>
1309+
1310+#include "kerncompat.h"
1311+#include "btrfs_cmds.h"
1312+#include "version.h"
1313+
1314+typedef int (*CommandFunction)(int argc, char **argv);
1315+
1316+struct Command {
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
1323+ indented */
1324+
1325+ /* the following fields are run-time filled by the program */
1326+ char **cmds; /* array of subcommands */
1327+ int ncmds; /* number of subcommand */
1328+};
1329+
1330+static struct Command commands[] = {
1331+
1332+ /*
1333+ avoid short commands different for the case only
1334+ */
1335+ { do_clone, 2,
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."
1339+ },
1340+ { do_delete_subvolume, 1,
1341+ "subvolume delete", "<subvolume>\n"
1342+ "Delete the subvolume <subvolume>."
1343+ },
1344+ { do_create_subvol, 1,
1345+ "subvolume create", "[<dest>/]<name>\n"
1346+ "Create a subvolume in <dest> (or the current directory if\n"
1347+ "not passed)."
1348+ },
1349+ { do_subvol_list, 1, "subvolume list", "<path>\n"
1350+ "List the snapshot/subvolume of a filesystem."
1351+ },
1352+ { do_find_newer, 2, "subvolume find-new", "<path> <last_gen>\n"
1353+ "List the recently modified files in a filesystem."
1354+ },
1355+ { do_defrag, -1,
1356+ "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] <file>|<dir> [<file>|<dir>...]\n"
1357+ "Defragment a file or a directory."
1358+ },
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"
1362+ "as default."
1363+ },
1364+ { do_fssync, 1,
1365+ "filesystem sync", "<path>\n"
1366+ "Force a sync on the filesystem <path>."
1367+ },
1368+ { do_resize, 2,
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."
1372+ },
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."
1377+ },
1378+ { do_df_filesystem, 1,
1379+ "filesystem df", "<path>\n"
1380+ "Show space usage information for a mount point\n."
1381+ },
1382+ { do_balance, 1,
1383+ "filesystem balance", "<path>\n"
1384+ "Balance the chunks across the device."
1385+ },
1386+ { do_scan,
1387+ 999, "device scan", "[<device> [<device>..]\n"
1388+ "Scan all device for or the passed device for a btrfs\n"
1389+ "filesystem."
1390+ },
1391+ { do_add_volume, -2,
1392+ "device add", "<dev> [<dev>..] <path>\n"
1393+ "Add a device to a filesystem."
1394+ },
1395+ { do_remove_volume, -2,
1396+ "device delete", "<dev> [<dev>..] <path>\n"
1397+ "Remove a device from a filesystem."
1398+ },
1399+ /* coming soon
1400+ { 2, "filesystem label", "<label> <path>\n"
1401+ "Set the label of a filesystem"
1402+ }
1403+ */
1404+ { 0, 0 , 0 }
1405+};
1406+
1407+static char *get_prgname(char *programname)
1408+{
1409+ char *np;
1410+ np = strrchr(programname,'/');
1411+ if(!np)
1412+ np = programname;
1413+ else
1414+ np++;
1415+
1416+ return np;
1417+}
1418+
1419+static void print_help(char *programname, struct Command *cmd)
1420+{
1421+ char *pc;
1422+
1423+ printf("\t%s %s ", programname, cmd->verb );
1424+
1425+ for(pc = cmd->help; *pc; pc++){
1426+ putchar(*pc);
1427+ if(*pc == '\n')
1428+ printf("\t\t");
1429+ }
1430+ putchar('\n');
1431+}
1432+
1433+static void help(char *np)
1434+{
1435+ struct Command *cp;
1436+
1437+ printf("Usage:\n");
1438+ for( cp = commands; cp->verb; cp++ )
1439+ print_help(np, cp);
1440+
1441+ printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np);
1442+ printf("\n%s\n", BTRFS_BUILD_VERSION);
1443+}
1444+
1445+static int split_command(char *cmd, char ***commands)
1446+{
1447+ int c, l;
1448+ char *p, *s;
1449+
1450+ for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){
1451+ if ( *p && *p != ' ' )
1452+ continue;
1453+
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);
1457+ c++;
1458+ l = 0;
1459+ s = p+1;
1460+ if( !*p ) break;
1461+ }
1462+
1463+ (*commands)[c] = 0;
1464+ return c;
1465+}
1466+
1467+/*
1468+ This function checks if the passed command is ambiguous
1469+*/
1470+static int check_ambiguity(struct Command *cmd, char **argv){
1471+ int i;
1472+ struct Command *cp;
1473+ /* check for ambiguity */
1474+ for( i = 0 ; i < cmd->ncmds ; i++ ){
1475+ int match;
1476+ for( match = 0, cp = commands; cp->verb; cp++ ){
1477+ int j, skip;
1478+ char *s1, *s2;
1479+
1480+ if( cp->ncmds < i )
1481+ continue;
1482+
1483+ for( skip = 0, j = 0 ; j < i ; j++ )
1484+ if( strcmp(cmd->cmds[j], cp->cmds[j])){
1485+ skip=1;
1486+ break;
1487+ }
1488+ if(skip)
1489+ continue;
1490+
1491+ if( !strcmp(cmd->cmds[i], cp->cmds[i]))
1492+ continue;
1493+ for(s2 = cp->cmds[i], s1 = argv[i+1];
1494+ *s1 == *s2 && *s1; s1++, s2++ ) ;
1495+ if( !*s1 )
1496+ match++;
1497+ }
1498+ if(match){
1499+ int j;
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]);
1504+ return -2;
1505+ }
1506+ }
1507+ return 0;
1508+}
1509+
1510+/*
1511+ * This function, compacts the program name and the command in the first
1512+ * element of the '*av' array
1513+ */
1514+static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){
1515+
1516+ char **ret;
1517+ int i;
1518+ char *newname;
1519+
1520+ ret = (char **)malloc(sizeof(char*)*(*ac+1));
1521+ newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2);
1522+ if( !ret || !newname ){
1523+ free(ret);
1524+ free(newname);
1525+ return -1;
1526+ }
1527+
1528+ ret[0] = newname;
1529+ for(i=0; i < *ac ; i++ )
1530+ ret[i+1] = (*av)[i];
1531+
1532+ strcpy(newname, prgname);
1533+ strcat(newname, " ");
1534+ strcat(newname, cmd->verb);
1535+
1536+ (*ac)++;
1537+ *av = ret;
1538+
1539+ return 0;
1540+
1541+}
1542+
1543+
1544+
1545+/*
1546+
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
1555+ the arguments
1556+
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
1563+
1564+*/
1565+static int parse_args(int argc, char **argv,
1566+ CommandFunction *func_,
1567+ int *nargs_, char **cmd_, char ***args_ )
1568+{
1569+ struct Command *cp;
1570+ struct Command *matchcmd=0;
1571+ char *prgname = get_prgname(argv[0]);
1572+ int i=0, helprequested=0;
1573+
1574+ if( argc < 2 || !strcmp(argv[1], "help") ||
1575+ !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
1576+ help(prgname);
1577+ return 0;
1578+ }
1579+
1580+ for( cp = commands; cp->verb; cp++ )
1581+ if( !cp->ncmds)
1582+ cp->ncmds = split_command(cp->verb, &(cp->cmds));
1583+
1584+ for( cp = commands; cp->verb; cp++ ){
1585+ int match;
1586+
1587+ if( argc-1 < cp->ncmds )
1588+ continue;
1589+ for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){
1590+ char *s1, *s2;
1591+ s1 = cp->cmds[i];
1592+ s2 = argv[i+1];
1593+
1594+ for(s2 = cp->cmds[i], s1 = argv[i+1];
1595+ *s1 == *s2 && *s1;
1596+ s1++, s2++ ) ;
1597+ if( *s1 ){
1598+ match=0;
1599+ break;
1600+ }
1601+ }
1602+
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);
1609+ helprequested=1;
1610+ continue;
1611+ }
1612+
1613+ if(!match)
1614+ continue;
1615+
1616+ matchcmd = cp;
1617+ *nargs_ = argc-matchcmd->ncmds-1;
1618+ *cmd_ = matchcmd->verb;
1619+ *args_ = argv+matchcmd->ncmds+1;
1620+ *func_ = cp->func;
1621+
1622+ break;
1623+ }
1624+
1625+ if(helprequested){
1626+ printf("\n%s\n", BTRFS_BUILD_VERSION);
1627+ return 0;
1628+ }
1629+
1630+ if(!matchcmd){
1631+ fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]);
1632+ help(prgname);
1633+ return -1;
1634+ }
1635+
1636+ if(check_ambiguity(matchcmd, argv))
1637+ return -2;
1638+
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);
1643+ return -2;
1644+ }
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);
1648+ return -2;
1649+ }
1650+
1651+ if (prepare_args( nargs_, args_, prgname, matchcmd )){
1652+ fprintf(stderr, "ERROR: not enough memory\\n");
1653+ return -20;
1654+ }
1655+
1656+
1657+ return 1;
1658+}
1659+int main(int ac, char **av )
1660+{
1661+
1662+ char *cmd=0, **args=0;
1663+ int nargs=0, r;
1664+ CommandFunction func=0;
1665+
1666+ r = parse_args(ac, av, &func, &nargs, &cmd, &args);
1667+ if( r <= 0 ){
1668+ /* error or no command to parse*/
1669+ exit(-r);
1670+ }
1671+
1672+ exit(func(nargs, args));
1673+
1674+}
1675+
1676diff --git a/btrfs_cmds.c b/btrfs_cmds.c
1677new file mode 100644
1678index 0000000..8031c58
1679--- /dev/null
1680+++ b/btrfs_cmds.c
1681@@ -0,0 +1,924 @@
1682+/*
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.
1686+ *
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.
1691+ *
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.
1696+ */
1697+
1698+
1699+#include <stdio.h>
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>
1707+#include <fcntl.h>
1708+#include <libgen.h>
1709+#include <limits.h>
1710+#include <uuid/uuid.h>
1711+#include <ctype.h>
1712+
1713+#undef ULONG_MAX
1714+
1715+#include "kerncompat.h"
1716+#include "ctree.h"
1717+#include "transaction.h"
1718+#include "utils.h"
1719+#include "version.h"
1720+#include "ioctl.h"
1721+#include "volumes.h"
1722+
1723+#include "btrfs_cmds.h"
1724+
1725+#ifdef __CHECKER__
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; }
1731+#endif
1732+
1733+/*
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
1739+ */
1740+static int test_issubvolume(char *path)
1741+{
1742+
1743+ struct stat st;
1744+ int res;
1745+
1746+ res = stat(path, &st);
1747+ if(res < 0 )
1748+ return -1;
1749+
1750+ return (st.st_ino == 256) && S_ISDIR(st.st_mode);
1751+
1752+}
1753+
1754+/*
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
1760+ */
1761+static int test_isdir(char *path)
1762+{
1763+ struct stat st;
1764+ int res;
1765+
1766+ res = stat(path, &st);
1767+ if(res < 0 )
1768+ return -1;
1769+
1770+ return S_ISDIR(st.st_mode);
1771+
1772+}
1773+
1774+static int open_file_or_dir(const char *fname)
1775+{
1776+ int ret;
1777+ struct stat st;
1778+ DIR *dirstream;
1779+ int fd;
1780+
1781+ ret = stat(fname, &st);
1782+ if (ret < 0) {
1783+ return -1;
1784+ }
1785+ if (S_ISDIR(st.st_mode)) {
1786+ dirstream = opendir(fname);
1787+ if (!dirstream) {
1788+ return -2;
1789+ }
1790+ fd = dirfd(dirstream);
1791+ } else {
1792+ fd = open(fname, O_RDWR);
1793+ }
1794+ if (fd < 0) {
1795+ return -3;
1796+ }
1797+ return fd;
1798+}
1799+
1800+static u64 parse_size(char *s)
1801+{
1802+ int len = strlen(s);
1803+ char c;
1804+ u64 mult = 1;
1805+
1806+ if (!isdigit(s[len - 1])) {
1807+ c = tolower(s[len - 1]);
1808+ switch (c) {
1809+ case 'g':
1810+ mult *= 1024;
1811+ case 'm':
1812+ mult *= 1024;
1813+ case 'k':
1814+ mult *= 1024;
1815+ case 'b':
1816+ break;
1817+ default:
1818+ fprintf(stderr, "Unknown size descriptor %c\n", c);
1819+ exit(1);
1820+ }
1821+ s[len - 1] = '\0';
1822+ }
1823+ return atoll(s) * mult;
1824+}
1825+
1826+int do_defrag(int ac, char **av)
1827+{
1828+ int fd;
1829+ int compress = 0;
1830+ int flush = 0;
1831+ u64 start = 0;
1832+ u64 len = (u64)-1;
1833+ u32 thresh = 0;
1834+ int i;
1835+ int errors = 0;
1836+ int ret = 0;
1837+ int verbose = 0;
1838+ int fancy_ioctl = 0;
1839+ struct btrfs_ioctl_defrag_range_args range;
1840+
1841+ optind = 1;
1842+ while(1) {
1843+ int c = getopt(ac, av, "vcfs:l:t:");
1844+ if (c < 0)
1845+ break;
1846+ switch(c) {
1847+ case 'c':
1848+ compress = 1;
1849+ fancy_ioctl = 1;
1850+ break;
1851+ case 'f':
1852+ flush = 1;
1853+ fancy_ioctl = 1;
1854+ break;
1855+ case 'v':
1856+ verbose = 1;
1857+ break;
1858+ case 's':
1859+ start = parse_size(optarg);
1860+ fancy_ioctl = 1;
1861+ break;
1862+ case 'l':
1863+ len = parse_size(optarg);
1864+ fancy_ioctl = 1;
1865+ break;
1866+ case 't':
1867+ thresh = parse_size(optarg);
1868+ fancy_ioctl = 1;
1869+ break;
1870+ default:
1871+ fprintf(stderr, "Invalid arguments for defragment\n");
1872+ free(av);
1873+ return 1;
1874+ }
1875+ }
1876+ if (ac - optind == 0) {
1877+ fprintf(stderr, "Invalid arguments for defragment\n");
1878+ free(av);
1879+ return 1;
1880+ }
1881+
1882+ memset(&range, 0, sizeof(range));
1883+ range.start = start;
1884+ range.len = len;
1885+ range.extent_thresh = thresh;
1886+ if (compress)
1887+ range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1888+ if (flush)
1889+ range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1890+
1891+ for (i = optind; i < ac; i++) {
1892+ if (verbose)
1893+ printf("%s\n", av[i]);
1894+ fd = open_file_or_dir(av[i]);
1895+ if (fd < 0) {
1896+ fprintf(stderr, "failed to open %s\n", av[i]);
1897+ perror("open:");
1898+ errors++;
1899+ continue;
1900+ }
1901+ if (!fancy_ioctl) {
1902+ ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
1903+ } else {
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");
1909+ errors++;
1910+ break;
1911+ }
1912+ }
1913+ if (ret) {
1914+ fprintf(stderr, "ioctl failed on %s ret %d errno %d\n",
1915+ av[i], ret, errno);
1916+ errors++;
1917+ }
1918+ close(fd);
1919+ }
1920+ if (verbose)
1921+ printf("%s\n", BTRFS_BUILD_VERSION);
1922+ if (errors) {
1923+ fprintf(stderr, "total %d failures\n", errors);
1924+ exit(1);
1925+ }
1926+
1927+ free(av);
1928+ return errors + 20;
1929+}
1930+
1931+int do_find_newer(int argc, char **argv)
1932+{
1933+ int fd;
1934+ int ret;
1935+ char *subvol;
1936+ u64 last_gen;
1937+
1938+ subvol = argv[1];
1939+ last_gen = atoll(argv[2]);
1940+
1941+ ret = test_issubvolume(subvol);
1942+ if (ret < 0) {
1943+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1944+ return 12;
1945+ }
1946+ if (!ret) {
1947+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1948+ return 13;
1949+ }
1950+
1951+ fd = open_file_or_dir(subvol);
1952+ if (fd < 0) {
1953+ fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1954+ return 12;
1955+ }
1956+ ret = find_updated_files(fd, 0, last_gen);
1957+ if (ret)
1958+ return 19;
1959+ return 0;
1960+}
1961+
1962+int do_subvol_list(int argc, char **argv)
1963+{
1964+ int fd;
1965+ int ret;
1966+ char *subvol;
1967+
1968+ subvol = argv[1];
1969+
1970+ ret = test_issubvolume(subvol);
1971+ if (ret < 0) {
1972+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1973+ return 12;
1974+ }
1975+ if (!ret) {
1976+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1977+ return 13;
1978+ }
1979+
1980+ fd = open_file_or_dir(subvol);
1981+ if (fd < 0) {
1982+ fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1983+ return 12;
1984+ }
1985+ ret = list_subvols(fd);
1986+ if (ret)
1987+ return 19;
1988+ return 0;
1989+}
1990+
1991+int do_clone(int argc, char **argv)
1992+{
1993+ char *subvol, *dst;
1994+ int res, fd, fddst, len;
1995+ char *newname;
1996+ char *dstdir;
1997+
1998+ subvol = argv[1];
1999+ dst = argv[2];
2000+ struct btrfs_ioctl_vol_args args;
2001+
2002+ res = test_issubvolume(subvol);
2003+ if(res<0){
2004+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
2005+ return 12;
2006+ }
2007+ if(!res){
2008+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
2009+ return 13;
2010+ }
2011+
2012+ res = test_isdir(dst);
2013+ if(res == 0 ){
2014+ fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
2015+ return 12;
2016+ }
2017+
2018+ if(res>0){
2019+ newname = strdup(subvol);
2020+ newname = basename(newname);
2021+ dstdir = dst;
2022+ }else{
2023+ newname = strdup(dst);
2024+ newname = basename(newname);
2025+ dstdir = strdup(dst);
2026+ dstdir = dirname(dstdir);
2027+ }
2028+
2029+ if( !strcmp(newname,".") || !strcmp(newname,"..") ||
2030+ strchr(newname, '/') ){
2031+ fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
2032+ newname);
2033+ return 14;
2034+ }
2035+
2036+ len = strlen(newname);
2037+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2038+ fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
2039+ newname);
2040+ return 14;
2041+ }
2042+
2043+ fddst = open_file_or_dir(dstdir);
2044+ if (fddst < 0) {
2045+ fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2046+ return 12;
2047+ }
2048+
2049+ fd = open_file_or_dir(subvol);
2050+ if (fd < 0) {
2051+ close(fddst);
2052+ fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2053+ return 12;
2054+ }
2055+
2056+ printf("Create a snapshot of '%s' in '%s/%s'\n",
2057+ subvol, dstdir, newname);
2058+ args.fd = fd;
2059+ strcpy(args.name, newname);
2060+ res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args);
2061+
2062+ close(fd);
2063+ close(fddst);
2064+
2065+ if(res < 0 ){
2066+ fprintf( stderr, "ERROR: cannot snapshot '%s'\n",subvol);
2067+ return 11;
2068+ }
2069+
2070+ return 0;
2071+
2072+}
2073+
2074+int do_delete_subvolume(int argc, char **argv)
2075+{
2076+ int res, fd, len;
2077+ struct btrfs_ioctl_vol_args args;
2078+ char *dname, *vname, *cpath;
2079+ char *path = argv[1];
2080+
2081+ res = test_issubvolume(path);
2082+ if(res<0){
2083+ fprintf(stderr, "ERROR: error accessing '%s'\n", path);
2084+ return 12;
2085+ }
2086+ if(!res){
2087+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
2088+ return 13;
2089+ }
2090+
2091+ cpath = realpath(path, 0);
2092+ dname = strdup(cpath);
2093+ dname = dirname(dname);
2094+ vname = strdup(cpath);
2095+ vname = basename(vname);
2096+ free(cpath);
2097+
2098+ if( !strcmp(vname,".") || !strcmp(vname,"..") ||
2099+ strchr(vname, '/') ){
2100+ fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
2101+ vname);
2102+ return 14;
2103+ }
2104+
2105+ len = strlen(vname);
2106+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2107+ fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
2108+ vname);
2109+ return 14;
2110+ }
2111+
2112+ fd = open_file_or_dir(dname);
2113+ if (fd < 0) {
2114+ close(fd);
2115+ fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
2116+ return 12;
2117+ }
2118+
2119+ printf("Delete subvolume '%s/%s'\n", dname, vname);
2120+ strcpy(args.name, vname);
2121+ res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
2122+
2123+ close(fd);
2124+
2125+ if(res < 0 ){
2126+ fprintf( stderr, "ERROR: cannot delete '%s/%s'\n",dname, vname);
2127+ return 11;
2128+ }
2129+
2130+ return 0;
2131+
2132+}
2133+
2134+int do_create_subvol(int argc, char **argv)
2135+{
2136+ int res, fddst, len;
2137+ char *newname;
2138+ char *dstdir;
2139+ struct btrfs_ioctl_vol_args args;
2140+ char *dst = argv[1];
2141+
2142+ res = test_isdir(dst);
2143+ if(res >= 0 ){
2144+ fprintf(stderr, "ERROR: '%s' exists\n", dst);
2145+ return 12;
2146+ }
2147+
2148+ newname = strdup(dst);
2149+ newname = basename(newname);
2150+ dstdir = strdup(dst);
2151+ dstdir = dirname(dstdir);
2152+
2153+ if( !strcmp(newname,".") || !strcmp(newname,"..") ||
2154+ strchr(newname, '/') ){
2155+ fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
2156+ newname);
2157+ return 14;
2158+ }
2159+
2160+ len = strlen(newname);
2161+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2162+ fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
2163+ newname);
2164+ return 14;
2165+ }
2166+
2167+ fddst = open_file_or_dir(dstdir);
2168+ if (fddst < 0) {
2169+ fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
2170+ return 12;
2171+ }
2172+
2173+ printf("Create subvolume '%s/%s'\n", dstdir, newname);
2174+ strcpy(args.name, newname);
2175+ res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
2176+
2177+ close(fddst);
2178+
2179+ if(res < 0 ){
2180+ fprintf( stderr, "ERROR: cannot create subvolume\n");
2181+ return 11;
2182+ }
2183+
2184+ return 0;
2185+
2186+}
2187+
2188+int do_fssync(int argc, char **argv)
2189+{
2190+ int fd, res;
2191+ char *path = argv[1];
2192+
2193+ fd = open_file_or_dir(path);
2194+ if (fd < 0) {
2195+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2196+ return 12;
2197+ }
2198+
2199+ printf("FSSync '%s'\n", path);
2200+ res = ioctl(fd, BTRFS_IOC_SYNC);
2201+ close(fd);
2202+ if( res < 0 ){
2203+ fprintf(stderr, "ERROR: unable to fs-syncing '%s'\n", path);
2204+ return 16;
2205+ }
2206+
2207+ return 0;
2208+}
2209+
2210+int do_scan(int argc, char **argv)
2211+{
2212+ int i, fd;
2213+ if(argc<=1){
2214+ int ret;
2215+
2216+ printf("Scanning for Btrfs filesystems\n");
2217+ ret = btrfs_scan_one_dir("/dev", 1);
2218+ if (ret){
2219+ fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2220+ return 18;
2221+ }
2222+ return 0;
2223+ }
2224+
2225+ fd = open("/dev/btrfs-control", O_RDWR);
2226+ if (fd < 0) {
2227+ perror("failed to open /dev/btrfs-control");
2228+ return 10;
2229+ }
2230+
2231+ for( i = 1 ; i < argc ; i++ ){
2232+ struct btrfs_ioctl_vol_args args;
2233+ int ret;
2234+
2235+ printf("Scanning for Btrfs filesystems in '%s'\n", argv[i]);
2236+
2237+ strcpy(args.name, argv[i]);
2238+ /*
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 !!!
2242+ */
2243+ ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
2244+
2245+ if( ret < 0 ){
2246+ close(fd);
2247+ fprintf(stderr, "ERROR: unable to scan the device '%s'\n", argv[i]);
2248+ return 11;
2249+ }
2250+ }
2251+
2252+ close(fd);
2253+ return 0;
2254+
2255+}
2256+
2257+int do_resize(int argc, char **argv)
2258+{
2259+
2260+ struct btrfs_ioctl_vol_args args;
2261+ int fd, res, len;
2262+ char *amount=argv[1], *path=argv[2];
2263+
2264+ fd = open_file_or_dir(path);
2265+ if (fd < 0) {
2266+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2267+ return 12;
2268+ }
2269+ len = strlen(amount);
2270+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2271+ fprintf(stderr, "ERROR: size value too long ('%s)\n",
2272+ amount);
2273+ return 14;
2274+ }
2275+
2276+ printf("Resize '%s' of '%s'\n", path, amount);
2277+ strcpy(args.name, amount);
2278+ res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
2279+ close(fd);
2280+ if( res < 0 ){
2281+ fprintf(stderr, "ERROR: unable to resize '%s'\n", path);
2282+ return 30;
2283+ }
2284+ return 0;
2285+}
2286+
2287+static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
2288+{
2289+ struct list_head *cur;
2290+ struct btrfs_device *device;
2291+
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)
2296+ return 1;
2297+ }
2298+ return 0;
2299+}
2300+
2301+static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
2302+{
2303+ char uuidbuf[37];
2304+ struct list_head *cur;
2305+ struct btrfs_device *device;
2306+ char *super_bytes_used;
2307+ u64 devs_found = 0;
2308+ u64 total;
2309+
2310+ uuid_unparse(fs_devices->fsid, uuidbuf);
2311+ device = list_entry(fs_devices->devices.next, struct btrfs_device,
2312+ dev_list);
2313+ if (device->label && device->label[0])
2314+ printf("Label: '%s' ", device->label);
2315+ else
2316+ printf("Label: none ");
2317+
2318+ super_bytes_used = pretty_sizes(device->super_bytes_used);
2319+
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);
2323+
2324+ free(super_bytes_used);
2325+
2326+ list_for_each(cur, &fs_devices->devices) {
2327+ char *total_bytes;
2328+ char *bytes_used;
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);
2336+ free(bytes_used);
2337+ devs_found++;
2338+ }
2339+ if (devs_found < total) {
2340+ printf("\t*** Some devices missing\n");
2341+ }
2342+ printf("\n");
2343+}
2344+
2345+int do_show_filesystem(int argc, char **argv)
2346+{
2347+ struct list_head *all_uuids;
2348+ struct btrfs_fs_devices *fs_devices;
2349+ struct list_head *cur_uuid;
2350+ char *search = argv[1];
2351+ int ret;
2352+
2353+ ret = btrfs_scan_one_dir("/dev", 0);
2354+ if (ret){
2355+ fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2356+ return 18;
2357+ }
2358+
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,
2362+ list);
2363+ if (search && uuid_search(fs_devices, search) == 0)
2364+ continue;
2365+ print_one_uuid(fs_devices);
2366+ }
2367+ printf("%s\n", BTRFS_BUILD_VERSION);
2368+ return 0;
2369+}
2370+
2371+int do_add_volume(int nargs, char **args)
2372+{
2373+
2374+ char *mntpnt = args[nargs-1];
2375+ int i, fdmnt, ret=0;
2376+
2377+
2378+ fdmnt = open_file_or_dir(mntpnt);
2379+ if (fdmnt < 0) {
2380+ fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2381+ return 12;
2382+ }
2383+
2384+ for(i=1 ; i < (nargs-1) ; i++ ){
2385+ struct btrfs_ioctl_vol_args ioctl_args;
2386+ int devfd, res;
2387+ u64 dev_block_count = 0;
2388+ struct stat st;
2389+
2390+ devfd = open(args[i], O_RDWR);
2391+ if (!devfd) {
2392+ fprintf(stderr, "ERROR: Unable to open device '%s'\n", args[i]);
2393+ close(devfd);
2394+ ret++;
2395+ continue;
2396+ }
2397+ ret = fstat(devfd, &st);
2398+ if (ret) {
2399+ fprintf(stderr, "ERROR: Unable to stat '%s'\n", args[i]);
2400+ close(devfd);
2401+ ret++;
2402+ continue;
2403+ }
2404+ if (!S_ISBLK(st.st_mode)) {
2405+ fprintf(stderr, "ERROR: '%s' is not a block device\n", args[i]);
2406+ close(devfd);
2407+ ret++;
2408+ continue;
2409+ }
2410+
2411+ res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count);
2412+ if (res) {
2413+ fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]);
2414+ close(devfd);
2415+ ret++;
2416+ continue;
2417+ }
2418+ close(devfd);
2419+
2420+ strcpy(ioctl_args.name, args[i]);
2421+ res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
2422+ if(res<0){
2423+ fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]);
2424+ ret++;
2425+ }
2426+
2427+ }
2428+
2429+ close(fdmnt);
2430+ if( ret)
2431+ return ret+20;
2432+ else
2433+ return 0;
2434+
2435+}
2436+
2437+int do_balance(int argc, char **argv)
2438+{
2439+
2440+ int fdmnt, ret=0;
2441+ struct btrfs_ioctl_vol_args args;
2442+ char *path = argv[1];
2443+
2444+ fdmnt = open_file_or_dir(path);
2445+ if (fdmnt < 0) {
2446+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2447+ return 12;
2448+ }
2449+
2450+ memset(&args, 0, sizeof(args));
2451+ ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args);
2452+ close(fdmnt);
2453+ if(ret<0){
2454+ fprintf(stderr, "ERROR: balancing '%s'\n", path);
2455+
2456+ return 19;
2457+ }
2458+ return 0;
2459+}
2460+int do_remove_volume(int nargs, char **args)
2461+{
2462+
2463+ char *mntpnt = args[nargs-1];
2464+ int i, fdmnt, ret=0;
2465+
2466+ fdmnt = open_file_or_dir(mntpnt);
2467+ if (fdmnt < 0) {
2468+ fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2469+ return 12;
2470+ }
2471+
2472+ for(i=1 ; i < (nargs-1) ; i++ ){
2473+ struct btrfs_ioctl_vol_args arg;
2474+ int res;
2475+
2476+ strcpy(arg.name, args[i]);
2477+ res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
2478+ if(res<0){
2479+ fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]);
2480+ ret++;
2481+ }
2482+ }
2483+
2484+ close(fdmnt);
2485+ if( ret)
2486+ return ret+20;
2487+ else
2488+ return 0;
2489+}
2490+
2491+int do_set_default_subvol(int nargs, char **argv)
2492+{
2493+ int ret=0, fd;
2494+ u64 objectid;
2495+ char *path = argv[2];
2496+ char *subvolid = argv[1];
2497+
2498+ fd = open_file_or_dir(path);
2499+ if (fd < 0) {
2500+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2501+ return 12;
2502+ }
2503+
2504+ objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
2505+ if (errno == ERANGE) {
2506+ fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
2507+ return 30;
2508+ }
2509+ ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
2510+ close(fd);
2511+ if( ret < 0 ){
2512+ fprintf(stderr, "ERROR: unable to set a new default subvolume\n");
2513+ return 30;
2514+ }
2515+ return 0;
2516+}
2517+
2518+int do_df_filesystem(int nargs, char **argv)
2519+{
2520+ struct btrfs_ioctl_space_args *sargs;
2521+ u64 count = 0, i;
2522+ int ret;
2523+ int fd;
2524+ char *path = argv[1];
2525+
2526+ fd = open_file_or_dir(path);
2527+ if (fd < 0) {
2528+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2529+ return 12;
2530+ }
2531+
2532+ sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
2533+ if (!sargs)
2534+ return -ENOMEM;
2535+
2536+ sargs->space_slots = 0;
2537+ sargs->total_spaces = 0;
2538+
2539+ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2540+ if (ret) {
2541+ free(sargs);
2542+ return ret;
2543+ }
2544+ if (!sargs->total_spaces)
2545+ return 0;
2546+
2547+ count = sargs->total_spaces;
2548+
2549+ sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
2550+ (count * sizeof(struct btrfs_ioctl_space_info)));
2551+ if (!sargs)
2552+ return -ENOMEM;
2553+
2554+ sargs->space_slots = count;
2555+ sargs->total_spaces = 0;
2556+
2557+ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2558+ if (ret) {
2559+ free(sargs);
2560+ return ret;
2561+ }
2562+
2563+ for (i = 0; i < sargs->total_spaces; i++) {
2564+ char description[80];
2565+ char *total_bytes;
2566+ char *used_bytes;
2567+ int written = 0;
2568+ u64 flags = sargs->spaces[i].flags;
2569+
2570+ memset(description, 0, 80);
2571+
2572+ if (flags & BTRFS_BLOCK_GROUP_DATA) {
2573+ snprintf(description, 5, "%s", "Data");
2574+ written += 4;
2575+ } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
2576+ snprintf(description, 7, "%s", "System");
2577+ written += 6;
2578+ } else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
2579+ snprintf(description, 9, "%s", "Metadata");
2580+ written += 8;
2581+ }
2582+
2583+ if (flags & BTRFS_BLOCK_GROUP_RAID0) {
2584+ snprintf(description+written, 8, "%s", ", RAID0");
2585+ written += 7;
2586+ } else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
2587+ snprintf(description+written, 8, "%s", ", RAID1");
2588+ written += 7;
2589+ } else if (flags & BTRFS_BLOCK_GROUP_DUP) {
2590+ snprintf(description+written, 6, "%s", ", DUP");
2591+ written += 5;
2592+ } else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
2593+ snprintf(description+written, 9, "%s", ", RAID10");
2594+ written += 8;
2595+ }
2596+
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,
2600+ used_bytes);
2601+ }
2602+ free(sargs);
2603+
2604+ return 0;
2605+}
2606diff --git a/btrfs_cmds.h b/btrfs_cmds.h
2607new file mode 100644
2608index 0000000..7bde191
2609--- /dev/null
2610+++ b/btrfs_cmds.h
2611@@ -0,0 +1,34 @@
2612+/*
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.
2616+ *
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.
2621+ *
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.
2626+ */
2627+
2628+/* btrfs_cmds.c*/
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);
2646diff --git a/btrfsck.c b/btrfsck.c
2647index 40c90f8..63e44d1 100644
2648--- a/btrfsck.c
2649+++ b/btrfsck.c
2650@@ -20,7 +20,9 @@
2651 #define _GNU_SOURCE 1
2652 #include <stdio.h>
2653 #include <stdlib.h>
2654+#include <unistd.h>
2655 #include <fcntl.h>
2656+#include <sys/stat.h>
2657 #include "kerncompat.h"
2658 #include "ctree.h"
2659 #include "disk-io.h"
2660@@ -28,6 +30,7 @@
2661 #include "transaction.h"
2662 #include "list.h"
2663 #include "version.h"
2664+#include "utils.h"
2665
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;
2674
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)
2687
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)
2693
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;
2701+ int errors;
2702+ u64 ref_root;
2703+ u64 dir;
2704+ u64 index;
2705+ u16 namelen;
2706+ char name[0];
2707+};
2708+
2709+struct root_record {
2710+ struct list_head backrefs;
2711+ struct cache_extent cache;
2712+ unsigned int found_root_item:1;
2713+ u64 objectid;
2714+ u32 found_ref;
2715+};
2716+
2717 struct ptr_node {
2718 struct cache_extent cache;
2719 void *data;
2720@@ -151,6 +181,7 @@ struct ptr_node {
2721
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;
2727 u32 refs;
2728@@ -258,6 +289,14 @@ static void free_inode_rec(struct inode_record *rec)
2729 free(rec);
2730 }
2731
2732+static int can_free_inode_rec(struct inode_record *rec)
2733+{
2734+ if (!rec->errors && rec->checked && rec->found_inode_item &&
2735+ rec->nlink == rec->found_link && list_empty(&rec->backrefs))
2736+ return 1;
2737+ return 0;
2738+}
2739+
2740 static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2741 struct inode_record *rec)
2742 {
2743@@ -309,8 +348,7 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2744 }
2745
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)
2754 return ret;
2755 }
2756
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)
2762 {
2763 struct inode_record *rec;
2764 struct btrfs_inode_item *item;
2765- int ret;
2766
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)
2771 rec->nodatasum = 1;
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;
2777- }
2778+ if (rec->nlink == 0)
2779+ rec->errors |= I_ERR_NO_ORPHAN_ITEM;
2780 maybe_free_inode_rec(&active_node->inode_cache, rec);
2781 return 0;
2782 }
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++;
2788 return backref;
2789 }
2790
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,
2800 }
2801
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)
2805 {
2806 struct inode_backref *backref;
2807- struct cache_tree *dst_cache = &dst_node->inode_cache;
2808+ u32 dir_count = 0;
2809
2810 dst->merging = 1;
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);
2814 }
2815 if (backref->found_dir_item) {
2816+ dir_count++;
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;
2823
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;
2831 }
2832 }
2833-
2834- if (src->checked) {
2835- dst->checked = 1;
2836- if (dst_node->current == dst)
2837- dst_node->current = NULL;
2838- }
2839 dst->merging = 0;
2840- maybe_free_inode_rec(dst_cache, dst);
2841+
2842 return 0;
2843 }
2844
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;
2848
2849- src = &src_node->inode_cache;
2850- dst = &dst_node->inode_cache;
2851+ src = &src_node->root_cache;
2852+ dst = &dst_node->root_cache;
2853+again:
2854 cache = find_first_cache_extent(src, 0);
2855 while (cache) {
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;
2867+ }
2868+ maybe_free_inode_rec(dst, conflict);
2869 free_inode_rec(rec);
2870 free(ins);
2871 } else {
2872 BUG_ON(ret);
2873 }
2874 }
2875+
2876+ if (src == &src_node->root_cache) {
2877+ src = &src_node->inode_cache;
2878+ dst = &dst_node->inode_cache;
2879+ goto again;
2880+ }
2881+
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);
2891 node->refs = refs;
2892
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);
2900 free(node);
2901@@ -708,10 +754,12 @@ static int process_dir_item(struct extent_buffer *eb,
2902 int filetype;
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];
2909
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);
2922 } else {
2923 fprintf(stderr, "warning line %d\n", __LINE__);
2924 }
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);
2927 break;
2928 case BTRFS_INODE_ITEM_KEY:
2929- ret = process_inode_item(root, eb, i, &key,
2930- active_node);
2931+ ret = process_inode_item(eb, i, &key, active_node);
2932 break;
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)
2936
2937 if (!rec->found_inode_item || rec->errors)
2938 goto out;
2939- if (rec->nlink != 1 || rec->found_link != 1)
2940+ if (rec->nlink != 1 || rec->found_link != 0)
2941 goto out;
2942 if (list_empty(&rec->backrefs))
2943 goto out;
2944@@ -1176,13 +1225,23 @@ static int check_inode_recs(struct btrfs_root *root,
2945 node = container_of(cache, struct ptr_node, cache);
2946 rec = node->data;
2947 remove_cache_extent(inode_cache, &node->cache);
2948+ free(node);
2949 if (rec->ino == root_dirid ||
2950 rec->ino == BTRFS_ORPHAN_OBJECTID) {
2951- free(node);
2952 free_inode_rec(rec);
2953 continue;
2954 }
2955
2956+ if (rec->errors & I_ERR_NO_ORPHAN_ITEM) {
2957+ ret = check_orphan_item(root, rec->ino);
2958+ if (ret == 0)
2959+ rec->errors &= ~I_ERR_NO_ORPHAN_ITEM;
2960+ if (can_free_inode_rec(rec)) {
2961+ free_inode_rec(rec);
2962+ continue;
2963+ }
2964+ }
2965+
2966 error++;
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);
2972 }
2973- free(node);
2974 free_inode_rec(rec);
2975 }
2976 return (error > 0) ? -1 : 0;
2977 }
2978
2979+static struct root_record *get_root_rec(struct cache_tree *root_cache,
2980+ u64 objectid)
2981+{
2982+ struct cache_extent *cache;
2983+ struct root_record *rec = NULL;
2984+ int ret;
2985+
2986+ cache = find_cache_extent(root_cache, objectid, 1);
2987+ if (cache) {
2988+ rec = container_of(cache, struct root_record, cache);
2989+ } else {
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;
2995+
2996+ ret = insert_existing_cache_extent(root_cache, &rec->cache);
2997+ BUG_ON(ret);
2998+ }
2999+ return rec;
3000+}
3001+
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)
3005+{
3006+ struct root_backref *backref;
3007+
3008+ list_for_each_entry(backref, &rec->backrefs, list) {
3009+ if (backref->ref_root != ref_root || backref->dir != dir ||
3010+ backref->namelen != namelen)
3011+ continue;
3012+ if (memcmp(name, backref->name, namelen))
3013+ continue;
3014+ return backref;
3015+ }
3016+
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);
3026+ return backref;
3027+}
3028+
3029+static void free_root_recs(struct cache_tree *root_cache)
3030+{
3031+ struct cache_extent *cache;
3032+ struct root_record *rec;
3033+ struct root_backref *backref;
3034+
3035+ while (1) {
3036+ cache = find_first_cache_extent(root_cache, 0);
3037+ if (!cache)
3038+ break;
3039+ rec = container_of(cache, struct root_record, cache);
3040+ remove_cache_extent(root_cache, &rec->cache);
3041+
3042+ while (!list_empty(&rec->backrefs)) {
3043+ backref = list_entry(rec->backrefs.next,
3044+ struct root_backref, list);
3045+ list_del(&backref->list);
3046+ free(backref);
3047+ }
3048+ kfree(rec);
3049+ }
3050+}
3051+
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)
3056+{
3057+ struct root_record *rec;
3058+ struct root_backref *backref;
3059+
3060+ rec = get_root_rec(root_cache, root_id);
3061+ backref = get_root_backref(rec, ref_root, dir, index, name, namelen);
3062+
3063+ backref->errors |= errors;
3064+
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;
3070+ } else {
3071+ backref->index = index;
3072+ }
3073+ }
3074+
3075+ if (item_type == BTRFS_DIR_ITEM_KEY) {
3076+ backref->found_dir_item = 1;
3077+ backref->reachable = 1;
3078+ rec->found_ref++;
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;
3089+ } else {
3090+ BUG_ON(1);
3091+ }
3092+
3093+ return 0;
3094+}
3095+
3096+static int merge_root_recs(struct btrfs_root *root,
3097+ struct cache_tree *src_cache,
3098+ struct cache_tree *dst_cache)
3099+{
3100+ struct cache_extent *cache;
3101+ struct ptr_node *node;
3102+ struct inode_record *rec;
3103+ struct inode_backref *backref;
3104+
3105+ if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
3106+ free_inode_recs(src_cache);
3107+ return 0;
3108+ }
3109+
3110+ while (1) {
3111+ cache = find_first_cache_extent(src_cache, 0);
3112+ if (!cache)
3113+ break;
3114+ node = container_of(cache, struct ptr_node, cache);
3115+ rec = node->data;
3116+ remove_cache_extent(src_cache, &node->cache);
3117+ free(node);
3118+
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,
3126+ backref->errors);
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,
3132+ backref->errors);
3133+ }
3134+ free_inode_rec(rec);
3135+ }
3136+ return 0;
3137+}
3138+
3139+static int check_root_refs(struct btrfs_root *root,
3140+ struct cache_tree *root_cache)
3141+{
3142+ struct root_record *rec;
3143+ struct root_record *ref_root;
3144+ struct root_backref *backref;
3145+ struct cache_extent *cache;
3146+ int loop = 1;
3147+ int ret;
3148+ int error;
3149+ int errors = 0;
3150+
3151+ rec = get_root_rec(root_cache, BTRFS_FS_TREE_OBJECTID);
3152+ rec->found_ref = 1;
3153+
3154+ /* fixme: this can not detect circular references */
3155+ while (loop) {
3156+ loop = 0;
3157+ cache = find_first_cache_extent(root_cache, 0);
3158+ while (1) {
3159+ if (!cache)
3160+ break;
3161+ rec = container_of(cache, struct root_record, cache);
3162+ cache = next_cache_extent(cache);
3163+
3164+ if (rec->found_ref == 0)
3165+ continue;
3166+
3167+ list_for_each_entry(backref, &rec->backrefs, list) {
3168+ if (!backref->reachable)
3169+ continue;
3170+
3171+ ref_root = get_root_rec(root_cache,
3172+ backref->ref_root);
3173+ if (ref_root->found_ref > 0)
3174+ continue;
3175+
3176+ backref->reachable = 0;
3177+ rec->found_ref--;
3178+ if (rec->found_ref == 0)
3179+ loop = 1;
3180+ }
3181+ }
3182+ }
3183+
3184+ cache = find_first_cache_extent(root_cache, 0);
3185+ while (1) {
3186+ if (!cache)
3187+ break;
3188+ rec = container_of(cache, struct root_record, cache);
3189+ cache = next_cache_extent(cache);
3190+
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,
3195+ rec->objectid);
3196+ if (ret == 0)
3197+ continue;
3198+ errors++;
3199+ fprintf(stderr, "fs tree %llu not referenced\n",
3200+ (unsigned long long)rec->objectid);
3201+ }
3202+
3203+ error = 0;
3204+ if (rec->found_ref > 0 && !rec->found_root_item)
3205+ error = 1;
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)
3216+ error = 1;
3217+ }
3218+ if (!error)
3219+ continue;
3220+
3221+ 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");
3225+
3226+ list_for_each_entry(backref, &rec->backrefs, list) {
3227+ if (!backref->reachable)
3228+ continue;
3229+ if (!backref->errors && rec->found_root_item)
3230+ continue;
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,
3237+ backref->errors);
3238+ }
3239+ }
3240+ return errors > 0 ? 1 : 0;
3241+}
3242+
3243+static int process_root_ref(struct extent_buffer *eb, int slot,
3244+ struct btrfs_key *key,
3245+ struct cache_tree *root_cache)
3246+{
3247+ u64 dirid;
3248+ u64 index;
3249+ u32 len;
3250+ u32 name_len;
3251+ struct btrfs_root_ref *ref;
3252+ char namebuf[BTRFS_NAME_LEN];
3253+ int error;
3254+
3255+ ref = btrfs_item_ptr(eb, slot, struct btrfs_root_ref);
3256+
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);
3260+
3261+ if (name_len <= BTRFS_NAME_LEN) {
3262+ len = name_len;
3263+ error = 0;
3264+ } else {
3265+ len = BTRFS_NAME_LEN;
3266+ error = REF_ERR_NAME_TOO_LONG;
3267+ }
3268+ read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
3269+
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);
3273+ } else {
3274+ add_root_backref(root_cache, key->objectid, key->offset, dirid,
3275+ index, namebuf, len, key->type, error);
3276+ }
3277+ return 0;
3278+}
3279+
3280 static int check_fs_root(struct btrfs_root *root,
3281+ struct cache_tree *root_cache,
3282 struct walk_control *wc)
3283 {
3284 int ret = 0;
3285@@ -1219,10 +1579,18 @@ static int check_fs_root(struct btrfs_root *root,
3286 int level;
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;
3291
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;
3296+ }
3297+
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);
3302
3303 level = btrfs_header_level(root->node);
3304@@ -1266,6 +1634,8 @@ static int check_fs_root(struct btrfs_root *root,
3305 }
3306 btrfs_release_path(root, &path);
3307
3308+ merge_root_recs(root, &root_node.root_cache, root_cache);
3309+
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)
3314 {
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))
3321 return 1;
3322 return 0;
3323 }
3324
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)
3328 {
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,
3334 &key);
3335- ret = check_fs_root(tmp_root, &wc);
3336+ ret = check_fs_root(tmp_root, root_cache, &wc);
3337 if (ret)
3338 err = 1;
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,
3343+ root_cache);
3344 }
3345 path.slots[0]++;
3346 }
3347@@ -1895,7 +2271,6 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
3348 return 0;
3349 }
3350
3351-
3352 static int add_pending(struct cache_tree *pending,
3353 struct cache_tree *seen, u64 bytenr, u32 size)
3354 {
3355@@ -2443,14 +2818,45 @@ static void print_usage(void)
3356
3357 int main(int ac, char **av)
3358 {
3359+ struct cache_tree root_cache;
3360 struct btrfs_root *root;
3361+ u64 bytenr = 0;
3362 int ret;
3363+ int num;
3364
3365- if (ac < 2)
3366+ while(1) {
3367+ int c;
3368+ c = getopt(ac, av, "s:");
3369+ if (c < 0)
3370+ break;
3371+ switch(c) {
3372+ case '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);
3377+ break;
3378+ default:
3379+ print_usage();
3380+ }
3381+ }
3382+ ac = ac - optind;
3383+
3384+ if (ac != 1)
3385 print_usage();
3386
3387 radix_tree_init();
3388- root = open_ctree(av[1], 0, 0);
3389+ cache_tree_init(&root_cache);
3390+
3391+ if((ret = check_mounted(av[optind])) < 0) {
3392+ fprintf(stderr, "Could not check mount status: %s\n", strerror(ret));
3393+ return ret;
3394+ } else if(ret) {
3395+ fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]);
3396+ return -EBUSY;
3397+ }
3398+
3399+ root = open_ctree(av[optind], bytenr, 0);
3400
3401 if (root == NULL)
3402 return 1;
3403@@ -2458,10 +2864,15 @@ int main(int ac, char **av)
3404 ret = check_extents(root);
3405 if (ret)
3406 goto out;
3407- ret = check_fs_roots(root);
3408+ ret = check_fs_roots(root, &root_cache);
3409+ if (ret)
3410+ goto out;
3411
3412+ ret = check_root_refs(root, &root_cache);
3413 out:
3414+ free_root_recs(&root_cache);
3415 close_ctree(root);
3416+
3417 if (found_old_backref) {
3418 /*
3419 * there was a disk format change when mixed
3420diff --git a/btrfsctl.c b/btrfsctl.c
3421index b323818..92bdf39 100644
3422--- a/btrfsctl.c
3423+++ b/btrfsctl.c
3424@@ -29,6 +29,7 @@
3425 #include <unistd.h>
3426 #include <dirent.h>
3427 #include <libgen.h>
3428+#include <stdlib.h>
3429 #include "kerncompat.h"
3430 #include "ctree.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)
3434 {
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);
3449 exit(1);
3450 }
3451@@ -99,7 +103,9 @@ int main(int ac, char **av)
3452 int i;
3453 unsigned long command = 0;
3454 int len;
3455+ char *pos;
3456 char *fullpath;
3457+ u64 objectid = 0;
3458
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)
3462 print_usage();
3463 }
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");
3468+ print_usage();
3469+ }
3470+ command = BTRFS_IOC_SNAP_DESTROY;
3471+ name = av[i + 1];
3472+ len = strlen(name);
3473+ pos = strchr(name, '/');
3474+ if (pos) {
3475+ if (*(pos + 1) == '\0')
3476+ *(pos) = '\0';
3477+ else {
3478+ fprintf(stderr,
3479+ "error: / not allowed in names\n");
3480+ exit(1);
3481+ }
3482+ }
3483+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
3484+ fprintf(stderr, "-D size too long\n");
3485+ exit(1);
3486+ }
3487 } else if (strcmp(av[i], "-A") == 0) {
3488 if (i >= ac - 1) {
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");
3501+ exit(1);
3502+ }
3503+ }
3504 }
3505 }
3506 if (command == 0) {
3507@@ -206,6 +244,9 @@ int main(int ac, char **av)
3508 if (command == BTRFS_IOC_SNAP_CREATE) {
3509 args.fd = fd;
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);
3514 } else
3515 ret = ioctl(fd, command, &args);
3516 if (ret < 0) {
3517@@ -219,8 +260,8 @@ int main(int ac, char **av)
3518 }
3519 printf("%s\n", BTRFS_BUILD_VERSION);
3520 if (ret)
3521- exit(0);
3522- else
3523 exit(1);
3524+
3525+ return 0;
3526 }
3527
3528diff --git a/convert.c b/convert.c
3529index d2c9efa..d037c98 100644
3530--- a/convert.c
3531+++ b/convert.c
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;
3535 u64 nbytes;
3536- u64 bytes_used;
3537
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);
3543
3544- bytes_used = btrfs_root_used(&root->root_item);
3545- btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
3546-
3547 btrfs_release_path(root, &path);
3548
3549 ins_key.objectid = disk_bytenr;
3550@@ -454,9 +450,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3551
3552 btrfs_mark_buffer_dirty(leaf);
3553
3554- bytes_used = btrfs_super_bytes_used(&info->super_copy);
3555- btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
3556- num_bytes);
3557 ret = btrfs_update_block_group(trans, root, disk_bytenr,
3558 num_bytes, 1, 0);
3559 if (ret)
3560diff --git a/ctree.h b/ctree.h
3561index a9062ea..b79e238 100644
3562--- a/ctree.h
3563+++ b/ctree.h
3564@@ -350,11 +350,13 @@ struct btrfs_super_block {
3565 * ones specified below then we will fail to mount
3566 */
3567 #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
3568+#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (2ULL << 0)
3569
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)
3576
3577 /*
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,
3580
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);
3585
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);
3590
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);
3594+
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)
3599
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);
3603
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)
3607
3608 BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
3609 disk_bytenr, 64);
3610+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item,
3611+ disk_bytenr, 64);
3612 BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
3613 generation, 64);
3614+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item,
3615+ generation, 64);
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,
3619 offset, 64);
3620+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item,
3621+ offset, 64);
3622 BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
3623 num_bytes, 64);
3624+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item,
3625+ num_bytes, 64);
3626 BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
3627 ram_bytes, 64);
3628+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item,
3629+ ram_bytes, 64);
3630 BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
3631 compression, 8);
3632+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item,
3633+ compression, 8);
3634 BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
3635 encryption, 8);
3636 BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
3637diff --git a/debug-tree.c b/debug-tree.c
3638index 1d47519..0525354 100644
3639--- a/debug-tree.c
3640+++ b/debug-tree.c
3641@@ -116,19 +116,27 @@ int main(int ac, char **av)
3642 int ret;
3643 int slot;
3644 int extent_only = 0;
3645+ int device_only = 0;
3646+ u64 block_only = 0;
3647 struct btrfs_root *tree_root_scan;
3648
3649 radix_tree_init();
3650
3651 while(1) {
3652 int c;
3653- c = getopt(ac, av, "e");
3654+ c = getopt(ac, av, "deb:");
3655 if (c < 0)
3656 break;
3657 switch(c) {
3658 case 'e':
3659 extent_only = 1;
3660 break;
3661+ case 'd':
3662+ device_only = 1;
3663+ break;
3664+ case 'b':
3665+ block_only = atoll(optarg);
3666+ break;
3667 default:
3668 print_usage();
3669 }
3670@@ -142,14 +150,37 @@ int main(int ac, char **av)
3671 fprintf(stderr, "unable to open %s\n", av[optind]);
3672 exit(1);
3673 }
3674+ if (block_only) {
3675+ leaf = read_tree_block(root,
3676+ block_only,
3677+ root->leafsize, 0);
3678+
3679+ if (leaf && btrfs_header_level(leaf) != 0) {
3680+ free_extent_buffer(leaf);
3681+ leaf = NULL;
3682+ }
3683+
3684+ if (!leaf) {
3685+ leaf = read_tree_block(root,
3686+ block_only,
3687+ root->nodesize, 0);
3688+ }
3689+ if (!leaf) {
3690+ fprintf(stderr, "failed to read %llu\n", block_only);
3691+ return 0;
3692+ }
3693+ btrfs_print_tree(root, leaf, 0);
3694+ return 0;
3695+ }
3696+
3697 if (!extent_only) {
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);
3702
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);
3707 }
3708 tree_root_scan = root->fs_info->tree_root;
3709
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;
3716
3717 offset = btrfs_item_ptr_offset(leaf, slot);
3718 read_extent_buffer(leaf, &ri, offset, sizeof(ri));
3719@@ -188,8 +219,9 @@ again:
3720 printf("root");
3721 break;
3722 case BTRFS_EXTENT_TREE_OBJECTID:
3723- skip = 0;
3724- if (!extent_only)
3725+ if (!device_only)
3726+ skip = 0;
3727+ if (!extent_only && !device_only)
3728 printf("extent");
3729 break;
3730 case BTRFS_CHUNK_TREE_OBJECTID:
3731@@ -198,9 +230,8 @@ again:
3732 }
3733 break;
3734 case BTRFS_DEV_TREE_OBJECTID:
3735- if (!skip) {
3736- printf("device");
3737- }
3738+ skip = 0;
3739+ printf("device");
3740 break;
3741 case BTRFS_FS_TREE_OBJECTID:
3742 if (!skip) {
3743@@ -208,9 +239,8 @@ again:
3744 }
3745 break;
3746 case BTRFS_ROOT_TREE_DIR_OBJECTID:
3747- if (!skip) {
3748- printf("directory");
3749- }
3750+ skip = 0;
3751+ printf("directory");
3752 break;
3753 case BTRFS_CSUM_TREE_OBJECTID:
3754 if (!skip) {
3755@@ -256,13 +286,13 @@ again:
3756 printf("file");
3757 }
3758 }
3759- if (!skip && !extent_only) {
3760+ if (extent_only && !skip) {
3761+ print_extents(tree_root_scan, buf);
3762+ } else if (!skip) {
3763 printf(" tree ");
3764 btrfs_print_key(&disk_key);
3765 printf(" \n");
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);
3770 }
3771 }
3772 path.slots[0]++;
3773@@ -275,7 +305,7 @@ again:
3774 goto again;
3775 }
3776
3777- if (extent_only)
3778+ if (extent_only || device_only)
3779 return 0;
3780
3781 printf("total bytes %llu\n",
3782diff --git a/dir-test.c b/dir-test.c
3783index 44f2758..3ae9c68 100644
3784--- a/dir-test.c
3785+++ b/dir-test.c
3786@@ -485,7 +485,7 @@ int main(int ac, char **av)
3787 if (ret) {
3788 fprintf(stderr, "op %d failed %d:%d\n",
3789 op, i, iterations);
3790- btrfs_print_tree(root, root->node);
3791+ btrfs_print_tree(root, root->node, 1);
3792 fprintf(stderr, "op %d failed %d:%d\n",
3793 op, i, iterations);
3794 err = ret;
3795diff --git a/disk-io.c b/disk-io.c
3796index addebe1..a6e1000 100644
3797--- a/disk-io.c
3798+++ b/disk-io.c
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));
3805 free(result);
3806 return 1;
3807 }
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);
3811
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);
3820 }
3821
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);
3827diff --git a/ioctl-test.c b/ioctl-test.c
3828new file mode 100644
3829index 0000000..7cf3bc2
3830--- /dev/null
3831+++ b/ioctl-test.c
3832@@ -0,0 +1,36 @@
3833+#include <stdio.h>
3834+#include <stdlib.h>
3835+#include "kerncompat.h"
3836+#include "ioctl.h"
3837+
3838+unsigned long ioctls[] = {
3839+ BTRFS_IOC_SNAP_CREATE,
3840+ BTRFS_IOC_DEFRAG,
3841+ BTRFS_IOC_RESIZE,
3842+ BTRFS_IOC_SCAN_DEV,
3843+ BTRFS_IOC_TRANS_START,
3844+ BTRFS_IOC_TRANS_END,
3845+ BTRFS_IOC_SYNC,
3846+ BTRFS_IOC_CLONE,
3847+ BTRFS_IOC_ADD_DEV,
3848+ BTRFS_IOC_RM_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,
3857+ 0 };
3858+
3859+int main(int ac, char **av)
3860+{
3861+ int i = 0;
3862+ while(ioctls[i]) {
3863+ printf("%lu\n" ,ioctls[i]);
3864+ i++;
3865+ }
3866+ return 0;
3867+}
3868+
3869diff --git a/ioctl.h b/ioctl.h
3870index a084f33..776d7a9 100644
3871--- a/ioctl.h
3872+++ b/ioctl.h
3873@@ -30,6 +30,108 @@ struct btrfs_ioctl_vol_args {
3874 char name[BTRFS_PATH_NAME_MAX + 1];
3875 };
3876
3877+struct btrfs_ioctl_search_key {
3878+ /* which root are we searching. 0 is the tree of tree roots */
3879+ __u64 tree_id;
3880+
3881+ /* keys returned will be >= min and <= max */
3882+ __u64 min_objectid;
3883+ __u64 max_objectid;
3884+
3885+ /* keys returned will be >= min and <= max */
3886+ __u64 min_offset;
3887+ __u64 max_offset;
3888+
3889+ /* max and min transids to search for */
3890+ __u64 min_transid;
3891+ __u64 max_transid;
3892+
3893+ /* keys returned will be >= min and <= max */
3894+ __u32 min_type;
3895+ __u32 max_type;
3896+
3897+ /*
3898+ * how many items did userland ask for, and how many are we
3899+ * returning
3900+ */
3901+ __u32 nr_items;
3902+
3903+ /* align to 64 bits */
3904+ __u32 unused;
3905+
3906+ /* some extra for later */
3907+ __u64 unused1;
3908+ __u64 unused2;
3909+ __u64 unused3;
3910+ __u64 unused4;
3911+};
3912+
3913+struct btrfs_ioctl_search_header {
3914+ __u64 transid;
3915+ __u64 objectid;
3916+ __u64 offset;
3917+ __u32 type;
3918+ __u32 len;
3919+} __attribute__((may_alias));
3920+
3921+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
3922+/*
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
3926+ */
3927+struct btrfs_ioctl_search_args {
3928+ struct btrfs_ioctl_search_key key;
3929+ char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
3930+};
3931+
3932+#define BTRFS_INO_LOOKUP_PATH_MAX 4080
3933+struct btrfs_ioctl_ino_lookup_args {
3934+ __u64 treeid;
3935+ __u64 objectid;
3936+ char name[BTRFS_INO_LOOKUP_PATH_MAX];
3937+};
3938+
3939+/* flags for the defrag range ioctl */
3940+#define BTRFS_DEFRAG_RANGE_COMPRESS 1
3941+#define BTRFS_DEFRAG_RANGE_START_IO 2
3942+
3943+struct btrfs_ioctl_defrag_range_args {
3944+ /* start of the defrag operation */
3945+ __u64 start;
3946+
3947+ /* number of bytes to defrag, use (u64)-1 to say all */
3948+ __u64 len;
3949+
3950+ /*
3951+ * flags for the operation, which can include turning
3952+ * on compression for this one defrag
3953+ */
3954+ __u64 flags;
3955+
3956+ /*
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
3960+ */
3961+ __u32 extent_thresh;
3962+
3963+ /* spare for later */
3964+ __u32 unused[5];
3965+};
3966+
3967+struct btrfs_ioctl_space_info {
3968+ __u64 flags;
3969+ __u64 total_bytes;
3970+ __u64 used_bytes;
3971+};
3972+
3973+struct btrfs_ioctl_space_args {
3974+ __u64 space_slots;
3975+ __u64 total_spaces;
3976+ struct btrfs_ioctl_space_info spaces[0];
3977+};
3978+
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)
3997 #endif
3998diff --git a/kerncompat.h b/kerncompat.h
3999index e4c8ce0..46236cd 100644
4000--- a/kerncompat.h
4001+++ b/kerncompat.h
4002@@ -42,7 +42,11 @@
4003 #define GFP_NOFS 0
4004 #define __read_mostly
4005 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
4006+
4007+#ifndef ULONG_MAX
4008 #define ULONG_MAX (~0UL)
4009+#endif
4010+
4011 #define BUG() abort()
4012 #ifdef __CHECKER__
4013 #define __force __attribute__((force))
4014diff --git a/man/Makefile b/man/Makefile
4015index 4e8893b..4a90b75 100644
4016--- a/man/Makefile
4017+++ b/man/Makefile
4018@@ -7,13 +7,16 @@ mandir = $(prefix)/man
4019 man8dir = $(mandir)/man8
4020
4021 MANPAGES = mkfs.btrfs.8.gz btrfsctl.8.gz btrfsck.8.gz btrfs-image.8.gz \
4022- btrfs-show.8.gz
4023+ btrfs-show.8.gz btrfs.8.gz
4024
4025 all: $(MANPAGES)
4026
4027 mkfs.btrfs.8.gz: mkfs.btrfs.8.in
4028 $(GZIP) -n -c mkfs.btrfs.8.in > mkfs.btrfs.8.gz
4029
4030+btrfs.8.gz: btrfs.8.in
4031+ $(GZIP) -n -c btrfs.8.in > btrfs.8.gz
4032+
4033 btrfsctl.8.gz: btrfsctl.8.in
4034 $(GZIP) -n -c btrfsctl.8.in > btrfsctl.8.gz
4035
4036diff --git a/man/btrfs.8.in b/man/btrfs.8.in
4037new file mode 100644
4038index 0000000..26ef982
4039--- /dev/null
4040+++ b/man/btrfs.8.in
4041@@ -0,0 +1,170 @@
4042+.TH BTRFS 8 "" "btrfs" "btrfs"
4043+.\"
4044+.\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
4045+.\"
4046+.SH NAME
4047+btrfs \- control a btrfs filesystem
4048+.SH SYNOPSIS
4049+\fBbtrfs\fP \fBsubvolume snapshot\fP\fI <source> [<dest>/]<name>\fP
4050+.PP
4051+\fBbtrfs\fP \fBsubvolume delete\fP\fI <subvolume>\fP
4052+.PP
4053+\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
4054+.PP
4055+\fBbtrfs\fP \fBsubvolume list\fP\fI <path>\fP
4056+.PP
4057+\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
4058+.PP
4059+\fBbtrfs\fP \fBfilesystem defrag\fP\fI <file>|<dir> [<file>|<dir>...]\fP
4060+.PP
4061+\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
4062+.PP
4063+\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
4064+.PP
4065+\fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
4066+.PP
4067+\fBbtrfs\fP \fBdevice show\fP\fI <dev>|<label> [<dev>|<label>...]\fP
4068+.PP
4069+\fBbtrfs\fP \fBdevice balance\fP\fI <path> \fP
4070+.PP
4071+\fBbtrfs\fP \fBdevice add\fP\fI <dev> [<dev>..] <path> \fP
4072+.PP
4073+\fBbtrfs\fP \fBdevice delete\fP\fI <dev> [<dev>..] <path> \fP]
4074+
4075+.PP
4076+\fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
4077+.PP
4078+.SH DESCRIPTION
4079+.B btrfs
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.
4084+
4085+It is possible to abbreviate the commands unless the commands are ambiguous.
4086+For example: it is possible to run
4087+.I btrfs sub snaps
4088+instead of
4089+.I btrfs subvolume snapshot.
4090+But
4091+.I btrfs dev s
4092+is not allowed, because
4093+.I dev s
4094+may be interpreted both as
4095+.I device show
4096+and as
4097+.I device scan.
4098+In this case
4099+.I btrfs
4100+returns an error.
4101+
4102+If a command is terminated by
4103+.I --help
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
4108+.I device*
4109+command.
4110+
4111+.SH COMMANDS
4112+.TP
4113+
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.
4118+.TP
4119+
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.
4123+.TP
4124+
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).
4128+.TP
4129+
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.
4138+.TP
4139+
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.
4144+.TP
4145+
4146+\fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fR
4147+Defragment files and/or directories.
4148+.TP
4149+
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.
4153+.TP
4154+
4155+\fBfilesystem sync\fR\fI <path> \fR
4156+Force a sync for the filesystem identified by \fI<path>\fR.
4157+.TP
4158+
4159+.\"
4160+.\" Some wording are extracted by the resize2fs man page
4161+.\"
4162+
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,
4171+respectively.
4172+
4173+If 'max' is passed, the filesystem will occupy all available space on the
4174+volume(s).
4175+
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.
4180+.TP
4181+
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.
4185+.TP
4186+
4187+\fBdevice balance\fR \fI<path>\fR
4188+Balance the chunks of the filesystem identified by \fI<path>\fR
4189+across the devices.
4190+.TP
4191+
4192+\fBdevice add\fR\fI <dev> [<dev>..] <path>\fR
4193+Add device(s) to the filesystem identified by \fI<path>\fR.
4194+.TP
4195+
4196+\fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
4197+Remove device(s) from a filesystem identified by \fI<path>\fR.
4198+.PP
4199+
4200+.SH EXIT STATUS
4201+\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
4202+case of failure.
4203+
4204+.SH AVAILABILITY
4205+.B btrfs
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
4209+further details.
4210+.SH SEE ALSO
4211+.BR mkfs.btrfs (8)
4212diff --git a/print-tree.c b/print-tree.c
4213index 59f4358..ac575d5 100644
4214--- a/print-tree.c
4215+++ b/print-tree.c
4216@@ -413,8 +413,11 @@ static void print_objectid(unsigned long long objectid, u8 type)
4217 printf("MULTIPLE");
4218 break;
4219 case BTRFS_FIRST_CHUNK_TREE_OBJECTID:
4220- printf("FIRST_CHUNK_TREE");
4221- break;
4222+ if (type == BTRFS_CHUNK_ITEM_KEY) {
4223+ printf("FIRST_CHUNK_TREE");
4224+ break;
4225+ }
4226+ /* fall-thru */
4227 default:
4228 printf("%llu", objectid);
4229 }
4230@@ -607,7 +610,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
4231 }
4232 }
4233
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)
4236 {
4237 int i;
4238 u32 nr;
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));
4241 fflush(stdout);
4242 }
4243+ if (!follow)
4244+ return;
4245+
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)
4252 BUG();
4253- btrfs_print_tree(root, next);
4254+ btrfs_print_tree(root, next, 1);
4255 free_extent_buffer(next);
4256 }
4257 }
4258-
4259diff --git a/print-tree.h b/print-tree.h
4260index 4d1a01a..495b81a 100644
4261--- a/print-tree.h
4262+++ b/print-tree.h
4263@@ -19,6 +19,6 @@
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);
4270 #endif
4271diff --git a/quick-test.c b/quick-test.c
4272index 351c706..fa6fd83 100644
4273--- a/quick-test.c
4274+++ b/quick-test.c
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);
4278 if (ret) {
4279- btrfs_print_tree(root, root->node);
4280+ btrfs_print_tree(root, root->node, 1);
4281 printf("unable to find %d\n", num);
4282 exit(1);
4283 }
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);
4287 if (ret) {
4288- btrfs_print_tree(root, root->node);
4289+ btrfs_print_tree(root, root->node, 1);
4290 printf("unable to find %d\n", num);
4291 exit(1);
4292 }
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);
4299 close_ctree(root);
4300 return 0;
4301 }
4302diff --git a/random-test.c b/random-test.c
4303index 571735d..0003236 100644
4304--- a/random-test.c
4305+++ b/random-test.c
4306@@ -404,7 +404,7 @@ int main(int ac, char **av)
4307 if (ret) {
4308 fprintf(stderr, "op %d failed %d:%d\n",
4309 op, i, iterations);
4310- btrfs_print_tree(root, root->node);
4311+ btrfs_print_tree(root, root->node, 1);
4312 fprintf(stderr, "op %d failed %d:%d\n",
4313 op, i, iterations);
4314 err = ret;
4315diff --git a/utils.c b/utils.c
4316index 2f4c6e1..fd894f3 100644
4317--- a/utils.c
4318+++ b/utils.c
4319@@ -31,6 +31,10 @@
4320 #include <fcntl.h>
4321 #include <unistd.h>
4322 #include <mntent.h>
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"
4329 #include "ctree.h"
4330@@ -586,55 +590,224 @@ error:
4331 return ret;
4332 }
4333
4334+/* checks if a device is a loop device */
4335+int is_loop_device (const char* device) {
4336+ struct stat statbuf;
4337+
4338+ if(stat(device, &statbuf) < 0)
4339+ return -errno;
4340+
4341+ return (S_ISBLK(statbuf.st_mode) &&
4342+ MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
4343+}
4344+
4345+
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)
4349+{
4350+ int loop_fd;
4351+ int ret_ioctl;
4352+ struct loop_info loopinfo;
4353+
4354+ if ((loop_fd = open(loop_dev, O_RDONLY)) < 0)
4355+ return -errno;
4356+
4357+ ret_ioctl = ioctl(loop_fd, LOOP_GET_STATUS, &loopinfo);
4358+ close(loop_fd);
4359+
4360+ if (ret_ioctl == 0)
4361+ strncpy(loop_file, loopinfo.lo_name, max_len);
4362+ else
4363+ return -errno;
4364+
4365+ return 0;
4366+}
4367+
4368+/* Checks whether a and b are identical or device
4369+ * files associated with the same block device
4370+ */
4371+int is_same_blk_file(const char* a, const char* b)
4372+{
4373+ struct stat st_buf_a, st_buf_b;
4374+ char real_a[PATH_MAX];
4375+ char real_b[PATH_MAX];
4376+
4377+ if(!realpath(a, real_a) ||
4378+ !realpath(b, real_b))
4379+ {
4380+ return -errno;
4381+ }
4382+
4383+ /* Identical path? */
4384+ if(strcmp(real_a, real_b) == 0)
4385+ return 1;
4386+
4387+ if(stat(a, &st_buf_a) < 0 ||
4388+ stat(b, &st_buf_b) < 0)
4389+ {
4390+ return -errno;
4391+ }
4392+
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)
4397+ {
4398+ return 1;
4399+ }
4400+
4401+ /* Hardlink? */
4402+ if (st_buf_a.st_dev == st_buf_b.st_dev &&
4403+ st_buf_a.st_ino == st_buf_b.st_ino)
4404+ {
4405+ return 1;
4406+ }
4407+
4408+ return 0;
4409+}
4410+
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
4414+ * file.
4415+ */
4416+int is_same_loop_file(const char* a, const char* b)
4417+{
4418+ char res_a[PATH_MAX];
4419+ char res_b[PATH_MAX];
4420+ const char* final_a;
4421+ const char* final_b;
4422+ int ret;
4423+
4424+ /* Resolve a if it is a loop device */
4425+ if((ret = is_loop_device(a)) < 0) {
4426+ return ret;
4427+ } else if(ret) {
4428+ if((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
4429+ return ret;
4430+
4431+ final_a = res_a;
4432+ } else {
4433+ final_a = a;
4434+ }
4435+
4436+ /* Resolve b if it is a loop device */
4437+ if((ret = is_loop_device(b)) < 0) {
4438+ return ret;
4439+ } else if(ret) {
4440+ if((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0)
4441+ return ret;
4442+
4443+ final_b = res_b;
4444+ } else {
4445+ final_b = b;
4446+ }
4447+
4448+ return is_same_blk_file(final_a, final_b);
4449+}
4450+
4451+/* Checks if a file exists and is a block or regular file*/
4452+int is_existing_blk_or_reg_file(const char* filename)
4453+{
4454+ struct stat st_buf;
4455+
4456+ if(stat(filename, &st_buf) < 0) {
4457+ if(errno == ENOENT)
4458+ return 0;
4459+ else
4460+ return -errno;
4461+ }
4462+
4463+ return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode));
4464+}
4465+
4466+/* Checks if a file is used (directly or indirectly via a loop device)
4467+ * by a device in fs_devices
4468+ */
4469+int blk_file_in_dev_list(struct btrfs_fs_devices* fs_devices, const char* file)
4470+{
4471+ int ret;
4472+ struct list_head *head;
4473+ struct list_head *cur;
4474+ struct btrfs_device *device;
4475+
4476+ head = &fs_devices->devices;
4477+ list_for_each(cur, head) {
4478+ device = list_entry(cur, struct btrfs_device, dev_list);
4479+
4480+ if((ret = is_same_loop_file(device->name, file)))
4481+ return ret;
4482+ }
4483+
4484+ return 0;
4485+}
4486+
4487 /*
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.
4491 */
4492-int check_mounted(char *file)
4493+int check_mounted(const char* file)
4494 {
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;
4500+ int ret;
4501+ int fd;
4502+ u64 total_devs = 1;
4503+ int is_btrfs;
4504+ struct btrfs_fs_devices* fs_devices_mnt = NULL;
4505 FILE *f;
4506- int ret = 0;
4507+ struct mntent *mnt;
4508
4509- if ((f = setmntent ("/proc/mounts", "r")) == NULL)
4510+ fd = open(file, O_RDONLY);
4511+ if (fd < 0) {
4512+ fprintf (stderr, "check_mounted(): Could not open %s\n", file);
4513 return -errno;
4514+ }
4515
4516- if (stat(file, &st_buf) < 0) {
4517- return -errno;
4518- } else {
4519- if (S_ISBLK(st_buf.st_mode)) {
4520- file_rdev = st_buf.st_rdev;
4521- } else {
4522- file_dev = st_buf.st_dev;
4523- file_ino = st_buf.st_ino;
4524- }
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);
4529+ close(fd);
4530+
4531+ /* scan other devices */
4532+ if (is_btrfs && total_devs > 1) {
4533+ if((ret = btrfs_scan_for_fsid(fs_devices_mnt, total_devs, 1)))
4534+ return ret;
4535 }
4536
4537+ /* iterate over the list of currently mountes filesystems */
4538+ if ((f = setmntent ("/proc/mounts", "r")) == NULL)
4539+ return -errno;
4540+
4541 while ((mnt = getmntent (f)) != NULL) {
4542- if (strcmp(file, mnt->mnt_fsname) == 0)
4543- break;
4544+ if(is_btrfs) {
4545+ if(strcmp(mnt->mnt_type, "btrfs") != 0)
4546+ continue;
4547
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))
4551- break;
4552- } else if (file_dev && ((file_dev == st_buf.st_dev) &&
4553- (file_ino == st_buf.st_ino))) {
4554- break;
4555- }
4556+ ret = blk_file_in_dev_list(fs_devices_mnt, mnt->mnt_fsname);
4557+ } else {
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;
4562+ else if(!ret)
4563+ continue;
4564+
4565+ ret = is_same_loop_file(file, mnt->mnt_fsname);
4566 }
4567- }
4568
4569- if (mnt) {
4570- /* found an entry in mnt table */
4571- ret = 1;
4572+ if(ret < 0)
4573+ goto out_mntloop_err;
4574+ else if(ret)
4575+ break;
4576 }
4577
4578+ /* Did we find an entry in mnt table? */
4579+ ret = (mnt != NULL);
4580+
4581+out_mntloop_err:
4582 endmntent (f);
4583+
4584 return ret;
4585 }
4586
4587diff --git a/utils.h b/utils.h
4588index 7ff542b..9dce5b0 100644
4589--- a/utils.h
4590+++ b/utils.h
4591@@ -36,7 +36,7 @@ int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
4592 int run_ioctls);
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,
4598 int super_offset);
4599 char *pretty_sizes(u64 size);