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