aboutsummaryrefslogtreecommitdiffstats
path: root/stubdom
diff options
context:
space:
mode:
authorMatt Wilson <msw@amazon.com>2012-04-04 11:09:15 +0100
committerMatt Wilson <msw@amazon.com>2012-04-04 11:09:15 +0100
commit8c1ba7af046fcd12d1f91ad8506a2f8f9667a7a5 (patch)
treeb2b6d35aaa20e17ef3383613f2c7dd2e98b588d3 /stubdom
parent9fcf9e7e34b6999aa721d3e70a2592b2966736d7 (diff)
downloadxen-8c1ba7af046fcd12d1f91ad8506a2f8f9667a7a5.tar.gz
xen-8c1ba7af046fcd12d1f91ad8506a2f8f9667a7a5.tar.bz2
xen-8c1ba7af046fcd12d1f91ad8506a2f8f9667a7a5.zip
PV-GRUB: add support for btrfs
This patch adds btrfs support to the GRUB tree used to build PV-GRUB. The original patch is from Gentoo: https://bugs.gentoo.org/show_bug.cgi?id=283637 Signed-off-by: Matt Wilson <msw@amazon.com> Committed-by: Ian Jackson <ian.jackson.citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Diffstat (limited to 'stubdom')
-rw-r--r--stubdom/grub.patches/61btrfs.diff3512
1 files changed, 3512 insertions, 0 deletions
diff --git a/stubdom/grub.patches/61btrfs.diff b/stubdom/grub.patches/61btrfs.diff
new file mode 100644
index 0000000000..fc72771477
--- /dev/null
+++ b/stubdom/grub.patches/61btrfs.diff
@@ -0,0 +1,3512 @@
+diff -up grub-upstream.wip/AUTHORS.btrfs grub-upstream.wip/AUTHORS
+--- grub-upstream.wip/AUTHORS.btrfs 2004-03-27 16:25:17.000000000 +0000
++++ grub-upstream.wip/AUTHORS 2012-03-20 05:07:09.000000000 +0000
+@@ -41,6 +41,8 @@ Kristoffer Branemyr added VSTa filesyste
+
+ Serguei Tzukanov added JFS and XFS support.
+
++Edward Shishkin added Btrfs support.
++
+ Jason Thomas added Linux DAC960 support and support for hiding/unhiding
+ logical partitions, and did a significant bugfix for the terminal stuff.
+
+diff -up grub-upstream.wip/configure.ac.btrfs grub-upstream.wip/configure.ac
+--- grub-upstream.wip/configure.ac.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/configure.ac 2012-03-20 05:07:09.000000000 +0000
+@@ -274,6 +274,13 @@ if test x"$enable_reiserfs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1"
+ fi
+
++AC_ARG_ENABLE(btrfs,
++ [ --disable-btrfs disable BtrFS support in Stage 2])
++
++if test x"$enable_btrfs" != xno; then
++ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_BTRFS=1"
++fi
++
+ AC_ARG_ENABLE(vstafs,
+ [ --disable-vstafs disable VSTa FS support in Stage 2])
+
+diff -up grub-upstream.wip/docs/grub.texi.btrfs grub-upstream.wip/docs/grub.texi
+--- grub-upstream.wip/docs/grub.texi.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/docs/grub.texi 2012-03-20 05:07:09.000000000 +0000
+@@ -1761,6 +1761,7 @@ itself. Usually, this is put in a filesy
+ @itemx jfs_stage1_5
+ @itemx minix_stage1_5
+ @itemx reiserfs_stage1_5
++@itemx btrfs_stage1_5
+ @itemx vstafs_stage1_5
+ @itemx xfs_stage1_5
+
+diff -up grub-upstream.wip/grub/Makefile.am.btrfs grub-upstream.wip/grub/Makefile.am
+--- grub-upstream.wip/grub/Makefile.am.btrfs 2005-02-02 20:38:19.000000000 +0000
++++ grub-upstream.wip/grub/Makefile.am 2012-03-20 05:07:09.000000000 +0000
+@@ -8,7 +8,7 @@ endif
+
+ AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
+ -DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
+- -DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
++ -DFSYS_BTRFS=1 -DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
+ -DUSE_MD5_PASSWORDS=1 -DSUPPORT_HERCULES=1 \
+ $(SERIAL_FLAGS) -I$(top_srcdir)/stage2 \
+ -I$(top_srcdir)/stage1 -I$(top_srcdir)/lib
+diff -up grub-upstream.wip/INSTALL.btrfs grub-upstream.wip/INSTALL
+--- grub-upstream.wip/INSTALL.btrfs 2005-05-08 02:43:15.000000000 +0000
++++ grub-upstream.wip/INSTALL 2012-03-20 05:07:09.000000000 +0000
+@@ -207,6 +207,9 @@ operates.
+ `--disable-reiserfs'
+ Omit the ReiserFS support in Stage 2.
+
++`--disable-btrfs'
++ Omit the BtrFS support in Stage 2.
++
+ `--disable-vstafs'
+ Omit the VSTa filesystem support in Stage 2.
+
+diff -up /dev/null grub-upstream.wip/stage2/btrfs.h
+--- /dev/null 2009-06-03 06:46:26.160951000 +0000
++++ grub-upstream.wip/stage2/btrfs.h 2012-03-20 05:07:09.000000000 +0000
+@@ -0,0 +1,1415 @@
++/* btrfs.h - an extraction from btrfs-progs-0.18/ctree.h into one file
++ *
++ * Copyright (C) 2007 Oracle. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 021110-1307, USA.
++ */
++
++/* include/asm-i386/types.h */
++
++typedef __signed__ char __s8;
++typedef unsigned char __u8;
++typedef __signed__ short __s16;
++typedef unsigned short __u16;
++typedef __signed__ int __s32;
++typedef unsigned int __u32;
++typedef unsigned long long __u64;
++typedef __signed__ long long __s64;
++
++typedef __s8 s8;
++typedef __u8 u8;
++typedef __u16 u16;
++typedef __u32 u32;
++typedef __u64 u64;
++typedef __s64 s64;
++
++#define __bitwise
++
++typedef u16 __bitwise __le16;
++typedef u32 __bitwise __le32;
++typedef u64 __bitwise __le64;
++
++/* linux/posix_type.h */
++typedef long linux_off_t;
++
++/* linux/little_endian.h */
++#define cpu_to_le64(x) ((__u64) (x))
++#define le64_to_cpu(x) ((__u64) (x))
++#define cpu_to_le32(x) ((__u32) (x))
++#define le32_to_cpu(x) ((__u32) (x))
++#define cpu_to_le16(x) ((__u16) (x))
++#define le16_to_cpu(x) ((__u16) (x))
++#define le8_to_cpu(x) ((__u8) (x))
++#define cpu_to_le8(x) ((__u8) (x))
++
++/* linux/stat.h */
++#define S_IFMT 00170000
++#define S_IFLNK 0120000
++#define S_IFREG 0100000
++#define S_IFDIR 0040000
++#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
++#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
++#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
++
++struct btrfs_root;
++#define BTRFS_MAGIC "_BHRfS_M"
++
++#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
++#define BTRFS_SUPER_INFO_SIZE 4096
++
++#define BTRFS_SUPER_MIRROR_MAX 3
++#define BTRFS_SUPER_MIRROR_SHIFT 12
++
++#define PATH_MAX 1024 /* include/linux/limits.h */
++#define MAX_LINK_COUNT 5 /* number of symbolic links
++ to follow */
++#define BTRFS_MAX_LEVEL 8
++#define BTRFS_ROOT_TREE_OBJECTID 1ULL
++#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
++#define BTRFS_CHUNK_TREE_OBJECTID 3ULL
++#define BTRFS_DEV_TREE_OBJECTID 4ULL
++#define BTRFS_FS_TREE_OBJECTID 5ULL
++#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
++#define BTRFS_CSUM_TREE_OBJECTID 7ULL
++
++#define BTRFS_ORPHAN_OBJECTID -5ULL
++#define BTRFS_TREE_LOG_OBJECTID -6ULL
++#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
++#define BTRFS_TREE_RELOC_OBJECTID -8ULL
++#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL
++#define BTRFS_EXTENT_CSUM_OBJECTID -10ULL
++
++#define BTRFS_MULTIPLE_OBJECTIDS -255ULL
++#define BTRFS_FIRST_FREE_OBJECTID 256ULL
++#define BTRFS_LAST_FREE_OBJECTID -256ULL
++#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
++#define BTRFS_DEV_ITEMS_OBJECTID 1ULL
++
++
++#define BTRFS_NAME_LEN 255
++#define BTRFS_CSUM_SIZE 32
++#define BTRFS_CSUM_TYPE_CRC32 0
++
++static int btrfs_csum_sizes[] = { 4, 0 };
++
++/* four bytes for CRC32 */
++#define BTRFS_CRC32_SIZE 4
++#define BTRFS_EMPTY_DIR_SIZE 0
++
++#define BTRFS_FT_UNKNOWN 0
++#define BTRFS_FT_REG_FILE 1
++#define BTRFS_FT_DIR 2
++#define BTRFS_FT_CHRDEV 3
++#define BTRFS_FT_BLKDEV 4
++#define BTRFS_FT_FIFO 5
++#define BTRFS_FT_SOCK 6
++#define BTRFS_FT_SYMLINK 7
++#define BTRFS_FT_XATTR 8
++#define BTRFS_FT_MAX 9
++
++#define BTRFS_UUID_SIZE 16
++
++#define BTRFS_DEFAULT_NUM_DEVICES 1
++#define BTRFS_DEFAULT_NODE_SIZE 4096
++#define BTRFS_DEFAULT_LEAF_SIZE 4096
++#define BTRFS_NUM_CACHED_DEVICES 128
++
++#define WARN_ON(c)
++#define cassert(cond) ({ switch (-1) { case (cond): case 0: break; } })
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++#define offsetof(type, memb) \
++ ((unsigned long)(&((type *)0)->memb))
++
++struct btrfs_disk_key {
++ __le64 objectid;
++ u8 type;
++ __le64 offset;
++} __attribute__ ((__packed__));
++
++/* cpu key */
++struct btrfs_key {
++ u64 objectid;
++ u8 type;
++ u64 offset;
++} __attribute__ ((__packed__));
++
++/* this represents a divice in a chunk tree */
++struct btrfs_dev_item {
++ __le64 devid; /* internal device id */
++ __le64 total_bytes; /* size of the device */
++ __le64 bytes_used;
++ __le32 io_align; /* optimal io alignment */
++ __le32 io_width; /* optimal io width */
++ __le32 sector_size; /* minimal io size */
++ __le64 type; /* type and info about this device */
++ __le64 generation; /* expected generation */
++ __le64 start_offset; /* of the partition on a device */
++
++ /* info for allocation decisions */
++ __le32 dev_group;
++
++ u8 seek_speed; /* 0-100 (100 is fastest) */
++ u8 bandwidth; /* 0-100 (100 is fastest) */
++
++ u8 uuid[BTRFS_UUID_SIZE]; /* dev uuid generated by btrfs */
++ u8 fsid[BTRFS_UUID_SIZE]; /* uuid of the host FS */
++} __attribute__ ((__packed__));
++
++struct btrfs_stripe {
++ __le64 devid;
++ __le64 offset;
++ u8 dev_uuid[BTRFS_UUID_SIZE];
++} __attribute__ ((__packed__));
++
++struct btrfs_chunk {
++ /* size of this chunk in bytes */
++ __le64 length;
++ __le64 owner; /* objectid of the root referincing this chunk */
++ __le64 stripe_len;
++ __le64 type;
++ __le32 io_align; /* optimal io alignment for this chunk */
++ __le32 io_width; /* optimal io width for this chunk */
++ __le32 sector_size; /* minimal io size for this chunk */
++ __le16 num_stripes;
++ __le16 sub_stripes; /* sub stripes (for raid10) */
++ struct btrfs_stripe stripe;
++} __attribute__ ((__packed__));
++
++static inline unsigned long btrfs_chunk_item_size(int num_stripes)
++{
++ return sizeof(struct btrfs_chunk) +
++ sizeof(struct btrfs_stripe) * (num_stripes - 1);
++}
++
++#define BTRFS_FSID_SIZE 16
++#define BTRFS_HEADER_FLAG_WRITTEN (1 << 0)
++
++struct btrfs_header {
++ /* these first four must match the super block */
++ u8 csum[BTRFS_CSUM_SIZE];
++ u8 fsid[BTRFS_FSID_SIZE]; /* uuid of the host fs */
++ __le64 bytenr; /* which block this node is supposed to live in */
++ __le64 flags;
++
++ /* allowed to be different from the super from here on down */
++ u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
++ __le64 generation;
++ __le64 owner;
++ __le32 nritems;
++ u8 level;
++} __attribute__ ((__packed__));
++
++#define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \
++ sizeof(struct btrfs_header)) / \
++ sizeof(struct btrfs_key_ptr))
++#define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
++#define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize))
++#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
++ sizeof(struct btrfs_item) - \
++ sizeof(struct btrfs_file_extent_item))
++
++#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
++#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
++
++/*
++ * a portion of superblock which is used
++ * for chunk translation (up to 14 chunks
++ * with 3 stripes each.
++ */
++#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
++#define BTRFS_LABEL_SIZE 256
++
++/*
++ * the super block basically lists the main trees of the FS
++ * it currently lacks any block count etc etc
++ */
++
++struct btrfs_super_block {
++ u8 csum[BTRFS_CSUM_SIZE];
++ /* the first 3 fields must match struct btrfs_header */
++ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
++ __le64 bytenr; /* this block number */
++ __le64 flags;
++
++ /* allowed to be different from the btrfs_header from here own down */
++ __le64 magic;
++ __le64 generation;
++ __le64 root; /* tree root */
++ __le64 chunk_root;
++ __le64 log_root;
++
++ /* this will help find the new super based on the log root */
++ __le64 log_root_transid;
++ __le64 total_bytes;
++ __le64 bytes_used;
++ __le64 root_dir_objectid;
++ __le64 num_devices;
++ __le32 sectorsize;
++ __le32 nodesize;
++ __le32 leafsize;
++ __le32 stripesize;
++ __le32 sys_chunk_array_size;
++ __le64 chunk_root_generation;
++ __le64 compat_flags;
++ __le64 compat_ro_flags;
++ __le64 incompat_flags;
++ __le16 csum_type;
++ u8 root_level;
++ u8 chunk_root_level;
++ u8 log_root_level;
++ struct btrfs_dev_item dev_item;
++
++ char label[BTRFS_LABEL_SIZE];
++
++ /* future expansion */
++ __le64 reserved[32];
++ u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
++} __attribute__ ((__packed__));
++
++/*
++ * Compat flags that we support. If any incompat flags are set other than the
++ * ones specified below then we will fail to mount
++ */
++#define BTRFS_FEATURE_COMPAT_SUPP 0x0
++#define BTRFS_FEATURE_COMPAT_RO_SUPP 0x0
++#define BTRFS_FEATURE_INCOMPAT_SUPP 0x0
++
++/* Item header for per-leaf lookup */
++struct btrfs_item {
++ struct btrfs_disk_key key;
++ __le32 offset;
++ __le32 size;
++} __attribute__ ((__packed__));
++
++/*
++ * Format of the leaves:
++ * [item0, item1....itemN] [free space] [dataN...data1, data0]
++ */
++struct btrfs_leaf {
++ struct btrfs_header header;
++ struct btrfs_item items[];
++} __attribute__ ((__packed__));
++
++/*
++ * keys-pointers pairs for per-node (non-leaf) lookup
++ */
++struct btrfs_key_ptr {
++ struct btrfs_disk_key key;
++ __le64 blockptr;
++ __le64 generation;
++} __attribute__ ((__packed__));
++
++struct btrfs_node {
++ struct btrfs_header header;
++ struct btrfs_key_ptr ptrs[];
++} __attribute__ ((__packed__));
++
++struct btrfs_device {
++ /* the internal btrfs device id */
++ u64 devid;
++ /* the internal grub device representation */
++ unsigned long drive;
++ unsigned long part;
++ unsigned long length;
++};
++
++struct extent_buffer {
++ /* metadata */
++ struct btrfs_device dev;
++ u64 start;
++ u64 dev_bytenr;
++ u32 len;
++ /* data */
++ char *data;
++};
++
++static inline void read_extent_buffer(struct extent_buffer *eb,
++ void *dst, unsigned long start,
++ unsigned long len)
++{
++ memcpy(dst, eb->data + start, len);
++}
++
++static inline void write_extent_buffer(struct extent_buffer *eb,
++ const void *src, unsigned long start,
++ unsigned long len)
++{
++ memcpy(eb->data + start, src, len);
++}
++
++/*
++ * NOTE:
++ * don't increase a number of levels for grub-0.97!
++ */
++typedef enum {
++ FIRST_EXTERNAL_LOOKUP_POOL,
++ SECOND_EXTERNAL_LOOKUP_POOL,
++ INTERNAL_LOOKUP_POOL,
++ LAST_LOOKUP_POOL
++} lookup_pool_id;
++
++/* Relationship between lookup pools:
++ * depth
++ *
++ * ^ +----> INTERNAL <----+
++ * | | |
++ * | | |
++ * - FIRST_EXTERNAL SECOND_EXTERNAL
++ */
++
++struct btrfs_path {
++ lookup_pool_id lpid;
++ struct extent_buffer nodes[BTRFS_MAX_LEVEL];
++ int slots[BTRFS_MAX_LEVEL];
++};
++
++/*
++ * items in the extent btree are used to record the objectid of the
++ * owner of the block and the number of references
++ */
++struct btrfs_extent_item {
++ __le32 refs;
++} __attribute__ ((__packed__));
++
++struct btrfs_extent_ref {
++ __le64 root;
++ __le64 generation;
++ __le64 objectid;
++ __le32 num_refs;
++} __attribute__ ((__packed__));
++
++/* dev extents record free space on individual devices. The owner
++ * field points back to the chunk allocation mapping tree that allocated
++ * the extent. The chunk tree uuid field is a way to double check the owner
++ */
++struct btrfs_dev_extent {
++ __le64 chunk_tree;
++ __le64 chunk_objectid;
++ __le64 chunk_offset;
++ __le64 length;
++ u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
++} __attribute__ ((__packed__));
++
++struct btrfs_inode_ref {
++ __le64 index;
++ __le16 name_len;
++ /* name goes here */
++} __attribute__ ((__packed__));
++
++struct btrfs_timespec {
++ __le64 sec;
++ __le32 nsec;
++} __attribute__ ((__packed__));
++
++typedef enum {
++ BTRFS_COMPRESS_NONE = 0,
++ BTRFS_COMPRESS_ZLIB = 1,
++ BTRFS_COMPRESS_LAST = 2,
++} btrfs_compression_type;
++
++/* we don't understand any encryption methods right now */
++typedef enum {
++ BTRFS_ENCRYPTION_NONE = 0,
++ BTRFS_ENCRYPTION_LAST = 1,
++} btrfs_encryption_type;
++
++struct btrfs_inode_item {
++ /* nfs style generation number */
++ __le64 generation;
++ /* transid that last touched this inode */
++ __le64 transid;
++ __le64 size;
++ __le64 nbytes;
++ __le64 block_group;
++ __le32 nlink;
++ __le32 uid;
++ __le32 gid;
++ __le32 mode;
++ __le64 rdev;
++ __le64 flags;
++
++ /* modification sequence number for NFS */
++ __le64 sequence;
++
++ /*
++ * a little future expansion, for more than this we can
++ * just grow the inode item and version it
++ */
++ __le64 reserved[4];
++ struct btrfs_timespec atime;
++ struct btrfs_timespec ctime;
++ struct btrfs_timespec mtime;
++ struct btrfs_timespec otime;
++} __attribute__ ((__packed__));
++
++struct btrfs_dir_item {
++ struct btrfs_disk_key location;
++ __le64 transid;
++ __le16 data_len;
++ __le16 name_len;
++ u8 type;
++} __attribute__ ((__packed__));
++
++struct btrfs_root_item {
++ struct btrfs_inode_item inode;
++ __le64 generation;
++ __le64 root_dirid;
++ __le64 bytenr;
++ __le64 byte_limit;
++ __le64 bytes_used;
++ __le64 last_snapshot;
++ __le64 flags;
++ __le32 refs;
++ struct btrfs_disk_key drop_progress;
++ u8 drop_level;
++ u8 level;
++} __attribute__ ((__packed__));
++
++/*
++ * this is used for both forward and backward root refs
++ */
++struct btrfs_root_ref {
++ __le64 dirid;
++ __le64 sequence;
++ __le16 name_len;
++} __attribute__ ((__packed__));
++
++#define BTRFS_FILE_EXTENT_INLINE 0
++#define BTRFS_FILE_EXTENT_REG 1
++#define BTRFS_FILE_EXTENT_PREALLOC 2
++
++struct btrfs_file_extent_item {
++ /*
++ * transaction id that created this extent
++ */
++ __le64 generation;
++ /*
++ * max number of bytes to hold this extent in ram
++ * when we split a compressed extent we can't know how big
++ * each of the resulting pieces will be. So, this is
++ * an upper limit on the size of the extent in ram instead of
++ * an exact limit.
++ */
++ __le64 ram_bytes;
++
++ /*
++ * 32 bits for the various ways we might encode the data,
++ * including compression and encryption. If any of these
++ * are set to something a given disk format doesn't understand
++ * it is treated like an incompat flag for reading and writing,
++ * but not for stat.
++ */
++ u8 compression;
++ u8 encryption;
++ __le16 other_encoding; /* spare for later use */
++
++ /* are we inline data or a real extent? */
++ u8 type;
++
++ /*
++ * disk space consumed by the extent, checksum blocks are included
++ * in these numbers
++ */
++ __le64 disk_bytenr;
++ __le64 disk_num_bytes;
++ /*
++ * the logical offset in file blocks (no csums)
++ * this extent record is for. This allows a file extent to point
++ * into the middle of an existing extent on disk, sharing it
++ * between two snapshots (useful if some bytes in the middle of the
++ * extent have changed
++ */
++ __le64 offset;
++ /*
++ * the logical number of file blocks (no csums included)
++ */
++ __le64 num_bytes;
++
++} __attribute__ ((__packed__));
++
++struct btrfs_csum_item {
++ u8 csum;
++} __attribute__ ((__packed__));
++
++/* tag for the radix tree of block groups in ram */
++#define BTRFS_BLOCK_GROUP_DATA (1 << 0)
++#define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1)
++#define BTRFS_BLOCK_GROUP_METADATA (1 << 2)
++#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3)
++#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4)
++#define BTRFS_BLOCK_GROUP_DUP (1 << 5)
++#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6)
++
++struct btrfs_block_group_item {
++ __le64 used;
++ __le64 chunk_objectid;
++ __le64 flags;
++} __attribute__ ((__packed__));
++
++/*
++ * in ram representation of the tree. extent_root is used for all allocations
++ * and for the extent tree extent_root root.
++ */
++struct btrfs_root {
++ struct extent_buffer node;
++ char data[4096];
++ struct btrfs_root_item root_item;
++ u64 objectid;
++
++ /* data allocations are done in sectorsize units */
++ u32 sectorsize;
++
++ /* node allocations are done in nodesize units */
++ u32 nodesize;
++
++ /* leaf allocations are done in leafsize units */
++ u32 leafsize;
++
++ /* leaf allocations are done in leafsize units */
++ u32 stripesize;
++};
++
++struct btrfs_file_info {
++ struct btrfs_key key;
++};
++
++struct btrfs_root;
++struct btrfs_fs_devices;
++struct btrfs_fs_info {
++ u8 fsid[BTRFS_FSID_SIZE];
++ struct btrfs_root fs_root;
++ struct btrfs_root tree_root;
++ struct btrfs_root chunk_root;
++
++ struct btrfs_file_info file_info; /* currently opened file */
++ struct btrfs_path paths [LAST_LOOKUP_POOL];
++
++ char mbr[SECTOR_SIZE];
++
++ int sb_mirror;
++ u64 sb_transid;
++ struct btrfs_device sb_dev;
++ struct btrfs_super_block sb_copy;
++
++ struct btrfs_device devices[BTRFS_NUM_CACHED_DEVICES + 1];
++};
++
++/*
++ * inode items have the data typically returned from stat and store other
++ * info about object characteristics. There is one for every file and dir in
++ * the FS
++ */
++#define BTRFS_INODE_ITEM_KEY 1
++#define BTRFS_INODE_REF_KEY 12
++#define BTRFS_XATTR_ITEM_KEY 24
++#define BTRFS_ORPHAN_ITEM_KEY 48
++
++#define BTRFS_DIR_LOG_ITEM_KEY 60
++#define BTRFS_DIR_LOG_INDEX_KEY 72
++/*
++ * dir items are the name -> inode pointers in a directory. There is one
++ * for every name in a directory.
++ */
++#define BTRFS_DIR_ITEM_KEY 84
++#define BTRFS_DIR_INDEX_KEY 96
++
++/*
++ * extent data is for file data
++ */
++#define BTRFS_EXTENT_DATA_KEY 108
++
++/*
++ * csum items have the checksums for data in the extents
++ */
++#define BTRFS_CSUM_ITEM_KEY 120
++/*
++ * extent csums are stored in a separate tree and hold csums for
++ * an entire extent on disk.
++ */
++#define BTRFS_EXTENT_CSUM_KEY 128
++
++/*
++ * root items point to tree roots. There are typically in the root
++ * tree used by the super block to find all the other trees
++ */
++#define BTRFS_ROOT_ITEM_KEY 132
++
++/*
++ * root backrefs tie subvols and snapshots to the directory entries that
++ * reference them
++ */
++#define BTRFS_ROOT_BACKREF_KEY 144
++
++/*
++ * root refs make a fast index for listing all of the snapshots and
++ * subvolumes referenced by a given root. They point directly to the
++ * directory item in the root that references the subvol
++ */
++#define BTRFS_ROOT_REF_KEY 156
++
++/*
+++ * extent items are in the extent map tree. These record which blocks
+++ * are used, and how many references there are to each block
+++ */
++#define BTRFS_EXTENT_ITEM_KEY 168
++#define BTRFS_EXTENT_REF_KEY 180
++
++/*
++ * block groups give us hints into the extent allocation trees. Which
++ * blocks are free etc etc
++ */
++#define BTRFS_BLOCK_GROUP_ITEM_KEY 192
++
++#define BTRFS_DEV_EXTENT_KEY 204
++#define BTRFS_DEV_ITEM_KEY 216
++#define BTRFS_CHUNK_ITEM_KEY 228
++
++/*
++ * string items are for debugging. They just store a short string of
++ * data in the FS
++ */
++#define BTRFS_STRING_ITEM_KEY 253
++/*
++ * Inode flags
++ */
++#define BTRFS_INODE_NODATASUM (1 << 0)
++#define BTRFS_INODE_NODATACOW (1 << 1)
++#define BTRFS_INODE_READONLY (1 << 2)
++
++#define read_eb_member(eb, ptr, type, member, result) ( \
++ read_extent_buffer(eb, (char *)(result), \
++ ((unsigned long)(ptr)) + \
++ offsetof(type, member), \
++ sizeof(((type *)0)->member)))
++
++#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
++static inline u##bits btrfs_##name(struct extent_buffer *eb) \
++{ \
++ struct btrfs_header *h = (struct btrfs_header *)eb->data; \
++ return le##bits##_to_cpu(h->member); \
++} \
++static inline void btrfs_set_##name(struct extent_buffer *eb, \
++ u##bits val) \
++{ \
++ struct btrfs_header *h = (struct btrfs_header *)eb->data; \
++ h->member = cpu_to_le##bits(val); \
++}
++
++#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
++static inline u##bits btrfs_##name(struct extent_buffer *eb, \
++ type *s) \
++{ \
++ unsigned long offset = (unsigned long)s; \
++ type *p = (type *) (eb->data + offset); \
++ return le##bits##_to_cpu(p->member); \
++} \
++static inline void btrfs_set_##name(struct extent_buffer *eb, \
++ type *s, u##bits val) \
++{ \
++ unsigned long offset = (unsigned long)s; \
++ type *p = (type *) (eb->data + offset); \
++ p->member = cpu_to_le##bits(val); \
++}
++
++#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
++static inline u##bits btrfs_##name(type *s) \
++{ \
++ return le##bits##_to_cpu(s->member); \
++} \
++static inline void btrfs_set_##name(type *s, u##bits val) \
++{ \
++ s->member = cpu_to_le##bits(val); \
++}
++
++BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64);
++BTRFS_SETGET_FUNCS(device_total_bytes, struct btrfs_dev_item, total_bytes, 64);
++BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64);
++BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32);
++BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);
++BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item,
++ start_offset, 64);
++BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);
++BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
++BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);
++BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);
++BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);
++BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);
++
++BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
++ total_bytes, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,
++ bytes_used, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,
++ io_align, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,
++ io_width, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,
++ sector_size, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item,
++ dev_group, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,
++ seek_speed, 8);
++BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
++ bandwidth, 8);
++BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
++ generation, 64);
++
++static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
++{
++ return (char *)d + offsetof(struct btrfs_dev_item, uuid);
++}
++
++static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)
++{
++ return (char *)d + offsetof(struct btrfs_dev_item, fsid);
++}
++
++BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
++BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);
++BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);
++BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32);
++BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);
++BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
++BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
++BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
++BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);
++BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
++BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);
++
++static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s)
++{
++ return (char *)s + offsetof(struct btrfs_stripe, dev_uuid);
++}
++
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk,
++ stripe_len, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk,
++ io_align, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk,
++ io_width, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,
++ sector_size, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
++ num_stripes, 16);
++BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,
++ sub_stripes, 16);
++BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);
++
++static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c,
++ int nr)
++{
++ unsigned long offset = (unsigned long)c;
++ offset += offsetof(struct btrfs_chunk, stripe);
++ offset += nr * sizeof(struct btrfs_stripe);
++ return (struct btrfs_stripe *)offset;
++}
++
++static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr)
++{
++ return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr));
++}
++
++static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb,
++ struct btrfs_chunk *c, int nr)
++{
++ return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));
++}
++
++static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb,
++ struct btrfs_chunk *c, int nr,
++ u64 val)
++{
++ btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val);
++}
++
++static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb,
++ struct btrfs_chunk *c, int nr)
++{
++ return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));
++}
++
++static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb,
++ struct btrfs_chunk *c, int nr,
++ u64 val)
++{
++ btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val);
++}
++
++/* struct btrfs_block_group_item */
++BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,
++ used, 64);
++BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item,
++ used, 64);
++BTRFS_SETGET_STACK_FUNCS(block_group_chunk_objectid,
++ struct btrfs_block_group_item, chunk_objectid, 64);
++
++BTRFS_SETGET_FUNCS(disk_block_group_chunk_objectid,
++ struct btrfs_block_group_item, chunk_objectid, 64);
++BTRFS_SETGET_FUNCS(disk_block_group_flags,
++ struct btrfs_block_group_item, flags, 64);
++BTRFS_SETGET_STACK_FUNCS(block_group_flags,
++ struct btrfs_block_group_item, flags, 64);
++
++/* struct btrfs_inode_ref */
++BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);
++BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
++
++/* struct btrfs_inode_item */
++BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
++BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64);
++BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);
++BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
++BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64);
++BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
++BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);
++BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);
++BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
++BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
++BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
++BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
++
++BTRFS_SETGET_STACK_FUNCS(stack_inode_generation,
++ struct btrfs_inode_item, generation, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence,
++ struct btrfs_inode_item, generation, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_size,
++ struct btrfs_inode_item, size, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes,
++ struct btrfs_inode_item, nbytes, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group,
++ struct btrfs_inode_item, block_group, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink,
++ struct btrfs_inode_item, nlink, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_uid,
++ struct btrfs_inode_item, uid, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_gid,
++ struct btrfs_inode_item, gid, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_mode,
++ struct btrfs_inode_item, mode, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev,
++ struct btrfs_inode_item, rdev, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_inode_flags,
++ struct btrfs_inode_item, flags, 64);
++
++BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
++BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec,
++ sec, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec,
++ nsec, 32);
++
++/* struct btrfs_dev_extent */
++BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,
++ chunk_tree, 64);
++BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent,
++ chunk_objectid, 64);
++BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,
++ chunk_offset, 64);
++BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);
++
++static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
++{
++ unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid);
++ return (u8 *)((unsigned long)dev + ptr);
++}
++
++/* struct btrfs_extent_ref */
++BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
++BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64);
++BTRFS_SETGET_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
++BTRFS_SETGET_FUNCS(ref_num_refs, struct btrfs_extent_ref, num_refs, 32);
++
++BTRFS_SETGET_STACK_FUNCS(stack_ref_root, struct btrfs_extent_ref, root, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_ref_generation, struct btrfs_extent_ref,
++ generation, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_ref_objectid, struct btrfs_extent_ref,
++ objectid, 64);
++BTRFS_SETGET_STACK_FUNCS(stack_ref_num_refs, struct btrfs_extent_ref,
++ num_refs, 32);
++
++/* struct btrfs_extent_item */
++BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
++BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
++ refs, 32);
++
++/* struct btrfs_node */
++BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
++BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
++
++static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)
++{
++ unsigned long ptr;
++ ptr = offsetof(struct btrfs_node, ptrs) +
++ sizeof(struct btrfs_key_ptr) * nr;
++ return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr);
++}
++
++static inline void btrfs_set_node_blockptr(struct extent_buffer *eb,
++ int nr, u64 val)
++{
++ unsigned long ptr;
++ ptr = offsetof(struct btrfs_node, ptrs) +
++ sizeof(struct btrfs_key_ptr) * nr;
++ btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
++}
++
++static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr)
++{
++ unsigned long ptr;
++ ptr = offsetof(struct btrfs_node, ptrs) +
++ sizeof(struct btrfs_key_ptr) * nr;
++ return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);
++}
++
++static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb,
++ int nr, u64 val)
++{
++ unsigned long ptr;
++ ptr = offsetof(struct btrfs_node, ptrs) +
++ sizeof(struct btrfs_key_ptr) * nr;
++ btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);
++}
++
++static inline unsigned long btrfs_node_key_ptr_offset(int nr)
++{
++ return offsetof(struct btrfs_node, ptrs) +
++ sizeof(struct btrfs_key_ptr) * nr;
++}
++
++static inline void btrfs_node_key(struct extent_buffer *eb,
++ struct btrfs_disk_key *disk_key, int nr)
++{
++ unsigned long ptr;
++ ptr = btrfs_node_key_ptr_offset(nr);
++ read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
++ struct btrfs_key_ptr, key, disk_key);
++}
++
++/* struct btrfs_item */
++BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32);
++BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32);
++
++static inline unsigned long btrfs_item_nr_offset(int nr)
++{
++ return offsetof(struct btrfs_leaf, items) +
++ sizeof(struct btrfs_item) * nr;
++}
++
++static inline struct btrfs_item *btrfs_item_nr(struct extent_buffer *eb,
++ int nr)
++{
++ return (struct btrfs_item *)btrfs_item_nr_offset(nr);
++}
++
++static inline u32 btrfs_item_end(struct extent_buffer *eb,
++ struct btrfs_item *item)
++{
++ return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);
++}
++
++static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
++{
++ return btrfs_item_end(eb, btrfs_item_nr(eb, nr));
++}
++
++static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
++{
++ return btrfs_item_offset(eb, btrfs_item_nr(eb, nr));
++}
++
++static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
++{
++ return btrfs_item_size(eb, btrfs_item_nr(eb, nr));
++}
++
++static inline void btrfs_item_key(struct extent_buffer *eb,
++ struct btrfs_disk_key *disk_key, int nr)
++{
++ struct btrfs_item *item = btrfs_item_nr(eb, nr);
++ read_eb_member(eb, item, struct btrfs_item, key, disk_key);
++}
++
++/*
++ * struct btrfs_root_ref
++ */
++BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);
++BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);
++BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);
++
++/* struct btrfs_dir_item */
++BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
++BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
++BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
++BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
++
++static inline void btrfs_dir_item_key(struct extent_buffer *eb,
++ struct btrfs_dir_item *item,
++ struct btrfs_disk_key *key)
++{
++ read_eb_member(eb, item, struct btrfs_dir_item, location, key);
++}
++
++/* struct btrfs_disk_key */
++BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,
++ objectid, 64);
++BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);
++BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);
++
++static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,
++ struct btrfs_disk_key *disk)
++{
++ cpu->offset = le64_to_cpu(disk->offset);
++ cpu->type = disk->type;
++ cpu->objectid = le64_to_cpu(disk->objectid);
++}
++
++static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,
++ struct btrfs_key *cpu)
++{
++ disk->offset = cpu_to_le64(cpu->offset);
++ disk->type = cpu->type;
++ disk->objectid = cpu_to_le64(cpu->objectid);
++}
++
++static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,
++ struct btrfs_key *key, int nr)
++{
++ struct btrfs_disk_key disk_key;
++ btrfs_node_key(eb, &disk_key, nr);
++ btrfs_disk_key_to_cpu(key, &disk_key);
++}
++
++static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,
++ struct btrfs_key *key, int nr)
++{
++ struct btrfs_disk_key disk_key;
++ btrfs_item_key(eb, &disk_key, nr);
++ btrfs_disk_key_to_cpu(key, &disk_key);
++}
++
++static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,
++ struct btrfs_dir_item *item,
++ struct btrfs_key *key)
++{
++ struct btrfs_disk_key disk_key;
++ btrfs_dir_item_key(eb, item, &disk_key);
++ btrfs_disk_key_to_cpu(key, &disk_key);
++}
++
++static inline u8 btrfs_key_type(struct btrfs_key *key)
++{
++ return key->type;
++}
++
++static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val)
++{
++ key->type = val;
++}
++
++static inline u64 btrfs_super_devid(struct btrfs_super_block *disk_super)
++{
++ return le64_to_cpu(disk_super->dev_item.devid);
++}
++
++/* struct btrfs_header */
++BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
++BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
++ generation, 64);
++BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
++BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
++BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
++BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
++
++/* struct btrfs_root_item */
++BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item,
++ generation, 64);
++BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);
++BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);
++BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);
++
++BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item,
++ generation, 64);
++BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);
++BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);
++BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);
++BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);
++BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64);
++BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
++BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
++BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
++ last_snapshot, 64);
++
++/* struct btrfs_super_block */
++
++BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
++BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
++BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
++ generation, 64);
++BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
++BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,
++ struct btrfs_super_block, sys_chunk_array_size, 32);
++BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,
++ struct btrfs_super_block, chunk_root_generation, 64);
++BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
++ root_level, 8);
++BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
++ chunk_root, 64);
++BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
++ chunk_root_level, 8);
++BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,
++ log_root, 64);
++BTRFS_SETGET_STACK_FUNCS(super_log_root_transid, struct btrfs_super_block,
++ log_root_transid, 64);
++BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
++ log_root_level, 8);
++BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
++ total_bytes, 64);
++BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
++ bytes_used, 64);
++BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,
++ sectorsize, 32);
++BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
++ nodesize, 32);
++BTRFS_SETGET_STACK_FUNCS(super_leafsize, struct btrfs_super_block,
++ leafsize, 32);
++BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
++ stripesize, 32);
++BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
++ root_dir_objectid, 64);
++BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,
++ num_devices, 64);
++BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,
++ compat_flags, 64);
++BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,
++ compat_flags, 64);
++BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,
++ incompat_flags, 64);
++BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
++ csum_type, 16);
++
++static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
++{
++ int t = btrfs_super_csum_type(s);
++ //BUG_ON(t >= ARRAY_SIZE(btrfs_csum_sizes));
++ return btrfs_csum_sizes[t];
++}
++
++static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
++{
++ return offsetof(struct btrfs_leaf, items);
++}
++
++/* struct btrfs_file_extent_item */
++BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
++
++static inline unsigned long btrfs_file_extent_inline_start(struct
++ btrfs_file_extent_item *e)
++{
++ unsigned long offset = (unsigned long)e;
++ offset += offsetof(struct btrfs_file_extent_item, disk_bytenr);
++ return offset;
++}
++
++static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
++{
++ return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize;
++}
++
++BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,
++ disk_bytenr, 64);
++BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,
++ generation, 64);
++BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,
++ disk_num_bytes, 64);
++BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,
++ offset, 64);
++BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,
++ num_bytes, 64);
++BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,
++ ram_bytes, 64);
++BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,
++ compression, 8);
++BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
++ encryption, 8);
++BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
++ other_encoding, 16);
++
++/* this returns the number of file bytes represented by the inline item.
++ * If an item is compressed, this is the uncompressed size
++ */
++static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
++ struct btrfs_file_extent_item *e)
++{
++ return btrfs_file_extent_ram_bytes(eb, e);
++}
++
++/*
++ * this returns the number of bytes used by the item on disk, minus the
++ * size of any extent headers. If a file is compressed on disk, this is
++ * the compressed size
++ */
++static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
++ struct btrfs_item *e)
++{
++ unsigned long offset;
++ offset = offsetof(struct btrfs_file_extent_item, disk_bytenr);
++ return btrfs_item_size(eb, e) - offset;
++}
++
++static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
++ if (level == 0)
++ return root->leafsize;
++ return root->nodesize;
++}
++
++static inline u32 btrfs_root_level_size(struct btrfs_super_block *sb) {
++ return btrfs_super_root_level(sb) == 0 ?
++ btrfs_super_leafsize(sb) :
++ btrfs_super_nodesize(sb);
++}
++
++static inline u32 btrfs_chunk_root_level_size(struct btrfs_super_block *sb) {
++ return btrfs_super_chunk_root_level(sb) == 0 ?
++ btrfs_super_leafsize(sb) :
++ btrfs_super_nodesize(sb);
++}
++
++/* helper function to cast into the data area of the leaf. */
++#define btrfs_item_ptr(leaf, slot, type) \
++ ((type *)(btrfs_leaf_data(leaf) + \
++ btrfs_item_offset_nr(leaf, slot)))
++
++#define btrfs_item_ptr_offset(leaf, slot) \
++ ((unsigned long)(btrfs_leaf_data(leaf) + \
++ btrfs_item_offset_nr(leaf, slot)))
++
++/*volumes.h */
++
++struct btrfs_fs_devices {
++ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
++
++ /* the device with this id has the most recent coyp of the super */
++ u64 latest_devid;
++ u64 latest_trans;
++ u64 lowest_devid;
++ int latest_bdev;
++ int lowest_bdev;
++ int seeding;
++ struct btrfs_fs_devices *seed;
++};
++
++struct btrfs_bio_stripe {
++ struct btrfs_device dev;
++ u64 physical;
++};
++
++#define MAX_NRSTRIPES 8
++struct btrfs_multi_bio {
++ int error;
++ int num_stripes;
++ struct btrfs_bio_stripe stripes[MAX_NRSTRIPES];
++};
++
++#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
++ (sizeof(struct btrfs_bio_stripe) * (n)))
++
++static int aux_tree_lookup(struct btrfs_root *root,
++ struct btrfs_key *key,
++ struct btrfs_path *path);
++
++struct cache_extent {
++ u64 start;
++ u64 size;
++};
++
++struct map_lookup {
++ struct cache_extent ce;
++ u64 type;
++ int io_align;
++ int io_width;
++ int stripe_len;
++ int sector_size;
++ int num_stripes;
++ int sub_stripes;
++ struct btrfs_bio_stripe stripes[MAX_NRSTRIPES];
++};
++
++/* "VFS" things */
++
++/* file types recognized by grub */
++typedef enum {
++ BTRFS_REGULAR_FILE,
++ BTRFS_DIRECTORY_FILE,
++ BTRFS_SYMLINK_FILE,
++ BTRFS_UNKNOWN_FILE
++} btrfs_file_type;
++
++static inline int coord_is_root(struct btrfs_root *root,
++ struct btrfs_path *path)
++{
++ return btrfs_header_bytenr(&path->nodes[0]) ==
++ btrfs_header_bytenr(&root->node);
++}
++
++static inline btrfs_file_type btrfs_get_file_type (int mode)
++{
++ if (S_ISLNK(mode))
++ return BTRFS_SYMLINK_FILE;
++ if (S_ISREG(mode))
++ return BTRFS_REGULAR_FILE;
++ if (S_ISDIR(mode))
++ return BTRFS_DIRECTORY_FILE;
++ return BTRFS_UNKNOWN_FILE;
++}
++
++#define min_t(type,x,y) \
++ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
++#define max_t(type,x,y) \
++ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
++
++
++int sys_array_lookup(struct map_lookup *map, u64 logical);
++int tree_chunk_lookup(struct map_lookup *map,
++ u64 logical);
++int __btrfs_map_block(u64 logical, u64 *length,
++ struct btrfs_multi_bio *multi_ret, int mirror_num);
++int read_tree_block(struct btrfs_root *root,
++ struct extent_buffer *eb,
++ u64 bytenr, /* logical */
++ u32 blocksize,
++ u64 parent_transid,
++ lookup_pool_id lpid);
++int check_read_chunk(struct btrfs_key *key,
++ struct extent_buffer *leaf,
++ struct btrfs_chunk *chunk,
++ struct map_lookup *map,
++ u64 logical);
++/*
++ Local variables:
++ c-indentation-style: "K&R"
++ mode-name: "LC"
++ c-basic-offset: 8
++ tab-width: 8
++ fill-column: 80
++ scroll-step: 1
++ End:
++*/
+\ No newline at end of file
+diff -up grub-upstream.wip/stage2/builtins.c.btrfs grub-upstream.wip/stage2/builtins.c
+--- grub-upstream.wip/stage2/builtins.c.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/stage2/builtins.c 2012-03-20 05:11:13.000000000 +0000
+@@ -2456,6 +2456,16 @@ install_func (char *arg, int flags)
+ else
+ #endif /* GRUB_UTIL */
+ {
++ /*
++ * FIXME: Ugly hack.
++ * Do not write to btrfs partition
++ * without a help of the file system!
++ */
++ if (!strcmp(fsys_table[fsys_type].name, "btrfs"))
++ {
++ errnum = ERR_BAD_ARGUMENT;
++ goto fail;
++ }
+ if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
+ goto fail;
+ }
+@@ -4281,6 +4291,7 @@ setup_func (char *arg, int flags)
+ {"jfs", "/jfs_stage1_5"},
+ {"minix", "/minix_stage1_5"},
+ {"reiserfs", "/reiserfs_stage1_5"},
++ {"btrfs", "/btrfs_stage1_5"},
+ {"vstafs", "/vstafs_stage1_5"},
+ {"xfs", "/xfs_stage1_5"}
+ };
+diff -up grub-upstream.wip/stage2/disk_io.c.btrfs grub-upstream.wip/stage2/disk_io.c
+--- grub-upstream.wip/stage2/disk_io.c.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/stage2/disk_io.c 2012-03-20 05:07:09.000000000 +0000
+@@ -78,6 +78,9 @@ struct fsys_entry fsys_table[NUM_FSYS +
+ # ifdef FSYS_ISO9660
+ {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, 0, 0},
+ # endif
++# ifdef FSYS_BTRFS
++ {"btrfs", btrfs_mount, btrfs_read, btrfs_dir, 0, btrfs_embed},
++# endif
+ /* XX FFS should come last as it's superblock is commonly crossing tracks
+ on floppies from track 1 to 2, while others only use 1. */
+ # ifdef FSYS_FFS
+diff -up grub-upstream.wip/stage2/filesys.h.btrfs grub-upstream.wip/stage2/filesys.h
+--- grub-upstream.wip/stage2/filesys.h.btrfs 2004-05-14 19:36:43.000000000 +0000
++++ grub-upstream.wip/stage2/filesys.h 2012-03-20 05:07:09.000000000 +0000
+@@ -77,6 +77,16 @@ int reiserfs_embed (int *start_sector, i
+ #define FSYS_REISERFS_NUM 0
+ #endif
+
++#ifdef FSYS_BTRFS
++#define FSYS_BTRFS_NUM 1
++int btrfs_mount (void);
++int btrfs_read (char *buf, int len);
++int btrfs_dir (char *dirname);
++int btrfs_embed (int *start_sector, int needed_sectors);
++#else
++#define FSYS_BTRFS_NUM 0
++#endif
++
+ #ifdef FSYS_VSTAFS
+ #define FSYS_VSTAFS_NUM 1
+ int vstafs_mount (void);
+@@ -127,8 +137,8 @@ int iso9660_dir (char *dirname);
+ #ifndef NUM_FSYS
+ #define NUM_FSYS \
+ (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \
+- + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \
+- + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
++ + FSYS_REISERFS_NUM + FSYS_BTRFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM \
++ + FSYS_XFS_NUM + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
+ #endif
+
+ /* defines for the block filesystem info area */
+diff -up /dev/null grub-upstream.wip/stage2/fsys_btrfs.c
+--- /dev/null 2009-06-03 06:46:26.160951000 +0000
++++ grub-upstream.wip/stage2/fsys_btrfs.c 2012-03-20 05:07:09.000000000 +0000
+@@ -0,0 +1,1820 @@
++/* fsys_btrfs.c - an implementation for the Btrfs filesystem
++ *
++ * Copyright 2009 Red Hat, Inc. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifdef FSYS_BTRFS
++
++#include "shared.h"
++#include "filesys.h"
++#include "btrfs.h"
++
++#define BTRFS_VERBOSE 0
++
++/* Cache layouts */
++
++#define LOOKUP_CACHE_BUF_SIZE (4096)
++#define LOOKUP_CACHE_SIZE (LOOKUP_CACHE_BUF_SIZE * LAST_LOOKUP_POOL)
++#define BTRFS_FS_INFO \
++ ((struct btrfs_fs_info *)((unsigned long)FSYS_BUF + \
++ LOOKUP_CACHE_SIZE))
++#define BTRFS_CACHE_SIZE (sizeof(struct btrfs_fs_info) + \
++ LOOKUP_CACHE_SIZE)
++#define BTRFS_TREE_ROOT (&BTRFS_FS_INFO->tree_root)
++#define BTRFS_CHUNK_ROOT (&BTRFS_FS_INFO->chunk_root)
++#define BTRFS_FS_ROOT (&BTRFS_FS_INFO->fs_root)
++#define BTRFS_SUPER (&BTRFS_FS_INFO->sb_copy)
++#define BTRFS_DEVICES (&BTRFS_FS_INFO->devices[0])
++#define BTRFS_FILE_INFO (&BTRFS_FS_INFO->file_info)
++#define BTRFS_FILE_INFO_KEY (&BTRFS_FILE_INFO->key)
++
++#define BTRFS_VOLATILE_DEV_CACHE \
++ (&BTRFS_FS_INFO->devices[BTRFS_NUM_CACHED_DEVICES])
++
++#define LOOKUP_CACHE_BUF(id) ((char *)((unsigned long)FSYS_BUF + \
++ id * LOOKUP_CACHE_BUF_SIZE))
++
++#define noop do {; } while (0)
++
++#if BTRFS_VERBOSE
++#define btrfs_msg(format, ...) printf(format , ## __VA_ARGS__)
++#else
++#define btrfs_msg(format, args...) noop
++#endif
++
++/* compile-time check to make sure we don't overlap
++ filesystem buffer */
++static inline void check_btrfs_cache_size(void)
++{
++ cassert(BTRFS_CACHE_SIZE <= FSYS_BUFLEN);
++}
++
++static inline u64 btrfs_sb_offset(int mirror)
++{
++ u64 start = 16 * 1024;
++ if (mirror)
++ return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror);
++ return BTRFS_SUPER_INFO_OFFSET;
++}
++
++static inline char *grab_lookup_cache(lookup_pool_id lpid)
++{
++ char *buf = LOOKUP_CACHE_BUF(lpid);
++ memset(buf, 0, LOOKUP_CACHE_BUF_SIZE);
++ return buf;
++}
++
++static inline struct btrfs_path *btrfs_grab_path(lookup_pool_id lpid)
++{
++ return &BTRFS_FS_INFO->paths[lpid];
++}
++
++static inline void btrfs_set_path_key(struct btrfs_path *path,
++ struct btrfs_key *key)
++{
++ btrfs_item_key_to_cpu(&path->nodes[0],
++ key,
++ path->slots[0]);
++}
++
++static inline void btrfs_update_file_info(struct btrfs_path *path)
++{
++ btrfs_set_path_key(path, BTRFS_FILE_INFO_KEY);
++}
++
++static inline void btrfs_set_root_dir_key(struct btrfs_key *key)
++{
++ key->objectid = BTRFS_FIRST_FREE_OBJECTID;
++ btrfs_set_key_type(key, BTRFS_INODE_ITEM_KEY);
++ key->offset = 0;
++}
++
++static inline void copy_extent_buffer(struct extent_buffer *dst,
++ struct extent_buffer *src)
++{
++ char *data = dst->data;
++ memcpy(dst, src, sizeof(*dst));
++ memcpy(data, src->data, 4096);
++ dst->data = data;
++}
++
++static inline void move_extent_buffer(struct extent_buffer *dst,
++ struct extent_buffer *src)
++{
++ memcpy(dst, src, sizeof(*dst));
++}
++
++static inline void init_btrfs_root (struct btrfs_root *root)
++{
++ root->node.data = root->data;
++}
++
++static inline void init_btrfs_path(lookup_pool_id lpid)
++{
++ struct btrfs_path *path;
++ path = btrfs_grab_path(lpid);
++ path->lpid = lpid;
++}
++
++static inline void init_btrfs_info(void)
++{
++ int i;
++
++ memset(BTRFS_FS_INFO, 0, sizeof(struct btrfs_fs_info));
++ for(i = 0; i < LAST_LOOKUP_POOL; i++)
++ init_btrfs_path(i);
++ init_btrfs_root(BTRFS_TREE_ROOT);
++ init_btrfs_root(BTRFS_CHUNK_ROOT);
++ init_btrfs_root(BTRFS_FS_ROOT);
++}
++
++static void setup_root(struct btrfs_root *root,
++ u32 nodesize,
++ u32 leafsize,
++ u32 sectorsize,
++ u32 stripesize,
++ u64 objectid)
++{
++ root->nodesize = nodesize;
++ root->leafsize = leafsize;
++ root->sectorsize = sectorsize;
++ root->stripesize = stripesize;
++ root->objectid = objectid;
++}
++
++/*
++ * Pick up the latest root of a
++ * tree with specified @objectid
++ */
++static int btrfs_find_last_root(struct btrfs_root *tree_root,
++ u64 objectid,
++ struct btrfs_root_item *item,
++ lookup_pool_id lpid)
++{
++ int ret;
++ int slot;
++ struct btrfs_key search_key;
++ struct btrfs_key found_key;
++ struct btrfs_path *path;
++
++ search_key.objectid = objectid;
++ search_key.type = BTRFS_ROOT_ITEM_KEY;
++ search_key.offset = (u64)-1;
++ path = btrfs_grab_path(lpid);
++
++ ret = aux_tree_lookup(tree_root, &search_key, path);
++ if (ret < 0)
++ return 1;
++ slot = path->slots[0];
++ WARN_ON(slot == 0);
++ slot -= 1;
++ btrfs_item_key_to_cpu(&path->nodes[0], &found_key, slot);
++ if (found_key.objectid != objectid)
++ return 1;
++
++ read_extent_buffer(&path->nodes[0], item,
++ btrfs_item_ptr_offset(&path->nodes[0], slot),
++ sizeof(*item));
++ return 0;
++}
++
++static int find_setup_root(struct btrfs_root *tree_root,
++ u32 nodesize,
++ u32 leafsize,
++ u32 sectorsize,
++ u32 stripesize,
++ u64 objectid,
++ struct btrfs_root *dest_root,
++ u64 bytenr,
++ u32 blocksize,
++ u64 generation,
++ lookup_pool_id lpid)
++{
++ int ret;
++ struct extent_buffer eb;
++
++ setup_root(dest_root,
++ nodesize,
++ leafsize,
++ sectorsize,
++ stripesize,
++ objectid);
++ if (tree_root) {
++ /*
++ * pick up the latest version
++ * of the root we want to set up
++ */
++ ret = btrfs_find_last_root(tree_root, objectid,
++ &dest_root->root_item,
++ lpid);
++ if (ret)
++ return ret;
++ bytenr = btrfs_root_bytenr(&dest_root->root_item);
++ blocksize = btrfs_level_size(dest_root,
++ btrfs_root_level(&dest_root->root_item));
++ generation = btrfs_root_generation(&dest_root->root_item);
++ }
++ ret = read_tree_block(dest_root,
++ &eb,
++ bytenr,
++ blocksize,
++ generation,
++ lpid);
++ if (!ret)
++ return 1;
++ copy_extent_buffer(&dest_root->node, &eb);
++ return 0;
++}
++
++static inline int btrfs_strncmp(const char *cs, const char *ct, int count)
++{
++ signed char __res = 0;
++
++ while (count) {
++ if ((__res = *cs - *ct++) != 0 || !*cs++)
++ break;
++ count--;
++ }
++ return __res;
++}
++
++/*
++ * the same as devread, but accepts
++ * device number, start and length.
++ */
++static int btrfs_devread(unsigned long drive, unsigned long part,
++ unsigned long dev_len, int sector,
++ int byte_offset, int byte_len, char *buf)
++{
++ if (sector < 0
++ || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
++ >= dev_len)) {
++ errnum = ERR_OUTSIDE_PART;
++ return 0;
++ }
++ sector += byte_offset >> SECTOR_BITS;
++ byte_offset &= SECTOR_SIZE - 1;
++#if !defined(STAGE1_5)
++ if (disk_read_hook && debug)
++ printf ("<%d, %d, %d>", sector, byte_offset, byte_len);
++#endif /* !STAGE1_5 */
++ return rawread(drive, part + sector, byte_offset,
++ byte_len, buf);
++}
++
++static int btrfs_check_super(void)
++{
++ struct btrfs_super_block *sb = BTRFS_SUPER;
++
++ if (sb->nodesize != BTRFS_DEFAULT_NODE_SIZE) {
++ btrfs_msg("Btrfs node size (%d) != %d unsupported\n",
++ sb->nodesize, BTRFS_DEFAULT_NODE_SIZE);
++ goto error;
++ }
++ if (sb->leafsize != BTRFS_DEFAULT_LEAF_SIZE) {
++ btrfs_msg("Btrfs leaf size (%d) != %d unsupported\n",
++ sb->leafsize, BTRFS_DEFAULT_LEAF_SIZE);
++ goto error;
++ }
++
++ return 0;
++error:
++ return 1;
++}
++
++/* lift the super block */
++static int btrfs_uptodate_super_copy(struct btrfs_fs_info *fs)
++{
++ errnum = ERR_NONE;
++ btrfs_devread(BTRFS_FS_INFO->sb_dev.drive,
++ BTRFS_FS_INFO->sb_dev.part,
++ BTRFS_FS_INFO->sb_dev.length,
++ btrfs_sb_offset(BTRFS_FS_INFO->sb_mirror) >> SECTOR_BITS,
++ 0,
++ sizeof(struct btrfs_super_block),
++ (char *)BTRFS_SUPER);
++ return btrfs_check_super();
++}
++
++/*
++ * Looking for a btrfs super block by magic, @fsid and @devid
++ * (the last two ones are optional). Update latest transid (if
++ * any). Return 0, if such super block was found. Otherwise,
++ * return 1.
++ *
++ * NOTE:
++ * After calling this function the sb_copy of global btrfs_fs_info
++ * can contain garbage, so the caller is responsible for this to be
++ * uptodate (see the function btrfs_uptodate_super_copy()).
++ */
++static int btrfs_find_super(struct btrfs_device *dev, char *fsid, u64 *devid)
++{
++ int i, ret;
++ int found = 0;
++
++ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
++ ret = btrfs_devread(dev->drive,
++ dev->part,
++ dev->length,
++ btrfs_sb_offset(i) >> SECTOR_BITS,
++ 0,
++ sizeof(struct btrfs_super_block),
++ (char *)BTRFS_SUPER);
++ if (!ret) {
++ if (errnum == ERR_OUTSIDE_PART) {
++ errnum = ERR_NONE;
++ break;
++ } else {
++ errnum = ERR_NONE;
++ continue;
++ }
++ }
++ if (btrfs_super_bytenr(BTRFS_SUPER) != btrfs_sb_offset(i) ||
++ btrfs_strncmp((char *)(&BTRFS_SUPER->magic),
++ BTRFS_MAGIC,
++ sizeof(BTRFS_SUPER->magic)))
++ continue;
++ if (fsid &&
++ btrfs_strncmp(fsid,
++ (char *)BTRFS_SUPER->fsid,
++ BTRFS_FSID_SIZE))
++ return 1;
++ if (devid &&
++ *devid != btrfs_super_devid(BTRFS_SUPER))
++ return 1;
++ found = 1;
++ dev->devid = btrfs_super_devid(BTRFS_SUPER);
++
++ if (btrfs_super_generation(BTRFS_SUPER) >
++ BTRFS_FS_INFO->sb_transid) {
++ BTRFS_FS_INFO->sb_transid =
++ btrfs_super_generation(BTRFS_SUPER);
++ BTRFS_FS_INFO->sb_mirror = i;
++ BTRFS_FS_INFO->sb_dev.devid =
++ btrfs_super_devid(BTRFS_SUPER);
++ BTRFS_FS_INFO->sb_dev.drive = dev->drive;
++ BTRFS_FS_INFO->sb_dev.part = dev->part;
++ BTRFS_FS_INFO->sb_dev.length = dev->length;
++ }
++ }
++ return !found;
++}
++
++/*
++ * "Discern" a btrfs device by fsid and
++ * optionaly by devid (if lookup is set).
++ * Populate persistent device cache (if
++ * there are free slots).
++ */
++static int btrfs_discerner(struct btrfs_device **dev, int lookup)
++{
++ if (btrfs_find_super(*dev,
++ (char *)BTRFS_FS_INFO->fsid,
++ (lookup ? &(*dev)->devid : 0)))
++ /* not found */
++ return 0;
++ if (*dev < BTRFS_VOLATILE_DEV_CACHE) {
++ /* populate persistent device cache */
++ memcpy(*dev + 1, *dev, sizeof(struct btrfs_device));
++ (*dev)++;
++ }
++ return 1;
++}
++
++/*
++ * Scan available grub devices and call discerner
++ * for them. Return a number of discerned devices
++ * The scanner was stolen from print_completions().
++ *
++ * Preconditions:
++ * The global structure btrfs_fs_info contains
++ * the latest valid version of btrfs superblock
++ * (the field @sb_copy)
++ */
++static u64 scan_grub_devices(struct btrfs_device *dev,
++ int (*discerner)(struct btrfs_device **, int),
++ int lookup)
++{
++ int i, j;
++ u64 count = 0;
++ struct geometry geom;
++
++ for (i = 0; i < 2; i++)
++ for (j = 0; j < 8; j++) {
++ unsigned long part = 0xFFFFFF;
++ int type, entry, gpt_count, gpt_size;
++ unsigned long offset, ext_offset, gpt_offset;
++
++ dev->drive = (i * 0x80) + j;
++ if (get_diskinfo(dev->drive, &geom))
++ continue;
++ while (1) {
++ int ret;
++ buf_drive = -1;
++ errnum = ERR_NONE;
++ ret = next_partition(dev->drive, 0xFFFFFF,
++ &part, &type, &dev->part,
++ &dev->length, &offset,
++ &entry, &ext_offset,
++ &gpt_offset, &gpt_count,
++ &gpt_size,
++ BTRFS_FS_INFO->mbr);
++ if (!ret)
++ break;
++ if (discerner(&dev, lookup)) {
++ count++;
++ if (lookup)
++ goto exit;
++ }
++ }
++ }
++#if 0
++ errnum = ERR_NONE;
++ if (cdrom_drive != GRUB_INVALID_DRIVE &&
++ !get_diskinfo(cdrom_drive, &geom)) {
++ dev->drive = cdrom_drive;
++ dev->part = 0;
++ dev->length = geom.total_sectors;
++ if (discerner(&dev, lookup)) {
++ count++;
++ if (lookup)
++ goto exit;
++ }
++ }
++#ifdef SUPPORT_NETBOOT
++ errnum = ERR_NONE;
++ if (network_ready &&
++ !get_diskinfo(NETWORK_DRIVE, &geom)) {
++ dev->drive = NETWORK_DRIVE;
++ dev->part = 0;
++ dev->length = geom.total_sectors;
++ if (discerner(&dev, lookup)) {
++ count++;
++ if (lookup)
++ goto exit;
++ }
++ }
++#endif /* SUPPORT_NETBOOT */
++#endif /* 0 */
++ exit:
++ return count;
++}
++
++#if 0
++static int btrfs_next_item(struct btrfs_root *root,
++ struct btrfs_path *path);
++
++/*
++ * Scan the chunk tree for dev items
++ * and call a seeker for all of them.
++ * Preconditions: chunk root is installed
++ * to the global btrfs_fs_info.
++ */
++static int scan_dev_tree(struct btrfs_device* (*seeker)(u64))
++{
++ int ret;
++ u64 num_devices = 0;
++ struct btrfs_key key;
++ struct btrfs_key found_key;
++ struct btrfs_path *path;
++ struct btrfs_root *root;
++
++ root = BTRFS_CHUNK_ROOT;
++ path = btrfs_grab_path(FIRST_EXTERNAL_LOOKUP_POOL);
++ key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
++ key.type = 0;
++ key.offset = 0;
++
++ ret = aux_tree_lookup(root, &key, path);
++ if (ret == -1)
++ goto corrupted;
++ while (1) {
++ struct btrfs_device *result;
++ struct btrfs_dev_item *dev_item;
++
++ btrfs_item_key_to_cpu(&path->nodes[0],
++ &found_key,
++ path->slots[0]);
++ if (found_key.objectid != BTRFS_DEV_ITEMS_OBJECTID)
++ break;
++ dev_item = btrfs_item_ptr(&path->nodes[0],
++ path->slots[0],
++ struct btrfs_dev_item);
++ result = seeker(btrfs_device_id(&path->nodes[0], dev_item));
++ if (result == NULL) {
++ btrfs_msg("Btrfs device %llu is not available\n",
++ btrfs_device_id(&path->nodes[0], dev_item));
++ goto missed_dev;
++ }
++ num_devices++;
++ ret = btrfs_next_item(root, path);
++ if (ret)
++ break;
++ }
++ if (num_devices == btrfs_super_num_devices(BTRFS_SUPER))
++ return 0;
++ corrupted:
++ errnum = ERR_FSYS_CORRUPT;
++ return 1;
++ missed_dev:
++ errnum = ERR_FSYS_MOUNT;
++ return 1;
++}
++#endif /* 0 */
++
++/*
++ * Find a grub btrfs device by devid.
++ * Preconditions: global btrfs_fs_info
++ * contains a copy of btrfs super block.
++ *
++ * Return pointer to the cached device on success.
++ * Otherwise return NULL.
++ */
++static struct btrfs_device *btrfs_lookup_device(u64 devid)
++{
++ int i, result;
++ struct btrfs_device *cdev;
++
++ for (i = 0; i < BTRFS_NUM_CACHED_DEVICES; i++) {
++ cdev = &BTRFS_DEVICES[i];
++ if (cdev->devid == devid)
++ goto found_in_cache;
++ if (cdev->devid == 0)
++ goto not_found_in_cache;
++ }
++not_found_in_cache:
++ cdev = BTRFS_VOLATILE_DEV_CACHE;
++ cdev->devid = devid;
++ result = scan_grub_devices(cdev,
++ btrfs_discerner,
++ 1);
++ if (result == 0)
++ /*
++ * At mount time we have figured out that
++ * number of available devices is not less
++ * then number of devices recorded in the
++ * super block. Hence we treat this case as
++ * file system corruption.
++ */
++ goto corrupt;
++ result = btrfs_uptodate_super_copy(BTRFS_FS_INFO);
++ if (result)
++ goto corrupt;
++found_in_cache:
++ return cdev;
++corrupt:
++ errnum = ERR_FSYS_CORRUPT;
++ return NULL;
++}
++
++static int btrfs_find_device(struct btrfs_device *dev)
++{
++ struct btrfs_device *cdev;
++
++ if (btrfs_super_num_devices(BTRFS_SUPER) == 1) {
++ dev->drive = current_drive;
++ dev->part = part_start;
++ dev->length = part_length;
++ return 0;
++ }
++ cdev = btrfs_lookup_device(dev->devid);
++ if (cdev == NULL)
++ return 1;
++ dev->drive = cdev->drive;
++ dev->part = cdev->part;
++ dev->length = cdev->length;
++ return 0;
++}
++
++static inline void init_btrfs_volatile_dev_cache(void)
++{
++ BTRFS_VOLATILE_DEV_CACHE->devid = 0;
++ BTRFS_VOLATILE_DEV_CACHE->drive = current_drive;
++ BTRFS_VOLATILE_DEV_CACHE->part = part_start;
++ BTRFS_VOLATILE_DEV_CACHE->length = part_length;
++}
++
++/*
++ * check availability of btrfs devices
++ * and populate the persistent device cache
++ */
++static int btrfs_check_devices(void)
++{
++ u64 num_dev;
++
++ if (btrfs_super_num_devices(BTRFS_SUPER) == 1)
++ return 0;
++ num_dev = scan_grub_devices(BTRFS_DEVICES,
++ btrfs_discerner, 0);
++ if (btrfs_uptodate_super_copy(BTRFS_FS_INFO))
++ return 1;
++ if (num_dev < btrfs_super_num_devices(BTRFS_SUPER)) {
++ btrfs_msg("Some (%llu) Btrfs devices is not available\n",
++ btrfs_super_num_devices(BTRFS_SUPER) - num_dev);
++ return 1;
++ }
++ return 0;
++}
++
++int btrfs_mount(void)
++{
++ int ret;
++
++ check_btrfs_cache_size();
++ init_btrfs_info();
++ init_btrfs_volatile_dev_cache();
++
++ ret = btrfs_find_super(BTRFS_VOLATILE_DEV_CACHE, NULL, NULL);
++ if (ret) {
++ btrfs_msg("Drive %lu, partition %lu: no Btrfs metadata\n",
++ current_drive, part_start);
++ goto error;
++ }
++ ret = btrfs_uptodate_super_copy(BTRFS_FS_INFO);
++ if (ret)
++ goto error;
++ BTRFS_FS_INFO->sb_transid =
++ btrfs_super_generation(BTRFS_SUPER);
++ memcpy(BTRFS_FS_INFO->fsid,
++ BTRFS_SUPER->fsid,
++ BTRFS_FSID_SIZE);
++ ret = btrfs_check_devices();
++ if (ret)
++ goto error;
++ /* setup chunk root */
++ ret = find_setup_root(NULL,
++ btrfs_super_nodesize(BTRFS_SUPER),
++ btrfs_super_leafsize(BTRFS_SUPER),
++ btrfs_super_sectorsize(BTRFS_SUPER),
++ btrfs_super_stripesize(BTRFS_SUPER),
++ BTRFS_CHUNK_TREE_OBJECTID,
++ BTRFS_CHUNK_ROOT,
++ btrfs_super_chunk_root(BTRFS_SUPER),
++ btrfs_chunk_root_level_size(BTRFS_SUPER),
++ btrfs_super_chunk_root_generation(BTRFS_SUPER),
++ FIRST_EXTERNAL_LOOKUP_POOL);
++ if (ret)
++ return 0;
++ /* setup tree root */
++ ret = find_setup_root(NULL,
++ btrfs_super_nodesize(BTRFS_SUPER),
++ btrfs_super_leafsize(BTRFS_SUPER),
++ btrfs_super_sectorsize(BTRFS_SUPER),
++ btrfs_super_stripesize(BTRFS_SUPER),
++ BTRFS_ROOT_TREE_OBJECTID,
++ BTRFS_TREE_ROOT,
++ btrfs_super_root(BTRFS_SUPER),
++ btrfs_root_level_size(BTRFS_SUPER),
++ btrfs_super_generation(BTRFS_SUPER),
++ FIRST_EXTERNAL_LOOKUP_POOL);
++ if (ret)
++ return 0;
++ /* setup fs_root */
++ ret = find_setup_root(BTRFS_TREE_ROOT,
++ btrfs_super_nodesize(BTRFS_SUPER),
++ btrfs_super_leafsize(BTRFS_SUPER),
++ btrfs_super_sectorsize(BTRFS_SUPER),
++ btrfs_super_stripesize(BTRFS_SUPER),
++ BTRFS_FS_TREE_OBJECTID,
++ BTRFS_FS_ROOT,
++ 0,
++ 0,
++ 0,
++ FIRST_EXTERNAL_LOOKUP_POOL);
++ return !ret;
++
++error:
++ errnum = ERR_FSYS_MOUNT;
++ return 0;
++}
++
++/*
++ * Check, whether @chunk is the map for a
++ * block with @logical block number.
++ * If yes, then fill the @map.
++ * Return 1 on affirmative result,
++ * otherwise return 0.
++ */
++int check_read_chunk(struct btrfs_key *key,
++ struct extent_buffer *leaf,
++ struct btrfs_chunk *chunk,
++ struct map_lookup *map,
++ u64 logical)
++{
++ int i, ret;
++ u64 chunk_start;
++ u64 chunk_size;
++ int num_stripes;
++
++ chunk_start = key->offset;
++ chunk_size = btrfs_chunk_length(leaf, chunk);
++
++ if (logical + 1 > chunk_start + chunk_size ||
++ logical < chunk_start)
++ /* not a fit */
++ return 0;
++ num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
++ map->ce.start = chunk_start;
++ map->ce.size = chunk_size;
++ map->num_stripes = num_stripes;
++ map->io_width = btrfs_chunk_io_width(leaf, chunk);
++ map->io_align = btrfs_chunk_io_align(leaf, chunk);
++ map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
++ map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
++ map->type = btrfs_chunk_type(leaf, chunk);
++ map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
++
++ for (i = 0; i < num_stripes; i++) {
++ map->stripes[i].physical =
++ btrfs_stripe_offset_nr(leaf, chunk, i);
++ map->stripes[i].dev.devid =
++ btrfs_stripe_devid_nr(leaf, chunk, i);
++ ret = btrfs_find_device(&map->stripes[i].dev);
++ if (ret)
++ return 0;
++ }
++ return 1;
++}
++
++static void init_extent_buffer(struct extent_buffer *eb,
++ struct btrfs_device *dev,
++ u64 logical,
++ u32 blocksize,
++ u64 physical,
++ lookup_pool_id lpid)
++{
++ if (dev)
++ memcpy(&eb->dev, dev, sizeof(*dev));
++ eb->start = logical;
++ eb->len = blocksize;
++ eb->dev_bytenr = physical;
++ eb->data = grab_lookup_cache(lpid);
++}
++
++/*
++ * Search for a map by logical offset in sys array.
++ * Return -1 on errors;
++ * Return 1 if the map is found,
++ * Return 0 if the map is not found.
++ */
++int sys_array_lookup(struct map_lookup *map, u64 logical)
++{
++ struct extent_buffer sb;
++ struct btrfs_disk_key *disk_key;
++ struct btrfs_chunk *chunk;
++ struct btrfs_key key;
++ u32 num_stripes;
++ u32 array_size;
++ u32 len = 0;
++ u8 *ptr;
++ unsigned long sb_ptr;
++ u32 cur;
++ int ret;
++ int i = 0;
++
++ sb.data = (char *)BTRFS_SUPER;
++ array_size = btrfs_super_sys_array_size(BTRFS_SUPER);
++
++ ptr = BTRFS_SUPER->sys_chunk_array;
++ sb_ptr = offsetof(struct btrfs_super_block, sys_chunk_array);
++ cur = 0;
++
++ while (cur < array_size) {
++ disk_key = (struct btrfs_disk_key *)ptr;
++ btrfs_disk_key_to_cpu(&key, disk_key);
++
++ len = sizeof(*disk_key);
++ ptr += len;
++ sb_ptr += len;
++ cur += len;
++
++ if (key.type == BTRFS_CHUNK_ITEM_KEY) {
++ chunk = (struct btrfs_chunk *)sb_ptr;
++ ret = check_read_chunk(&key, &sb,
++ chunk, map, logical);
++ if (ret)
++ /* map is found */
++ return ret;
++ num_stripes = btrfs_chunk_num_stripes(&sb, chunk);
++ len = btrfs_chunk_item_size(num_stripes);
++ } else {
++ errnum = ERR_FSYS_CORRUPT;
++ return -1;
++ }
++ ptr += len;
++ sb_ptr += len;
++ cur += len;
++ i++;
++ }
++ return 0;
++}
++
++/*
++ * Search for a map by logical offset in the chunk tree.
++ * Return 1 if map is found, otherwise return 0.
++ */
++static int chunk_tree_lookup(struct map_lookup *map,
++ u64 logical)
++{
++ int ret;
++ int slot;
++ struct extent_buffer *leaf;
++ struct btrfs_key key;
++ struct btrfs_key found_key;
++ struct btrfs_chunk *chunk;
++ struct btrfs_path *path;
++
++ path = btrfs_grab_path(INTERNAL_LOOKUP_POOL);
++
++ key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
++ key.offset = logical;
++ key.type = BTRFS_CHUNK_ITEM_KEY;
++
++ ret = aux_tree_lookup(BTRFS_CHUNK_ROOT, &key, path);
++ if (ret < 0)
++ return 0;
++ leaf = &path->nodes[0];
++ slot = path->slots[0];
++ if (ret == 1) {
++ WARN_ON(slot == 0);
++ slot -= 1;
++ }
++ btrfs_item_key_to_cpu(leaf, &found_key, slot);
++ if (found_key.type != BTRFS_CHUNK_ITEM_KEY)
++ return 0;
++ chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
++ return check_read_chunk(&found_key, leaf,
++ chunk, map, logical);
++}
++
++/*
++ * Btrfs logical/physical block mapper.
++ * Look for an appropriate map-extent and
++ * perform a translation. Return 1 on errors.
++ */
++static int btrfs_map_block(u64 logical, u64 *length,
++ struct btrfs_multi_bio *multi,
++ int mirror_num)
++{
++ struct map_lookup map;
++ u64 offset;
++ u64 stripe_offset;
++ u64 stripe_nr;
++ struct cache_extent *ce;
++ int stripe_index;
++ int i;
++ int ret;
++
++ memset(&map, 0, sizeof(map));
++ ret = sys_array_lookup(&map, logical);
++ if (ret == -1) {
++ errnum = ERR_FSYS_CORRUPT;
++ return 1;
++ }
++ if (ret == 0) {
++ ret = chunk_tree_lookup(&map, logical);
++ if (!ret) {
++ /* something should be found! */
++ errnum = ERR_FSYS_CORRUPT;
++ return 1;
++ }
++ }
++ /* do translation */
++ ce = &map.ce;
++
++ offset = logical - ce->start;
++ stripe_nr = offset / map.stripe_len;
++ stripe_offset = stripe_nr * map.stripe_len;
++ WARN_ON(offset < stripe_offset);
++
++ stripe_offset = offset - stripe_offset;
++
++ if (map.type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
++ BTRFS_BLOCK_GROUP_RAID10 |
++ BTRFS_BLOCK_GROUP_DUP)) {
++ *length = min_t(u64, ce->size - offset,
++ map.stripe_len - stripe_offset);
++ } else {
++ *length = ce->size - offset;
++ }
++ multi->num_stripes = 1;
++ stripe_index = 0;
++ if (map.type & BTRFS_BLOCK_GROUP_RAID1) {
++ if (mirror_num)
++ stripe_index = mirror_num - 1;
++ else
++ stripe_index = stripe_nr % map.num_stripes;
++ } else if (map.type & BTRFS_BLOCK_GROUP_RAID10) {
++ int factor = map.num_stripes / map.sub_stripes;
++
++ stripe_index = stripe_nr % factor;
++ stripe_index *= map.sub_stripes;
++
++ if (mirror_num)
++ stripe_index += mirror_num - 1;
++ else
++ stripe_index = stripe_nr % map.sub_stripes;
++
++ stripe_nr = stripe_nr / factor;
++ } else if (map.type & BTRFS_BLOCK_GROUP_DUP) {
++ if (mirror_num)
++ stripe_index = mirror_num - 1;
++ } else {
++ stripe_index = stripe_nr % map.num_stripes;
++ stripe_nr = stripe_nr / map.num_stripes;
++ }
++ WARN_ON(stripe_index >= map.num_stripes);
++
++ for (i = 0; i < multi->num_stripes; i++) {
++ asm("" : "+r"(multi));
++ multi->stripes[i].physical =
++ map.stripes[stripe_index].physical + stripe_offset +
++ stripe_nr * map.stripe_len;
++ memcpy(&multi->stripes[i].dev,
++ &map.stripes[stripe_index].dev,
++ sizeof(struct btrfs_device));
++ stripe_index++;
++ }
++ return 0;
++}
++
++static u64 read_data_extent(u64 logical_start, u64 to_read, char *pos)
++{
++ int ret;
++ u64 length;
++ struct btrfs_multi_bio multi;
++
++ while (to_read) {
++ ret = btrfs_map_block(logical_start, &length, &multi, 0);
++ if (ret) {
++ errnum = ERR_FSYS_CORRUPT;
++ return ret;
++ }
++ if (length > to_read)
++ length = to_read;
++ disk_read_func = disk_read_hook;
++ ret = btrfs_devread(multi.stripes[0].dev.drive,
++ multi.stripes[0].dev.part,
++ multi.stripes[0].dev.length,
++ multi.stripes[0].physical >> SECTOR_BITS,
++ logical_start & ((u64)SECTOR_SIZE - 1),
++ length,
++ pos);
++ disk_read_func = NULL;
++ if (!ret)
++ return 1;
++ btrfs_msg("BTRFS data extent: read %llu bytes\n", length);
++ to_read -= length;
++ pos += length;
++ logical_start += length;
++ }
++ return 0;
++}
++
++static int read_extent_from_disk(struct extent_buffer *eb)
++{
++ WARN_ON(eb->dev_bytenr % SECTOR_BITS);
++ return btrfs_devread(eb->dev.drive,
++ eb->dev.part,
++ eb->dev.length,
++ eb->dev_bytenr >> SECTOR_BITS,
++ 0,
++ eb->len,
++ eb->data);
++}
++
++static int verify_parent_transid(struct extent_buffer *eb, u64 parent_transid)
++{
++ return parent_transid && (btrfs_header_generation(eb) != parent_transid);
++}
++
++static int btrfs_num_copies(u64 logical, u64 len)
++{
++ return 1;
++}
++
++static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
++{
++ return 0;
++}
++
++static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
++ int verify)
++{
++ return 0;
++}
++
++/*
++ * Read a block of logical number @bytenr
++ * from disk to buffer @eb.
++ * Return 1 on success.
++ */
++int read_tree_block(struct btrfs_root *root,
++ struct extent_buffer *eb,
++ u64 bytenr, /* logical */
++ u32 blocksize,
++ u64 parent_transid,
++ lookup_pool_id lpid)
++{
++ int ret;
++ int dev_nr;
++ u64 length;
++ struct btrfs_multi_bio multi;
++ int mirror_num = 0;
++ int num_copies;
++
++ dev_nr = 0;
++ length = blocksize;
++ while (1) {
++ ret = btrfs_map_block(bytenr,
++ &length, &multi, mirror_num);
++ if (ret) {
++ errnum = ERR_FSYS_CORRUPT;
++ return 0;
++ }
++ init_extent_buffer(eb,
++ &multi.stripes[0].dev,
++ bytenr,
++ blocksize,
++ multi.stripes[0].physical,
++ lpid);
++
++ ret = read_extent_from_disk(eb);
++ if (ret &&
++ check_tree_block(root, eb) == 0 &&
++ csum_tree_block(root, eb, 1) == 0 &&
++ verify_parent_transid(eb, parent_transid) == 0)
++ return 1;
++
++ num_copies = btrfs_num_copies(eb->start, eb->len);
++ if (num_copies == 1)
++ break;
++ mirror_num++;
++ if (mirror_num > num_copies)
++ break;
++ }
++ return 0;
++}
++
++/*
++ * Read a child pointed by @slot node pointer
++ * of @parent. Put the result to @parent.
++ * Return 1 on success.
++ */
++static int parent2child(struct btrfs_root *root,
++ struct extent_buffer *parent,
++ int slot,
++ lookup_pool_id lpid)
++{
++ int level;
++
++ WARN_ON(slot < 0);
++ WARN_ON(slot >= btrfs_header_nritems(parent));
++
++ level = btrfs_header_level(parent);
++ WARN_ON(level <= 0);
++
++ return read_tree_block(root,
++ parent,
++ btrfs_node_blockptr(parent, slot),
++ btrfs_level_size(root, level - 1),
++ btrfs_node_ptr_generation(parent, slot),
++ lpid);
++}
++
++static int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2)
++{
++ struct btrfs_key k1;
++
++ btrfs_disk_key_to_cpu(&k1, disk);
++
++ if (k1.objectid > k2->objectid)
++ return 1;
++ if (k1.objectid < k2->objectid)
++ return -1;
++ if (k1.type > k2->type)
++ return 1;
++ if (k1.type < k2->type)
++ return -1;
++ if (k1.offset > k2->offset)
++ return 1;
++ if (k1.offset < k2->offset)
++ return -1;
++ return 0;
++}
++
++static int bin_search(struct extent_buffer *eb, unsigned long p,
++ int item_size, struct btrfs_key *key,
++ int max, int *slot)
++{
++ int low = 0;
++ int high = max;
++ int mid;
++ int ret;
++ unsigned long offset;
++ struct btrfs_disk_key *tmp;
++
++ while(low < high) {
++ mid = (low + high) / 2;
++ offset = p + mid * item_size;
++
++ tmp = (struct btrfs_disk_key *)(eb->data + offset);
++ ret = btrfs_comp_keys(tmp, key);
++
++ if (ret < 0)
++ low = mid + 1;
++ else if (ret > 0)
++ high = mid;
++ else {
++ *slot = mid;
++ return 0;
++ }
++ }
++ *slot = low;
++ return 1;
++}
++
++/* look for a key in a node */
++static int node_lookup(struct extent_buffer *eb,
++ struct btrfs_key *key,
++ int *slot)
++{
++ if (btrfs_header_level(eb) == 0) {
++ return bin_search(eb,
++ offsetof(struct btrfs_leaf, items),
++ sizeof(struct btrfs_item),
++ key, btrfs_header_nritems(eb),
++ slot);
++ } else {
++ return bin_search(eb,
++ offsetof(struct btrfs_node, ptrs),
++ sizeof(struct btrfs_key_ptr),
++ key, btrfs_header_nritems(eb),
++ slot);
++ }
++ return -1;
++}
++
++static inline int check_node(struct extent_buffer *buf, int slot)
++{
++ return 0;
++}
++
++/*
++ * Look for an item by key in read-only tree.
++ * Return 0, if key was found. Return -1 on io errors.
++ *
++ * Preconditions: btrfs_mount already executed.
++ * Postconditions: if returned value is non-negative,
++ * then path[0] represents the found position in the
++ * tree. All components of the @path from leaf to root
++ * are valid except their data buffers (only path[0]
++ * has valid attached data buffer).
++ */
++
++int aux_tree_lookup(struct btrfs_root *root,
++ struct btrfs_key *key,
++ struct btrfs_path *path)
++{
++ int ret;
++ int slot = 0;
++ int level;
++ struct extent_buffer node;
++ init_extent_buffer(&node,
++ NULL,
++ 0,
++ 0,
++ 0,
++ path->lpid);
++ copy_extent_buffer(&node, &root->node);
++ do {
++ level = btrfs_header_level(&node);
++ ret = check_node(&node, slot);
++ if (ret)
++ return -1;
++ move_extent_buffer(&path->nodes[level],
++ &node);
++ ret = node_lookup(&node, key, &slot);
++ if (ret < 0)
++ return ret;
++ if (level) {
++ /*
++ * non-leaf,
++ * jump to the next level
++ */
++ if (ret && slot > 0)
++ slot -= 1;
++ ret = parent2child(root, &node, slot, path->lpid);
++ if (ret == 0)
++ return -1;
++ }
++ path->slots[level] = slot;
++ } while (level);
++ return ret;
++}
++
++static int readup_buffer(struct extent_buffer *buf, lookup_pool_id lpid)
++{
++ buf->data = grab_lookup_cache(lpid);
++ return read_extent_from_disk(buf);
++}
++
++/*
++ * Find the next leaf in accordance with tree order;
++ * walk up the tree as far as required to find it.
++ * Returns 0 if something was found, or 1 if there
++ * are no greater leaves. Returns < 0 on io errors.
++ *
++ * Preconditions: all @path components from leaf to
++ * root have valid meta-data fields. path[0] has a
++ * valid attached data buffer with initial leaf.
++ * Postcondition: the same as above, but path[0] has
++ * an attached data buffer with the next leaf.
++ */
++static int btrfs_next_leaf(struct btrfs_root *root,
++ struct btrfs_path *path)
++{
++ int res;
++ int slot;
++ int level = 1;
++ struct extent_buffer *buf;
++
++ while(level < BTRFS_MAX_LEVEL) {
++ buf = &path->nodes[level];
++ slot = path->slots[level] + 1;
++ /*
++ * lift data on this level
++ */
++ res = readup_buffer(buf, path->lpid);
++ if (!res)
++ break;
++ if (slot >= btrfs_header_nritems(buf)) {
++ /* alas, go to parent (if any) */
++ level++;
++ res = 1;
++ continue;
++ }
++ break;
++ }
++ if (!res)
++ return 1;
++ /*
++ * At this level slot points to
++ * the subtree we are interested in.
++ */
++ path->slots[level] = slot;
++ while(level) {
++ struct extent_buffer tmp;
++ move_extent_buffer(&tmp, &path->nodes[level]);
++ res = parent2child(root, &tmp, slot, path->lpid);
++ if (res == 0)
++ return -1;
++ level --;
++ slot = 0;
++ move_extent_buffer(&path->nodes[level], &tmp);
++ path->slots[level] = slot;
++ }
++ return 0;
++}
++
++/* Preconditions: path is valid, data buffer
++ * is attached to leaf node.
++ * Postcondition: path is updated to point to
++ * the next position with respect to the tree
++ * order.
++ *
++ * Return -1 on io errors.
++ * Return 0, if next item was found.
++ * Return 1, if next item wasn't found (no more items).
++ */
++static int btrfs_next_item(struct btrfs_root *root,
++ struct btrfs_path *path)
++{
++ WARN_ON(path->slots[0] >= btrfs_header_nritems(&path->nodes[0]));
++
++ path->slots[0] += 1;
++
++ if (path->slots[0] < btrfs_header_nritems(&path->nodes[0]))
++ return 0;
++ if (coord_is_root(root, path))
++ /* no more items */
++ return 1;
++ return btrfs_next_leaf(root, path);
++}
++
++/*
++ * check if we can reuse results of previous
++ * search for read operation
++ */
++static int path_is_valid(struct btrfs_path *path,
++ struct btrfs_key *key, u64 offset)
++{
++ btrfs_item_key_to_cpu(&path->nodes[0],
++ key,
++ path->slots[0]);
++ if (BTRFS_FILE_INFO_KEY->objectid != key->objectid)
++ return 0;
++ if (btrfs_key_type(key) == BTRFS_INODE_ITEM_KEY)
++ return 1;
++ if (btrfs_key_type(key) != BTRFS_EXTENT_DATA_KEY)
++ return 0;
++ return BTRFS_FILE_INFO_KEY->offset <= offset;
++}
++
++/* ->read_func() */
++int btrfs_read(char *buf, int len)
++{
++ int ret;
++ struct btrfs_root *fs_root;
++ struct btrfs_path *path;
++ struct btrfs_key path_key;
++ u64 ioff;
++ u64 bytes;
++ int to_read;
++ char *pos = buf;
++
++ fs_root = BTRFS_FS_ROOT;
++ path = btrfs_grab_path(FIRST_EXTERNAL_LOOKUP_POOL);
++
++ if (!path_is_valid(path, &path_key, filepos)) {
++ ret = aux_tree_lookup(fs_root, BTRFS_FILE_INFO_KEY, path);
++ if (ret < 0)
++ errnum = ERR_FSYS_CORRUPT;
++ }
++ while (!errnum) {
++ struct btrfs_item *item;
++ struct btrfs_file_extent_item *fi;
++ u64 from;
++
++ btrfs_item_key_to_cpu(&path->nodes[0],
++ &path_key,
++ path->slots[0]);
++ if (BTRFS_FILE_INFO_KEY->objectid != path_key.objectid)
++ break;
++ if (btrfs_key_type(&path_key) != BTRFS_EXTENT_DATA_KEY)
++ goto next;
++ /*
++ * current position is extent item
++ */
++ item = btrfs_item_nr(&path->nodes[0], path->slots[0]);
++ fi = btrfs_item_ptr(&path->nodes[0],
++ path->slots[0],
++ struct btrfs_file_extent_item);
++ if (btrfs_file_extent_compression(&path->nodes[0], fi)) {
++ btrfs_msg("Btrfs transparent compression unsupported\n");
++ errnum = ERR_BAD_FILETYPE;
++ goto exit;
++ }
++ ioff = filepos - path_key.offset;
++
++ switch (btrfs_file_extent_type(&path->nodes[0], fi)) {
++ case BTRFS_FILE_EXTENT_INLINE:
++ bytes = btrfs_file_extent_inline_item_len(&path->
++ nodes[0],
++ item);
++ if (path_key.offset + bytes < filepos)
++ goto next;
++ to_read = bytes - ioff;
++ if (to_read > len)
++ to_read = len;
++ from = ioff + btrfs_file_extent_inline_start(fi);
++ if (disk_read_hook != NULL) {
++ disk_read_func = disk_read_hook;
++ ret = btrfs_devread(path->nodes[0].dev.drive,
++ path->nodes[0].dev.part,
++ path->nodes[0].dev.length,
++ path->nodes[0].dev_bytenr >>
++ SECTOR_BITS,
++ from,
++ to_read,
++ pos);
++ disk_read_func = NULL;
++ if (ret)
++ goto exit;
++ } else
++ memcpy(pos,
++ path->nodes[0].data + from,
++ to_read);
++ btrfs_msg("BTRFS inline extent: read %d bytes pos %d\n",
++ to_read, filepos);
++ break;
++ case BTRFS_FILE_EXTENT_REG:
++ bytes = btrfs_file_extent_num_bytes(&path->nodes[0],
++ fi);
++ if (path_key.offset + bytes < filepos)
++ goto next;
++ to_read = bytes - ioff;
++ if (to_read > len)
++ to_read = len;
++ from = ioff +
++ btrfs_file_extent_disk_bytenr(&path->nodes[0],
++ fi) +
++ btrfs_file_extent_offset(&path->nodes[0],
++ fi);
++ ret = read_data_extent(from, to_read, pos);
++ if (ret)
++ goto exit;
++ break;
++ case BTRFS_FILE_EXTENT_PREALLOC:
++ btrfs_msg("Btrfs preallocated extents unsupported\n");
++ errnum = ERR_BAD_FILETYPE;
++ goto exit;
++ default:
++ errnum = ERR_FSYS_CORRUPT;
++ goto exit;
++ }
++ len -= to_read;
++ pos += to_read;
++ filepos += to_read;
++ if (len == 0)
++ break;
++ /* not everything was read */
++ next:
++ ret = btrfs_next_item(fs_root, path);
++ if (ret < 0) {
++ errnum = ERR_FSYS_CORRUPT;
++ break;
++ }
++ btrfs_update_file_info(path);
++ continue;
++ }
++exit:
++ return errnum ? 0 : pos - buf;
++}
++
++static int btrfs_follow_link(struct btrfs_root *root,
++ struct btrfs_path *path,
++ char **dirname, char *linkbuf,
++ int *link_count,
++ struct btrfs_inode_item *sd)
++{
++ int ret;
++ int len;
++ char *name = *dirname;
++
++ if (++(*link_count) > MAX_LINK_COUNT) {
++ errnum = ERR_SYMLINK_LOOP;
++ return 0;
++ }
++ /* calculate remaining name size */
++ filemax = btrfs_inode_size(&path->nodes[0], sd);
++ for (len = 0;
++ name[len] && isspace(name[len]);
++ len ++);
++
++ if (filemax + len > PATH_MAX - 1) {
++ errnum = ERR_FILELENGTH;
++ return 0;
++ }
++ grub_memmove(linkbuf + filemax, name, len + 1);
++ btrfs_update_file_info(path);
++ filepos = 0;
++ /* extract symlink content */
++ while (1) {
++ u64 oid = BTRFS_FILE_INFO_KEY->objectid;
++ ret = btrfs_next_item(root, path);
++ if (ret)
++ break;
++ btrfs_update_file_info(path);
++ if (oid != BTRFS_FILE_INFO_KEY->objectid)
++ break;
++ if (btrfs_key_type(BTRFS_FILE_INFO_KEY) ==
++ BTRFS_EXTENT_DATA_KEY)
++ goto found;
++ }
++ /* no target was found */
++ errnum = ERR_FSYS_CORRUPT;
++ return 0;
++found:
++ /* fill the rest of linkbuf with the content */
++ ret = btrfs_read(linkbuf, filemax);
++ if (ret != filemax) {
++ errnum = ERR_FSYS_CORRUPT;
++ return 0;
++ }
++ return 1;
++}
++
++static int update_fs_root(struct btrfs_root *fs_root,
++ struct btrfs_key *location)
++{
++ int ret;
++ struct btrfs_root *tree_root;
++
++ if (location->offset != (u64)-1)
++ return 0;
++ tree_root = &BTRFS_FS_INFO->tree_root;
++ ret = find_setup_root(tree_root,
++ tree_root->nodesize,
++ tree_root->leafsize,
++ tree_root->sectorsize,
++ tree_root->stripesize,
++ location->objectid,
++ fs_root,
++ 0,
++ 0,
++ 0,
++ SECOND_EXTERNAL_LOOKUP_POOL);
++ if (ret)
++ return ret;
++ location->objectid = btrfs_root_dirid(&fs_root->root_item);
++ btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
++ location->offset = 0;
++ return 0;
++}
++
++#ifndef STAGE1_5
++static inline void update_possibilities(void)
++{
++ if (print_possibilities > 0)
++ print_possibilities =
++ -print_possibilities;
++}
++#endif
++
++/*
++ * Look for a directory item by name.
++ * Print possibilities, if needed.
++ * Postconditions: on success @sd_key points
++ * to the key contained in the directory entry.
++ */
++static int btrfs_de_index_by_name(struct btrfs_root *root,
++ struct btrfs_path *path,
++ char **dirname,
++ struct btrfs_key *sd_key)
++{
++ char ch;
++ int ret;
++ char *rest;
++ struct btrfs_dir_item *di;
++#ifndef STAGE1_5
++ int do_possibilities = 0;
++#endif
++ for (; **dirname == '/'; (*dirname)++);
++ for (rest = *dirname;
++ (ch = *rest) && !isspace(ch) && ch != '/';
++ rest++);
++ *rest = 0; /* for substrung() */
++#ifndef STAGE1_5
++ if (print_possibilities && ch != '/')
++ do_possibilities = 1;
++#endif
++ /* scan a directory */
++ while (1) {
++ u32 total;
++ u32 cur = 0;
++ u32 len;
++ struct btrfs_key di_key;
++ struct btrfs_disk_key location;
++ struct btrfs_item *item;
++
++ /* extract next dir entry */
++ ret = btrfs_next_item(root, path);
++ if (ret)
++ break;
++ item = btrfs_item_nr(&path->nodes[0],
++ path->slots[0]);
++ btrfs_item_key_to_cpu(&path->nodes[0],
++ &di_key,
++ path->slots[0]);
++ if (di_key.objectid != sd_key->objectid)
++ /* no more entries */
++ break;
++ di = btrfs_item_ptr(&path->nodes[0],
++ path->slots[0],
++ struct btrfs_dir_item);
++ /*
++ * working around special cases:
++ * btrfs doesn't maintain directory entries
++ * which contain names "." and ".."
++ */
++ if (!substring(".", *dirname)) {
++#ifndef STAGE1_5
++ if (do_possibilities) {
++ update_possibilities();
++ return 1;
++ }
++#endif
++ goto found;
++ }
++ if (!substring("..", *dirname)) {
++ if (di_key.type != BTRFS_INODE_REF_KEY)
++ continue;
++ sd_key->objectid = di_key.offset;
++ btrfs_set_key_type(sd_key, BTRFS_INODE_ITEM_KEY);
++ sd_key->offset = 0;
++#ifndef STAGE1_5
++ if (do_possibilities) {
++ update_possibilities();
++ return 1;
++ }
++#endif
++ goto found;
++ }
++ if (di_key.type != BTRFS_DIR_ITEM_KEY)
++ continue;
++ total = btrfs_item_size(&path->nodes[0], item);
++ /* scan a directory item */
++ while (cur < total) {
++ char tmp;
++ int result;
++ char *filename;
++ char *end_of_name;
++ int name_len;
++ int data_len;
++
++ btrfs_dir_item_key(&path->nodes[0], di, &location);
++
++ name_len = btrfs_dir_name_len(&path->nodes[0], di);
++ data_len = btrfs_dir_data_len(&path->nodes[0], di);
++
++ WARN_ON(name_len > BTRFS_NAME_LEN);
++
++ filename = (char *)(path->nodes[0].data +
++ (unsigned long)(di + 1));
++ end_of_name = filename + name_len;
++ /*
++ * working around not null-terminated
++ * directory names in btrfs: just
++ * a short-term overwrite of the
++ * cache with the following rollback
++ * of the change.
++ */
++ tmp = *end_of_name;
++ *end_of_name = 0;
++ result = substring(*dirname, filename);
++ *end_of_name = tmp;
++#ifndef STAGE1_5
++ if (do_possibilities) {
++ if (result <= 0) {
++ update_possibilities();
++ *end_of_name = 0;
++ print_a_completion(filename);
++ *end_of_name = tmp;
++ }
++ }
++ else
++#endif
++ if (result == 0) {
++ btrfs_dir_item_key_to_cpu(&path->nodes[0],
++ di, sd_key);
++ goto found;
++ }
++ len = sizeof(*di) + name_len + data_len;
++ di = (struct btrfs_dir_item *)((char *)di + len);
++ cur += len;
++ }
++ }
++#ifndef STAGE1_5
++ if (print_possibilities < 0)
++ return 1;
++#endif
++ errnum = ERR_FILE_NOT_FOUND;
++ *rest = ch;
++ return 0;
++ found:
++ *rest = ch;
++ *dirname = rest;
++ return 1;
++}
++
++/*
++ * ->dir_func().
++ * Postcondition: on a non-zero return BTRFS_FS_INFO
++ * contains the latest fs_root of file's subvolume.
++ * BTRFS_FS_INFO points to a subvolume of a file we
++ * were trying to look up.
++ * BTRFS_FILE_INFO contains info of the file we were
++ * trying to look up.
++ */
++
++int btrfs_dir(char *dirname)
++{
++ int ret;
++ int mode;
++ u64 size;
++ int linkcount = 0;
++ char linkbuf[PATH_MAX];
++
++ struct btrfs_path *path;
++ struct btrfs_root *root;
++
++ struct btrfs_key sd_key;
++ struct btrfs_inode_item *sd;
++ struct btrfs_key parent_sd_key;
++
++ root = BTRFS_FS_ROOT;
++ path = btrfs_grab_path(FIRST_EXTERNAL_LOOKUP_POOL);
++
++ btrfs_set_root_dir_key(&sd_key);
++ while (1) {
++ struct extent_buffer *leaf;
++ ret = aux_tree_lookup(root, &sd_key, path);
++ if (ret)
++ return 0;
++ leaf = &path->nodes[0];
++ sd = btrfs_item_ptr(leaf,
++ path->slots[0],
++ struct btrfs_inode_item);
++ mode = btrfs_inode_mode(leaf, sd);
++ size = btrfs_inode_size(leaf, sd);
++ switch (btrfs_get_file_type(mode)) {
++ case BTRFS_SYMLINK_FILE:
++ ret = btrfs_follow_link(root,
++ path,
++ &dirname,
++ linkbuf,
++ &linkcount,
++ sd);
++ if (!ret)
++ return 0;
++ dirname = linkbuf;
++ if (*dirname == '/')
++ /* absolute name */
++ btrfs_set_root_dir_key(&sd_key);
++ else
++ memcpy(&sd_key, &parent_sd_key,
++ sizeof(sd_key));
++ continue;
++ case BTRFS_REGULAR_FILE:
++ /*
++ * normally we want to exit here
++ */
++ if (*dirname && !isspace (*dirname)) {
++ errnum = ERR_BAD_FILETYPE;
++ return 0;
++ }
++ filepos = 0;
++ filemax = btrfs_inode_size(leaf, sd);
++ btrfs_update_file_info(path);
++ return 1;
++ case BTRFS_DIRECTORY_FILE:
++ memcpy(&parent_sd_key, &sd_key, sizeof(sd_key));
++ ret = btrfs_de_index_by_name(root,
++ path,
++ &dirname,
++ &sd_key);
++ if (!ret)
++ return 0;
++#ifndef STAGE1_5
++ if (print_possibilities < 0)
++ return 1;
++#endif
++ /*
++ * update fs_tree:
++ * subvolume stuff goes here
++ */
++ ret = update_fs_root(root, &sd_key);
++ if (ret)
++ return 0;
++ continue;
++ case BTRFS_UNKNOWN_FILE:
++ default:
++ btrfs_msg("Btrfs: bad file type\n");
++ errnum = ERR_BAD_FILETYPE;
++ return 0;
++ }
++ }
++}
++
++int btrfs_embed(int *start_sector, int needed_sectors)
++{
++ int ret;
++ init_btrfs_info();
++ init_btrfs_volatile_dev_cache();
++
++ ret = btrfs_find_super(BTRFS_VOLATILE_DEV_CACHE, NULL, NULL);
++ if (ret)
++ return 0;
++ ret = btrfs_uptodate_super_copy(BTRFS_FS_INFO);
++ if (ret)
++ return 0;
++ *start_sector = 1; /* reserve first sector for stage1 */
++ return needed_sectors <=
++ ((BTRFS_SUPER_INFO_OFFSET >> SECTOR_BITS) - 1);
++}
++#endif /* FSYS_BTRFS */
++
++/*
++ Local variables:
++ c-indentation-style: "K&R"
++ mode-name: "LC"
++ c-basic-offset: 8
++ tab-width: 8
++ fill-column: 80
++ scroll-step: 1
++ End:
++*/
+diff -up grub-upstream.wip/stage2/Makefile.am.btrfs grub-upstream.wip/stage2/Makefile.am
+--- grub-upstream.wip/stage2/Makefile.am.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/stage2/Makefile.am 2012-03-20 05:07:09.000000000 +0000
+@@ -17,13 +17,13 @@ INCLUDES = -I$(top_srcdir)/stage1
+ noinst_LIBRARIES = libgrub.a
+ libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
+ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
+- fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
++ fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_btrfs.c fsys_ufs2.c \
+ fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
+ terminfo.c tparm.c graphics.c
+ libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
+ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
+ -DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
+- -DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
++ -DFSYS_BTRFS=1 -DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
+ -DUSE_MD5_PASSWORDS=1 -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1
+
+ # Stage 2 and Stage 1.5's.
+@@ -34,24 +34,26 @@ EXTRA_PROGRAMS = nbloader.exec pxeloader
+ if DISKLESS_SUPPORT
+ pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
+ ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
+- reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5 \
+- nbgrub pxegrub
++ reiserfs_stage1_5 btrfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 \
++ xfs_stage1_5 nbgrub pxegrub
+ noinst_DATA = pre_stage2 start start_eltorito nbloader pxeloader diskless
+ noinst_PROGRAMS = pre_stage2.exec start.exec start_eltorito.exec \
+ e2fs_stage1_5.exec fat_stage1_5.exec ffs_stage1_5.exec \
+ iso9660_stage1_5.exec jfs_stage1_5.exec minix_stage1_5.exec \
+- reiserfs_stage1_5.exec ufs2_stage1_5.exec vstafs_stage1_5.exec \
+- xfs_stage1_5.exec nbloader.exec pxeloader.exec diskless.exec
++ reiserfs_stage1_5.exec btrfs_stage1_5.exec ufs2_stage1_5.exec \
++ vstafs_stage1_5.exec xfs_stage1_5.exec nbloader.exec \
++ pxeloader.exec diskless.exec
+ else
+ pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
+ ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
+- reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5
++ reiserfs_stage1_5 btrfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 \
++ xfs_stage1_5
+ noinst_DATA = pre_stage2 start start_eltorito
+ noinst_PROGRAMS = pre_stage2.exec start.exec start_eltorito.exec \
+ e2fs_stage1_5.exec fat_stage1_5.exec ffs_stage1_5.exec \
+ iso9660_stage1_5.exec jfs_stage1_5.exec minix_stage1_5.exec \
+- reiserfs_stage1_5.exec ufs2_stage1_5.exec vstafs_stage1_5.exec \
+- xfs_stage1_5.exec
++ reiserfs_stage1_5.exec btrfs_stage1_5.exec ufs2_stage1_5.exec \
++ vstafs_stage1_5.exec xfs_stage1_5.exec
+ endif
+ MOSTLYCLEANFILES = $(noinst_PROGRAMS)
+
+@@ -95,15 +97,17 @@ STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DN
+ pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \
+ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
+ fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \
+- fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \
+- hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c \
+- graphics.c
++ fsys_reiserfs.c fsys_btrfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c \
++ gunzip.c hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c \
++ tparm.c graphics.c
+ pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
+ pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
+ pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
+
+ if NETBOOT_SUPPORT
+-pre_stage2_exec_LDADD = ../netboot/libdrivers.a
++pre_stage2_exec_LDADD = ../netboot/libdrivers.a -lgcc
++else
++pre_stage2_exec_LDADD = -lgcc
+ endif
+
+ if DISKLESS_SUPPORT
+@@ -197,6 +201,16 @@ reiserfs_stage1_5_exec_CCASFLAGS = $(STA
+ -DNO_BLOCK_FILES=1
+ reiserfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
++# For btrfs_stage1_5 target.
++btrfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
++ disk_io.c stage1_5.c fsys_btrfs.c bios.c
++btrfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_BTRFS=1 \
++ -DNO_BLOCK_FILES=1
++btrfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_BTRFS=1 \
++ -DNO_BLOCK_FILES=1
++btrfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
++btrfs_stage1_5_exec_LDADD = -lgcc
++
+ # For vstafs_stage1_5 target.
+ vstafs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
+ disk_io.c stage1_5.c fsys_vstafs.c bios.c
+@@ -240,7 +254,7 @@ diskless_exec_CFLAGS = $(STAGE2_COMPILE)
+ diskless_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
+ -DSUPPORT_DISKLESS=1
+ diskless_exec_LDFLAGS = $(PRE_STAGE2_LINK)
+-diskless_exec_LDADD = ../netboot/libdrivers.a
++diskless_exec_LDADD = ../netboot/libdrivers.a -lgcc
+
+ diskless_size.h: diskless
+ -rm -f $@
+diff -up grub-upstream.wip/stage2/shared.h.btrfs grub-upstream.wip/stage2/shared.h
+--- grub-upstream.wip/stage2/shared.h.btrfs 2012-03-20 05:06:49.000000000 +0000
++++ grub-upstream.wip/stage2/shared.h 2012-03-20 05:07:09.000000000 +0000
+@@ -207,11 +207,12 @@ extern char *grub_scratch_mem;
+ #define STAGE2_ID_FAT_STAGE1_5 3
+ #define STAGE2_ID_MINIX_STAGE1_5 4
+ #define STAGE2_ID_REISERFS_STAGE1_5 5
+-#define STAGE2_ID_VSTAFS_STAGE1_5 6
+-#define STAGE2_ID_JFS_STAGE1_5 7
+-#define STAGE2_ID_XFS_STAGE1_5 8
+-#define STAGE2_ID_ISO9660_STAGE1_5 9
+-#define STAGE2_ID_UFS2_STAGE1_5 10
++#define STAGE2_ID_BTRFS_STAGE1_5 6
++#define STAGE2_ID_VSTAFS_STAGE1_5 7
++#define STAGE2_ID_JFS_STAGE1_5 8
++#define STAGE2_ID_XFS_STAGE1_5 9
++#define STAGE2_ID_ISO9660_STAGE1_5 10
++#define STAGE2_ID_UFS2_STAGE1_5 11
+
+ #ifndef STAGE1_5
+ # define STAGE2_ID STAGE2_ID_STAGE2
+@@ -226,6 +227,8 @@ extern char *grub_scratch_mem;
+ # define STAGE2_ID STAGE2_ID_MINIX_STAGE1_5
+ # elif defined(FSYS_REISERFS)
+ # define STAGE2_ID STAGE2_ID_REISERFS_STAGE1_5
++# elif defined(FSYS_BTRFS)
++# define STAGE2_ID STAGE2_ID_BTRFS_STAGE1_5
+ # elif defined(FSYS_VSTAFS)
+ # define STAGE2_ID STAGE2_ID_VSTAFS_STAGE1_5
+ # elif defined(FSYS_JFS)