* [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs
@ 2012-03-20 18:47 Matt Wilson
2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: Matt Wilson @ 2012-03-20 18:47 UTC (permalink / raw)
To: xen-devel; +Cc: Samuel Thibault, Keir Fraser, Ian Jackson
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
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB 2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson @ 2012-03-20 18:47 ` Matt Wilson 2012-03-21 10:24 ` Ian Campbell 2012-03-21 11:27 ` Ian Jackson 2012-03-20 18:47 ` [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 Matt Wilson ` (4 subsequent siblings) 5 siblings, 2 replies; 14+ messages in thread From: Matt Wilson @ 2012-03-20 18:47 UTC (permalink / raw) To: xen-devel; +Cc: Samuel Thibault, Keir Fraser, Ian Jackson 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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB 2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson @ 2012-03-21 10:24 ` Ian Campbell 2012-03-21 11:27 ` Ian Jackson 1 sibling, 0 replies; 14+ messages in thread From: Ian Campbell @ 2012-03-21 10:24 UTC (permalink / raw) To: Matt Wilson Cc: Samuel Thibault, Keir (Xen.org), Ian Jackson, xen-devel@lists.xen.org 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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB 2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson 2012-03-21 10:24 ` Ian Campbell @ 2012-03-21 11:27 ` Ian Jackson 2012-03-21 16:17 ` Matt Wilson 1 sibling, 1 reply; 14+ messages in thread From: Ian Jackson @ 2012-03-21 11:27 UTC (permalink / raw) To: Matt Wilson; +Cc: Samuel Thibault, Keir (Xen.org), xen-devel@lists.xen.org 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; \ > done This looks correct but wouldn't it be better done with a "set -e" at the top of the shell command ? Ian. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB 2012-03-21 11:27 ` Ian Jackson @ 2012-03-21 16:17 ` Matt Wilson 2012-03-21 16:25 ` Ian Jackson 0 siblings, 1 reply; 14+ messages in thread From: Matt Wilson @ 2012-03-21 16:17 UTC (permalink / raw) To: Ian Jackson; +Cc: Samuel Thibault, Keir (Xen.org), xen-devel@lists.xen.org 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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB 2012-03-21 16:17 ` Matt Wilson @ 2012-03-21 16:25 ` Ian Jackson 0 siblings, 0 replies; 14+ messages in thread From: Ian Jackson @ 2012-03-21 16:25 UTC (permalink / raw) To: Matt Wilson; +Cc: Samuel Thibault, Keir (Xen.org), xen-devel@lists.xen.org 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. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson 2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson @ 2012-03-20 18:47 ` Matt Wilson 2012-03-21 10:28 ` Ian Campbell 2012-03-20 18:47 ` [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs Matt Wilson ` (3 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Matt Wilson @ 2012-03-20 18:47 UTC (permalink / raw) To: xen-devel; +Cc: Samuel Thibault, Keir Fraser, Ian Jackson 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; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 2012-03-20 18:47 ` [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 Matt Wilson @ 2012-03-21 10:28 ` Ian Campbell 0 siblings, 0 replies; 14+ messages in thread From: Ian Campbell @ 2012-03-21 10:28 UTC (permalink / raw) To: Matt Wilson Cc: Samuel Thibault, Keir (Xen.org), Ian Jackson, xen-devel@lists.xen.org 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=32bf414af04d377055957167aac7dedec691ef57 I'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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs 2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson 2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson 2012-03-20 18:47 ` [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 Matt Wilson @ 2012-03-20 18:47 ` Matt Wilson 2012-03-21 10:29 ` Ian Campbell 2012-03-27 14:02 ` [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Ian Jackson ` (2 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Matt Wilson @ 2012-03-20 18:47 UTC (permalink / raw) To: xen-devel; +Cc: Samuel Thibault, Keir Fraser, Ian Jackson 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) ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs 2012-03-20 18:47 ` [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs Matt Wilson @ 2012-03-21 10:29 ` Ian Campbell 0 siblings, 0 replies; 14+ messages in thread From: Ian Campbell @ 2012-03-21 10:29 UTC (permalink / raw) To: Matt Wilson Cc: Samuel Thibault, Keir (Xen.org), Ian Jackson, xen-devel@lists.xen.org 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=283637 Basically 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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs 2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson ` (2 preceding siblings ...) 2012-03-20 18:47 ` [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs Matt Wilson @ 2012-03-27 14:02 ` Ian Jackson [not found] ` <20120325170728.GP4316@type.famille.thibault.fr> 2012-04-04 10:20 ` Ian Jackson 5 siblings, 0 replies; 14+ messages in thread From: Ian Jackson @ 2012-03-27 14:02 UTC (permalink / raw) To: Matt Wilson; +Cc: Samuel Thibault, Keir (Xen.org), xen-devel@lists.xen.org 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 patches Thanks. This looks OK to me. Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <20120325170728.GP4316@type.famille.thibault.fr>]
* Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs [not found] ` <20120325170728.GP4316@type.famille.thibault.fr> @ 2012-04-03 18:48 ` Matt Wilson 2012-04-04 10:06 ` Ian Jackson 0 siblings, 1 reply; 14+ messages in thread From: Matt Wilson @ 2012-04-03 18:48 UTC (permalink / raw) To: Samuel Thibault, xen-devel, Keir Fraser, Ian Jackson 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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs 2012-04-03 18:48 ` Matt Wilson @ 2012-04-04 10:06 ` Ian Jackson 0 siblings, 0 replies; 14+ messages in thread From: Ian Jackson @ 2012-04-04 10:06 UTC (permalink / raw) To: Matt Wilson; +Cc: Samuel Thibault, Keir (Xen.org), xen-devel@lists.xen.org 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. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs 2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson ` (4 preceding siblings ...) [not found] ` <20120325170728.GP4316@type.famille.thibault.fr> @ 2012-04-04 10:20 ` Ian Jackson 5 siblings, 0 replies; 14+ messages in thread From: Ian Jackson @ 2012-04-04 10:20 UTC (permalink / raw) To: Matt Wilson; +Cc: Samuel Thibault, Keir Fraser, xen-devel 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> ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-04-04 10:20 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-20 18:47 [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Matt Wilson
2012-03-20 18:47 ` [PATCH 1 of 3 v2] PV-GRUB: Check for errors when applying patches to GRUB Matt Wilson
2012-03-21 10:24 ` Ian Campbell
2012-03-21 11:27 ` Ian Jackson
2012-03-21 16:17 ` Matt Wilson
2012-03-21 16:25 ` Ian Jackson
2012-03-20 18:47 ` [PATCH 2 of 3 v2] PV-GRUB: add support for ext4 Matt Wilson
2012-03-21 10:28 ` Ian Campbell
2012-03-20 18:47 ` [PATCH 3 of 3 v2] PV-GRUB: add support for btrfs Matt Wilson
2012-03-21 10:29 ` Ian Campbell
2012-03-27 14:02 ` [PATCH 0 of 3 v2] PV-GRUB: add support for ext4 and btrfs Ian Jackson
[not found] ` <20120325170728.GP4316@type.famille.thibault.fr>
2012-04-03 18:48 ` Matt Wilson
2012-04-04 10:06 ` Ian Jackson
2012-04-04 10:20 ` Ian Jackson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).