Matt Wilson
2012-Mar-20 18:47 UTC
[PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
Hi, The following patches add support for ext4 and btrfs to PV-GRUB. These patches are taken nearly verbatim from those provided by Fedora and Gentoo. We''ve been using these patches for the PV-GRUB images available in EC2 for some time now with no problems. Changes from v1: - Makefile has been changed to check the exit code from patch - The btrfs patch has been rebased to apply cleanly - The patch file names have been adjusted to match existing patches Matt
Matt Wilson
2012-Mar-20 18:47 UTC
[PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB
We want to ensure that patches apply cleanly without rejects. Bail if patch returns a non-zero exit code. Signed-off-by: Matt Wilson <msw@amazon.com> diff -r 4e1d091d10d8 -r 8124b28e88a4 stubdom/Makefile --- a/stubdom/Makefile Fri Mar 16 15:24:25 2012 +0000 +++ b/stubdom/Makefile Tue Mar 20 18:28:29 2012 +0000 @@ -331,7 +331,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar. tar xzf $< mv grub-$(GRUB_VERSION) $@ for i in grub.patches/* ; do \ - patch -d $@ -p1 < $$i ; \ + patch -d $@ -p1 < $$i || exit 1; \ done .PHONY: grub
This patch adds support for ext4 to the GRUB tree used to build PV-GRUB. The original patch is taken from the Fedora GRUB package in this commit: http://pkgs.fedoraproject.org/gitweb/?p=grub.git;a=commitdiff;h=32bf414af04d377055957167aac7dedec691ef57 Signed-off-by: Matt Wilson <msw@amazon.com> diff -r 8124b28e88a4 -r de132a33f171 stubdom/grub.patches/60ext4.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubdom/grub.patches/60ext4.diff Tue Mar 20 18:29:22 2012 +0000 @@ -0,0 +1,474 @@ +Index: grub-0.97/stage2/fsys_ext2fs.c +==================================================================+--- grub-0.97.orig/stage2/fsys_ext2fs.c ++++ grub-0.97/stage2/fsys_ext2fs.c +@@ -41,6 +41,7 @@ typedef __signed__ short __s16; + typedef unsigned short __u16; + typedef __signed__ int __s32; + typedef unsigned int __u32; ++typedef unsigned long long __u64; + + /* + * Constants relative to the data blocks, from ext2_fs.h +@@ -51,7 +52,7 @@ typedef unsigned int __u32; + #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) + #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +-/* include/linux/ext2_fs.h */ ++/* lib/ext2fs/ext2_fs.h from e2fsprogs */ + struct ext2_super_block + { + __u32 s_inodes_count; /* Inodes count */ +@@ -61,9 +62,9 @@ struct ext2_super_block + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ +- __s32 s_log_frag_size; /* Fragment size */ ++ __s32 s_obso_log_frag_size; /* Obsoleted Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ +- __u32 s_frags_per_group; /* # Fragments per group */ ++ __u32 s_obso_frags_per_group; /* Obsoleted Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ +@@ -72,7 +73,7 @@ struct ext2_super_block + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ +- __u16 s_pad; ++ __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ +@@ -119,15 +120,29 @@ struct ext2_super_block + __u32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_jnl_backup_type; /* Default type of journal backup */ +- __u16 s_reserved_word_pad; ++ __u16 s_desc_size; /* size of group descriptor */ + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; /* First metablock group */ + __u32 s_mkfs_time; /* When the filesystem was created */ + __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ +- __u32 s_reserved[172]; /* Padding to the end of the block */ +- }; ++ /* 64bit desc support valid if EXT4_FEATURE_INCOMPAT_64BIT */ ++ __u32 s_blocks_count_hi; /* Blocks count */ ++ __u32 s_r_blocks_count_hi; /* Reserved blocks count */ ++ __u32 s_free_blocks_count_hi; /* Free blocks count */ ++ __u16 s_min_extra_isize; /* All inodes have at least # bytes */ ++ __u16 s_max_extra_isize; /* New inodes should reverve # bytes */ ++ __u32 s_flags; /* Miscellaneous flags */ ++ __u16 s_raid_stride; /* Raid stride */ ++ __u16 s_mmp_interval; /* # seconds to wait MMP checking */ ++ __u64 s_mmp_block; /* Block for multi-mount protection */ ++ __u32 s_raid_stripe_width; /* Blocks on all data disks (N*stride)*/ ++ __u8 s_log_groups_per_flex;/* FLEX_BG group size*/ ++ __u8 s_reserved_char_pad; ++ __u16 s_reserved_pad; ++ __u32 s_reserved[162]; /* Padding to the end of the block */ ++}; + +-struct ext2_group_desc ++struct ext4_group_desc + { + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ +@@ -135,8 +150,18 @@ struct ext2_group_desc + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ +- __u16 bg_pad; +- __u32 bg_reserved[3]; ++ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ ++ __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ ++ __u16 bg_itable_unused; /* Unused inodes count */ ++ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ ++ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ ++ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ ++ __u32 bg_inode_table_hi; /* Inodes table block MSB */ ++ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ ++ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ ++ __u16 bg_used_dirs_count_hi; /* Directories count MSB */ ++ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ ++ __u32 bg_reserved2[3]; + }; + + struct ext2_inode +@@ -174,22 +199,22 @@ struct ext2_inode + __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ + __u32 i_version; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ +- __u32 i_dir_acl; /* Directory ACL */ +- __u32 i_faddr; /* Fragment address */ ++ __u32 i_size_high; ++ __u32 i_obso_faddr; /* Obsoleted fragment address */ + union + { + struct + { +- __u8 l_i_frag; /* Fragment number */ +- __u8 l_i_fsize; /* Fragment size */ +- __u16 i_pad1; +- __u32 l_i_reserved2[2]; ++ __u16 l_i_blocks_high; /* were l_i_reserved1 */ ++ __u16 l_i_file_acl_high; ++ __u16 l_i_uid_high; /* these 2 fields */ ++ __u16 l_i_gid_high; /* were reserved2[0] */ ++ __u32 l_i_reserved2; + } + linux2; + struct + { +- __u8 h_i_frag; /* Fragment number */ +- __u8 h_i_fsize; /* Fragment size */ ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; +@@ -198,16 +223,36 @@ struct ext2_inode + hurd2; + struct + { +- __u8 m_i_frag; /* Fragment number */ +- __u8 m_i_fsize; /* Fragment size */ +- __u16 m_pad1; ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ ++ __u16 m_i_file_acl_high; + __u32 m_i_reserved2[2]; + } + masix2; + } + osd2; /* OS dependent 2 */ ++ __u16 i_extra_isize; ++ __u16 i_pad1; ++ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ ++ __u32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ ++ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ ++ __u32 i_crtime; /* File Creation time */ ++ __u32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ ++ __u32 i_version_hi; /* high 32 bits for 64-bit version */ + }; + ++#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ ++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 /* grub not supported*/ ++#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 ++#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 ++ ++#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ ++ ( sb->s_feature_incompat & mask ) ++ ++#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ ++#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ ++ ++#define EXT4_MIN_DESC_SIZE 32 ++ + /* linux/limits.h */ + #define NAME_MAX 255 /* # chars in a file name */ + +@@ -225,6 +270,57 @@ struct ext2_dir_entry + char name[EXT2_NAME_LEN]; /* File name */ + }; + ++/* linux/ext4_fs_extents.h */ ++/* This is the extent on-disk structure. ++ * It''s used at the bottom of the tree. ++ */ ++struct ext4_extent ++ { ++ __u32 ee_block; /* first logical block extent covers */ ++ __u16 ee_len; /* number of blocks covered by extent */ ++ __u16 ee_start_hi; /* high 16 bits of physical block */ ++ __u32 ee_start_lo; /* low 32 bits of physical block */ ++ }; ++ ++/* ++ * This is index on-disk structure. ++ * It''s used at all the levels except the bottom. ++ */ ++struct ext4_extent_idx ++ { ++ __u32 ei_block; /* index covers logical blocks from ''block'' */ ++ __u32 ei_leaf_lo; /* pointer to the physical block of the next * ++ * level. leaf or next index could be there */ ++ __u16 ei_leaf_hi; /* high 16 bits of physical block */ ++ __u16 ei_unused; ++ }; ++ ++/* ++ * Each block (leaves and indexes), even inode-stored has header. ++ */ ++struct ext4_extent_header ++ { ++ __u16 eh_magic; /* probably will support different formats */ ++ __u16 eh_entries; /* number of valid entries */ ++ __u16 eh_max; /* capacity of store in entries */ ++ __u16 eh_depth; /* has tree real underlying blocks? */ ++ __u32 eh_generation; /* generation of the tree */ ++ }; ++ ++#define EXT4_EXT_MAGIC (0xf30a) ++#define EXT_FIRST_EXTENT(__hdr__) \ ++ ((struct ext4_extent *) (((char *) (__hdr__)) + \ ++ sizeof(struct ext4_extent_header))) ++#define EXT_FIRST_INDEX(__hdr__) \ ++ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ ++ sizeof(struct ext4_extent_header))) ++#define EXT_LAST_EXTENT(__hdr__) \ ++ (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) ++#define EXT_LAST_INDEX(__hdr__) \ ++ (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) ++ ++ ++ + /* linux/ext2fs.h */ + /* + * EXT2_DIR_PAD defines the directory entries boundaries +@@ -271,8 +367,17 @@ struct ext2_dir_entry + /* kind of from ext2/super.c */ + #define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) + /* linux/ext2fs.h */ ++/* sizeof(struct ext2_group_desc) is changed in ext4 ++ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate ++ * number of desc per block, while ext4 uses superblock->s_desc_size in stead ++ * superblock->s_desc_size is not available in ext2/3 ++ * */ ++#define EXT2_DESC_SIZE(s) \ ++ (EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \ ++ s->s_desc_size : EXT4_MIN_DESC_SIZE) + #define EXT2_DESC_PER_BLOCK(s) \ +- (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) ++ (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) ++ + /* linux/stat.h */ + #define S_IFMT 00170000 + #define S_IFLNK 0120000 +@@ -434,6 +539,122 @@ ext2fs_block_map (int logical_block) + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]; + } + ++/* extent binary search index ++ * find closest index in the current level extent tree ++ * kind of from ext4_ext_binsearch_idx in ext4/extents.c ++ */ ++static struct ext4_extent_idx* ++ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block) ++{ ++ struct ext4_extent_idx *r, *l, *m; ++ l = EXT_FIRST_INDEX(eh) + 1; ++ r = EXT_LAST_INDEX(eh); ++ while (l <= r) ++ { ++ m = l + (r - l) / 2; ++ if (logical_block < m->ei_block) ++ r = m - 1; ++ else ++ l = m + 1; ++ } ++ return (struct ext4_extent_idx*)(l - 1); ++} ++ ++/* extent binary search ++ * find closest extent in the leaf level ++ * kind of from ext4_ext_binsearch in ext4/extents.c ++ */ ++static struct ext4_extent* ++ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block) ++{ ++ struct ext4_extent *r, *l, *m; ++ l = EXT_FIRST_EXTENT(eh) + 1; ++ r = EXT_LAST_EXTENT(eh); ++ while (l <= r) ++ { ++ m = l + (r - l) / 2; ++ if (logical_block < m->ee_block) ++ r = m - 1; ++ else ++ l = m + 1; ++ } ++ return (struct ext4_extent*)(l - 1); ++} ++ ++/* Maps extents enabled logical block into physical block via an inode. ++ * EXT4_HUGE_FILE_FL should be checked before calling this. ++ */ ++static int ++ext4fs_block_map (int logical_block) ++{ ++ struct ext4_extent_header *eh; ++ struct ext4_extent *ex, *extent; ++ struct ext4_extent_idx *ei, *index; ++ int depth; ++ int i; ++ ++#ifdef E2DEBUG ++ unsigned char *i; ++ for (i = (unsigned char *) INODE; ++ i < ((unsigned char *) INODE + sizeof (struct ext2_inode)); ++ i++) ++ { ++ printf ("%c", "0123456789abcdef"[*i >> 4]); ++ printf ("%c", "0123456789abcdef"[*i % 16]); ++ if (!((i + 1 - (unsigned char *) INODE) % 16)) ++ { ++ printf ("\n"); ++ } ++ else ++ { ++ printf (" "); ++ } ++ } ++ printf ("logical block %d\n", logical_block); ++#endif /* E2DEBUG */ ++ eh = (struct ext4_extent_header*)INODE->i_block; ++ if (eh->eh_magic != EXT4_EXT_MAGIC) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ while((depth = eh->eh_depth) != 0) ++ { /* extent index */ ++ if (eh->eh_magic != EXT4_EXT_MAGIC) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ ei = ext4_ext_binsearch_idx(eh, logical_block); ++ if (ei->ei_leaf_hi) ++ {/* 64bit physical block number not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1)) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ eh = (struct ext4_extent_header*)DATABLOCK1; ++ } ++ ++ /* depth==0, we come to the leaf */ ++ ex = ext4_ext_binsearch(eh, logical_block); ++ if (ex->ee_start_hi) ++ {/* 64bit physical block number not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ if ((ex->ee_block + ex->ee_len) < logical_block) ++ { ++ errnum = ERR_FSYS_CORRUPT; ++ return -1; ++ } ++ return ex->ee_start_lo + logical_block - ex->ee_block; ++ ++} ++ + /* preconditions: all preconds of ext2fs_block_map */ + int + ext2fs_read (char *buf, int len) +@@ -468,6 +689,11 @@ ext2fs_read (char *buf, int len) + /* find the (logical) block component of our location */ + logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); ++ /* map extents enabled logical block number to physical fs on-disk block number */ ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) ++ && INODE->i_flags & EXT4_EXTENTS_FL) ++ map = ext4fs_block_map (logical_block); ++ else + map = ext2fs_block_map (logical_block); + #ifdef E2DEBUG + printf ("map=%d\n", map); +@@ -552,7 +778,7 @@ ext2fs_dir (char *dirname) + int desc; /* index within that group */ + int ino_blk; /* fs pointer of the inode''s information */ + int str_chk = 0; /* used to hold the results of a string compare */ +- struct ext2_group_desc *gdp; ++ struct ext4_group_desc *ext4_gdp; + struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ + + char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ +@@ -598,8 +824,15 @@ ext2fs_dir (char *dirname) + { + return 0; + } +- gdp = GROUP_DESC; +- ino_blk = gdp[desc].bg_inode_table + ++ ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC + ++ desc * EXT2_DESC_SIZE(SUPERBLOCK)); ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT) ++ && (! ext4_gdp->bg_inode_table_hi)) ++ {/* 64bit itable not supported */ ++ errnum = ERR_FILELENGTH; ++ return -1; ++ } ++ ino_blk = ext4_gdp->bg_inode_table + + (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) + >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); + #ifdef E2DEBUG +@@ -676,7 +909,10 @@ ext2fs_dir (char *dirname) + } + linkbuf[filemax + len] = ''\0''; + +- /* Read the symlink data. */ ++ /* Read the symlink data. ++ * Slow symlink is extents enabled ++ * But since grub_read invokes ext2fs_read, nothing to change here ++ */ + if (! ext2_is_fast_symlink ()) + { + /* Read the necessary blocks, and reset the file pointer. */ +@@ -687,7 +923,9 @@ ext2fs_dir (char *dirname) + } + else + { +- /* Copy the data directly from the inode. */ ++ /* Copy the data directly from the inode. ++ * Fast symlink is not extents enabled ++ */ + len = filemax; + memmove (linkbuf, (char *) INODE->i_block, len); + } +@@ -721,6 +959,13 @@ ext2fs_dir (char *dirname) + errnum = ERR_BAD_FILETYPE; + return 0; + } ++ /* if file is too large, just stop and report an error*/ ++ if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high)) ++ { ++ /* file too large, stop reading */ ++ errnum = ERR_FILELENGTH; ++ return 0; ++ } + + filemax = (INODE->i_size); + return 1; +@@ -775,17 +1020,28 @@ ext2fs_dir (char *dirname) + } + + /* else, find the (logical) block component of our location */ ++ /* ext4 logical block number the same as ext2/3 */ + blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); + + /* we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ ++ /* map extents enabled logical block number to physical fs on-disk block number */ ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) ++ && INODE->i_flags & EXT4_EXTENTS_FL) ++ map = ext4fs_block_map (blk); ++ else + map = ext2fs_block_map (blk); + #ifdef E2DEBUG + printf ("fs block=%d\n", map); + #endif /* E2DEBUG */ + mapblock2 = -1; +- if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) ++ if (map < 0) ++ { ++ *rest = ch; ++ return 0; ++ } ++ if (!ext2_rdfsb (map, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch;
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> diff -r de132a33f171 -r f4a35d869477 stubdom/grub.patches/61btrfs.diff --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubdom/grub.patches/61btrfs.diff Tue Mar 20 18:44:49 2012 +0000 @@ -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)
Ian Campbell
2012-Mar-21 10:24 UTC
Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB
On Tue, 2012-03-20 at 18:47 +0000, Matt Wilson wrote:> We want to ensure that patches apply cleanly without rejects. Bail if > patch returns a non-zero exit code. > > Signed-off-by: Matt Wilson <msw@amazon.com>Acked-by: Ian Campbell <ian.campbell@citrix.com>> > diff -r 4e1d091d10d8 -r 8124b28e88a4 stubdom/Makefile > --- a/stubdom/Makefile Fri Mar 16 15:24:25 2012 +0000 > +++ b/stubdom/Makefile Tue Mar 20 18:28:29 2012 +0000 > @@ -331,7 +331,7 @@ grub-upstream: grub-$(GRUB_VERSION).tar. > tar xzf $< > mv grub-$(GRUB_VERSION) $@ > for i in grub.patches/* ; do \ > - patch -d $@ -p1 < $$i ; \ > + patch -d $@ -p1 < $$i || exit 1; \ > done > > .PHONY: grub > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On Tue, 2012-03-20 at 18:47 +0000, Matt Wilson wrote:> This patch adds support for ext4 to the GRUB tree used to build PV-GRUB. > The original patch is taken from the Fedora GRUB package in this commit: > http://pkgs.fedoraproject.org/gitweb/?p=grub.git;a=commitdiff;h=32bf414af04d377055957167aac7dedec691ef57I''m not really in a position to evaluate this in terms of ext4 but taking from Fedora seems reasonable so I think we should take it. Looks like libfsimage took the ubuntu version of ext4 support (see 20652:c6ee21dca848). Not sure if that matters or not.> Signed-off-by: Matt Wilson <msw@amazon.com> > > diff -r 8124b28e88a4 -r de132a33f171 stubdom/grub.patches/60ext4.diff > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/stubdom/grub.patches/60ext4.diff Tue Mar 20 18:29:22 2012 +0000 > @@ -0,0 +1,474 @@ > +Index: grub-0.97/stage2/fsys_ext2fs.c > +==================================================================> +--- grub-0.97.orig/stage2/fsys_ext2fs.c > ++++ grub-0.97/stage2/fsys_ext2fs.c > +@@ -41,6 +41,7 @@ typedef __signed__ short __s16; > + typedef unsigned short __u16; > + typedef __signed__ int __s32; > + typedef unsigned int __u32; > ++typedef unsigned long long __u64; > + > + /* > + * Constants relative to the data blocks, from ext2_fs.h > +@@ -51,7 +52,7 @@ typedef unsigned int __u32; > + #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) > + #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) > + > +-/* include/linux/ext2_fs.h */ > ++/* lib/ext2fs/ext2_fs.h from e2fsprogs */ > + struct ext2_super_block > + { > + __u32 s_inodes_count; /* Inodes count */ > +@@ -61,9 +62,9 @@ struct ext2_super_block > + __u32 s_free_inodes_count; /* Free inodes count */ > + __u32 s_first_data_block; /* First Data Block */ > + __u32 s_log_block_size; /* Block size */ > +- __s32 s_log_frag_size; /* Fragment size */ > ++ __s32 s_obso_log_frag_size; /* Obsoleted Fragment size */ > + __u32 s_blocks_per_group; /* # Blocks per group */ > +- __u32 s_frags_per_group; /* # Fragments per group */ > ++ __u32 s_obso_frags_per_group; /* Obsoleted Fragments per group */ > + __u32 s_inodes_per_group; /* # Inodes per group */ > + __u32 s_mtime; /* Mount time */ > + __u32 s_wtime; /* Write time */ > +@@ -72,7 +73,7 @@ struct ext2_super_block > + __u16 s_magic; /* Magic signature */ > + __u16 s_state; /* File system state */ > + __u16 s_errors; /* Behaviour when detecting errors */ > +- __u16 s_pad; > ++ __u16 s_minor_rev_level; /* minor revision level */ > + __u32 s_lastcheck; /* time of last check */ > + __u32 s_checkinterval; /* max. time between checks */ > + __u32 s_creator_os; /* OS */ > +@@ -119,15 +120,29 @@ struct ext2_super_block > + __u32 s_hash_seed[4]; /* HTREE hash seed */ > + __u8 s_def_hash_version; /* Default hash version to use */ > + __u8 s_jnl_backup_type; /* Default type of journal backup */ > +- __u16 s_reserved_word_pad; > ++ __u16 s_desc_size; /* size of group descriptor */ > + __u32 s_default_mount_opts; > + __u32 s_first_meta_bg; /* First metablock group */ > + __u32 s_mkfs_time; /* When the filesystem was created */ > + __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ > +- __u32 s_reserved[172]; /* Padding to the end of the block */ > +- }; > ++ /* 64bit desc support valid if EXT4_FEATURE_INCOMPAT_64BIT */ > ++ __u32 s_blocks_count_hi; /* Blocks count */ > ++ __u32 s_r_blocks_count_hi; /* Reserved blocks count */ > ++ __u32 s_free_blocks_count_hi; /* Free blocks count */ > ++ __u16 s_min_extra_isize; /* All inodes have at least # bytes */ > ++ __u16 s_max_extra_isize; /* New inodes should reverve # bytes */ > ++ __u32 s_flags; /* Miscellaneous flags */ > ++ __u16 s_raid_stride; /* Raid stride */ > ++ __u16 s_mmp_interval; /* # seconds to wait MMP checking */ > ++ __u64 s_mmp_block; /* Block for multi-mount protection */ > ++ __u32 s_raid_stripe_width; /* Blocks on all data disks (N*stride)*/ > ++ __u8 s_log_groups_per_flex;/* FLEX_BG group size*/ > ++ __u8 s_reserved_char_pad; > ++ __u16 s_reserved_pad; > ++ __u32 s_reserved[162]; /* Padding to the end of the block */ > ++}; > + > +-struct ext2_group_desc > ++struct ext4_group_desc > + { > + __u32 bg_block_bitmap; /* Blocks bitmap block */ > + __u32 bg_inode_bitmap; /* Inodes bitmap block */ > +@@ -135,8 +150,18 @@ struct ext2_group_desc > + __u16 bg_free_blocks_count; /* Free blocks count */ > + __u16 bg_free_inodes_count; /* Free inodes count */ > + __u16 bg_used_dirs_count; /* Directories count */ > +- __u16 bg_pad; > +- __u32 bg_reserved[3]; > ++ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ > ++ __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ > ++ __u16 bg_itable_unused; /* Unused inodes count */ > ++ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ > ++ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ > ++ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ > ++ __u32 bg_inode_table_hi; /* Inodes table block MSB */ > ++ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ > ++ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ > ++ __u16 bg_used_dirs_count_hi; /* Directories count MSB */ > ++ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ > ++ __u32 bg_reserved2[3]; > + }; > + > + struct ext2_inode > +@@ -174,22 +199,22 @@ struct ext2_inode > + __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ > + __u32 i_version; /* File version (for NFS) */ > + __u32 i_file_acl; /* File ACL */ > +- __u32 i_dir_acl; /* Directory ACL */ > +- __u32 i_faddr; /* Fragment address */ > ++ __u32 i_size_high; > ++ __u32 i_obso_faddr; /* Obsoleted fragment address */ > + union > + { > + struct > + { > +- __u8 l_i_frag; /* Fragment number */ > +- __u8 l_i_fsize; /* Fragment size */ > +- __u16 i_pad1; > +- __u32 l_i_reserved2[2]; > ++ __u16 l_i_blocks_high; /* were l_i_reserved1 */ > ++ __u16 l_i_file_acl_high; > ++ __u16 l_i_uid_high; /* these 2 fields */ > ++ __u16 l_i_gid_high; /* were reserved2[0] */ > ++ __u32 l_i_reserved2; > + } > + linux2; > + struct > + { > +- __u8 h_i_frag; /* Fragment number */ > +- __u8 h_i_fsize; /* Fragment size */ > ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ > + __u16 h_i_mode_high; > + __u16 h_i_uid_high; > + __u16 h_i_gid_high; > +@@ -198,16 +223,36 @@ struct ext2_inode > + hurd2; > + struct > + { > +- __u8 m_i_frag; /* Fragment number */ > +- __u8 m_i_fsize; /* Fragment size */ > +- __u16 m_pad1; > ++ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ > ++ __u16 m_i_file_acl_high; > + __u32 m_i_reserved2[2]; > + } > + masix2; > + } > + osd2; /* OS dependent 2 */ > ++ __u16 i_extra_isize; > ++ __u16 i_pad1; > ++ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ > ++ __u32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ > ++ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ > ++ __u32 i_crtime; /* File Creation time */ > ++ __u32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ > ++ __u32 i_version_hi; /* high 32 bits for 64-bit version */ > + }; > + > ++#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ > ++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 /* grub not supported*/ > ++#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 > ++#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 > ++ > ++#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \ > ++ ( sb->s_feature_incompat & mask ) > ++ > ++#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ > ++#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ > ++ > ++#define EXT4_MIN_DESC_SIZE 32 > ++ > + /* linux/limits.h */ > + #define NAME_MAX 255 /* # chars in a file name */ > + > +@@ -225,6 +270,57 @@ struct ext2_dir_entry > + char name[EXT2_NAME_LEN]; /* File name */ > + }; > + > ++/* linux/ext4_fs_extents.h */ > ++/* This is the extent on-disk structure. > ++ * It''s used at the bottom of the tree. > ++ */ > ++struct ext4_extent > ++ { > ++ __u32 ee_block; /* first logical block extent covers */ > ++ __u16 ee_len; /* number of blocks covered by extent */ > ++ __u16 ee_start_hi; /* high 16 bits of physical block */ > ++ __u32 ee_start_lo; /* low 32 bits of physical block */ > ++ }; > ++ > ++/* > ++ * This is index on-disk structure. > ++ * It''s used at all the levels except the bottom. > ++ */ > ++struct ext4_extent_idx > ++ { > ++ __u32 ei_block; /* index covers logical blocks from ''block'' */ > ++ __u32 ei_leaf_lo; /* pointer to the physical block of the next * > ++ * level. leaf or next index could be there */ > ++ __u16 ei_leaf_hi; /* high 16 bits of physical block */ > ++ __u16 ei_unused; > ++ }; > ++ > ++/* > ++ * Each block (leaves and indexes), even inode-stored has header. > ++ */ > ++struct ext4_extent_header > ++ { > ++ __u16 eh_magic; /* probably will support different formats */ > ++ __u16 eh_entries; /* number of valid entries */ > ++ __u16 eh_max; /* capacity of store in entries */ > ++ __u16 eh_depth; /* has tree real underlying blocks? */ > ++ __u32 eh_generation; /* generation of the tree */ > ++ }; > ++ > ++#define EXT4_EXT_MAGIC (0xf30a) > ++#define EXT_FIRST_EXTENT(__hdr__) \ > ++ ((struct ext4_extent *) (((char *) (__hdr__)) + \ > ++ sizeof(struct ext4_extent_header))) > ++#define EXT_FIRST_INDEX(__hdr__) \ > ++ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ > ++ sizeof(struct ext4_extent_header))) > ++#define EXT_LAST_EXTENT(__hdr__) \ > ++ (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) > ++#define EXT_LAST_INDEX(__hdr__) \ > ++ (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1) > ++ > ++ > ++ > + /* linux/ext2fs.h */ > + /* > + * EXT2_DIR_PAD defines the directory entries boundaries > +@@ -271,8 +367,17 @@ struct ext2_dir_entry > + /* kind of from ext2/super.c */ > + #define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) > + /* linux/ext2fs.h */ > ++/* sizeof(struct ext2_group_desc) is changed in ext4 > ++ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate > ++ * number of desc per block, while ext4 uses superblock->s_desc_size in stead > ++ * superblock->s_desc_size is not available in ext2/3 > ++ * */ > ++#define EXT2_DESC_SIZE(s) \ > ++ (EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \ > ++ s->s_desc_size : EXT4_MIN_DESC_SIZE) > + #define EXT2_DESC_PER_BLOCK(s) \ > +- (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) > ++ (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) > ++ > + /* linux/stat.h */ > + #define S_IFMT 00170000 > + #define S_IFLNK 0120000 > +@@ -434,6 +539,122 @@ ext2fs_block_map (int logical_block) > + [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]; > + } > + > ++/* extent binary search index > ++ * find closest index in the current level extent tree > ++ * kind of from ext4_ext_binsearch_idx in ext4/extents.c > ++ */ > ++static struct ext4_extent_idx* > ++ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block) > ++{ > ++ struct ext4_extent_idx *r, *l, *m; > ++ l = EXT_FIRST_INDEX(eh) + 1; > ++ r = EXT_LAST_INDEX(eh); > ++ while (l <= r) > ++ { > ++ m = l + (r - l) / 2; > ++ if (logical_block < m->ei_block) > ++ r = m - 1; > ++ else > ++ l = m + 1; > ++ } > ++ return (struct ext4_extent_idx*)(l - 1); > ++} > ++ > ++/* extent binary search > ++ * find closest extent in the leaf level > ++ * kind of from ext4_ext_binsearch in ext4/extents.c > ++ */ > ++static struct ext4_extent* > ++ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block) > ++{ > ++ struct ext4_extent *r, *l, *m; > ++ l = EXT_FIRST_EXTENT(eh) + 1; > ++ r = EXT_LAST_EXTENT(eh); > ++ while (l <= r) > ++ { > ++ m = l + (r - l) / 2; > ++ if (logical_block < m->ee_block) > ++ r = m - 1; > ++ else > ++ l = m + 1; > ++ } > ++ return (struct ext4_extent*)(l - 1); > ++} > ++ > ++/* Maps extents enabled logical block into physical block via an inode. > ++ * EXT4_HUGE_FILE_FL should be checked before calling this. > ++ */ > ++static int > ++ext4fs_block_map (int logical_block) > ++{ > ++ struct ext4_extent_header *eh; > ++ struct ext4_extent *ex, *extent; > ++ struct ext4_extent_idx *ei, *index; > ++ int depth; > ++ int i; > ++ > ++#ifdef E2DEBUG > ++ unsigned char *i; > ++ for (i = (unsigned char *) INODE; > ++ i < ((unsigned char *) INODE + sizeof (struct ext2_inode)); > ++ i++) > ++ { > ++ printf ("%c", "0123456789abcdef"[*i >> 4]); > ++ printf ("%c", "0123456789abcdef"[*i % 16]); > ++ if (!((i + 1 - (unsigned char *) INODE) % 16)) > ++ { > ++ printf ("\n"); > ++ } > ++ else > ++ { > ++ printf (" "); > ++ } > ++ } > ++ printf ("logical block %d\n", logical_block); > ++#endif /* E2DEBUG */ > ++ eh = (struct ext4_extent_header*)INODE->i_block; > ++ if (eh->eh_magic != EXT4_EXT_MAGIC) > ++ { > ++ errnum = ERR_FSYS_CORRUPT; > ++ return -1; > ++ } > ++ while((depth = eh->eh_depth) != 0) > ++ { /* extent index */ > ++ if (eh->eh_magic != EXT4_EXT_MAGIC) > ++ { > ++ errnum = ERR_FSYS_CORRUPT; > ++ return -1; > ++ } > ++ ei = ext4_ext_binsearch_idx(eh, logical_block); > ++ if (ei->ei_leaf_hi) > ++ {/* 64bit physical block number not supported */ > ++ errnum = ERR_FILELENGTH; > ++ return -1; > ++ } > ++ if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1)) > ++ { > ++ errnum = ERR_FSYS_CORRUPT; > ++ return -1; > ++ } > ++ eh = (struct ext4_extent_header*)DATABLOCK1; > ++ } > ++ > ++ /* depth==0, we come to the leaf */ > ++ ex = ext4_ext_binsearch(eh, logical_block); > ++ if (ex->ee_start_hi) > ++ {/* 64bit physical block number not supported */ > ++ errnum = ERR_FILELENGTH; > ++ return -1; > ++ } > ++ if ((ex->ee_block + ex->ee_len) < logical_block) > ++ { > ++ errnum = ERR_FSYS_CORRUPT; > ++ return -1; > ++ } > ++ return ex->ee_start_lo + logical_block - ex->ee_block; > ++ > ++} > ++ > + /* preconditions: all preconds of ext2fs_block_map */ > + int > + ext2fs_read (char *buf, int len) > +@@ -468,6 +689,11 @@ ext2fs_read (char *buf, int len) > + /* find the (logical) block component of our location */ > + logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); > + offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); > ++ /* map extents enabled logical block number to physical fs on-disk block number */ > ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) > ++ && INODE->i_flags & EXT4_EXTENTS_FL) > ++ map = ext4fs_block_map (logical_block); > ++ else > + map = ext2fs_block_map (logical_block); > + #ifdef E2DEBUG > + printf ("map=%d\n", map); > +@@ -552,7 +778,7 @@ ext2fs_dir (char *dirname) > + int desc; /* index within that group */ > + int ino_blk; /* fs pointer of the inode''s information */ > + int str_chk = 0; /* used to hold the results of a string compare */ > +- struct ext2_group_desc *gdp; > ++ struct ext4_group_desc *ext4_gdp; > + struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ > + > + char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ > +@@ -598,8 +824,15 @@ ext2fs_dir (char *dirname) > + { > + return 0; > + } > +- gdp = GROUP_DESC; > +- ino_blk = gdp[desc].bg_inode_table + > ++ ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC + > ++ desc * EXT2_DESC_SIZE(SUPERBLOCK)); > ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT) > ++ && (! ext4_gdp->bg_inode_table_hi)) > ++ {/* 64bit itable not supported */ > ++ errnum = ERR_FILELENGTH; > ++ return -1; > ++ } > ++ ino_blk = ext4_gdp->bg_inode_table + > + (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) > + >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK))); > + #ifdef E2DEBUG > +@@ -676,7 +909,10 @@ ext2fs_dir (char *dirname) > + } > + linkbuf[filemax + len] = ''\0''; > + > +- /* Read the symlink data. */ > ++ /* Read the symlink data. > ++ * Slow symlink is extents enabled > ++ * But since grub_read invokes ext2fs_read, nothing to change here > ++ */ > + if (! ext2_is_fast_symlink ()) > + { > + /* Read the necessary blocks, and reset the file pointer. */ > +@@ -687,7 +923,9 @@ ext2fs_dir (char *dirname) > + } > + else > + { > +- /* Copy the data directly from the inode. */ > ++ /* Copy the data directly from the inode. > ++ * Fast symlink is not extents enabled > ++ */ > + len = filemax; > + memmove (linkbuf, (char *) INODE->i_block, len); > + } > +@@ -721,6 +959,13 @@ ext2fs_dir (char *dirname) > + errnum = ERR_BAD_FILETYPE; > + return 0; > + } > ++ /* if file is too large, just stop and report an error*/ > ++ if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high)) > ++ { > ++ /* file too large, stop reading */ > ++ errnum = ERR_FILELENGTH; > ++ return 0; > ++ } > + > + filemax = (INODE->i_size); > + return 1; > +@@ -775,17 +1020,28 @@ ext2fs_dir (char *dirname) > + } > + > + /* else, find the (logical) block component of our location */ > ++ /* ext4 logical block number the same as ext2/3 */ > + blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); > + > + /* we know which logical block of the directory entry we are looking > + for, now we have to translate that to the physical (fs) block on > + the disk */ > ++ /* map extents enabled logical block number to physical fs on-disk block number */ > ++ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS) > ++ && INODE->i_flags & EXT4_EXTENTS_FL) > ++ map = ext4fs_block_map (blk); > ++ else > + map = ext2fs_block_map (blk); > + #ifdef E2DEBUG > + printf ("fs block=%d\n", map); > + #endif /* E2DEBUG */ > + mapblock2 = -1; > +- if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) > ++ if (map < 0) > ++ { > ++ *rest = ch; > ++ return 0; > ++ } > ++ if (!ext2_rdfsb (map, DATABLOCK2)) > + { > + errnum = ERR_FSYS_CORRUPT; > + *rest = ch; > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On Tue, 2012-03-20 at 18:47 +0000, Matt Wilson wrote:> 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=283637Basically the same comment as for the ext4 patch. libfsimage doesn''t seem to have btrfs support. Does anyone feel up to importing it? Thanks, Ian.> > Signed-off-by: Matt Wilson <msw@amazon.com> > > diff -r de132a33f171 -r f4a35d869477 stubdom/grub.patches/61btrfs.diff > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/stubdom/grub.patches/61btrfs.diff Tue Mar 20 18:44:49 2012 +0000 > @@ -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) > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Ian Jackson
2012-Mar-21 11:27 UTC
Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB
Matt Wilson writes ("[PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB"):> We want to ensure that patches apply cleanly without rejects. Bail if > patch returns a non-zero exit code.Thanks.> for i in grub.patches/* ; do \ > - patch -d $@ -p1 < $$i ; \ > + patch -d $@ -p1 < $$i || exit 1; \ > doneThis looks correct but wouldn''t it be better done with a "set -e" at the top of the shell command ? Ian.
Matt Wilson
2012-Mar-21 16:17 UTC
Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB
On Wed, Mar 21, 2012 at 04:27:26AM -0700, Ian Jackson wrote:> > This looks correct but wouldn''t it be better done with a "set -e" at > the top of the shell command ?Sure, that works too. And it''s the more common style for other Makefiles. Would you like me to repost with this change? Matt
Ian Jackson
2012-Mar-21 16:25 UTC
Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB
Matt Wilson writes ("Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB"):> On Wed, Mar 21, 2012 at 04:27:26AM -0700, Ian Jackson wrote: > > This looks correct but wouldn''t it be better done with a "set -e" at > > the top of the shell command ? > > Sure, that works too. And it''s the more common style for other > Makefiles. Would you like me to repost with this change?That would be great, thanks. Ian.
Ian Jackson
2012-Mar-27 14:02 UTC
Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
Matt Wilson writes ("[PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs"):> The following patches add support for ext4 and btrfs to > PV-GRUB. These patches are taken nearly verbatim from those provided > by Fedora and Gentoo. > > We''ve been using these patches for the PV-GRUB images available in EC2 > for some time now with no problems. > > Changes from v1: > - Makefile has been changed to check the exit code from patch > - The btrfs patch has been rebased to apply cleanly > - The patch file names have been adjusted to match existing patchesThanks. This looks OK to me. Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Matt Wilson
2012-Apr-03 18:48 UTC
Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
On Sun, Mar 25, 2012 at 10:07:28AM -0700, Samuel Thibault wrote:> Matt Wilson, le Tue 20 Mar 2012 18:47:46 +0000, a écrit : > > Changes from v1: > > - Makefile has been changed to check the exit code from patch > > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > > > - The btrfs patch has been rebased to apply cleanly > > - The patch file names have been adjusted to match existing patches > > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>I haven''t seen these changes land in staging yet. Is anything blocked on me? Matt
Ian Jackson
2012-Apr-04 10:06 UTC
Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
Matt Wilson writes ("Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs"):> On Sun, Mar 25, 2012 at 10:07:28AM -0700, Samuel Thibault wrote: > > Matt Wilson, le Tue 20 Mar 2012 18:47:46 +0000, a écrit : > > > Changes from v1: > > > - Makefile has been changed to check the exit code from patch > > > > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > > > > > - The btrfs patch has been rebased to apply cleanly > > > - The patch file names have been adjusted to match existing patches > > > > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > > I haven''t seen these changes land in staging yet. Is anything blocked > on me?Looking back at the thread, I had a minor comment about the Makefile, which you said you were going to repost to change, but TBH it''s not that important. I will apply the v2 series. Ian.
Ian Jackson
2012-Apr-04 10:20 UTC
Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
Matt Wilson writes ("[Xen-devel] [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs"):> The following patches add support for ext4 and btrfs to > PV-GRUB. These patches are taken nearly verbatim from those provided > by Fedora and Gentoo.Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>