Home | History | Annotate | Download | only in btrfs
      1 /*
      2  * btrfs.c -- readonly btrfs support for syslinux
      3  * Some data structures are derivated from btrfs-tools-0.19 ctree.h
      4  * Copyright 2009-2014 Intel Corporation; authors: Alek Du, H. Peter Anvin
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
      9  * Boston MA 02111-1307, USA; either version 2 of the License, or
     10  * (at your option) any later version; incorporated herein by reference.
     11  *
     12  */
     13 
     14 #include <dprintf.h>
     15 #include <stdio.h>
     16 #include <string.h>
     17 #include <cache.h>
     18 #include <core.h>
     19 #include <disk.h>
     20 #include <fs.h>
     21 #include <dirent.h>
     22 #include <minmax.h>
     23 #include "btrfs.h"
     24 
     25 union tree_buf {
     26 	struct btrfs_header header;
     27 	struct btrfs_node node;
     28 	struct btrfs_leaf leaf;
     29 };
     30 
     31 /* filesystem instance structure */
     32 struct btrfs_info {
     33 	u64 fs_tree;
     34 	struct btrfs_super_block sb;
     35 	struct btrfs_chunk_map chunk_map;
     36 	union tree_buf *tree_buf;
     37 };
     38 
     39 /* compare function used for bin_search */
     40 typedef int (*cmp_func)(const void *ptr1, const void *ptr2);
     41 
     42 /* simple but useful bin search, used for chunk search and btree search */
     43 static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
     44 		      int min, int max, int *slot)
     45 {
     46 	int low = min;
     47 	int high = max;
     48 	int mid;
     49 	int ret;
     50 	unsigned long offset;
     51 	void *item;
     52 
     53 	while (low < high) {
     54 		mid = (low + high) / 2;
     55 		offset = mid * item_size;
     56 
     57 		item = ptr + offset;
     58 		ret = func(item, cmp_item);
     59 
     60 		if (ret < 0)
     61 			low = mid + 1;
     62 		else if (ret > 0)
     63 			high = mid;
     64 		else {
     65 			*slot = mid;
     66 			return 0;
     67 		}
     68 	}
     69 	*slot = low;
     70 	return 1;
     71 }
     72 
     73 static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
     74 				struct btrfs_chunk_map_item *m2)
     75 {
     76 	if (m1->logical > m2->logical)
     77 		return 1;
     78 	if (m1->logical < m2->logical)
     79 		return -1;
     80 	return 0;
     81 }
     82 
     83 /* insert a new chunk mapping item */
     84 static void insert_map(struct fs_info *fs, struct btrfs_chunk_map_item *item)
     85 {
     86 	struct btrfs_info * const bfs = fs->fs_info;
     87 	struct btrfs_chunk_map *chunk_map = &bfs->chunk_map;
     88 	int ret;
     89 	int slot;
     90 	int i;
     91 
     92 	if (chunk_map->map == NULL) { /* first item */
     93 		chunk_map->map_length = BTRFS_MAX_CHUNK_ENTRIES;
     94 		chunk_map->map = malloc(chunk_map->map_length
     95 					* sizeof(chunk_map->map[0]));
     96 		chunk_map->map[0] = *item;
     97 		chunk_map->cur_length = 1;
     98 		return;
     99 	}
    100 	ret = bin_search(chunk_map->map, sizeof(*item), item,
    101 			(cmp_func)btrfs_comp_chunk_map, 0,
    102 			chunk_map->cur_length, &slot);
    103 	if (ret == 0)/* already in map */
    104 		return;
    105 	if (chunk_map->cur_length == BTRFS_MAX_CHUNK_ENTRIES) {
    106 		/* should be impossible */
    107 		printf("too many chunk items\n");
    108 		return;
    109 	}
    110 	for (i = chunk_map->cur_length; i > slot; i--)
    111 		chunk_map->map[i] = chunk_map->map[i-1];
    112 	chunk_map->map[slot] = *item;
    113 	chunk_map->cur_length++;
    114 }
    115 
    116 /*
    117  * from sys_chunk_array or chunk_tree, we can convert a logical address to
    118  * a physical address we can not support multi device case yet
    119  */
    120 static u64 logical_physical(struct fs_info *fs, u64 logical)
    121 {
    122 	struct btrfs_info * const bfs = fs->fs_info;
    123 	struct btrfs_chunk_map *chunk_map = &bfs->chunk_map;
    124 	struct btrfs_chunk_map_item item;
    125 	int slot, ret;
    126 
    127 	item.logical = logical;
    128 	ret = bin_search(chunk_map->map, sizeof(chunk_map->map[0]), &item,
    129 			(cmp_func)btrfs_comp_chunk_map, 0,
    130 			chunk_map->cur_length, &slot);
    131 	if (ret == 0)
    132 		slot++;
    133 	else if (slot == 0)
    134 		return -1;
    135 	if (logical >=
    136 		chunk_map->map[slot-1].logical + chunk_map->map[slot-1].length)
    137 		return -1;
    138 	return chunk_map->map[slot-1].physical + logical -
    139 			chunk_map->map[slot-1].logical;
    140 }
    141 
    142 /* btrfs has several super block mirrors, need to calculate their location */
    143 static inline u64 btrfs_sb_offset(int mirror)
    144 {
    145 	u64 start = 16 * 1024;
    146 	if (mirror)
    147 		return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror);
    148 	return BTRFS_SUPER_INFO_OFFSET;
    149 }
    150 
    151 /* find the most recent super block */
    152 static void btrfs_read_super_block(struct fs_info *fs)
    153 {
    154 	int i;
    155 	int ret;
    156 	u8 fsid[BTRFS_FSID_SIZE];
    157 	u64 offset;
    158 	u64 transid = 0;
    159 	struct btrfs_super_block buf;
    160 	struct btrfs_info * const bfs = fs->fs_info;
    161 
    162 	bfs->sb.total_bytes = ~0; /* Unknown as of yet */
    163 
    164 	/* find most recent super block */
    165 	for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
    166 		offset = btrfs_sb_offset(i);
    167 		if (offset >= bfs->sb.total_bytes)
    168 			break;
    169 
    170 		ret = cache_read(fs, (char *)&buf, offset, sizeof(buf));
    171 		if (ret < sizeof(buf))
    172 			break;
    173 
    174 		if (buf.bytenr != offset ||
    175 		    strncmp((char *)(&buf.magic), BTRFS_MAGIC,
    176 			    sizeof(buf.magic)))
    177 			continue;
    178 
    179 		if (i == 0)
    180 			memcpy(fsid, buf.fsid, sizeof(fsid));
    181 		else if (memcmp(fsid, buf.fsid, sizeof(fsid)))
    182 			continue;
    183 
    184 		if (buf.generation > transid) {
    185 			memcpy(&bfs->sb, &buf, sizeof(bfs->sb));
    186 			transid = buf.generation;
    187 		}
    188 	}
    189 }
    190 
    191 static inline unsigned long btrfs_chunk_item_size(int num_stripes)
    192 {
    193 	return sizeof(struct btrfs_chunk) +
    194 		sizeof(struct btrfs_stripe) * (num_stripes - 1);
    195 }
    196 
    197 static void clear_path(struct btrfs_path *path)
    198 {
    199 	memset(path, 0, sizeof(*path));
    200 }
    201 
    202 static int btrfs_comp_keys(const struct btrfs_disk_key *k1,
    203 			   const struct btrfs_disk_key *k2)
    204 {
    205 	if (k1->objectid > k2->objectid)
    206 		return 1;
    207 	if (k1->objectid < k2->objectid)
    208 		return -1;
    209 	if (k1->type > k2->type)
    210 		return 1;
    211 	if (k1->type < k2->type)
    212 		return -1;
    213 	if (k1->offset > k2->offset)
    214 		return 1;
    215 	if (k1->offset < k2->offset)
    216 		return -1;
    217 	return 0;
    218 }
    219 
    220 /* compare keys but ignore offset, is useful to enumerate all same kind keys */
    221 static int btrfs_comp_keys_type(const struct btrfs_disk_key *k1,
    222 				const struct btrfs_disk_key *k2)
    223 {
    224 	if (k1->objectid > k2->objectid)
    225 		return 1;
    226 	if (k1->objectid < k2->objectid)
    227 		return -1;
    228 	if (k1->type > k2->type)
    229 		return 1;
    230 	if (k1->type < k2->type)
    231 		return -1;
    232 	return 0;
    233 }
    234 
    235 /* seach tree directly on disk ... */
    236 static int search_tree(struct fs_info *fs, u64 loffset,
    237 		       struct btrfs_disk_key *key, struct btrfs_path *path)
    238 {
    239 	struct btrfs_info * const bfs = fs->fs_info;
    240 	union tree_buf *tree_buf = bfs->tree_buf;
    241 	int slot, ret;
    242 	u64 offset;
    243 
    244 	offset = logical_physical(fs, loffset);
    245 	cache_read(fs, &tree_buf->header, offset, sizeof(tree_buf->header));
    246 	if (tree_buf->header.level) {
    247 		/* inner node */
    248 		cache_read(fs, (char *)&tree_buf->node.ptrs[0],
    249 			   offset + sizeof tree_buf->header,
    250 			   bfs->sb.nodesize - sizeof tree_buf->header);
    251 		path->itemsnr[tree_buf->header.level] = tree_buf->header.nritems;
    252 		path->offsets[tree_buf->header.level] = loffset;
    253 		ret = bin_search(&tree_buf->node.ptrs[0],
    254 				 sizeof(struct btrfs_key_ptr),
    255 				 key, (cmp_func)btrfs_comp_keys,
    256 				 path->slots[tree_buf->header.level],
    257 				 tree_buf->header.nritems, &slot);
    258 		if (ret && slot > path->slots[tree_buf->header.level])
    259 			slot--;
    260 		path->slots[tree_buf->header.level] = slot;
    261 		ret = search_tree(fs, tree_buf->node.ptrs[slot].blockptr,
    262 				  key, path);
    263 	} else {
    264 		/* leaf node */
    265 		cache_read(fs, (char *)&tree_buf->leaf.items[0],
    266 			   offset + sizeof tree_buf->header,
    267 			   bfs->sb.leafsize - sizeof tree_buf->header);
    268 		path->itemsnr[tree_buf->header.level] = tree_buf->header.nritems;
    269 		path->offsets[tree_buf->header.level] = loffset;
    270 		ret = bin_search(&tree_buf->leaf.items[0],
    271 				 sizeof(struct btrfs_item),
    272 				 key, (cmp_func)btrfs_comp_keys,
    273 				 path->slots[0],
    274 				 tree_buf->header.nritems, &slot);
    275 		if (ret && slot > path->slots[tree_buf->header.level])
    276 			slot--;
    277 		path->slots[tree_buf->header.level] = slot;
    278 		path->item = tree_buf->leaf.items[slot];
    279 		cache_read(fs, (char *)&path->data,
    280 			   offset + sizeof tree_buf->header +
    281 			   tree_buf->leaf.items[slot].offset,
    282 			   tree_buf->leaf.items[slot].size);
    283 	}
    284 	return ret;
    285 }
    286 
    287 /* return 0 if leaf found */
    288 static int next_leaf(struct fs_info *fs, struct btrfs_disk_key *key, struct btrfs_path *path)
    289 {
    290 	int slot;
    291 	int level = 1;
    292 
    293 	while (level < BTRFS_MAX_LEVEL) {
    294 		if (!path->itemsnr[level]) /* no more nodes */
    295 			return 1;
    296 		slot = path->slots[level] + 1;
    297 		if (slot >= path->itemsnr[level]) {
    298 			level++;
    299 			continue;;
    300 		}
    301 		path->slots[level] = slot;
    302 		path->slots[level-1] = 0; /* reset low level slots info */
    303 		search_tree(fs, path->offsets[level], key, path);
    304 		break;
    305 	}
    306 	if (level == BTRFS_MAX_LEVEL)
    307 		return 1;
    308 	return 0;
    309 }
    310 
    311 /* return 0 if slot found */
    312 static int next_slot(struct fs_info *fs, struct btrfs_disk_key *key,
    313 		     struct btrfs_path *path)
    314 {
    315 	int slot;
    316 
    317 	if (!path->itemsnr[0])
    318 		return 1;
    319 	slot = path->slots[0] + 1;
    320 	if (slot >= path->itemsnr[0])
    321 		return 1;
    322 	path->slots[0] = slot;
    323 	search_tree(fs, path->offsets[0], key, path);
    324 	return 0;
    325 }
    326 
    327 /*
    328  * read chunk_array in super block
    329  */
    330 static void btrfs_read_sys_chunk_array(struct fs_info *fs)
    331 {
    332 	struct btrfs_info * const bfs = fs->fs_info;
    333 	struct btrfs_chunk_map_item item;
    334 	struct btrfs_disk_key *key;
    335 	struct btrfs_chunk *chunk;
    336 	int cur;
    337 
    338 	/* read chunk array in superblock */
    339 	cur = 0;
    340 	while (cur < bfs->sb.sys_chunk_array_size) {
    341 		key = (struct btrfs_disk_key *)(bfs->sb.sys_chunk_array + cur);
    342 		cur += sizeof(*key);
    343 		chunk = (struct btrfs_chunk *)(bfs->sb.sys_chunk_array + cur);
    344 		cur += btrfs_chunk_item_size(chunk->num_stripes);
    345 		/* insert to mapping table, ignore multi stripes */
    346 		item.logical = key->offset;
    347 		item.length = chunk->length;
    348 		item.devid = chunk->stripe.devid;
    349 		item.physical = chunk->stripe.offset;/*ignore other stripes */
    350 		insert_map(fs, &item);
    351 	}
    352 }
    353 
    354 /* read chunk items from chunk_tree and insert them to chunk map */
    355 static void btrfs_read_chunk_tree(struct fs_info *fs)
    356 {
    357 	struct btrfs_info * const bfs = fs->fs_info;
    358 	struct btrfs_disk_key search_key;
    359 	struct btrfs_chunk *chunk;
    360 	struct btrfs_chunk_map_item item;
    361 	struct btrfs_path path;
    362 
    363 	if (!(bfs->sb.flags & BTRFS_SUPER_FLAG_METADUMP)) {
    364 		if (bfs->sb.num_devices > 1)
    365 			printf("warning: only support single device btrfs\n");
    366 		/* read chunk from chunk_tree */
    367 		search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
    368 		search_key.type = BTRFS_CHUNK_ITEM_KEY;
    369 		search_key.offset = 0;
    370 		clear_path(&path);
    371 		search_tree(fs, bfs->sb.chunk_root, &search_key, &path);
    372 		do {
    373 			do {
    374 				if (btrfs_comp_keys_type(&search_key,
    375 							&path.item.key))
    376 					break;
    377 				chunk = (struct btrfs_chunk *)(path.data);
    378 				/* insert to mapping table, ignore stripes */
    379 				item.logical = path.item.key.offset;
    380 				item.length = chunk->length;
    381 				item.devid = chunk->stripe.devid;
    382 				item.physical = chunk->stripe.offset;
    383 				insert_map(fs, &item);
    384 			} while (!next_slot(fs, &search_key, &path));
    385 			if (btrfs_comp_keys_type(&search_key, &path.item.key))
    386 				break;
    387 		} while (!next_leaf(fs, &search_key, &path));
    388 	}
    389 }
    390 
    391 static inline u64 btrfs_name_hash(const char *name, int len)
    392 {
    393 	return btrfs_crc32c((u32)~1, name, len);
    394 }
    395 
    396 static struct inode *btrfs_iget_by_inr(struct fs_info *fs, u64 inr)
    397 {
    398 	struct btrfs_info * const bfs = fs->fs_info;
    399 	struct inode *inode;
    400 	struct btrfs_inode_item inode_item;
    401 	struct btrfs_disk_key search_key;
    402 	struct btrfs_path path;
    403 	int ret;
    404 
    405 	/* FIXME: some BTRFS inode member are u64, while our logical inode
    406            is u32, we may need change them to u64 later */
    407 	search_key.objectid = inr;
    408 	search_key.type = BTRFS_INODE_ITEM_KEY;
    409 	search_key.offset = 0;
    410 	clear_path(&path);
    411 	ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
    412 	if (ret)
    413 		return NULL;
    414 	inode_item = *(struct btrfs_inode_item *)path.data;
    415 	if (!(inode = alloc_inode(fs, inr, sizeof(struct btrfs_pvt_inode))))
    416 		return NULL;
    417 	inode->ino = inr;
    418 	inode->size = inode_item.size;
    419 	inode->mode = IFTODT(inode_item.mode);
    420 
    421 	if (inode->mode == DT_REG || inode->mode == DT_LNK) {
    422 		struct btrfs_file_extent_item extent_item;
    423 		u64 offset;
    424 
    425 		/* get file_extent_item */
    426 		search_key.type = BTRFS_EXTENT_DATA_KEY;
    427 		search_key.offset = 0;
    428 		clear_path(&path);
    429 		ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
    430 		if (ret)
    431 			return NULL; /* impossible */
    432 		extent_item = *(struct btrfs_file_extent_item *)path.data;
    433 		if (extent_item.type == BTRFS_FILE_EXTENT_INLINE)/* inline file */
    434 			offset = path.offsets[0] + sizeof(struct btrfs_header)
    435 				+ path.item.offset
    436 				+ offsetof(struct btrfs_file_extent_item, disk_bytenr);
    437 		else
    438 			offset = extent_item.disk_bytenr;
    439 		PVT(inode)->offset = offset;
    440 	}
    441 	return inode;
    442 }
    443 
    444 static struct inode *btrfs_iget_root(struct fs_info *fs)
    445 {
    446 	/* BTRFS_FIRST_CHUNK_TREE_OBJECTID(256) actually is first OBJECTID for FS_TREE */
    447 	return btrfs_iget_by_inr(fs, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
    448 }
    449 
    450 static struct inode *btrfs_iget(const char *name, struct inode *parent)
    451 {
    452 	struct fs_info * const fs = parent->fs;
    453 	struct btrfs_info * const bfs = fs->fs_info;
    454 	struct btrfs_disk_key search_key;
    455 	struct btrfs_path path;
    456 	struct btrfs_dir_item dir_item;
    457 	int ret;
    458 
    459 	search_key.objectid = parent->ino;
    460 	search_key.type = BTRFS_DIR_ITEM_KEY;
    461 	search_key.offset = btrfs_name_hash(name, strlen(name));
    462 	clear_path(&path);
    463 	ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
    464 	if (ret)
    465 		return NULL;
    466 	dir_item = *(struct btrfs_dir_item *)path.data;
    467 
    468 	return btrfs_iget_by_inr(fs, dir_item.location.objectid);
    469 }
    470 
    471 static int btrfs_readlink(struct inode *inode, char *buf)
    472 {
    473 	cache_read(inode->fs, buf,
    474 		   logical_physical(inode->fs, PVT(inode)->offset),
    475 		   inode->size);
    476 	buf[inode->size] = '\0';
    477 	return inode->size;
    478 }
    479 
    480 static int btrfs_readdir(struct file *file, struct dirent *dirent)
    481 {
    482 	struct fs_info * const fs = file->fs;
    483 	struct btrfs_info * const bfs = fs->fs_info;
    484 	struct inode * const inode = file->inode;
    485 	struct btrfs_disk_key search_key;
    486 	struct btrfs_path path;
    487 	struct btrfs_dir_item *dir_item;
    488 	int ret;
    489 
    490 	/*
    491 	 * we use file->offset to store last search key.offset, will will search
    492 	 * key that lower that offset, 0 means first search and we will search
    493          * -1UL, which is the biggest possible key
    494          */
    495 	search_key.objectid = inode->ino;
    496 	search_key.type = BTRFS_DIR_ITEM_KEY;
    497 	search_key.offset = file->offset - 1;
    498 	clear_path(&path);
    499 	ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
    500 
    501 	if (ret) {
    502 		if (btrfs_comp_keys_type(&search_key, &path.item.key))
    503 			return -1;
    504 	}
    505 
    506 	dir_item = (struct btrfs_dir_item *)path.data;
    507 	file->offset = path.item.key.offset;
    508 	dirent->d_ino = dir_item->location.objectid;
    509 	dirent->d_off = file->offset;
    510 	dirent->d_reclen = offsetof(struct dirent, d_name)
    511 		+ dir_item->name_len + 1;
    512 	dirent->d_type = IFTODT(dir_item->type);
    513 	memcpy(dirent->d_name, dir_item + 1, dir_item->name_len);
    514 	dirent->d_name[dir_item->name_len] = '\0';
    515 
    516 	return 0;
    517 }
    518 
    519 static int btrfs_next_extent(struct inode *inode, uint32_t lstart)
    520 {
    521 	struct btrfs_disk_key search_key;
    522 	struct btrfs_file_extent_item extent_item;
    523 	struct btrfs_path path;
    524 	int ret;
    525 	u64 offset;
    526 	struct fs_info * const fs = inode->fs;
    527 	struct btrfs_info * const bfs = fs->fs_info;
    528 	u32 sec_shift = SECTOR_SHIFT(fs);
    529 	u32 sec_size = SECTOR_SIZE(fs);
    530 
    531 	search_key.objectid = inode->ino;
    532 	search_key.type = BTRFS_EXTENT_DATA_KEY;
    533 	search_key.offset = lstart << sec_shift;
    534 	clear_path(&path);
    535 	ret = search_tree(fs, bfs->fs_tree, &search_key, &path);
    536 	if (ret) { /* impossible */
    537 		printf("btrfs: search extent data error!\n");
    538 		return -1;
    539 	}
    540 	extent_item = *(struct btrfs_file_extent_item *)path.data;
    541 
    542 	if (extent_item.encryption) {
    543 	    printf("btrfs: found encrypted data, cannot continue!\n");
    544 	    return -1;
    545 	}
    546 	if (extent_item.compression) {
    547 	    printf("btrfs: found compressed data, cannot continue!\n");
    548 	    return -1;
    549 	}
    550 
    551 	if (extent_item.type == BTRFS_FILE_EXTENT_INLINE) {/* inline file */
    552 		/* we fake a extent here, and PVT of inode will tell us */
    553 		offset = path.offsets[0] + sizeof(struct btrfs_header)
    554 			+ path.item.offset
    555 			+ offsetof(struct btrfs_file_extent_item, disk_bytenr);
    556 		inode->next_extent.len =
    557 			(inode->size + sec_size -1) >> sec_shift;
    558 	} else {
    559 		offset = extent_item.disk_bytenr + extent_item.offset;
    560 		inode->next_extent.len =
    561 			(extent_item.num_bytes + sec_size - 1) >> sec_shift;
    562 	}
    563 	inode->next_extent.pstart = logical_physical(fs, offset) >> sec_shift;
    564 	PVT(inode)->offset = offset;
    565 	return 0;
    566 }
    567 
    568 static uint32_t btrfs_getfssec(struct file *file, char *buf, int sectors,
    569 					bool *have_more)
    570 {
    571 	u32 ret;
    572 	struct fs_info *fs = file->fs;
    573 	u32 off = PVT(file->inode)->offset % SECTOR_SIZE(fs);
    574 	bool handle_inline = false;
    575 
    576 	if (off && !file->offset) {/* inline file first read patch */
    577 		file->inode->size += off;
    578 		handle_inline = true;
    579 	}
    580 	ret = generic_getfssec(file, buf, sectors, have_more);
    581 	if (!ret)
    582 		return ret;
    583 	off = PVT(file->inode)->offset % SECTOR_SIZE(fs);
    584 	if (handle_inline) {/* inline file patch */
    585 		ret -= off;
    586 		memcpy(buf, buf + off, ret);
    587 	}
    588 	return ret;
    589 }
    590 
    591 static void btrfs_get_fs_tree(struct fs_info *fs)
    592 {
    593 	struct btrfs_info * const bfs = fs->fs_info;
    594 	struct btrfs_disk_key search_key;
    595 	struct btrfs_path path;
    596 	struct btrfs_root_item *tree;
    597 	bool subvol_ok = false;
    598 
    599 	/* check if subvol is filled by installer */
    600 	if (*SubvolName) {
    601 		search_key.objectid = BTRFS_FS_TREE_OBJECTID;
    602 		search_key.type = BTRFS_ROOT_REF_KEY;
    603 		search_key.offset = 0;
    604 		clear_path(&path);
    605 		if (search_tree(fs, bfs->sb.root, &search_key, &path))
    606 			next_slot(fs, &search_key, &path);
    607 		do {
    608 			do {
    609 				struct btrfs_root_ref *ref;
    610 				int pathlen;
    611 
    612 				if (btrfs_comp_keys_type(&search_key,
    613 							&path.item.key))
    614 					break;
    615 				ref = (struct btrfs_root_ref *)path.data;
    616 				pathlen = path.item.size - sizeof(struct btrfs_root_ref);
    617 
    618 				if (!strncmp((char*)(ref + 1), SubvolName, pathlen)) {
    619 					subvol_ok = true;
    620 					break;
    621 				}
    622 			} while (!next_slot(fs, &search_key, &path));
    623 			if (subvol_ok)
    624 				break;
    625 			if (btrfs_comp_keys_type(&search_key, &path.item.key))
    626 				break;
    627 		} while (!next_leaf(fs, &search_key, &path));
    628 		if (!subvol_ok) /* should be impossible */
    629 			printf("no subvol found!\n");
    630 	}
    631 	/* find fs_tree from tree_root */
    632 	if (subvol_ok)
    633 		search_key.objectid = path.item.key.offset;
    634 	else /* "default" volume */
    635 		search_key.objectid = BTRFS_FS_TREE_OBJECTID;
    636 	search_key.type = BTRFS_ROOT_ITEM_KEY;
    637 	search_key.offset = -1;
    638 	clear_path(&path);
    639 	search_tree(fs, bfs->sb.root, &search_key, &path);
    640 	tree = (struct btrfs_root_item *)path.data;
    641 	bfs->fs_tree = tree->bytenr;
    642 }
    643 
    644 /* init. the fs meta data, return the block size shift bits. */
    645 static int btrfs_fs_init(struct fs_info *fs)
    646 {
    647 	struct disk *disk = fs->fs_dev->disk;
    648 	struct btrfs_info *bfs;
    649 
    650 	btrfs_init_crc32c();
    651 
    652 	bfs = zalloc(sizeof(struct btrfs_info));
    653 	if (!bfs)
    654 		return -1;
    655 
    656 	fs->fs_info = bfs;
    657 
    658 	fs->sector_shift = disk->sector_shift;
    659 	fs->sector_size  = 1 << fs->sector_shift;
    660 	fs->block_shift  = BTRFS_BLOCK_SHIFT;
    661 	fs->block_size   = 1 << fs->block_shift;
    662 
    663 	/* Initialize the block cache */
    664 	cache_init(fs->fs_dev, fs->block_shift);
    665 
    666 	btrfs_read_super_block(fs);
    667 	if (bfs->sb.magic != BTRFS_MAGIC_N)
    668 		return -1;
    669 	bfs->tree_buf = malloc(max(bfs->sb.nodesize, bfs->sb.leafsize));
    670 	if (!bfs->tree_buf)
    671 		return -1;
    672 	btrfs_read_sys_chunk_array(fs);
    673 	btrfs_read_chunk_tree(fs);
    674 	btrfs_get_fs_tree(fs);
    675 
    676 	return fs->block_shift;
    677 }
    678 
    679 const struct fs_ops btrfs_fs_ops = {
    680     .fs_name       = "btrfs",
    681     .fs_flags      = 0,
    682     .fs_init       = btrfs_fs_init,
    683     .iget_root     = btrfs_iget_root,
    684     .iget          = btrfs_iget,
    685     .readlink      = btrfs_readlink,
    686     .getfssec      = btrfs_getfssec,
    687     .close_file    = generic_close_file,
    688     .mangle_name   = generic_mangle_name,
    689     .next_extent   = btrfs_next_extent,
    690     .readdir       = btrfs_readdir,
    691     .chdir_start   = generic_chdir_start,
    692     .open_config   = generic_open_config,
    693     .fs_uuid       = NULL,
    694 };
    695