source: bootcd/isolinux/syslinux-6.03/core/fs/btrfs/btrfs.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 19.0 KB
Line 
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
25union tree_buf {
26        struct btrfs_header header;
27        struct btrfs_node node;
28        struct btrfs_leaf leaf;
29};
30
31/* filesystem instance structure */
32struct 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 */
40typedef int (*cmp_func)(const void *ptr1, const void *ptr2);
41
42/* simple but useful bin search, used for chunk search and btree search */
43static 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
73static 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 */
84static 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 */
120static 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 */
143static 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 */
152static 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
191static 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
197static void clear_path(struct btrfs_path *path)
198{
199        memset(path, 0, sizeof(*path));
200}
201
202static 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 */
221static 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 ... */
236static 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 */
288static 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 */
312static 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 */
330static 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 */
355static 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
391static inline u64 btrfs_name_hash(const char *name, int len)
392{
393        return btrfs_crc32c((u32)~1, name, len);
394}
395
396static 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
444static 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
450static 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
471static 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
480static 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
519static 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
568static 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
591static 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. */
645static 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
679const 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};
Note: See TracBrowser for help on using the repository browser.