]> git.pld-linux.org Git - packages/btrfs-progs.git/blame - btrfs-progs-upstream.patch
- add patches from fedora
[packages/btrfs-progs.git] / btrfs-progs-upstream.patch
CommitLineData
45019325 1diff --git a/Makefile b/Makefile
2index 8097b5a..525676e 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@@ -56,6 +62,9 @@ btrfs-debug-tree: $(objects) debug-tree.o
37 btrfstune: $(objects) btrfstune.o
38 gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
39
40+btrfs-map-logical: $(objects) btrfs-map-logical.o
41+ gcc $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS)
42+
43 btrfs-image: $(objects) btrfs-image.o
44 gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS)
45
46@@ -68,6 +77,9 @@ quick-test: $(objects) quick-test.o
47 convert: $(objects) convert.o
48 gcc $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs $(LDFLAGS) $(LIBS)
49
50+ioctl-test: $(objects) ioctl-test.o
51+ gcc $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS)
52+
53 manpages:
54 cd man; make
55
56diff --git a/btrfs-defrag.c b/btrfs-defrag.c
57new file mode 100644
58index 0000000..8f1525a
59--- /dev/null
60+++ b/btrfs-defrag.c
61@@ -0,0 +1,39 @@
62+/*
63+ * Copyright (C) 2010 Oracle. All rights reserved.
64+ *
65+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public
67+ * License v2 as published by the Free Software Foundation.
68+ *
69+ * This program is distributed in the hope that it will be useful,
70+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
71+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
72+ * General Public License for more details.
73+ *
74+ * You should have received a copy of the GNU General Public
75+ * License along with this program; if not, write to the
76+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
77+ * Boston, MA 021110-1307, USA.
78+ */
79+
80+#ifndef __CHECKER__
81+#include <sys/ioctl.h>
82+#include <sys/mount.h>
83+#include "ioctl.h"
84+#endif
85+#include <stdio.h>
86+#include <stdlib.h>
87+#include <sys/types.h>
88+#include <sys/stat.h>
89+#include <fcntl.h>
90+#include <ctype.h>
91+#include <unistd.h>
92+#include <dirent.h>
93+#include <libgen.h>
94+#include <getopt.h>
95+#include "kerncompat.h"
96+#include "ctree.h"
97+#include "transaction.h"
98+#include "utils.h"
99+#include "version.h"
100+
101diff --git a/btrfs-list.c b/btrfs-list.c
102new file mode 100644
103index 0000000..7741705
104--- /dev/null
105+++ b/btrfs-list.c
106@@ -0,0 +1,825 @@
107+/*
108+ * Copyright (C) 2010 Oracle. All rights reserved.
109+ *
110+ * This program is free software; you can redistribute it and/or
111+ * modify it under the terms of the GNU General Public
112+ * License v2 as published by the Free Software Foundation.
113+ *
114+ * This program is distributed in the hope that it will be useful,
115+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
116+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
117+ * General Public License for more details.
118+ *
119+ * You should have received a copy of the GNU General Public
120+ * License along with this program; if not, write to the
121+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
122+ * Boston, MA 021110-1307, USA.
123+ */
124+
125+#ifndef __CHECKER__
126+#include <sys/ioctl.h>
127+#include <sys/mount.h>
128+#include "ioctl.h"
129+#endif
130+#include <stdio.h>
131+#include <stdlib.h>
132+#include <sys/types.h>
133+#include <sys/stat.h>
134+#include <fcntl.h>
135+#include <unistd.h>
136+#include <dirent.h>
137+#include <libgen.h>
138+#include "kerncompat.h"
139+#include "ctree.h"
140+#include "transaction.h"
141+#include "utils.h"
142+#include "version.h"
143+
144+/* we store all the roots we find in an rbtree so that we can
145+ * search for them later.
146+ */
147+struct root_lookup {
148+ struct rb_root root;
149+};
150+
151+/*
152+ * one of these for each root we find.
153+ */
154+struct root_info {
155+ struct rb_node rb_node;
156+
157+ /* this root's id */
158+ u64 root_id;
159+
160+ /* the id of the root that references this one */
161+ u64 ref_tree;
162+
163+ /* the dir id we're in from ref_tree */
164+ u64 dir_id;
165+
166+ /* path from the subvol we live in to this root, including the
167+ * root's name. This is null until we do the extra lookup ioctl.
168+ */
169+ char *path;
170+
171+ /* the name of this root in the directory it lives in */
172+ char name[];
173+};
174+
175+static void root_lookup_init(struct root_lookup *tree)
176+{
177+ tree->root.rb_node = NULL;
178+}
179+
180+static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree)
181+{
182+ if (entry->root_id > root_id)
183+ return 1;
184+ if (entry->root_id < root_id)
185+ return -1;
186+ if (entry->ref_tree > ref_tree)
187+ return 1;
188+ if (entry->ref_tree < ref_tree)
189+ return -1;
190+ return 0;
191+}
192+
193+/*
194+ * insert a new root into the tree. returns the existing root entry
195+ * if one is already there. Both root_id and ref_tree are used
196+ * as the key
197+ */
198+static struct rb_node *tree_insert(struct rb_root *root, u64 root_id,
199+ u64 ref_tree, struct rb_node *node)
200+{
201+ struct rb_node ** p = &root->rb_node;
202+ struct rb_node * parent = NULL;
203+ struct root_info *entry;
204+ int comp;
205+
206+ while(*p) {
207+ parent = *p;
208+ entry = rb_entry(parent, struct root_info, rb_node);
209+
210+ comp = comp_entry(entry, root_id, ref_tree);
211+
212+ if (comp < 0)
213+ p = &(*p)->rb_left;
214+ else if (comp > 0)
215+ p = &(*p)->rb_right;
216+ else
217+ return parent;
218+ }
219+
220+ entry = rb_entry(parent, struct root_info, rb_node);
221+ rb_link_node(node, parent, p);
222+ rb_insert_color(node, root);
223+ return NULL;
224+}
225+
226+/*
227+ * find a given root id in the tree. We return the smallest one,
228+ * rb_next can be used to move forward looking for more if required
229+ */
230+static struct root_info *tree_search(struct rb_root *root, u64 root_id)
231+{
232+ struct rb_node * n = root->rb_node;
233+ struct root_info *entry;
234+
235+ while(n) {
236+ entry = rb_entry(n, struct root_info, rb_node);
237+
238+ if (entry->root_id < root_id)
239+ n = n->rb_left;
240+ else if (entry->root_id > root_id)
241+ n = n->rb_right;
242+ else {
243+ struct root_info *prev;
244+ struct rb_node *prev_n;
245+ while (1) {
246+ prev_n = rb_prev(n);
247+ if (!prev_n)
248+ break;
249+ prev = rb_entry(prev_n, struct root_info,
250+ rb_node);
251+ if (prev->root_id != root_id)
252+ break;
253+ entry = prev;
254+ n = prev_n;
255+ }
256+ return entry;
257+ }
258+ }
259+ return NULL;
260+}
261+
262+/*
263+ * this allocates a new root in the lookup tree.
264+ *
265+ * root_id should be the object id of the root
266+ *
267+ * ref_tree is the objectid of the referring root.
268+ *
269+ * dir_id is the directory in ref_tree where this root_id can be found.
270+ *
271+ * name is the name of root_id in that directory
272+ *
273+ * name_len is the length of name
274+ */
275+static int add_root(struct root_lookup *root_lookup,
276+ u64 root_id, u64 ref_tree, u64 dir_id, char *name,
277+ int name_len)
278+{
279+ struct root_info *ri;
280+ struct rb_node *ret;
281+ ri = malloc(sizeof(*ri) + name_len + 1);
282+ if (!ri) {
283+ printf("memory allocation failed\n");
284+ exit(1);
285+ }
286+ memset(ri, 0, sizeof(*ri) + name_len + 1);
287+ ri->path = NULL;
288+ ri->dir_id = dir_id;
289+ ri->root_id = root_id;
290+ ri->ref_tree = ref_tree;
291+ strncpy(ri->name, name, name_len);
292+
293+ ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node);
294+ if (ret) {
295+ printf("failed to insert tree %llu\n", (unsigned long long)root_id);
296+ exit(1);
297+ }
298+ return 0;
299+}
300+
301+/*
302+ * for a given root_info, search through the root_lookup tree to construct
303+ * the full path name to it.
304+ *
305+ * This can't be called until all the root_info->path fields are filled
306+ * in by lookup_ino_path
307+ */
308+static int resolve_root(struct root_lookup *rl, struct root_info *ri)
309+{
310+ u64 top_id;
311+ char *full_path = NULL;
312+ int len = 0;
313+ struct root_info *found;
314+
315+ /*
316+ * we go backwards from the root_info object and add pathnames
317+ * from parent directories as we go.
318+ */
319+ found = ri;
320+ while (1) {
321+ char *tmp;
322+ u64 next;
323+ int add_len = strlen(found->path);
324+
325+ /* room for / and for null */
326+ tmp = malloc(add_len + 2 + len);
327+ if (full_path) {
328+ memcpy(tmp + add_len + 1, full_path, len);
329+ tmp[add_len] = '/';
330+ memcpy(tmp, found->path, add_len);
331+ tmp [add_len + len + 1] = '\0';
332+ free(full_path);
333+ full_path = tmp;
334+ len += add_len + 1;
335+ } else {
336+ full_path = strdup(found->path);
337+ len = add_len;
338+ }
339+
340+ next = found->ref_tree;
341+ /* if the ref_tree refers to ourselves, we're at the top */
342+ if (next == found->root_id) {
343+ top_id = next;
344+ break;
345+ }
346+
347+ /*
348+ * if the ref_tree wasn't in our tree of roots, we're
349+ * at the top
350+ */
351+ found = tree_search(&rl->root, next);
352+ if (!found) {
353+ top_id = next;
354+ break;
355+ }
356+ }
357+ printf("ID %llu top level %llu path %s\n", ri->root_id, top_id,
358+ full_path);
359+ free(full_path);
360+ return 0;
361+}
362+
363+/*
364+ * for a single root_info, ask the kernel to give us a path name
365+ * inside it's ref_root for the dir_id where it lives.
366+ *
367+ * This fills in root_info->path with the path to the directory and and
368+ * appends this root's name.
369+ */
370+static int lookup_ino_path(int fd, struct root_info *ri)
371+{
372+ struct btrfs_ioctl_ino_lookup_args args;
373+ int ret;
374+
375+ if (ri->path)
376+ return 0;
377+
378+ memset(&args, 0, sizeof(args));
379+ args.treeid = ri->ref_tree;
380+ args.objectid = ri->dir_id;
381+
382+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
383+ if (ret) {
384+ fprintf(stderr, "ERROR: Failed to lookup path for root %llu\n",
385+ (unsigned long long)ri->ref_tree);
386+ return ret;
387+ }
388+
389+ if (args.name[0]) {
390+ /*
391+ * we're in a subdirectory of ref_tree, the kernel ioctl
392+ * puts a / in there for us
393+ */
394+ ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1);
395+ if (!ri->path) {
396+ perror("malloc failed");
397+ exit(1);
398+ }
399+ strcpy(ri->path, args.name);
400+ strcat(ri->path, ri->name);
401+ } else {
402+ /* we're at the root of ref_tree */
403+ ri->path = strdup(ri->name);
404+ if (!ri->path) {
405+ perror("strdup failed");
406+ exit(1);
407+ }
408+ }
409+ return 0;
410+}
411+
412+/* finding the generation for a given path is a two step process.
413+ * First we use the inode loookup routine to find out the root id
414+ *
415+ * Then we use the tree search ioctl to scan all the root items for a
416+ * given root id and spit out the latest generation we can find
417+ */
418+static u64 find_root_gen(int fd)
419+{
420+ struct btrfs_ioctl_ino_lookup_args ino_args;
421+ int ret;
422+ struct btrfs_ioctl_search_args args;
423+ struct btrfs_ioctl_search_key *sk = &args.key;
424+ struct btrfs_ioctl_search_header *sh;
425+ unsigned long off = 0;
426+ u64 max_found = 0;
427+ int i;
428+
429+ memset(&ino_args, 0, sizeof(ino_args));
430+ ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID;
431+
432+ /* this ioctl fills in ino_args->treeid */
433+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args);
434+ if (ret) {
435+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
436+ (unsigned long long)BTRFS_FIRST_FREE_OBJECTID);
437+ return 0;
438+ }
439+
440+ memset(&args, 0, sizeof(args));
441+
442+ sk->tree_id = 1;
443+
444+ /*
445+ * there may be more than one ROOT_ITEM key if there are
446+ * snapshots pending deletion, we have to loop through
447+ * them.
448+ */
449+ sk->min_objectid = ino_args.treeid;
450+ sk->max_objectid = ino_args.treeid;
451+ sk->max_type = BTRFS_ROOT_ITEM_KEY;
452+ sk->min_type = BTRFS_ROOT_ITEM_KEY;
453+ sk->max_offset = (u64)-1;
454+ sk->max_transid = (u64)-1;
455+ sk->nr_items = 4096;
456+
457+ while (1) {
458+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
459+ if (ret < 0) {
460+ fprintf(stderr, "ERROR: can't perform the search\n");
461+ return 0;
462+ }
463+ /* the ioctl returns the number of item it found in nr_items */
464+ if (sk->nr_items == 0)
465+ break;
466+
467+ off = 0;
468+ for (i = 0; i < sk->nr_items; i++) {
469+ struct btrfs_root_item *item;
470+ sh = (struct btrfs_ioctl_search_header *)(args.buf +
471+ off);
472+
473+ off += sizeof(*sh);
474+ item = (struct btrfs_root_item *)(args.buf + off);
475+ off += sh->len;
476+
477+ sk->min_objectid = sh->objectid;
478+ sk->min_type = sh->type;
479+ sk->min_offset = sh->offset;
480+
481+ if (sh->objectid > ino_args.treeid)
482+ break;
483+
484+ if (sh->objectid == ino_args.treeid &&
485+ sh->type == BTRFS_ROOT_ITEM_KEY) {
486+ max_found = max(max_found,
487+ btrfs_root_generation(item));
488+ }
489+ }
490+ if (sk->min_offset < (u64)-1)
491+ sk->min_offset++;
492+ else
493+ break;
494+
495+ if (sk->min_type != BTRFS_ROOT_ITEM_KEY)
496+ break;
497+ if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY)
498+ break;
499+ }
500+ return max_found;
501+}
502+
503+/* pass in a directory id and this will return
504+ * the full path of the parent directory inside its
505+ * subvolume root.
506+ *
507+ * It may return NULL if it is in the root, or an ERR_PTR if things
508+ * go badly.
509+ */
510+static char *__ino_resolve(int fd, u64 dirid)
511+{
512+ struct btrfs_ioctl_ino_lookup_args args;
513+ int ret;
514+ char *full;
515+
516+ memset(&args, 0, sizeof(args));
517+ args.objectid = dirid;
518+
519+ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
520+ if (ret) {
521+ fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu\n",
522+ (unsigned long long)dirid);
523+ return ERR_PTR(ret);
524+ }
525+
526+ if (args.name[0]) {
527+ /*
528+ * we're in a subdirectory of ref_tree, the kernel ioctl
529+ * puts a / in there for us
530+ */
531+ full = strdup(args.name);
532+ if (!full) {
533+ perror("malloc failed");
534+ return ERR_PTR(-ENOMEM);
535+ }
536+ } else {
537+ /* we're at the root of ref_tree */
538+ full = NULL;
539+ }
540+ return full;
541+}
542+
543+/*
544+ * simple string builder, returning a new string with both
545+ * dirid and name
546+ */
547+char *build_name(char *dirid, char *name)
548+{
549+ char *full;
550+ if (!dirid)
551+ return strdup(name);
552+
553+ full = malloc(strlen(dirid) + strlen(name) + 1);
554+ if (!full)
555+ return NULL;
556+ strcpy(full, dirid);
557+ strcat(full, name);
558+ return full;
559+}
560+
561+/*
562+ * given an inode number, this returns the full path name inside the subvolume
563+ * to that file/directory. cache_dirid and cache_name are used to
564+ * cache the results so we can avoid tree searches if a later call goes
565+ * to the same directory or file name
566+ */
567+static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name)
568+
569+{
570+ u64 dirid;
571+ char *dirname;
572+ char *name;
573+ char *full;
574+ int ret;
575+ struct btrfs_ioctl_search_args args;
576+ struct btrfs_ioctl_search_key *sk = &args.key;
577+ struct btrfs_ioctl_search_header *sh;
578+ unsigned long off = 0;
579+ int namelen;
580+
581+ memset(&args, 0, sizeof(args));
582+
583+ sk->tree_id = 0;
584+
585+ /*
586+ * step one, we search for the inode back ref. We just use the first
587+ * one
588+ */
589+ sk->min_objectid = ino;
590+ sk->max_objectid = ino;
591+ sk->max_type = BTRFS_INODE_REF_KEY;
592+ sk->max_offset = (u64)-1;
593+ sk->min_type = BTRFS_INODE_REF_KEY;
594+ sk->max_transid = (u64)-1;
595+ sk->nr_items = 1;
596+
597+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
598+ if (ret < 0) {
599+ fprintf(stderr, "ERROR: can't perform the search\n");
600+ return NULL;
601+ }
602+ /* the ioctl returns the number of item it found in nr_items */
603+ if (sk->nr_items == 0)
604+ return NULL;
605+
606+ off = 0;
607+ sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
608+
609+ if (sh->type == BTRFS_INODE_REF_KEY) {
610+ struct btrfs_inode_ref *ref;
611+ dirid = sh->offset;
612+
613+ ref = (struct btrfs_inode_ref *)(sh + 1);
614+ namelen = btrfs_stack_inode_ref_name_len(ref);
615+
616+ name = (char *)(ref + 1);
617+ name = strndup(name, namelen);
618+
619+ /* use our cached value */
620+ if (dirid == *cache_dirid && *cache_name) {
621+ dirname = *cache_name;
622+ goto build;
623+ }
624+ } else {
625+ return NULL;
626+ }
627+ /*
628+ * the inode backref gives us the file name and the parent directory id.
629+ * From here we use __ino_resolve to get the path to the parent
630+ */
631+ dirname = __ino_resolve(fd, dirid);
632+build:
633+ full = build_name(dirname, name);
634+ if (*cache_name && dirname != *cache_name)
635+ free(*cache_name);
636+
637+ *cache_name = dirname;
638+ *cache_dirid = dirid;
639+ free(name);
640+
641+ return full;
642+}
643+
644+int list_subvols(int fd)
645+{
646+ struct root_lookup root_lookup;
647+ struct rb_node *n;
648+ int ret;
649+ struct btrfs_ioctl_search_args args;
650+ struct btrfs_ioctl_search_key *sk = &args.key;
651+ struct btrfs_ioctl_search_header *sh;
652+ struct btrfs_root_ref *ref;
653+ unsigned long off = 0;
654+ int name_len;
655+ char *name;
656+ u64 dir_id;
657+ int i;
658+
659+ root_lookup_init(&root_lookup);
660+
661+ memset(&args, 0, sizeof(args));
662+
663+ /* search in the tree of tree roots */
664+ sk->tree_id = 1;
665+
666+ /*
667+ * set the min and max to backref keys. The search will
668+ * only send back this type of key now.
669+ */
670+ sk->max_type = BTRFS_ROOT_BACKREF_KEY;
671+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
672+
673+ /*
674+ * set all the other params to the max, we'll take any objectid
675+ * and any trans
676+ */
677+ sk->max_objectid = (u64)-1;
678+ sk->max_offset = (u64)-1;
679+ sk->max_transid = (u64)-1;
680+
681+ /* just a big number, doesn't matter much */
682+ sk->nr_items = 4096;
683+
684+ while(1) {
685+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
686+ if (ret < 0) {
687+ fprintf(stderr, "ERROR: can't perform the search\n");
688+ return ret;
689+ }
690+ /* the ioctl returns the number of item it found in nr_items */
691+ if (sk->nr_items == 0)
692+ break;
693+
694+ off = 0;
695+
696+ /*
697+ * for each item, pull the key out of the header and then
698+ * read the root_ref item it contains
699+ */
700+ for (i = 0; i < sk->nr_items; i++) {
701+ sh = (struct btrfs_ioctl_search_header *)(args.buf +
702+ off);
703+ off += sizeof(*sh);
704+ if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
705+ ref = (struct btrfs_root_ref *)(args.buf + off);
706+ name_len = btrfs_stack_root_ref_name_len(ref);
707+ name = (char *)(ref + 1);
708+ dir_id = btrfs_stack_root_ref_dirid(ref);
709+
710+ add_root(&root_lookup, sh->objectid, sh->offset,
711+ dir_id, name, name_len);
712+ }
713+
714+ off += sh->len;
715+
716+ /*
717+ * record the mins in sk so we can make sure the
718+ * next search doesn't repeat this root
719+ */
720+ sk->min_objectid = sh->objectid;
721+ sk->min_type = sh->type;
722+ sk->min_offset = sh->offset;
723+ }
724+ sk->nr_items = 4096;
725+ /* this iteration is done, step forward one root for the next
726+ * ioctl
727+ */
728+ if (sk->min_objectid < (u64)-1) {
729+ sk->min_objectid++;
730+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
731+ sk->min_offset = 0;
732+ } else
733+ break;
734+ }
735+ /*
736+ * now we have an rbtree full of root_info objects, but we need to fill
737+ * in their path names within the subvol that is referencing each one.
738+ */
739+ n = rb_first(&root_lookup.root);
740+ while (n) {
741+ struct root_info *entry;
742+ int ret;
743+ entry = rb_entry(n, struct root_info, rb_node);
744+ ret = lookup_ino_path(fd, entry);
745+ if(ret < 0)
746+ return ret;
747+ n = rb_next(n);
748+ }
749+
750+ /* now that we have all the subvol-relative paths filled in,
751+ * we have to string the subvols together so that we can get
752+ * a path all the way back to the FS root
753+ */
754+ n = rb_last(&root_lookup.root);
755+ while (n) {
756+ struct root_info *entry;
757+ entry = rb_entry(n, struct root_info, rb_node);
758+ resolve_root(&root_lookup, entry);
759+ n = rb_prev(n);
760+ }
761+
762+ return ret;
763+}
764+
765+static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh,
766+ struct btrfs_file_extent_item *item,
767+ u64 found_gen, u64 *cache_dirid,
768+ char **cache_dir_name, u64 *cache_ino,
769+ char **cache_full_name)
770+{
771+ u64 len;
772+ u64 disk_start;
773+ u64 disk_offset;
774+ u8 type;
775+ int compressed = 0;
776+ int flags = 0;
777+ char *name = NULL;
778+
779+ if (sh->objectid == *cache_ino) {
780+ name = *cache_full_name;
781+ } else if (*cache_full_name) {
782+ free(*cache_full_name);
783+ *cache_full_name = NULL;
784+ }
785+ if (!name) {
786+ name = ino_resolve(fd, sh->objectid, cache_dirid,
787+ cache_dir_name);
788+ *cache_full_name = name;
789+ *cache_ino = sh->objectid;
790+ }
791+ if (!name)
792+ return -EIO;
793+
794+ type = btrfs_stack_file_extent_type(item);
795+ compressed = btrfs_stack_file_extent_compression(item);
796+
797+ if (type == BTRFS_FILE_EXTENT_REG ||
798+ type == BTRFS_FILE_EXTENT_PREALLOC) {
799+ disk_start = btrfs_stack_file_extent_disk_bytenr(item);
800+ disk_offset = btrfs_stack_file_extent_offset(item);
801+ len = btrfs_stack_file_extent_num_bytes(item);
802+ } else if (type == BTRFS_FILE_EXTENT_INLINE) {
803+ disk_start = 0;
804+ disk_offset = 0;
805+ len = btrfs_stack_file_extent_ram_bytes(item);
806+ }
807+ printf("inode %llu file offset %llu len %llu disk start %llu "
808+ "offset %llu gen %llu flags ",
809+ (unsigned long long)sh->objectid,
810+ (unsigned long long)sh->offset,
811+ (unsigned long long)len,
812+ (unsigned long long)disk_start,
813+ (unsigned long long)disk_offset,
814+ (unsigned long long)found_gen);
815+
816+ if (compressed) {
817+ printf("COMPRESS");
818+ flags++;
819+ }
820+ if (type == BTRFS_FILE_EXTENT_PREALLOC) {
821+ printf("%sPREALLOC", flags ? "|" : "");
822+ flags++;
823+ }
824+ if (type == BTRFS_FILE_EXTENT_INLINE) {
825+ printf("%sINLINE", flags ? "|" : "");
826+ flags++;
827+ }
828+ if (!flags)
829+ printf("NONE");
830+
831+ printf(" %s\n", name);
832+ return 0;
833+}
834+
835+int find_updated_files(int fd, u64 root_id, u64 oldest_gen)
836+{
837+ int ret;
838+ struct btrfs_ioctl_search_args args;
839+ struct btrfs_ioctl_search_key *sk = &args.key;
840+ struct btrfs_ioctl_search_header *sh;
841+ struct btrfs_file_extent_item *item;
842+ unsigned long off = 0;
843+ u64 found_gen;
844+ u64 max_found = 0;
845+ int i;
846+ u64 cache_dirid = 0;
847+ u64 cache_ino = 0;
848+ char *cache_dir_name = NULL;
849+ char *cache_full_name = NULL;
850+ struct btrfs_file_extent_item backup;
851+
852+ memset(&backup, 0, sizeof(backup));
853+ memset(&args, 0, sizeof(args));
854+
855+ sk->tree_id = root_id;
856+
857+ /*
858+ * set all the other params to the max, we'll take any objectid
859+ * and any trans
860+ */
861+ sk->max_objectid = (u64)-1;
862+ sk->max_offset = (u64)-1;
863+ sk->max_transid = (u64)-1;
864+ sk->max_type = BTRFS_EXTENT_DATA_KEY;
865+ sk->min_transid = oldest_gen;
866+ /* just a big number, doesn't matter much */
867+ sk->nr_items = 4096;
868+
869+ max_found = find_root_gen(fd);
870+ while(1) {
871+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
872+ if (ret < 0) {
873+ fprintf(stderr, "ERROR: can't perform the search\n");
874+ return ret;
875+ }
876+ /* the ioctl returns the number of item it found in nr_items */
877+ if (sk->nr_items == 0)
878+ break;
879+
880+ off = 0;
881+
882+ /*
883+ * for each item, pull the key out of the header and then
884+ * read the root_ref item it contains
885+ */
886+ for (i = 0; i < sk->nr_items; i++) {
887+ sh = (struct btrfs_ioctl_search_header *)(args.buf +
888+ off);
889+ off += sizeof(*sh);
890+
891+ /*
892+ * just in case the item was too big, pass something other
893+ * than garbage
894+ */
895+ if (sh->len == 0)
896+ item = &backup;
897+ else
898+ item = (struct btrfs_file_extent_item *)(args.buf +
899+ off);
900+ found_gen = btrfs_stack_file_extent_generation(item);
901+ if (sh->type == BTRFS_EXTENT_DATA_KEY &&
902+ found_gen >= oldest_gen) {
903+ print_one_extent(fd, sh, item, found_gen,
904+ &cache_dirid, &cache_dir_name,
905+ &cache_ino, &cache_full_name);
906+ }
907+ off += sh->len;
908+
909+ /*
910+ * record the mins in sk so we can make sure the
911+ * next search doesn't repeat this root
912+ */
913+ sk->min_objectid = sh->objectid;
914+ sk->min_offset = sh->offset;
915+ sk->min_type = sh->type;
916+ }
917+ sk->nr_items = 4096;
918+ if (sk->min_offset < (u64)-1)
919+ sk->min_offset++;
920+ else if (sk->min_objectid < (u64)-1) {
921+ sk->min_objectid++;
922+ sk->min_offset = 0;
923+ sk->min_type = 0;
924+ } else
925+ break;
926+ }
927+ free(cache_dir_name);
928+ free(cache_full_name);
929+ printf("transid marker was %llu\n", (unsigned long long)max_found);
930+ return ret;
931+}
932diff --git a/btrfs-map-logical.c b/btrfs-map-logical.c
933new file mode 100644
934index 0000000..a109c6a
935--- /dev/null
936+++ b/btrfs-map-logical.c
937@@ -0,0 +1,221 @@
938+/*
939+ * Copyright (C) 2009 Oracle. All rights reserved.
940+ *
941+ * This program is free software; you can redistribute it and/or
942+ * modify it under the terms of the GNU General Public
943+ * License v2 as published by the Free Software Foundation.
944+ *
945+ * This program is distributed in the hope that it will be useful,
946+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
947+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
948+ * General Public License for more details.
949+ *
950+ * You should have received a copy of the GNU General Public
951+ * License along with this program; if not, write to the
952+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
953+ * Boston, MA 021110-1307, USA.
954+ */
955+
956+#define _XOPEN_SOURCE 500
957+#define _GNU_SOURCE 1
958+#include <stdio.h>
959+#include <stdlib.h>
960+#include <fcntl.h>
961+#include <unistd.h>
962+#include <getopt.h>
963+#include "kerncompat.h"
964+#include "ctree.h"
965+#include "volumes.h"
966+#include "disk-io.h"
967+#include "print-tree.h"
968+#include "transaction.h"
969+#include "list.h"
970+#include "version.h"
971+
972+/* we write the mirror info to stdout unless they are dumping the data
973+ * to stdout
974+ * */
975+static FILE *info_file;
976+
977+struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr,
978+ u32 blocksize, int copy)
979+{
980+ int ret;
981+ int dev_nr;
982+ struct extent_buffer *eb;
983+ u64 length;
984+ struct btrfs_multi_bio *multi = NULL;
985+ struct btrfs_device *device;
986+ int num_copies;
987+ int mirror_num = 1;
988+
989+ eb = btrfs_find_create_tree_block(root, bytenr, blocksize);
990+ if (!eb)
991+ return NULL;
992+
993+ dev_nr = 0;
994+ length = blocksize;
995+ while (1) {
996+ ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
997+ eb->start, &length, &multi, mirror_num);
998+ BUG_ON(ret);
999+ device = multi->stripes[0].dev;
1000+ eb->fd = device->fd;
1001+ device->total_ios++;
1002+ eb->dev_bytenr = multi->stripes[0].physical;
1003+
1004+ fprintf(info_file, "mirror %d logical %Lu physical %Lu "
1005+ "device %s\n", mirror_num, bytenr, eb->dev_bytenr,
1006+ device->name);
1007+ kfree(multi);
1008+
1009+ if (!copy || mirror_num == copy)
1010+ ret = read_extent_from_disk(eb);
1011+
1012+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
1013+ eb->start, eb->len);
1014+ if (num_copies == 1)
1015+ break;
1016+
1017+ mirror_num++;
1018+ if (mirror_num > num_copies)
1019+ break;
1020+ }
1021+ return eb;
1022+}
1023+
1024+static void print_usage(void)
1025+{
1026+ fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n");
1027+ fprintf(stderr, "\t-l Logical extent to map\n");
1028+ fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n");
1029+ fprintf(stderr, "\t-o Output file to hold the extent\n");
1030+ fprintf(stderr, "\t-s Number of bytes to read\n");
1031+ exit(1);
1032+}
1033+
1034+static struct option long_options[] = {
1035+ /* { "byte-count", 1, NULL, 'b' }, */
1036+ { "logical", 1, NULL, 'l' },
1037+ { "copy", 1, NULL, 'c' },
1038+ { "output", 1, NULL, 'c' },
1039+ { "bytes", 1, NULL, 'b' },
1040+ { 0, 0, 0, 0}
1041+};
1042+
1043+int main(int ac, char **av)
1044+{
1045+ struct cache_tree root_cache;
1046+ struct btrfs_root *root;
1047+ struct extent_buffer *eb;
1048+ char *dev;
1049+ char *output_file = NULL;
1050+ u64 logical = 0;
1051+ int ret = 0;
1052+ int option_index = 0;
1053+ int copy = 0;
1054+ u64 bytes = 0;
1055+ int out_fd = 0;
1056+ int err;
1057+
1058+ while(1) {
1059+ int c;
1060+ c = getopt_long(ac, av, "l:c:o:b:", long_options,
1061+ &option_index);
1062+ if (c < 0)
1063+ break;
1064+ switch(c) {
1065+ case 'l':
1066+ logical = atoll(optarg);
1067+ if (logical == 0) {
1068+ fprintf(stderr,
1069+ "invalid extent number\n");
1070+ print_usage();
1071+ }
1072+ break;
1073+ case 'c':
1074+ copy = atoi(optarg);
1075+ if (copy == 0) {
1076+ fprintf(stderr,
1077+ "invalid copy number\n");
1078+ print_usage();
1079+ }
1080+ break;
1081+ case 'b':
1082+ bytes = atoll(optarg);
1083+ if (bytes == 0) {
1084+ fprintf(stderr,
1085+ "invalid byte count\n");
1086+ print_usage();
1087+ }
1088+ break;
1089+ case 'o':
1090+ output_file = strdup(optarg);
1091+ break;
1092+ default:
1093+ print_usage();
1094+ }
1095+ }
1096+ ac = ac - optind;
1097+ if (ac == 0)
1098+ print_usage();
1099+ if (logical == 0)
1100+ print_usage();
1101+ if (copy < 0)
1102+ print_usage();
1103+
1104+ dev = av[optind];
1105+
1106+ radix_tree_init();
1107+ cache_tree_init(&root_cache);
1108+
1109+ root = open_ctree(dev, 0, 0);
1110+ if (!root) {
1111+ fprintf(stderr, "Open ctree failed\n");
1112+ exit(1);
1113+ }
1114+
1115+ if (output_file) {
1116+ if (strcmp(output_file, "-") == 0) {
1117+ out_fd = 1;
1118+ info_file = stderr;
1119+ } else {
1120+ out_fd = open(output_file, O_RDWR | O_CREAT, 0600);
1121+ if (out_fd < 0)
1122+ goto close;
1123+ err = ftruncate(out_fd, 0);
1124+ if (err) {
1125+ close(out_fd);
1126+ goto close;
1127+ }
1128+ info_file = stdout;
1129+ }
1130+ }
1131+
1132+ if (bytes == 0)
1133+ bytes = root->sectorsize;
1134+
1135+ bytes = (bytes + root->sectorsize - 1) / root->sectorsize;
1136+ bytes *= root->sectorsize;
1137+
1138+ while (bytes > 0) {
1139+ eb = debug_read_block(root, logical, root->sectorsize, copy);
1140+ if (eb && output_file) {
1141+ err = write(out_fd, eb->data, eb->len);
1142+ if (err < 0 || err != eb->len) {
1143+ fprintf(stderr, "output file write failed\n");
1144+ goto out_close_fd;
1145+ }
1146+ }
1147+ free_extent_buffer(eb);
1148+ logical += root->sectorsize;
1149+ bytes -= root->sectorsize;
1150+ }
1151+
1152+out_close_fd:
1153+ if (output_file && out_fd != 1)
1154+ close(out_fd);
1155+close:
1156+ close_ctree(root);
1157+ return ret;
1158+}
1159diff --git a/btrfs.c b/btrfs.c
1160new file mode 100644
1161index 0000000..ab5e57f
1162--- /dev/null
1163+++ b/btrfs.c
1164@@ -0,0 +1,387 @@
1165+/*
1166+ * This program is free software; you can redistribute it and/or
1167+ * modify it under the terms of the GNU General Public
1168+ * License v2 as published by the Free Software Foundation.
1169+ *
1170+ * This program is distributed in the hope that it will be useful,
1171+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1172+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1173+ * General Public License for more details.
1174+ *
1175+ * You should have received a copy of the GNU General Public
1176+ * License along with this program; if not, write to the
1177+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1178+ * Boston, MA 021110-1307, USA.
1179+ */
1180+
1181+
1182+#include <stdio.h>
1183+#include <stdlib.h>
1184+#include <string.h>
1185+
1186+#include "kerncompat.h"
1187+#include "btrfs_cmds.h"
1188+#include "version.h"
1189+
1190+typedef int (*CommandFunction)(int argc, char **argv);
1191+
1192+struct Command {
1193+ CommandFunction func; /* function which implements the command */
1194+ int nargs; /* if == 999, any number of arguments
1195+ if >= 0, number of arguments,
1196+ if < 0, _minimum_ number of arguments */
1197+ char *verb; /* verb */
1198+ char *help; /* help lines; form the 2nd onward they are
1199+ indented */
1200+
1201+ /* the following fields are run-time filled by the program */
1202+ char **cmds; /* array of subcommands */
1203+ int ncmds; /* number of subcommand */
1204+};
1205+
1206+static struct Command commands[] = {
1207+
1208+ /*
1209+ avoid short commands different for the case only
1210+ */
1211+ { do_clone, 2,
1212+ "subvolume snapshot", "<source> [<dest>/]<name>\n"
1213+ "Create a writable snapshot of the subvolume <source> with\n"
1214+ "the name <name> in the <dest> directory."
1215+ },
1216+ { do_delete_subvolume, 1,
1217+ "subvolume delete", "<subvolume>\n"
1218+ "Delete the subvolume <subvolume>."
1219+ },
1220+ { do_create_subvol, 1,
1221+ "subvolume create", "[<dest>/]<name>\n"
1222+ "Create a subvolume in <dest> (or the current directory if\n"
1223+ "not passed)."
1224+ },
1225+ { do_subvol_list, 1, "subvolume list", "<path>\n"
1226+ "List the snapshot/subvolume of a filesystem."
1227+ },
1228+ { do_find_newer, 2, "subvolume find-new", "<path> <last_gen>\n"
1229+ "List the recently modified files in a filesystem."
1230+ },
1231+ { do_defrag, -1,
1232+ "filesystem defragment", "[-vcf] [-s start] [-l len] [-t size] <file>|<dir> [<file>|<dir>...]\n"
1233+ "Defragment a file or a directory."
1234+ },
1235+ { do_set_default_subvol, 2,
1236+ "subvolume set-default", "<id> <path>\n"
1237+ "Set the subvolume of the filesystem <path> which will be mounted\n"
1238+ "as default."
1239+ },
1240+ { do_fssync, 1,
1241+ "filesystem sync", "<path>\n"
1242+ "Force a sync on the filesystem <path>."
1243+ },
1244+ { do_resize, 2,
1245+ "filesystem resize", "[+/-]<newsize>[gkm]|max <filesystem>\n"
1246+ "Resize the file system. If 'max' is passed, the filesystem\n"
1247+ "will occupe all available space on the device."
1248+ },
1249+ { do_show_filesystem, 999,
1250+ "filesystem show", "[<uuid>|<label>]\n"
1251+ "Show the info of a btrfs filesystem. If no <uuid> or <label>\n"
1252+ "is passed, info of all the btrfs filesystem are shown."
1253+ },
1254+ { do_df_filesystem, 1,
1255+ "filesystem df", "<path>\n"
1256+ "Show space usage information for a mount point\n."
1257+ },
1258+ { do_balance, 1,
1259+ "filesystem balance", "<path>\n"
1260+ "Balance the chunks across the device."
1261+ },
1262+ { do_scan,
1263+ 999, "device scan", "[<device> [<device>..]\n"
1264+ "Scan all device for or the passed device for a btrfs\n"
1265+ "filesystem."
1266+ },
1267+ { do_add_volume, -2,
1268+ "device add", "<dev> [<dev>..] <path>\n"
1269+ "Add a device to a filesystem."
1270+ },
1271+ { do_remove_volume, -2,
1272+ "device delete", "<dev> [<dev>..] <path>\n"
1273+ "Remove a device from a filesystem."
1274+ },
1275+ /* coming soon
1276+ { 2, "filesystem label", "<label> <path>\n"
1277+ "Set the label of a filesystem"
1278+ }
1279+ */
1280+ { 0, 0 , 0 }
1281+};
1282+
1283+static char *get_prgname(char *programname)
1284+{
1285+ char *np;
1286+ np = strrchr(programname,'/');
1287+ if(!np)
1288+ np = programname;
1289+ else
1290+ np++;
1291+
1292+ return np;
1293+}
1294+
1295+static void print_help(char *programname, struct Command *cmd)
1296+{
1297+ char *pc;
1298+
1299+ printf("\t%s %s ", programname, cmd->verb );
1300+
1301+ for(pc = cmd->help; *pc; pc++){
1302+ putchar(*pc);
1303+ if(*pc == '\n')
1304+ printf("\t\t");
1305+ }
1306+ putchar('\n');
1307+}
1308+
1309+static void help(char *np)
1310+{
1311+ struct Command *cp;
1312+
1313+ printf("Usage:\n");
1314+ for( cp = commands; cp->verb; cp++ )
1315+ print_help(np, cp);
1316+
1317+ printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np);
1318+ printf("\n%s\n", BTRFS_BUILD_VERSION);
1319+}
1320+
1321+static int split_command(char *cmd, char ***commands)
1322+{
1323+ int c, l;
1324+ char *p, *s;
1325+
1326+ for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){
1327+ if ( *p && *p != ' ' )
1328+ continue;
1329+
1330+ /* c + 2 so that we have room for the null */
1331+ (*commands) = realloc( (*commands), sizeof(char *)*(c + 2));
1332+ (*commands)[c] = strndup(s, l);
1333+ c++;
1334+ l = 0;
1335+ s = p+1;
1336+ if( !*p ) break;
1337+ }
1338+
1339+ (*commands)[c] = 0;
1340+ return c;
1341+}
1342+
1343+/*
1344+ This function checks if the passed command is ambiguous
1345+*/
1346+static int check_ambiguity(struct Command *cmd, char **argv){
1347+ int i;
1348+ struct Command *cp;
1349+ /* check for ambiguity */
1350+ for( i = 0 ; i < cmd->ncmds ; i++ ){
1351+ int match;
1352+ for( match = 0, cp = commands; cp->verb; cp++ ){
1353+ int j, skip;
1354+ char *s1, *s2;
1355+
1356+ if( cp->ncmds < i )
1357+ continue;
1358+
1359+ for( skip = 0, j = 0 ; j < i ; j++ )
1360+ if( strcmp(cmd->cmds[j], cp->cmds[j])){
1361+ skip=1;
1362+ break;
1363+ }
1364+ if(skip)
1365+ continue;
1366+
1367+ if( !strcmp(cmd->cmds[i], cp->cmds[i]))
1368+ continue;
1369+ for(s2 = cp->cmds[i], s1 = argv[i+1];
1370+ *s1 == *s2 && *s1; s1++, s2++ ) ;
1371+ if( !*s1 )
1372+ match++;
1373+ }
1374+ if(match){
1375+ int j;
1376+ fprintf(stderr, "ERROR: in command '");
1377+ for( j = 0 ; j <= i ; j++ )
1378+ fprintf(stderr, "%s%s",j?" ":"", argv[j+1]);
1379+ fprintf(stderr, "', '%s' is ambiguous\n",argv[j]);
1380+ return -2;
1381+ }
1382+ }
1383+ return 0;
1384+}
1385+
1386+/*
1387+ * This function, compacts the program name and the command in the first
1388+ * element of the '*av' array
1389+ */
1390+static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){
1391+
1392+ char **ret;
1393+ int i;
1394+ char *newname;
1395+
1396+ ret = (char **)malloc(sizeof(char*)*(*ac+1));
1397+ newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2);
1398+ if( !ret || !newname ){
1399+ free(ret);
1400+ free(newname);
1401+ return -1;
1402+ }
1403+
1404+ ret[0] = newname;
1405+ for(i=0; i < *ac ; i++ )
1406+ ret[i+1] = (*av)[i];
1407+
1408+ strcpy(newname, prgname);
1409+ strcat(newname, " ");
1410+ strcat(newname, cmd->verb);
1411+
1412+ (*ac)++;
1413+ *av = ret;
1414+
1415+ return 0;
1416+
1417+}
1418+
1419+
1420+
1421+/*
1422+
1423+ This function perform the following jobs:
1424+ - show the help if '--help' or 'help' or '-h' are passed
1425+ - verify that a command is not ambiguous, otherwise show which
1426+ part of the command is ambiguous
1427+ - if after a (even partial) command there is '--help' show the help
1428+ for all the matching commands
1429+ - if the command doesn't' match show an error
1430+ - finally, if a command match, they return which command is matched and
1431+ the arguments
1432+
1433+ The function return 0 in case of help is requested; <0 in case
1434+ of uncorrect command; >0 in case of matching commands
1435+ argc, argv are the arg-counter and arg-vector (input)
1436+ *nargs_ is the number of the arguments after the command (output)
1437+ **cmd_ is the invoked command (output)
1438+ ***args_ are the arguments after the command
1439+
1440+*/
1441+static int parse_args(int argc, char **argv,
1442+ CommandFunction *func_,
1443+ int *nargs_, char **cmd_, char ***args_ )
1444+{
1445+ struct Command *cp;
1446+ struct Command *matchcmd=0;
1447+ char *prgname = get_prgname(argv[0]);
1448+ int i=0, helprequested=0;
1449+
1450+ if( argc < 2 || !strcmp(argv[1], "help") ||
1451+ !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
1452+ help(prgname);
1453+ return 0;
1454+ }
1455+
1456+ for( cp = commands; cp->verb; cp++ )
1457+ if( !cp->ncmds)
1458+ cp->ncmds = split_command(cp->verb, &(cp->cmds));
1459+
1460+ for( cp = commands; cp->verb; cp++ ){
1461+ int match;
1462+
1463+ if( argc-1 < cp->ncmds )
1464+ continue;
1465+ for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){
1466+ char *s1, *s2;
1467+ s1 = cp->cmds[i];
1468+ s2 = argv[i+1];
1469+
1470+ for(s2 = cp->cmds[i], s1 = argv[i+1];
1471+ *s1 == *s2 && *s1;
1472+ s1++, s2++ ) ;
1473+ if( *s1 ){
1474+ match=0;
1475+ break;
1476+ }
1477+ }
1478+
1479+ /* If you understand why this code works ...
1480+ you are a genious !! */
1481+ if(argc>i+1 && !strcmp(argv[i+1],"--help")){
1482+ if(!helprequested)
1483+ printf("Usage:\n");
1484+ print_help(prgname, cp);
1485+ helprequested=1;
1486+ continue;
1487+ }
1488+
1489+ if(!match)
1490+ continue;
1491+
1492+ matchcmd = cp;
1493+ *nargs_ = argc-matchcmd->ncmds-1;
1494+ *cmd_ = matchcmd->verb;
1495+ *args_ = argv+matchcmd->ncmds+1;
1496+ *func_ = cp->func;
1497+
1498+ break;
1499+ }
1500+
1501+ if(helprequested){
1502+ printf("\n%s\n", BTRFS_BUILD_VERSION);
1503+ return 0;
1504+ }
1505+
1506+ if(!matchcmd){
1507+ fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]);
1508+ help(prgname);
1509+ return -1;
1510+ }
1511+
1512+ if(check_ambiguity(matchcmd, argv))
1513+ return -2;
1514+
1515+ /* check the number of argument */
1516+ if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){
1517+ fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n",
1518+ matchcmd->verb, -matchcmd->nargs);
1519+ return -2;
1520+ }
1521+ if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){
1522+ fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n",
1523+ matchcmd->verb, matchcmd->nargs);
1524+ return -2;
1525+ }
1526+
1527+ if (prepare_args( nargs_, args_, prgname, matchcmd )){
1528+ fprintf(stderr, "ERROR: not enough memory\\n");
1529+ return -20;
1530+ }
1531+
1532+
1533+ return 1;
1534+}
1535+int main(int ac, char **av )
1536+{
1537+
1538+ char *cmd=0, **args=0;
1539+ int nargs=0, r;
1540+ CommandFunction func=0;
1541+
1542+ r = parse_args(ac, av, &func, &nargs, &cmd, &args);
1543+ if( r <= 0 ){
1544+ /* error or no command to parse*/
1545+ exit(-r);
1546+ }
1547+
1548+ exit(func(nargs, args));
1549+
1550+}
1551+
1552diff --git a/btrfs_cmds.c b/btrfs_cmds.c
1553new file mode 100644
1554index 0000000..8031c58
1555--- /dev/null
1556+++ b/btrfs_cmds.c
1557@@ -0,0 +1,924 @@
1558+/*
1559+ * This program is free software; you can redistribute it and/or
1560+ * modify it under the terms of the GNU General Public
1561+ * License v2 as published by the Free Software Foundation.
1562+ *
1563+ * This program is distributed in the hope that it will be useful,
1564+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1565+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1566+ * General Public License for more details.
1567+ *
1568+ * You should have received a copy of the GNU General Public
1569+ * License along with this program; if not, write to the
1570+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1571+ * Boston, MA 021110-1307, USA.
1572+ */
1573+
1574+
1575+#include <stdio.h>
1576+#include <stdlib.h>
1577+#include <string.h>
1578+#include <sys/ioctl.h>
1579+#include <sys/types.h>
1580+#include <dirent.h>
1581+#include <sys/stat.h>
1582+#include <unistd.h>
1583+#include <fcntl.h>
1584+#include <libgen.h>
1585+#include <limits.h>
1586+#include <uuid/uuid.h>
1587+#include <ctype.h>
1588+
1589+#undef ULONG_MAX
1590+
1591+#include "kerncompat.h"
1592+#include "ctree.h"
1593+#include "transaction.h"
1594+#include "utils.h"
1595+#include "version.h"
1596+#include "ioctl.h"
1597+#include "volumes.h"
1598+
1599+#include "btrfs_cmds.h"
1600+
1601+#ifdef __CHECKER__
1602+#define BLKGETSIZE64 0
1603+#define BTRFS_IOC_SNAP_CREATE 0
1604+#define BTRFS_VOL_NAME_MAX 255
1605+struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; };
1606+static inline int ioctl(int fd, int define, void *arg) { return 0; }
1607+#endif
1608+
1609+/*
1610+ * test if path is a subvolume:
1611+ * this function return
1612+ * 0-> path exists but it is not a subvolume
1613+ * 1-> path exists and it is a subvolume
1614+ * -1 -> path is unaccessible
1615+ */
1616+static int test_issubvolume(char *path)
1617+{
1618+
1619+ struct stat st;
1620+ int res;
1621+
1622+ res = stat(path, &st);
1623+ if(res < 0 )
1624+ return -1;
1625+
1626+ return (st.st_ino == 256) && S_ISDIR(st.st_mode);
1627+
1628+}
1629+
1630+/*
1631+ * test if path is a directory
1632+ * this function return
1633+ * 0-> path exists but it is not a directory
1634+ * 1-> path exists and it is a directory
1635+ * -1 -> path is unaccessible
1636+ */
1637+static int test_isdir(char *path)
1638+{
1639+ struct stat st;
1640+ int res;
1641+
1642+ res = stat(path, &st);
1643+ if(res < 0 )
1644+ return -1;
1645+
1646+ return S_ISDIR(st.st_mode);
1647+
1648+}
1649+
1650+static int open_file_or_dir(const char *fname)
1651+{
1652+ int ret;
1653+ struct stat st;
1654+ DIR *dirstream;
1655+ int fd;
1656+
1657+ ret = stat(fname, &st);
1658+ if (ret < 0) {
1659+ return -1;
1660+ }
1661+ if (S_ISDIR(st.st_mode)) {
1662+ dirstream = opendir(fname);
1663+ if (!dirstream) {
1664+ return -2;
1665+ }
1666+ fd = dirfd(dirstream);
1667+ } else {
1668+ fd = open(fname, O_RDWR);
1669+ }
1670+ if (fd < 0) {
1671+ return -3;
1672+ }
1673+ return fd;
1674+}
1675+
1676+static u64 parse_size(char *s)
1677+{
1678+ int len = strlen(s);
1679+ char c;
1680+ u64 mult = 1;
1681+
1682+ if (!isdigit(s[len - 1])) {
1683+ c = tolower(s[len - 1]);
1684+ switch (c) {
1685+ case 'g':
1686+ mult *= 1024;
1687+ case 'm':
1688+ mult *= 1024;
1689+ case 'k':
1690+ mult *= 1024;
1691+ case 'b':
1692+ break;
1693+ default:
1694+ fprintf(stderr, "Unknown size descriptor %c\n", c);
1695+ exit(1);
1696+ }
1697+ s[len - 1] = '\0';
1698+ }
1699+ return atoll(s) * mult;
1700+}
1701+
1702+int do_defrag(int ac, char **av)
1703+{
1704+ int fd;
1705+ int compress = 0;
1706+ int flush = 0;
1707+ u64 start = 0;
1708+ u64 len = (u64)-1;
1709+ u32 thresh = 0;
1710+ int i;
1711+ int errors = 0;
1712+ int ret = 0;
1713+ int verbose = 0;
1714+ int fancy_ioctl = 0;
1715+ struct btrfs_ioctl_defrag_range_args range;
1716+
1717+ optind = 1;
1718+ while(1) {
1719+ int c = getopt(ac, av, "vcfs:l:t:");
1720+ if (c < 0)
1721+ break;
1722+ switch(c) {
1723+ case 'c':
1724+ compress = 1;
1725+ fancy_ioctl = 1;
1726+ break;
1727+ case 'f':
1728+ flush = 1;
1729+ fancy_ioctl = 1;
1730+ break;
1731+ case 'v':
1732+ verbose = 1;
1733+ break;
1734+ case 's':
1735+ start = parse_size(optarg);
1736+ fancy_ioctl = 1;
1737+ break;
1738+ case 'l':
1739+ len = parse_size(optarg);
1740+ fancy_ioctl = 1;
1741+ break;
1742+ case 't':
1743+ thresh = parse_size(optarg);
1744+ fancy_ioctl = 1;
1745+ break;
1746+ default:
1747+ fprintf(stderr, "Invalid arguments for defragment\n");
1748+ free(av);
1749+ return 1;
1750+ }
1751+ }
1752+ if (ac - optind == 0) {
1753+ fprintf(stderr, "Invalid arguments for defragment\n");
1754+ free(av);
1755+ return 1;
1756+ }
1757+
1758+ memset(&range, 0, sizeof(range));
1759+ range.start = start;
1760+ range.len = len;
1761+ range.extent_thresh = thresh;
1762+ if (compress)
1763+ range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1764+ if (flush)
1765+ range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1766+
1767+ for (i = optind; i < ac; i++) {
1768+ if (verbose)
1769+ printf("%s\n", av[i]);
1770+ fd = open_file_or_dir(av[i]);
1771+ if (fd < 0) {
1772+ fprintf(stderr, "failed to open %s\n", av[i]);
1773+ perror("open:");
1774+ errors++;
1775+ continue;
1776+ }
1777+ if (!fancy_ioctl) {
1778+ ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
1779+ } else {
1780+ ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
1781+ if (ret && errno == ENOTTY) {
1782+ fprintf(stderr, "defrag range ioctl not "
1783+ "supported in this kernel, please try "
1784+ "without any options.\n");
1785+ errors++;
1786+ break;
1787+ }
1788+ }
1789+ if (ret) {
1790+ fprintf(stderr, "ioctl failed on %s ret %d errno %d\n",
1791+ av[i], ret, errno);
1792+ errors++;
1793+ }
1794+ close(fd);
1795+ }
1796+ if (verbose)
1797+ printf("%s\n", BTRFS_BUILD_VERSION);
1798+ if (errors) {
1799+ fprintf(stderr, "total %d failures\n", errors);
1800+ exit(1);
1801+ }
1802+
1803+ free(av);
1804+ return errors + 20;
1805+}
1806+
1807+int do_find_newer(int argc, char **argv)
1808+{
1809+ int fd;
1810+ int ret;
1811+ char *subvol;
1812+ u64 last_gen;
1813+
1814+ subvol = argv[1];
1815+ last_gen = atoll(argv[2]);
1816+
1817+ ret = test_issubvolume(subvol);
1818+ if (ret < 0) {
1819+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1820+ return 12;
1821+ }
1822+ if (!ret) {
1823+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1824+ return 13;
1825+ }
1826+
1827+ fd = open_file_or_dir(subvol);
1828+ if (fd < 0) {
1829+ fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1830+ return 12;
1831+ }
1832+ ret = find_updated_files(fd, 0, last_gen);
1833+ if (ret)
1834+ return 19;
1835+ return 0;
1836+}
1837+
1838+int do_subvol_list(int argc, char **argv)
1839+{
1840+ int fd;
1841+ int ret;
1842+ char *subvol;
1843+
1844+ subvol = argv[1];
1845+
1846+ ret = test_issubvolume(subvol);
1847+ if (ret < 0) {
1848+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1849+ return 12;
1850+ }
1851+ if (!ret) {
1852+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1853+ return 13;
1854+ }
1855+
1856+ fd = open_file_or_dir(subvol);
1857+ if (fd < 0) {
1858+ fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
1859+ return 12;
1860+ }
1861+ ret = list_subvols(fd);
1862+ if (ret)
1863+ return 19;
1864+ return 0;
1865+}
1866+
1867+int do_clone(int argc, char **argv)
1868+{
1869+ char *subvol, *dst;
1870+ int res, fd, fddst, len;
1871+ char *newname;
1872+ char *dstdir;
1873+
1874+ subvol = argv[1];
1875+ dst = argv[2];
1876+ struct btrfs_ioctl_vol_args args;
1877+
1878+ res = test_issubvolume(subvol);
1879+ if(res<0){
1880+ fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
1881+ return 12;
1882+ }
1883+ if(!res){
1884+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
1885+ return 13;
1886+ }
1887+
1888+ res = test_isdir(dst);
1889+ if(res == 0 ){
1890+ fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
1891+ return 12;
1892+ }
1893+
1894+ if(res>0){
1895+ newname = strdup(subvol);
1896+ newname = basename(newname);
1897+ dstdir = dst;
1898+ }else{
1899+ newname = strdup(dst);
1900+ newname = basename(newname);
1901+ dstdir = strdup(dst);
1902+ dstdir = dirname(dstdir);
1903+ }
1904+
1905+ if( !strcmp(newname,".") || !strcmp(newname,"..") ||
1906+ strchr(newname, '/') ){
1907+ fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
1908+ newname);
1909+ return 14;
1910+ }
1911+
1912+ len = strlen(newname);
1913+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1914+ fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
1915+ newname);
1916+ return 14;
1917+ }
1918+
1919+ fddst = open_file_or_dir(dstdir);
1920+ if (fddst < 0) {
1921+ fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
1922+ return 12;
1923+ }
1924+
1925+ fd = open_file_or_dir(subvol);
1926+ if (fd < 0) {
1927+ close(fddst);
1928+ fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
1929+ return 12;
1930+ }
1931+
1932+ printf("Create a snapshot of '%s' in '%s/%s'\n",
1933+ subvol, dstdir, newname);
1934+ args.fd = fd;
1935+ strcpy(args.name, newname);
1936+ res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args);
1937+
1938+ close(fd);
1939+ close(fddst);
1940+
1941+ if(res < 0 ){
1942+ fprintf( stderr, "ERROR: cannot snapshot '%s'\n",subvol);
1943+ return 11;
1944+ }
1945+
1946+ return 0;
1947+
1948+}
1949+
1950+int do_delete_subvolume(int argc, char **argv)
1951+{
1952+ int res, fd, len;
1953+ struct btrfs_ioctl_vol_args args;
1954+ char *dname, *vname, *cpath;
1955+ char *path = argv[1];
1956+
1957+ res = test_issubvolume(path);
1958+ if(res<0){
1959+ fprintf(stderr, "ERROR: error accessing '%s'\n", path);
1960+ return 12;
1961+ }
1962+ if(!res){
1963+ fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
1964+ return 13;
1965+ }
1966+
1967+ cpath = realpath(path, 0);
1968+ dname = strdup(cpath);
1969+ dname = dirname(dname);
1970+ vname = strdup(cpath);
1971+ vname = basename(vname);
1972+ free(cpath);
1973+
1974+ if( !strcmp(vname,".") || !strcmp(vname,"..") ||
1975+ strchr(vname, '/') ){
1976+ fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
1977+ vname);
1978+ return 14;
1979+ }
1980+
1981+ len = strlen(vname);
1982+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1983+ fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
1984+ vname);
1985+ return 14;
1986+ }
1987+
1988+ fd = open_file_or_dir(dname);
1989+ if (fd < 0) {
1990+ close(fd);
1991+ fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
1992+ return 12;
1993+ }
1994+
1995+ printf("Delete subvolume '%s/%s'\n", dname, vname);
1996+ strcpy(args.name, vname);
1997+ res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
1998+
1999+ close(fd);
2000+
2001+ if(res < 0 ){
2002+ fprintf( stderr, "ERROR: cannot delete '%s/%s'\n",dname, vname);
2003+ return 11;
2004+ }
2005+
2006+ return 0;
2007+
2008+}
2009+
2010+int do_create_subvol(int argc, char **argv)
2011+{
2012+ int res, fddst, len;
2013+ char *newname;
2014+ char *dstdir;
2015+ struct btrfs_ioctl_vol_args args;
2016+ char *dst = argv[1];
2017+
2018+ res = test_isdir(dst);
2019+ if(res >= 0 ){
2020+ fprintf(stderr, "ERROR: '%s' exists\n", dst);
2021+ return 12;
2022+ }
2023+
2024+ newname = strdup(dst);
2025+ newname = basename(newname);
2026+ dstdir = strdup(dst);
2027+ dstdir = dirname(dstdir);
2028+
2029+ if( !strcmp(newname,".") || !strcmp(newname,"..") ||
2030+ strchr(newname, '/') ){
2031+ fprintf(stderr, "ERROR: uncorrect subvolume 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: subvolume 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+ printf("Create subvolume '%s/%s'\n", dstdir, newname);
2050+ strcpy(args.name, newname);
2051+ res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
2052+
2053+ close(fddst);
2054+
2055+ if(res < 0 ){
2056+ fprintf( stderr, "ERROR: cannot create subvolume\n");
2057+ return 11;
2058+ }
2059+
2060+ return 0;
2061+
2062+}
2063+
2064+int do_fssync(int argc, char **argv)
2065+{
2066+ int fd, res;
2067+ char *path = argv[1];
2068+
2069+ fd = open_file_or_dir(path);
2070+ if (fd < 0) {
2071+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2072+ return 12;
2073+ }
2074+
2075+ printf("FSSync '%s'\n", path);
2076+ res = ioctl(fd, BTRFS_IOC_SYNC);
2077+ close(fd);
2078+ if( res < 0 ){
2079+ fprintf(stderr, "ERROR: unable to fs-syncing '%s'\n", path);
2080+ return 16;
2081+ }
2082+
2083+ return 0;
2084+}
2085+
2086+int do_scan(int argc, char **argv)
2087+{
2088+ int i, fd;
2089+ if(argc<=1){
2090+ int ret;
2091+
2092+ printf("Scanning for Btrfs filesystems\n");
2093+ ret = btrfs_scan_one_dir("/dev", 1);
2094+ if (ret){
2095+ fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2096+ return 18;
2097+ }
2098+ return 0;
2099+ }
2100+
2101+ fd = open("/dev/btrfs-control", O_RDWR);
2102+ if (fd < 0) {
2103+ perror("failed to open /dev/btrfs-control");
2104+ return 10;
2105+ }
2106+
2107+ for( i = 1 ; i < argc ; i++ ){
2108+ struct btrfs_ioctl_vol_args args;
2109+ int ret;
2110+
2111+ printf("Scanning for Btrfs filesystems in '%s'\n", argv[i]);
2112+
2113+ strcpy(args.name, argv[i]);
2114+ /*
2115+ * FIXME: which are the error code returned by this ioctl ?
2116+ * it seems that is impossible to understand if there no is
2117+ * a btrfs filesystem from an I/O error !!!
2118+ */
2119+ ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
2120+
2121+ if( ret < 0 ){
2122+ close(fd);
2123+ fprintf(stderr, "ERROR: unable to scan the device '%s'\n", argv[i]);
2124+ return 11;
2125+ }
2126+ }
2127+
2128+ close(fd);
2129+ return 0;
2130+
2131+}
2132+
2133+int do_resize(int argc, char **argv)
2134+{
2135+
2136+ struct btrfs_ioctl_vol_args args;
2137+ int fd, res, len;
2138+ char *amount=argv[1], *path=argv[2];
2139+
2140+ fd = open_file_or_dir(path);
2141+ if (fd < 0) {
2142+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2143+ return 12;
2144+ }
2145+ len = strlen(amount);
2146+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
2147+ fprintf(stderr, "ERROR: size value too long ('%s)\n",
2148+ amount);
2149+ return 14;
2150+ }
2151+
2152+ printf("Resize '%s' of '%s'\n", path, amount);
2153+ strcpy(args.name, amount);
2154+ res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
2155+ close(fd);
2156+ if( res < 0 ){
2157+ fprintf(stderr, "ERROR: unable to resize '%s'\n", path);
2158+ return 30;
2159+ }
2160+ return 0;
2161+}
2162+
2163+static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
2164+{
2165+ struct list_head *cur;
2166+ struct btrfs_device *device;
2167+
2168+ list_for_each(cur, &fs_devices->devices) {
2169+ device = list_entry(cur, struct btrfs_device, dev_list);
2170+ if ((device->label && strcmp(device->label, search) == 0) ||
2171+ strcmp(device->name, search) == 0)
2172+ return 1;
2173+ }
2174+ return 0;
2175+}
2176+
2177+static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
2178+{
2179+ char uuidbuf[37];
2180+ struct list_head *cur;
2181+ struct btrfs_device *device;
2182+ char *super_bytes_used;
2183+ u64 devs_found = 0;
2184+ u64 total;
2185+
2186+ uuid_unparse(fs_devices->fsid, uuidbuf);
2187+ device = list_entry(fs_devices->devices.next, struct btrfs_device,
2188+ dev_list);
2189+ if (device->label && device->label[0])
2190+ printf("Label: '%s' ", device->label);
2191+ else
2192+ printf("Label: none ");
2193+
2194+ super_bytes_used = pretty_sizes(device->super_bytes_used);
2195+
2196+ total = device->total_devs;
2197+ printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
2198+ (unsigned long long)total, super_bytes_used);
2199+
2200+ free(super_bytes_used);
2201+
2202+ list_for_each(cur, &fs_devices->devices) {
2203+ char *total_bytes;
2204+ char *bytes_used;
2205+ device = list_entry(cur, struct btrfs_device, dev_list);
2206+ total_bytes = pretty_sizes(device->total_bytes);
2207+ bytes_used = pretty_sizes(device->bytes_used);
2208+ printf("\tdevid %4llu size %s used %s path %s\n",
2209+ (unsigned long long)device->devid,
2210+ total_bytes, bytes_used, device->name);
2211+ free(total_bytes);
2212+ free(bytes_used);
2213+ devs_found++;
2214+ }
2215+ if (devs_found < total) {
2216+ printf("\t*** Some devices missing\n");
2217+ }
2218+ printf("\n");
2219+}
2220+
2221+int do_show_filesystem(int argc, char **argv)
2222+{
2223+ struct list_head *all_uuids;
2224+ struct btrfs_fs_devices *fs_devices;
2225+ struct list_head *cur_uuid;
2226+ char *search = argv[1];
2227+ int ret;
2228+
2229+ ret = btrfs_scan_one_dir("/dev", 0);
2230+ if (ret){
2231+ fprintf(stderr, "ERROR: error %d while scanning\n", ret);
2232+ return 18;
2233+ }
2234+
2235+ all_uuids = btrfs_scanned_uuids();
2236+ list_for_each(cur_uuid, all_uuids) {
2237+ fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
2238+ list);
2239+ if (search && uuid_search(fs_devices, search) == 0)
2240+ continue;
2241+ print_one_uuid(fs_devices);
2242+ }
2243+ printf("%s\n", BTRFS_BUILD_VERSION);
2244+ return 0;
2245+}
2246+
2247+int do_add_volume(int nargs, char **args)
2248+{
2249+
2250+ char *mntpnt = args[nargs-1];
2251+ int i, fdmnt, ret=0;
2252+
2253+
2254+ fdmnt = open_file_or_dir(mntpnt);
2255+ if (fdmnt < 0) {
2256+ fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2257+ return 12;
2258+ }
2259+
2260+ for(i=1 ; i < (nargs-1) ; i++ ){
2261+ struct btrfs_ioctl_vol_args ioctl_args;
2262+ int devfd, res;
2263+ u64 dev_block_count = 0;
2264+ struct stat st;
2265+
2266+ devfd = open(args[i], O_RDWR);
2267+ if (!devfd) {
2268+ fprintf(stderr, "ERROR: Unable to open device '%s'\n", args[i]);
2269+ close(devfd);
2270+ ret++;
2271+ continue;
2272+ }
2273+ ret = fstat(devfd, &st);
2274+ if (ret) {
2275+ fprintf(stderr, "ERROR: Unable to stat '%s'\n", args[i]);
2276+ close(devfd);
2277+ ret++;
2278+ continue;
2279+ }
2280+ if (!S_ISBLK(st.st_mode)) {
2281+ fprintf(stderr, "ERROR: '%s' is not a block device\n", args[i]);
2282+ close(devfd);
2283+ ret++;
2284+ continue;
2285+ }
2286+
2287+ res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count);
2288+ if (res) {
2289+ fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]);
2290+ close(devfd);
2291+ ret++;
2292+ continue;
2293+ }
2294+ close(devfd);
2295+
2296+ strcpy(ioctl_args.name, args[i]);
2297+ res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
2298+ if(res<0){
2299+ fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]);
2300+ ret++;
2301+ }
2302+
2303+ }
2304+
2305+ close(fdmnt);
2306+ if( ret)
2307+ return ret+20;
2308+ else
2309+ return 0;
2310+
2311+}
2312+
2313+int do_balance(int argc, char **argv)
2314+{
2315+
2316+ int fdmnt, ret=0;
2317+ struct btrfs_ioctl_vol_args args;
2318+ char *path = argv[1];
2319+
2320+ fdmnt = open_file_or_dir(path);
2321+ if (fdmnt < 0) {
2322+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2323+ return 12;
2324+ }
2325+
2326+ memset(&args, 0, sizeof(args));
2327+ ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args);
2328+ close(fdmnt);
2329+ if(ret<0){
2330+ fprintf(stderr, "ERROR: balancing '%s'\n", path);
2331+
2332+ return 19;
2333+ }
2334+ return 0;
2335+}
2336+int do_remove_volume(int nargs, char **args)
2337+{
2338+
2339+ char *mntpnt = args[nargs-1];
2340+ int i, fdmnt, ret=0;
2341+
2342+ fdmnt = open_file_or_dir(mntpnt);
2343+ if (fdmnt < 0) {
2344+ fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
2345+ return 12;
2346+ }
2347+
2348+ for(i=1 ; i < (nargs-1) ; i++ ){
2349+ struct btrfs_ioctl_vol_args arg;
2350+ int res;
2351+
2352+ strcpy(arg.name, args[i]);
2353+ res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
2354+ if(res<0){
2355+ fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]);
2356+ ret++;
2357+ }
2358+ }
2359+
2360+ close(fdmnt);
2361+ if( ret)
2362+ return ret+20;
2363+ else
2364+ return 0;
2365+}
2366+
2367+int do_set_default_subvol(int nargs, char **argv)
2368+{
2369+ int ret=0, fd;
2370+ u64 objectid;
2371+ char *path = argv[2];
2372+ char *subvolid = argv[1];
2373+
2374+ fd = open_file_or_dir(path);
2375+ if (fd < 0) {
2376+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2377+ return 12;
2378+ }
2379+
2380+ objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
2381+ if (errno == ERANGE) {
2382+ fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
2383+ return 30;
2384+ }
2385+ ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
2386+ close(fd);
2387+ if( ret < 0 ){
2388+ fprintf(stderr, "ERROR: unable to set a new default subvolume\n");
2389+ return 30;
2390+ }
2391+ return 0;
2392+}
2393+
2394+int do_df_filesystem(int nargs, char **argv)
2395+{
2396+ struct btrfs_ioctl_space_args *sargs;
2397+ u64 count = 0, i;
2398+ int ret;
2399+ int fd;
2400+ char *path = argv[1];
2401+
2402+ fd = open_file_or_dir(path);
2403+ if (fd < 0) {
2404+ fprintf(stderr, "ERROR: can't access to '%s'\n", path);
2405+ return 12;
2406+ }
2407+
2408+ sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
2409+ if (!sargs)
2410+ return -ENOMEM;
2411+
2412+ sargs->space_slots = 0;
2413+ sargs->total_spaces = 0;
2414+
2415+ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2416+ if (ret) {
2417+ free(sargs);
2418+ return ret;
2419+ }
2420+ if (!sargs->total_spaces)
2421+ return 0;
2422+
2423+ count = sargs->total_spaces;
2424+
2425+ sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
2426+ (count * sizeof(struct btrfs_ioctl_space_info)));
2427+ if (!sargs)
2428+ return -ENOMEM;
2429+
2430+ sargs->space_slots = count;
2431+ sargs->total_spaces = 0;
2432+
2433+ ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
2434+ if (ret) {
2435+ free(sargs);
2436+ return ret;
2437+ }
2438+
2439+ for (i = 0; i < sargs->total_spaces; i++) {
2440+ char description[80];
2441+ char *total_bytes;
2442+ char *used_bytes;
2443+ int written = 0;
2444+ u64 flags = sargs->spaces[i].flags;
2445+
2446+ memset(description, 0, 80);
2447+
2448+ if (flags & BTRFS_BLOCK_GROUP_DATA) {
2449+ snprintf(description, 5, "%s", "Data");
2450+ written += 4;
2451+ } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
2452+ snprintf(description, 7, "%s", "System");
2453+ written += 6;
2454+ } else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
2455+ snprintf(description, 9, "%s", "Metadata");
2456+ written += 8;
2457+ }
2458+
2459+ if (flags & BTRFS_BLOCK_GROUP_RAID0) {
2460+ snprintf(description+written, 8, "%s", ", RAID0");
2461+ written += 7;
2462+ } else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
2463+ snprintf(description+written, 8, "%s", ", RAID1");
2464+ written += 7;
2465+ } else if (flags & BTRFS_BLOCK_GROUP_DUP) {
2466+ snprintf(description+written, 6, "%s", ", DUP");
2467+ written += 5;
2468+ } else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
2469+ snprintf(description+written, 9, "%s", ", RAID10");
2470+ written += 8;
2471+ }
2472+
2473+ total_bytes = pretty_sizes(sargs->spaces[i].total_bytes);
2474+ used_bytes = pretty_sizes(sargs->spaces[i].used_bytes);
2475+ printf("%s: total=%s, used=%s\n", description, total_bytes,
2476+ used_bytes);
2477+ }
2478+ free(sargs);
2479+
2480+ return 0;
2481+}
2482diff --git a/btrfs_cmds.h b/btrfs_cmds.h
2483new file mode 100644
2484index 0000000..7bde191
2485--- /dev/null
2486+++ b/btrfs_cmds.h
2487@@ -0,0 +1,34 @@
2488+/*
2489+ * This program is free software; you can redistribute it and/or
2490+ * modify it under the terms of the GNU General Public
2491+ * License v2 as published by the Free Software Foundation.
2492+ *
2493+ * This program is distributed in the hope that it will be useful,
2494+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2495+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2496+ * General Public License for more details.
2497+ *
2498+ * You should have received a copy of the GNU General Public
2499+ * License along with this program; if not, write to the
2500+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2501+ * Boston, MA 021110-1307, USA.
2502+ */
2503+
2504+/* btrfs_cmds.c*/
2505+int do_clone(int nargs, char **argv);
2506+int do_delete_subvolume(int nargs, char **argv);
2507+int do_create_subvol(int nargs, char **argv);
2508+int do_fssync(int nargs, char **argv);
2509+int do_defrag(int argc, char **argv);
2510+int do_show_filesystem(int nargs, char **argv);
2511+int do_add_volume(int nargs, char **args);
2512+int do_balance(int nargs, char **argv);
2513+int do_remove_volume(int nargs, char **args);
2514+int do_scan(int nargs, char **argv);
2515+int do_resize(int nargs, char **argv);
2516+int do_subvol_list(int nargs, char **argv);
2517+int do_set_default_subvol(int nargs, char **argv);
2518+int list_subvols(int fd);
2519+int do_df_filesystem(int nargs, char **argv);
2520+int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
2521+int do_find_newer(int argc, char **argv);
2522diff --git a/btrfsck.c b/btrfsck.c
2523index 40c90f8..73f1836 100644
2524--- a/btrfsck.c
2525+++ b/btrfsck.c
2526@@ -36,7 +36,7 @@ static u64 total_fs_tree_bytes = 0;
2527 static u64 btree_space_waste = 0;
2528 static u64 data_bytes_allocated = 0;
2529 static u64 data_bytes_referenced = 0;
2530-int found_old_backref = 0;
2531+static int found_old_backref = 0;
2532
2533 struct extent_backref {
2534 struct list_head list;
2535@@ -100,7 +100,11 @@ struct inode_backref {
2536 #define REF_ERR_DUP_INODE_REF (1 << 5)
2537 #define REF_ERR_INDEX_UNMATCH (1 << 6)
2538 #define REF_ERR_FILETYPE_UNMATCH (1 << 7)
2539-#define REF_ERR_NAME_TOO_LONG (1 << 8)
2540+#define REF_ERR_NAME_TOO_LONG (1 << 8) // 100
2541+#define REF_ERR_NO_ROOT_REF (1 << 9)
2542+#define REF_ERR_NO_ROOT_BACKREF (1 << 10)
2543+#define REF_ERR_DUP_ROOT_REF (1 << 11)
2544+#define REF_ERR_DUP_ROOT_BACKREF (1 << 12)
2545
2546 struct inode_record {
2547 struct list_head backrefs;
2548@@ -144,6 +148,29 @@ struct inode_record {
2549 #define I_ERR_SOME_CSUM_MISSING (1 << 12)
2550 #define I_ERR_LINK_COUNT_WRONG (1 << 13)
2551
2552+struct root_backref {
2553+ struct list_head list;
2554+ unsigned int found_dir_item:1;
2555+ unsigned int found_dir_index:1;
2556+ unsigned int found_back_ref:1;
2557+ unsigned int found_forward_ref:1;
2558+ unsigned int reachable:1;
2559+ int errors;
2560+ u64 ref_root;
2561+ u64 dir;
2562+ u64 index;
2563+ u16 namelen;
2564+ char name[0];
2565+};
2566+
2567+struct root_record {
2568+ struct list_head backrefs;
2569+ struct cache_extent cache;
2570+ unsigned int found_root_item:1;
2571+ u64 objectid;
2572+ u32 found_ref;
2573+};
2574+
2575 struct ptr_node {
2576 struct cache_extent cache;
2577 void *data;
2578@@ -151,6 +178,7 @@ struct ptr_node {
2579
2580 struct shared_node {
2581 struct cache_extent cache;
2582+ struct cache_tree root_cache;
2583 struct cache_tree inode_cache;
2584 struct inode_record *current;
2585 u32 refs;
2586@@ -258,6 +286,14 @@ static void free_inode_rec(struct inode_record *rec)
2587 free(rec);
2588 }
2589
2590+static int can_free_inode_rec(struct inode_record *rec)
2591+{
2592+ if (!rec->errors && rec->checked && rec->found_inode_item &&
2593+ rec->nlink == rec->found_link && list_empty(&rec->backrefs))
2594+ return 1;
2595+ return 0;
2596+}
2597+
2598 static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2599 struct inode_record *rec)
2600 {
2601@@ -309,8 +345,7 @@ static void maybe_free_inode_rec(struct cache_tree *inode_cache,
2602 }
2603
2604 BUG_ON(rec->refs != 1);
2605- if (!rec->errors && rec->nlink == rec->found_link &&
2606- list_empty(&rec->backrefs)) {
2607+ if (can_free_inode_rec(rec)) {
2608 cache = find_cache_extent(inode_cache, rec->ino, 1);
2609 node = container_of(cache, struct ptr_node, cache);
2610 BUG_ON(node->data != rec);
2611@@ -338,14 +373,12 @@ static int check_orphan_item(struct btrfs_root *root, u64 ino)
2612 return ret;
2613 }
2614
2615-static int process_inode_item(struct btrfs_root *root,
2616- struct extent_buffer *eb,
2617+static int process_inode_item(struct extent_buffer *eb,
2618 int slot, struct btrfs_key *key,
2619 struct shared_node *active_node)
2620 {
2621 struct inode_record *rec;
2622 struct btrfs_inode_item *item;
2623- int ret;
2624
2625 rec = active_node->current;
2626 BUG_ON(rec->ino != key->objectid || rec->refs > 1);
2627@@ -361,11 +394,8 @@ static int process_inode_item(struct btrfs_root *root,
2628 if (btrfs_inode_flags(eb, item) & BTRFS_INODE_NODATASUM)
2629 rec->nodatasum = 1;
2630 rec->found_inode_item = 1;
2631- if (rec->nlink == 0) {
2632- ret = check_orphan_item(root, rec->ino);
2633- if (ret == -ENOENT)
2634- rec->errors |= I_ERR_NO_ORPHAN_ITEM;
2635- }
2636+ if (rec->nlink == 0)
2637+ rec->errors |= I_ERR_NO_ORPHAN_ITEM;
2638 maybe_free_inode_rec(&active_node->inode_cache, rec);
2639 return 0;
2640 }
2641@@ -443,10 +473,9 @@ static int add_inode_backref(struct cache_tree *inode_cache,
2642 }
2643
2644 static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2645- struct shared_node *dst_node)
2646+ struct cache_tree *dst_cache)
2647 {
2648 struct inode_backref *backref;
2649- struct cache_tree *dst_cache = &dst_node->inode_cache;
2650
2651 dst->merging = 1;
2652 list_for_each_entry(backref, &src->backrefs, list) {
2653@@ -510,14 +539,8 @@ static int merge_inode_recs(struct inode_record *src, struct inode_record *dst,
2654 dst->errors |= I_ERR_DUP_INODE_ITEM;
2655 }
2656 }
2657-
2658- if (src->checked) {
2659- dst->checked = 1;
2660- if (dst_node->current == dst)
2661- dst_node->current = NULL;
2662- }
2663 dst->merging = 0;
2664- maybe_free_inode_rec(dst_cache, dst);
2665+
2666 return 0;
2667 }
2668
2669@@ -537,8 +560,9 @@ static int splice_shared_node(struct shared_node *src_node,
2670 if (src_node->current)
2671 current_ino = src_node->current->ino;
2672
2673- src = &src_node->inode_cache;
2674- dst = &dst_node->inode_cache;
2675+ src = &src_node->root_cache;
2676+ dst = &dst_node->root_cache;
2677+again:
2678 cache = find_first_cache_extent(src, 0);
2679 while (cache) {
2680 node = container_of(cache, struct ptr_node, cache);
2681@@ -557,14 +581,28 @@ static int splice_shared_node(struct shared_node *src_node,
2682 }
2683 ret = insert_existing_cache_extent(dst, &ins->cache);
2684 if (ret == -EEXIST) {
2685+ WARN_ON(src == &src_node->root_cache);
2686 conflict = get_inode_rec(dst, rec->ino, 1);
2687- merge_inode_recs(rec, conflict, dst_node);
2688+ merge_inode_recs(rec, conflict, dst);
2689+ if (rec->checked) {
2690+ conflict->checked = 1;
2691+ if (dst_node->current == conflict)
2692+ dst_node->current = NULL;
2693+ }
2694+ maybe_free_inode_rec(dst, conflict);
2695 free_inode_rec(rec);
2696 free(ins);
2697 } else {
2698 BUG_ON(ret);
2699 }
2700 }
2701+
2702+ if (src == &src_node->root_cache) {
2703+ src = &src_node->inode_cache;
2704+ dst = &dst_node->inode_cache;
2705+ goto again;
2706+ }
2707+
2708 if (current_ino > 0 && (!dst_node->current ||
2709 current_ino > dst_node->current->ino)) {
2710 if (dst_node->current) {
2711@@ -616,6 +654,7 @@ static int add_shared_node(struct cache_tree *shared, u64 bytenr, u32 refs)
2712 node = calloc(1, sizeof(*node));
2713 node->cache.start = bytenr;
2714 node->cache.size = 1;
2715+ cache_tree_init(&node->root_cache);
2716 cache_tree_init(&node->inode_cache);
2717 node->refs = refs;
2718
2719@@ -646,6 +685,7 @@ static int enter_shared_node(struct btrfs_root *root, u64 bytenr, u32 refs,
2720 if (wc->root_level == wc->active_node &&
2721 btrfs_root_refs(&root->root_item) == 0) {
2722 if (--node->refs == 0) {
2723+ free_inode_recs(&node->root_cache);
2724 free_inode_recs(&node->inode_cache);
2725 remove_cache_extent(&wc->shared, &node->cache);
2726 free(node);
2727@@ -708,10 +748,12 @@ static int process_dir_item(struct extent_buffer *eb,
2728 int filetype;
2729 struct btrfs_dir_item *di;
2730 struct inode_record *rec;
2731+ struct cache_tree *root_cache;
2732 struct cache_tree *inode_cache;
2733 struct btrfs_key location;
2734 char namebuf[BTRFS_NAME_LEN];
2735
2736+ root_cache = &active_node->root_cache;
2737 inode_cache = &active_node->inode_cache;
2738 rec = active_node->current;
2739 rec->found_dir_item = 1;
2740@@ -740,7 +782,9 @@ static int process_dir_item(struct extent_buffer *eb,
2741 key->objectid, key->offset, namebuf,
2742 len, filetype, key->type, error);
2743 } else if (location.type == BTRFS_ROOT_ITEM_KEY) {
2744- /* fixme: check root back & forward references */
2745+ add_inode_backref(root_cache, location.objectid,
2746+ key->objectid, key->offset, namebuf,
2747+ len, filetype, key->type, error);
2748 } else {
2749 fprintf(stderr, "warning line %d\n", __LINE__);
2750 }
2751@@ -977,8 +1021,7 @@ static int process_one_leaf(struct btrfs_root *root, struct extent_buffer *eb,
2752 ret = process_inode_ref(eb, i, &key, active_node);
2753 break;
2754 case BTRFS_INODE_ITEM_KEY:
2755- ret = process_inode_item(root, eb, i, &key,
2756- active_node);
2757+ ret = process_inode_item(eb, i, &key, active_node);
2758 break;
2759 case BTRFS_EXTENT_DATA_KEY:
2760 ret = process_file_extent(root, eb, i, &key,
2761@@ -1176,13 +1219,23 @@ static int check_inode_recs(struct btrfs_root *root,
2762 node = container_of(cache, struct ptr_node, cache);
2763 rec = node->data;
2764 remove_cache_extent(inode_cache, &node->cache);
2765+ free(node);
2766 if (rec->ino == root_dirid ||
2767 rec->ino == BTRFS_ORPHAN_OBJECTID) {
2768- free(node);
2769 free_inode_rec(rec);
2770 continue;
2771 }
2772
2773+ if (rec->errors & I_ERR_NO_ORPHAN_ITEM) {
2774+ ret = check_orphan_item(root, rec->ino);
2775+ if (ret == 0)
2776+ rec->errors &= ~I_ERR_NO_ORPHAN_ITEM;
2777+ if (can_free_inode_rec(rec)) {
2778+ free_inode_rec(rec);
2779+ continue;
2780+ }
2781+ }
2782+
2783 error++;
2784 if (!rec->found_inode_item)
2785 rec->errors |= I_ERR_NO_INODE_ITEM;
2786@@ -1205,13 +1258,314 @@ static int check_inode_recs(struct btrfs_root *root,
2787 backref->namelen, backref->name,
2788 backref->filetype, backref->errors);
2789 }
2790- free(node);
2791 free_inode_rec(rec);
2792 }
2793 return (error > 0) ? -1 : 0;
2794 }
2795
2796+static struct root_record *get_root_rec(struct cache_tree *root_cache,
2797+ u64 objectid)
2798+{
2799+ struct cache_extent *cache;
2800+ struct root_record *rec = NULL;
2801+ int ret;
2802+
2803+ cache = find_cache_extent(root_cache, objectid, 1);
2804+ if (cache) {
2805+ rec = container_of(cache, struct root_record, cache);
2806+ } else {
2807+ rec = calloc(1, sizeof(*rec));
2808+ rec->objectid = objectid;
2809+ INIT_LIST_HEAD(&rec->backrefs);
2810+ rec->cache.start = objectid;
2811+ rec->cache.size = 1;
2812+
2813+ ret = insert_existing_cache_extent(root_cache, &rec->cache);
2814+ BUG_ON(ret);
2815+ }
2816+ return rec;
2817+}
2818+
2819+static struct root_backref *get_root_backref(struct root_record *rec,
2820+ u64 ref_root, u64 dir, u64 index,
2821+ const char *name, int namelen)
2822+{
2823+ struct root_backref *backref;
2824+
2825+ list_for_each_entry(backref, &rec->backrefs, list) {
2826+ if (backref->ref_root != ref_root || backref->dir != dir ||
2827+ backref->namelen != namelen)
2828+ continue;
2829+ if (memcmp(name, backref->name, namelen))
2830+ continue;
2831+ return backref;
2832+ }
2833+
2834+ backref = malloc(sizeof(*backref) + namelen + 1);
2835+ memset(backref, 0, sizeof(*backref));
2836+ backref->ref_root = ref_root;
2837+ backref->dir = dir;
2838+ backref->index = index;
2839+ backref->namelen = namelen;
2840+ memcpy(backref->name, name, namelen);
2841+ backref->name[namelen] = '\0';
2842+ list_add_tail(&backref->list, &rec->backrefs);
2843+ return backref;
2844+}
2845+
2846+static void free_root_recs(struct cache_tree *root_cache)
2847+{
2848+ struct cache_extent *cache;
2849+ struct root_record *rec;
2850+ struct root_backref *backref;
2851+
2852+ while (1) {
2853+ cache = find_first_cache_extent(root_cache, 0);
2854+ if (!cache)
2855+ break;
2856+ rec = container_of(cache, struct root_record, cache);
2857+ remove_cache_extent(root_cache, &rec->cache);
2858+
2859+ while (!list_empty(&rec->backrefs)) {
2860+ backref = list_entry(rec->backrefs.next,
2861+ struct root_backref, list);
2862+ list_del(&backref->list);
2863+ free(backref);
2864+ }
2865+ kfree(rec);
2866+ }
2867+}
2868+
2869+static int add_root_backref(struct cache_tree *root_cache,
2870+ u64 root_id, u64 ref_root, u64 dir, u64 index,
2871+ const char *name, int namelen,
2872+ int item_type, int errors)
2873+{
2874+ struct root_record *rec;
2875+ struct root_backref *backref;
2876+
2877+ rec = get_root_rec(root_cache, root_id);
2878+ backref = get_root_backref(rec, ref_root, dir, index, name, namelen);
2879+
2880+ backref->errors |= errors;
2881+
2882+ if (item_type != BTRFS_DIR_ITEM_KEY) {
2883+ if (backref->found_dir_index || backref->found_back_ref ||
2884+ backref->found_forward_ref) {
2885+ if (backref->index != index)
2886+ backref->errors |= REF_ERR_INDEX_UNMATCH;
2887+ } else {
2888+ backref->index = index;
2889+ }
2890+ }
2891+
2892+ if (item_type == BTRFS_DIR_ITEM_KEY) {
2893+ backref->found_dir_item = 1;
2894+ backref->reachable = 1;
2895+ rec->found_ref++;
2896+ } else if (item_type == BTRFS_DIR_INDEX_KEY) {
2897+ backref->found_dir_index = 1;
2898+ } else if (item_type == BTRFS_ROOT_REF_KEY) {
2899+ if (backref->found_forward_ref)
2900+ backref->errors |= REF_ERR_DUP_ROOT_REF;
2901+ backref->found_forward_ref = 1;
2902+ } else if (item_type == BTRFS_ROOT_BACKREF_KEY) {
2903+ if (backref->found_back_ref)
2904+ backref->errors |= REF_ERR_DUP_ROOT_BACKREF;
2905+ backref->found_back_ref = 1;
2906+ } else {
2907+ BUG_ON(1);
2908+ }
2909+
2910+ return 0;
2911+}
2912+
2913+static int merge_root_recs(struct btrfs_root *root,
2914+ struct cache_tree *src_cache,
2915+ struct cache_tree *dst_cache)
2916+{
2917+ struct cache_extent *cache;
2918+ struct ptr_node *node;
2919+ struct inode_record *rec;
2920+ struct inode_backref *backref;
2921+
2922+ if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
2923+ free_inode_recs(src_cache);
2924+ return 0;
2925+ }
2926+
2927+ while (1) {
2928+ cache = find_first_cache_extent(src_cache, 0);
2929+ if (!cache)
2930+ break;
2931+ node = container_of(cache, struct ptr_node, cache);
2932+ rec = node->data;
2933+ remove_cache_extent(src_cache, &node->cache);
2934+ free(node);
2935+
2936+ list_for_each_entry(backref, &rec->backrefs, list) {
2937+ BUG_ON(backref->found_inode_ref);
2938+ if (backref->found_dir_item)
2939+ add_root_backref(dst_cache, rec->ino,
2940+ root->root_key.objectid, backref->dir,
2941+ backref->index, backref->name,
2942+ backref->namelen, BTRFS_DIR_ITEM_KEY,
2943+ backref->errors);
2944+ if (backref->found_dir_index)
2945+ add_root_backref(dst_cache, rec->ino,
2946+ root->root_key.objectid, backref->dir,
2947+ backref->index, backref->name,
2948+ backref->namelen, BTRFS_DIR_INDEX_KEY,
2949+ backref->errors);
2950+ }
2951+ free_inode_rec(rec);
2952+ }
2953+ return 0;
2954+}
2955+
2956+static int check_root_refs(struct btrfs_root *root,
2957+ struct cache_tree *root_cache)
2958+{
2959+ struct root_record *rec;
2960+ struct root_record *ref_root;
2961+ struct root_backref *backref;
2962+ struct cache_extent *cache;
2963+ int loop = 1;
2964+ int ret;
2965+ int error;
2966+ int errors = 0;
2967+
2968+ rec = get_root_rec(root_cache, BTRFS_FS_TREE_OBJECTID);
2969+ rec->found_ref = 1;
2970+
2971+ /* fixme: this can not detect circular references */
2972+ while (loop) {
2973+ loop = 0;
2974+ cache = find_first_cache_extent(root_cache, 0);
2975+ while (1) {
2976+ if (!cache)
2977+ break;
2978+ rec = container_of(cache, struct root_record, cache);
2979+ cache = next_cache_extent(cache);
2980+
2981+ if (rec->found_ref == 0)
2982+ continue;
2983+
2984+ list_for_each_entry(backref, &rec->backrefs, list) {
2985+ if (!backref->reachable)
2986+ continue;
2987+
2988+ ref_root = get_root_rec(root_cache,
2989+ backref->ref_root);
2990+ if (ref_root->found_ref > 0)
2991+ continue;
2992+
2993+ backref->reachable = 0;
2994+ rec->found_ref--;
2995+ if (rec->found_ref == 0)
2996+ loop = 1;
2997+ }
2998+ }
2999+ }
3000+
3001+ cache = find_first_cache_extent(root_cache, 0);
3002+ while (1) {
3003+ if (!cache)
3004+ break;
3005+ rec = container_of(cache, struct root_record, cache);
3006+ cache = next_cache_extent(cache);
3007+
3008+ if (rec->found_ref == 0 &&
3009+ rec->objectid >= BTRFS_FIRST_FREE_OBJECTID &&
3010+ rec->objectid <= BTRFS_LAST_FREE_OBJECTID) {
3011+ ret = check_orphan_item(root->fs_info->tree_root,
3012+ rec->objectid);
3013+ if (ret == 0)
3014+ continue;
3015+ errors++;
3016+ fprintf(stderr, "fs tree %llu not referenced\n",
3017+ (unsigned long long)rec->objectid);
3018+ }
3019+
3020+ error = 0;
3021+ if (rec->found_ref > 0 && !rec->found_root_item)
3022+ error = 1;
3023+ list_for_each_entry(backref, &rec->backrefs, list) {
3024+ if (!backref->found_dir_item)
3025+ backref->errors |= REF_ERR_NO_DIR_ITEM;
3026+ if (!backref->found_dir_index)
3027+ backref->errors |= REF_ERR_NO_DIR_INDEX;
3028+ if (!backref->found_back_ref)
3029+ backref->errors |= REF_ERR_NO_ROOT_BACKREF;
3030+ if (!backref->found_forward_ref)
3031+ backref->errors |= REF_ERR_NO_ROOT_REF;
3032+ if (backref->reachable && backref->errors)
3033+ error = 1;
3034+ }
3035+ if (!error)
3036+ continue;
3037+
3038+ errors++;
3039+ fprintf(stderr, "fs tree %llu refs %u %s\n",
3040+ (unsigned long long)rec->objectid, rec->found_ref,
3041+ rec->found_root_item ? "" : "not found");
3042+
3043+ list_for_each_entry(backref, &rec->backrefs, list) {
3044+ if (!backref->reachable)
3045+ continue;
3046+ if (!backref->errors && rec->found_root_item)
3047+ continue;
3048+ fprintf(stderr, "\tunresolved ref root %llu dir %llu"
3049+ " index %llu namelen %u name %s error %x\n",
3050+ (unsigned long long)backref->ref_root,
3051+ (unsigned long long)backref->dir,
3052+ (unsigned long long)backref->index,
3053+ backref->namelen, backref->name,
3054+ backref->errors);
3055+ }
3056+ }
3057+ return errors > 0 ? 1 : 0;
3058+}
3059+
3060+static int process_root_ref(struct extent_buffer *eb, int slot,
3061+ struct btrfs_key *key,
3062+ struct cache_tree *root_cache)
3063+{
3064+ u64 dirid;
3065+ u64 index;
3066+ u32 len;
3067+ u32 name_len;
3068+ struct btrfs_root_ref *ref;
3069+ char namebuf[BTRFS_NAME_LEN];
3070+ int error;
3071+
3072+ ref = btrfs_item_ptr(eb, slot, struct btrfs_root_ref);
3073+
3074+ dirid = btrfs_root_ref_dirid(eb, ref);
3075+ index = btrfs_root_ref_sequence(eb, ref);
3076+ name_len = btrfs_root_ref_name_len(eb, ref);
3077+
3078+ if (name_len <= BTRFS_NAME_LEN) {
3079+ len = name_len;
3080+ error = 0;
3081+ } else {
3082+ len = BTRFS_NAME_LEN;
3083+ error = REF_ERR_NAME_TOO_LONG;
3084+ }
3085+ read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
3086+
3087+ if (key->type == BTRFS_ROOT_REF_KEY) {
3088+ add_root_backref(root_cache, key->offset, key->objectid, dirid,
3089+ index, namebuf, len, key->type, error);
3090+ } else {
3091+ add_root_backref(root_cache, key->objectid, key->offset, dirid,
3092+ index, namebuf, len, key->type, error);
3093+ }
3094+ return 0;
3095+}
3096+
3097 static int check_fs_root(struct btrfs_root *root,
3098+ struct cache_tree *root_cache,
3099 struct walk_control *wc)
3100 {
3101 int ret = 0;
3102@@ -1219,10 +1573,18 @@ static int check_fs_root(struct btrfs_root *root,
3103 int level;
3104 struct btrfs_path path;
3105 struct shared_node root_node;
3106+ struct root_record *rec;
3107 struct btrfs_root_item *root_item = &root->root_item;
3108
3109+ if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
3110+ rec = get_root_rec(root_cache, root->root_key.objectid);
3111+ if (btrfs_root_refs(root_item) > 0)
3112+ rec->found_root_item = 1;
3113+ }
3114+
3115 btrfs_init_path(&path);
3116 memset(&root_node, 0, sizeof(root_node));
3117+ cache_tree_init(&root_node.root_cache);
3118 cache_tree_init(&root_node.inode_cache);
3119
3120 level = btrfs_header_level(root->node);
3121@@ -1266,6 +1628,8 @@ static int check_fs_root(struct btrfs_root *root,
3122 }
3123 btrfs_release_path(root, &path);
3124
3125+ merge_root_recs(root, &root_node.root_cache, root_cache);
3126+
3127 if (root_node.current) {
3128 root_node.current->checked = 1;
3129 maybe_free_inode_rec(&root_node.inode_cache,
3130@@ -1280,13 +1644,15 @@ static int fs_root_objectid(u64 objectid)
3131 {
3132 if (objectid == BTRFS_FS_TREE_OBJECTID ||
3133 objectid == BTRFS_TREE_RELOC_OBJECTID ||
3134+ objectid == BTRFS_DATA_RELOC_TREE_OBJECTID ||
3135 (objectid >= BTRFS_FIRST_FREE_OBJECTID &&
3136- objectid < BTRFS_LAST_FREE_OBJECTID))
3137+ objectid <= BTRFS_LAST_FREE_OBJECTID))
3138 return 1;
3139 return 0;
3140 }
3141
3142-static int check_fs_roots(struct btrfs_root *root)
3143+static int check_fs_roots(struct btrfs_root *root,
3144+ struct cache_tree *root_cache)
3145 {
3146 struct btrfs_path path;
3147 struct btrfs_key key;
3148@@ -1319,10 +1685,14 @@ static int check_fs_roots(struct btrfs_root *root)
3149 fs_root_objectid(key.objectid)) {
3150 tmp_root = btrfs_read_fs_root_no_cache(root->fs_info,
3151 &key);
3152- ret = check_fs_root(tmp_root, &wc);
3153+ ret = check_fs_root(tmp_root, root_cache, &wc);
3154 if (ret)
3155 err = 1;
3156 btrfs_free_fs_root(root->fs_info, tmp_root);
3157+ } else if (key.type == BTRFS_ROOT_REF_KEY ||
3158+ key.type == BTRFS_ROOT_BACKREF_KEY) {
3159+ process_root_ref(leaf, path.slots[0], &key,
3160+ root_cache);
3161 }
3162 path.slots[0]++;
3163 }
3164@@ -1895,7 +2265,6 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
3165 return 0;
3166 }
3167
3168-
3169 static int add_pending(struct cache_tree *pending,
3170 struct cache_tree *seen, u64 bytenr, u32 size)
3171 {
3172@@ -2443,6 +2812,7 @@ static void print_usage(void)
3173
3174 int main(int ac, char **av)
3175 {
3176+ struct cache_tree root_cache;
3177 struct btrfs_root *root;
3178 int ret;
3179
3180@@ -2450,6 +2820,7 @@ int main(int ac, char **av)
3181 print_usage();
3182
3183 radix_tree_init();
3184+ cache_tree_init(&root_cache);
3185 root = open_ctree(av[1], 0, 0);
3186
3187 if (root == NULL)
3188@@ -2458,10 +2829,15 @@ int main(int ac, char **av)
3189 ret = check_extents(root);
3190 if (ret)
3191 goto out;
3192- ret = check_fs_roots(root);
3193+ ret = check_fs_roots(root, &root_cache);
3194+ if (ret)
3195+ goto out;
3196
3197+ ret = check_root_refs(root, &root_cache);
3198 out:
3199+ free_root_recs(&root_cache);
3200 close_ctree(root);
3201+
3202 if (found_old_backref) {
3203 /*
3204 * there was a disk format change when mixed
3205diff --git a/btrfsctl.c b/btrfsctl.c
3206index b323818..be6bf25 100644
3207--- a/btrfsctl.c
3208+++ b/btrfsctl.c
3209@@ -29,6 +29,7 @@
3210 #include <unistd.h>
3211 #include <dirent.h>
3212 #include <libgen.h>
3213+#include <stdlib.h>
3214 #include "kerncompat.h"
3215 #include "ctree.h"
3216 #include "transaction.h"
3217@@ -46,7 +47,7 @@ static inline int ioctl(int fd, int define, void *arg) { return 0; }
3218 static void print_usage(void)
3219 {
3220 printf("usage: btrfsctl [ -d file|dir] [ -s snap_name subvol|tree ]\n");
3221- printf(" [-r size] [-A device] [-a] [-c]\n");
3222+ printf(" [-r size] [-A device] [-a] [-c] [-D dir .]\n");
3223 printf("\t-d filename: defragments one file\n");
3224 printf("\t-d directory: defragments the entire Btree\n");
3225 printf("\t-s snap_name dir: creates a new snapshot of dir\n");
3226@@ -55,6 +56,9 @@ static void print_usage(void)
3227 printf("\t-A device: scans the device file for a Btrfs filesystem\n");
3228 printf("\t-a: scans all devices for Btrfs filesystems\n");
3229 printf("\t-c: forces a single FS sync\n");
3230+ printf("\t-D: delete snapshot\n");
3231+ printf("\t-m [tree id] directory: set the default mounted subvolume"
3232+ " to the [tree id] or the directory\n");
3233 printf("%s\n", BTRFS_BUILD_VERSION);
3234 exit(1);
3235 }
3236@@ -100,6 +104,7 @@ int main(int ac, char **av)
3237 unsigned long command = 0;
3238 int len;
3239 char *fullpath;
3240+ u64 objectid = 0;
3241
3242 if (ac == 2 && strcmp(av[1], "-a") == 0) {
3243 fprintf(stderr, "Scanning for Btrfs filesystems\n");
3244@@ -158,6 +163,18 @@ int main(int ac, char **av)
3245 print_usage();
3246 }
3247 command = BTRFS_IOC_DEFRAG;
3248+ } else if (strcmp(av[i], "-D") == 0) {
3249+ if (i >= ac - 1) {
3250+ fprintf(stderr, "-D requires an arg\n");
3251+ print_usage();
3252+ }
3253+ command = BTRFS_IOC_SNAP_DESTROY;
3254+ name = av[i + 1];
3255+ len = strlen(name);
3256+ if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
3257+ fprintf(stderr, "-D size too long\n");
3258+ exit(1);
3259+ }
3260 } else if (strcmp(av[i], "-A") == 0) {
3261 if (i >= ac - 1) {
3262 fprintf(stderr, "-A requires an arg\n");
3263@@ -178,6 +195,16 @@ int main(int ac, char **av)
3264 command = BTRFS_IOC_RESIZE;
3265 } else if (strcmp(av[i], "-c") == 0) {
3266 command = BTRFS_IOC_SYNC;
3267+ } else if (strcmp(av[i], "-m") == 0) {
3268+ command = BTRFS_IOC_DEFAULT_SUBVOL;
3269+ if (i == ac - 3) {
3270+ objectid = (unsigned long long)
3271+ strtoll(av[i + 1], NULL, 0);
3272+ if (errno == ERANGE) {
3273+ fprintf(stderr, "invalid tree id\n");
3274+ exit(1);
3275+ }
3276+ }
3277 }
3278 }
3279 if (command == 0) {
3280@@ -206,6 +233,9 @@ int main(int ac, char **av)
3281 if (command == BTRFS_IOC_SNAP_CREATE) {
3282 args.fd = fd;
3283 ret = ioctl(snap_fd, command, &args);
3284+ } else if (command == BTRFS_IOC_DEFAULT_SUBVOL) {
3285+ printf("objectid is %llu\n", objectid);
3286+ ret = ioctl(fd, command, &objectid);
3287 } else
3288 ret = ioctl(fd, command, &args);
3289 if (ret < 0) {
3290diff --git a/convert.c b/convert.c
3291index d2c9efa..d037c98 100644
3292--- a/convert.c
3293+++ b/convert.c
3294@@ -370,7 +370,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3295 struct btrfs_extent_item *ei;
3296 u32 blocksize = root->sectorsize;
3297 u64 nbytes;
3298- u64 bytes_used;
3299
3300 if (disk_bytenr == 0) {
3301 ret = btrfs_insert_file_extent(trans, root, objectid,
3302@@ -432,9 +431,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3303 nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes;
3304 btrfs_set_stack_inode_nbytes(inode, nbytes);
3305
3306- bytes_used = btrfs_root_used(&root->root_item);
3307- btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
3308-
3309 btrfs_release_path(root, &path);
3310
3311 ins_key.objectid = disk_bytenr;
3312@@ -454,9 +450,6 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
3313
3314 btrfs_mark_buffer_dirty(leaf);
3315
3316- bytes_used = btrfs_super_bytes_used(&info->super_copy);
3317- btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
3318- num_bytes);
3319 ret = btrfs_update_block_group(trans, root, disk_bytenr,
3320 num_bytes, 1, 0);
3321 if (ret)
3322diff --git a/ctree.h b/ctree.h
3323index a9062ea..64ecf12 100644
3324--- a/ctree.h
3325+++ b/ctree.h
3326@@ -1047,6 +1047,7 @@ BTRFS_SETGET_STACK_FUNCS(block_group_flags,
3327
3328 /* struct btrfs_inode_ref */
3329 BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
3330+BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
3331 BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
3332
3333 /* struct btrfs_inode_item */
3334@@ -1325,6 +1326,10 @@ BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
3335 BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
3336 BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
3337
3338+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
3339+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
3340+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
3341+
3342 /* struct btrfs_dir_item */
3343 BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
3344 BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
3345@@ -1572,6 +1577,7 @@ static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
3346
3347 /* struct btrfs_file_extent_item */
3348 BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
3349+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, type, 8);
3350
3351 static inline unsigned long btrfs_file_extent_inline_start(struct
3352 btrfs_file_extent_item *e)
3353@@ -1588,18 +1594,30 @@ static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
3354
3355 BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
3356 disk_bytenr, 64);
3357+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item,
3358+ disk_bytenr, 64);
3359 BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
3360 generation, 64);
3361+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item,
3362+ generation, 64);
3363 BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
3364 disk_num_bytes, 64);
3365 BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
3366 offset, 64);
3367+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item,
3368+ offset, 64);
3369 BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
3370 num_bytes, 64);
3371+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item,
3372+ num_bytes, 64);
3373 BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
3374 ram_bytes, 64);
3375+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item,
3376+ ram_bytes, 64);
3377 BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
3378 compression, 8);
3379+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item,
3380+ compression, 8);
3381 BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
3382 encryption, 8);
3383 BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
3384diff --git a/ioctl-test.c b/ioctl-test.c
3385new file mode 100644
3386index 0000000..7cf3bc2
3387--- /dev/null
3388+++ b/ioctl-test.c
3389@@ -0,0 +1,36 @@
3390+#include <stdio.h>
3391+#include <stdlib.h>
3392+#include "kerncompat.h"
3393+#include "ioctl.h"
3394+
3395+unsigned long ioctls[] = {
3396+ BTRFS_IOC_SNAP_CREATE,
3397+ BTRFS_IOC_DEFRAG,
3398+ BTRFS_IOC_RESIZE,
3399+ BTRFS_IOC_SCAN_DEV,
3400+ BTRFS_IOC_TRANS_START,
3401+ BTRFS_IOC_TRANS_END,
3402+ BTRFS_IOC_SYNC,
3403+ BTRFS_IOC_CLONE,
3404+ BTRFS_IOC_ADD_DEV,
3405+ BTRFS_IOC_RM_DEV,
3406+ BTRFS_IOC_BALANCE,
3407+ BTRFS_IOC_SUBVOL_CREATE,
3408+ BTRFS_IOC_SNAP_DESTROY,
3409+ BTRFS_IOC_DEFRAG_RANGE,
3410+ BTRFS_IOC_TREE_SEARCH,
3411+ BTRFS_IOC_INO_LOOKUP,
3412+ BTRFS_IOC_DEFAULT_SUBVOL,
3413+ BTRFS_IOC_SPACE_INFO,
3414+ 0 };
3415+
3416+int main(int ac, char **av)
3417+{
3418+ int i = 0;
3419+ while(ioctls[i]) {
3420+ printf("%lu\n" ,ioctls[i]);
3421+ i++;
3422+ }
3423+ return 0;
3424+}
3425+
3426diff --git a/ioctl.h b/ioctl.h
3427index a084f33..776d7a9 100644
3428--- a/ioctl.h
3429+++ b/ioctl.h
3430@@ -30,6 +30,108 @@ struct btrfs_ioctl_vol_args {
3431 char name[BTRFS_PATH_NAME_MAX + 1];
3432 };
3433
3434+struct btrfs_ioctl_search_key {
3435+ /* which root are we searching. 0 is the tree of tree roots */
3436+ __u64 tree_id;
3437+
3438+ /* keys returned will be >= min and <= max */
3439+ __u64 min_objectid;
3440+ __u64 max_objectid;
3441+
3442+ /* keys returned will be >= min and <= max */
3443+ __u64 min_offset;
3444+ __u64 max_offset;
3445+
3446+ /* max and min transids to search for */
3447+ __u64 min_transid;
3448+ __u64 max_transid;
3449+
3450+ /* keys returned will be >= min and <= max */
3451+ __u32 min_type;
3452+ __u32 max_type;
3453+
3454+ /*
3455+ * how many items did userland ask for, and how many are we
3456+ * returning
3457+ */
3458+ __u32 nr_items;
3459+
3460+ /* align to 64 bits */
3461+ __u32 unused;
3462+
3463+ /* some extra for later */
3464+ __u64 unused1;
3465+ __u64 unused2;
3466+ __u64 unused3;
3467+ __u64 unused4;
3468+};
3469+
3470+struct btrfs_ioctl_search_header {
3471+ __u64 transid;
3472+ __u64 objectid;
3473+ __u64 offset;
3474+ __u32 type;
3475+ __u32 len;
3476+} __attribute__((may_alias));
3477+
3478+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
3479+/*
3480+ * the buf is an array of search headers where
3481+ * each header is followed by the actual item
3482+ * the type field is expanded to 32 bits for alignment
3483+ */
3484+struct btrfs_ioctl_search_args {
3485+ struct btrfs_ioctl_search_key key;
3486+ char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
3487+};
3488+
3489+#define BTRFS_INO_LOOKUP_PATH_MAX 4080
3490+struct btrfs_ioctl_ino_lookup_args {
3491+ __u64 treeid;
3492+ __u64 objectid;
3493+ char name[BTRFS_INO_LOOKUP_PATH_MAX];
3494+};
3495+
3496+/* flags for the defrag range ioctl */
3497+#define BTRFS_DEFRAG_RANGE_COMPRESS 1
3498+#define BTRFS_DEFRAG_RANGE_START_IO 2
3499+
3500+struct btrfs_ioctl_defrag_range_args {
3501+ /* start of the defrag operation */
3502+ __u64 start;
3503+
3504+ /* number of bytes to defrag, use (u64)-1 to say all */
3505+ __u64 len;
3506+
3507+ /*
3508+ * flags for the operation, which can include turning
3509+ * on compression for this one defrag
3510+ */
3511+ __u64 flags;
3512+
3513+ /*
3514+ * any extent bigger than this will be considered
3515+ * already defragged. Use 0 to take the kernel default
3516+ * Use 1 to say every single extent must be rewritten
3517+ */
3518+ __u32 extent_thresh;
3519+
3520+ /* spare for later */
3521+ __u32 unused[5];
3522+};
3523+
3524+struct btrfs_ioctl_space_info {
3525+ __u64 flags;
3526+ __u64 total_bytes;
3527+ __u64 used_bytes;
3528+};
3529+
3530+struct btrfs_ioctl_space_args {
3531+ __u64 space_slots;
3532+ __u64 total_spaces;
3533+ struct btrfs_ioctl_space_info spaces[0];
3534+};
3535+
3536 #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
3537 struct btrfs_ioctl_vol_args)
3538 #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
3539@@ -56,4 +158,15 @@ struct btrfs_ioctl_vol_args {
3540 /* 13 is for CLONE_RANGE */
3541 #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
3542 struct btrfs_ioctl_vol_args)
3543+#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
3544+ struct btrfs_ioctl_vol_args)
3545+#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
3546+ struct btrfs_ioctl_defrag_range_args)
3547+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
3548+ struct btrfs_ioctl_search_args)
3549+#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
3550+ struct btrfs_ioctl_ino_lookup_args)
3551+#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
3552+#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
3553+ struct btrfs_ioctl_space_args)
3554 #endif
3555diff --git a/man/Makefile b/man/Makefile
3556index 4e8893b..4a90b75 100644
3557--- a/man/Makefile
3558+++ b/man/Makefile
3559@@ -7,13 +7,16 @@ mandir = $(prefix)/man
3560 man8dir = $(mandir)/man8
3561
3562 MANPAGES = mkfs.btrfs.8.gz btrfsctl.8.gz btrfsck.8.gz btrfs-image.8.gz \
3563- btrfs-show.8.gz
3564+ btrfs-show.8.gz btrfs.8.gz
3565
3566 all: $(MANPAGES)
3567
3568 mkfs.btrfs.8.gz: mkfs.btrfs.8.in
3569 $(GZIP) -n -c mkfs.btrfs.8.in > mkfs.btrfs.8.gz
3570
3571+btrfs.8.gz: btrfs.8.in
3572+ $(GZIP) -n -c btrfs.8.in > btrfs.8.gz
3573+
3574 btrfsctl.8.gz: btrfsctl.8.in
3575 $(GZIP) -n -c btrfsctl.8.in > btrfsctl.8.gz
3576
3577diff --git a/man/btrfs.8.in b/man/btrfs.8.in
3578new file mode 100644
3579index 0000000..26ef982
3580--- /dev/null
3581+++ b/man/btrfs.8.in
3582@@ -0,0 +1,170 @@
3583+.TH BTRFS 8 "" "btrfs" "btrfs"
3584+.\"
3585+.\" Man page written by Goffredo Baroncelli <kreijack@inwind.it> (Feb 2010)
3586+.\"
3587+.SH NAME
3588+btrfs \- control a btrfs filesystem
3589+.SH SYNOPSIS
3590+\fBbtrfs\fP \fBsubvolume snapshot\fP\fI <source> [<dest>/]<name>\fP
3591+.PP
3592+\fBbtrfs\fP \fBsubvolume delete\fP\fI <subvolume>\fP
3593+.PP
3594+\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
3595+.PP
3596+\fBbtrfs\fP \fBsubvolume list\fP\fI <path>\fP
3597+.PP
3598+\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
3599+.PP
3600+\fBbtrfs\fP \fBfilesystem defrag\fP\fI <file>|<dir> [<file>|<dir>...]\fP
3601+.PP
3602+\fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
3603+.PP
3604+\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
3605+.PP
3606+\fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
3607+.PP
3608+\fBbtrfs\fP \fBdevice show\fP\fI <dev>|<label> [<dev>|<label>...]\fP
3609+.PP
3610+\fBbtrfs\fP \fBdevice balance\fP\fI <path> \fP
3611+.PP
3612+\fBbtrfs\fP \fBdevice add\fP\fI <dev> [<dev>..] <path> \fP
3613+.PP
3614+\fBbtrfs\fP \fBdevice delete\fP\fI <dev> [<dev>..] <path> \fP]
3615+
3616+.PP
3617+\fBbtrfs\fP \fBhelp|\-\-help|\-h \fP\fI\fP
3618+.PP
3619+.SH DESCRIPTION
3620+.B btrfs
3621+is used to control the filesystem and the files and directories stored. It is
3622+the tool to create or destroy a snapshot or a subvolume for the
3623+filesystem, to defrag a file or a directory, flush the data to the disk,
3624+to resize the filesystem, to scan the device.
3625+
3626+It is possible to abbreviate the commands unless the commands are ambiguous.
3627+For example: it is possible to run
3628+.I btrfs sub snaps
3629+instead of
3630+.I btrfs subvolume snapshot.
3631+But
3632+.I btrfs dev s
3633+is not allowed, because
3634+.I dev s
3635+may be interpreted both as
3636+.I device show
3637+and as
3638+.I device scan.
3639+In this case
3640+.I btrfs
3641+returns an error.
3642+
3643+If a command is terminated by
3644+.I --help
3645+, the relevant help is showed. If the passed command matches more commands,
3646+the help of all the matched commands are showed. For example
3647+.I btrfs dev --help
3648+shows the help of all
3649+.I device*
3650+command.
3651+
3652+.SH COMMANDS
3653+.TP
3654+
3655+\fBsubvolume snapshot\fR\fI <source> [<dest>/]<name>\fR
3656+Create a writable snapshot of the subvolume \fI<source>\fR with the name
3657+\fI<name>\fR in the \fI<dest>\fR directory. If \fI<source>\fR is not a
3658+subvolume, \fBbtrfs\fR returns an error.
3659+.TP
3660+
3661+\fBsubvolume delete\fR\fI <subvolume>\fR
3662+Delete the subvolume \fI<subvolume>\fR. If \fI<subvolume>\fR is not a
3663+subvolume, \fBbtrfs\fR returns an error.
3664+.TP
3665+
3666+\fBsubvolume create\fR\fI [<dest>/]<name>\fR
3667+Create a subvolume in \fI<dest>\fR (or in the current directory if
3668+\fI<dest>\fR is omitted).
3669+.TP
3670+
3671+\fBsubvolume list\fR\fI <path>\fR
3672+List the subvolumes present in the filesystem \fI<path>\fR. For every
3673+subvolume is showed the subvolume ID (second column),
3674+the ID of the \fItop level\fR
3675+subvolume (fifth column), and the path (seventh column) relative to the
3676+\fItop level\fR subvolume.
3677+These <ID> may be used by the \fBsubvolume set-default\fR command, or at
3678+mount time via the \fIsubvol=\fR option.
3679+.TP
3680+
3681+\fBsubvolume set-default\fR\fI <id> <path>\fR
3682+Set the subvolume of the filesystem \fI<path>\fR which is mounted as
3683+\fIdefault\fR. The subvolume is identified by \fB<id>\fR, which
3684+is returned by the \fBsubvolume list\fR command.
3685+.TP
3686+
3687+\fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fR
3688+Defragment files and/or directories.
3689+.TP
3690+
3691+\fBdevice scan\fR \fI[<device> [<device>..]]\fR
3692+Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR scans
3693+all the block devices.
3694+.TP
3695+
3696+\fBfilesystem sync\fR\fI <path> \fR
3697+Force a sync for the filesystem identified by \fI<path>\fR.
3698+.TP
3699+
3700+.\"
3701+.\" Some wording are extracted by the resize2fs man page
3702+.\"
3703+
3704+\fBfilesystem resize\fR\fI [+/\-]<size>[gkm]|max <path>\fR
3705+Resize a filesystem identified by \fI<path>\fR.
3706+The \fI<size>\fR parameter specifies the new size of the filesystem.
3707+If the prefix \fI+\fR or \fI\-\fR is present the size is increased or decreased
3708+by the quantity \fI<size>\fR.
3709+If no units are specified, the unit of the \fI<size>\fR parameter defaults to
3710+bytes. Optionally, the size parameter may be suffixed by one of the following
3711+the units designators: 'K', 'M', or 'G', kilobytes, megabytes, or gigabytes,
3712+respectively.
3713+
3714+If 'max' is passed, the filesystem will occupy all available space on the
3715+volume(s).
3716+
3717+The \fBresize\fR command \fBdoes not\fR manipulate the size of underlying
3718+partition. If you wish to enlarge/reduce a filesystem, you must make sure you
3719+can expand the partition before enlarging the filesystem and shrink the
3720+partition after reducing the size of the filesystem.
3721+.TP
3722+
3723+\fBfilesystem show\fR [<uuid>|<label>]\fR
3724+Show the btrfs filesystem with some additional info. If no UUID or label is
3725+passed, \fBbtrfs\fR show info of all the btrfs filesystem.
3726+.TP
3727+
3728+\fBdevice balance\fR \fI<path>\fR
3729+Balance the chunks of the filesystem identified by \fI<path>\fR
3730+across the devices.
3731+.TP
3732+
3733+\fBdevice add\fR\fI <dev> [<dev>..] <path>\fR
3734+Add device(s) to the filesystem identified by \fI<path>\fR.
3735+.TP
3736+
3737+\fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
3738+Remove device(s) from a filesystem identified by \fI<path>\fR.
3739+.PP
3740+
3741+.SH EXIT STATUS
3742+\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
3743+case of failure.
3744+
3745+.SH AVAILABILITY
3746+.B btrfs
3747+is part of btrfs-progs. Btrfs filesystem is currently under heavy development,
3748+and not suitable for any uses other than benchmarking and review.
3749+Please refer to the btrfs wiki http://btrfs.wiki.kernel.org for
3750+further details.
3751+.SH SEE ALSO
3752+.BR mkfs.btrfs (8)
This page took 2.605509 seconds and 4 git commands to generate.