Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 212661 Details for
Bug 283637
sys-boot/grub-0.97-r9: Patch to add btrfs support
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
grub_0.97_btrfs.patch
grub_0.97_btrfs.patch (text/plain), 105.53 KB, created by
Johannes Hirte
on 2009-12-11 00:22:04 UTC
(
hide
)
Description:
grub_0.97_btrfs.patch
Filename:
MIME Type:
Creator:
Johannes Hirte
Created:
2009-12-11 00:22:04 UTC
Size:
105.53 KB
patch
obsolete
>diff -Nru grub-0.97-r9/AUTHORS grub-0.97-r10/AUTHORS >--- grub-0.97-r9/AUTHORS 2004-03-27 17:25:17.000000000 +0100 >+++ grub-0.97-r10/AUTHORS 2009-12-10 23:41:15.000000000 +0100 >@@ -41,6 +41,8 @@ > > 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 -Nru grub-0.97-r9/configure.ac grub-0.97-r10/configure.ac >--- grub-0.97-r9/configure.ac 2009-12-10 23:41:36.000000000 +0100 >+++ grub-0.97-r10/configure.ac 2009-12-10 23:41:15.000000000 +0100 >@@ -269,6 +269,13 @@ > 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 -Nru grub-0.97-r9/docs/grub.texi grub-0.97-r10/docs/grub.texi >--- grub-0.97-r9/docs/grub.texi 2009-12-10 23:41:37.000000000 +0100 >+++ grub-0.97-r10/docs/grub.texi 2009-12-10 23:41:15.000000000 +0100 >@@ -1761,6 +1761,7 @@ > @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 -Nru grub-0.97-r9/grub/Makefile.am grub-0.97-r10/grub/Makefile.am >--- grub-0.97-r9/grub/Makefile.am 2005-02-02 21:38:19.000000000 +0100 >+++ grub-0.97-r10/grub/Makefile.am 2009-12-10 23:41:15.000000000 +0100 >@@ -8,7 +8,7 @@ > > 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 -Nru grub-0.97-r9/INSTALL grub-0.97-r10/INSTALL >--- grub-0.97-r9/INSTALL 2005-05-08 04:43:15.000000000 +0200 >+++ grub-0.97-r10/INSTALL 2009-12-10 23:41:15.000000000 +0100 >@@ -207,6 +207,9 @@ > `--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 -Nru grub-0.97-r9/stage2/btrfs.h grub-0.97-r10/stage2/btrfs.h >--- grub-0.97-r9/stage2/btrfs.h 1970-01-01 01:00:00.000000000 +0100 >+++ grub-0.97-r10/stage2/btrfs.h 2009-12-10 23:41:15.000000000 +0100 >@@ -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: >+*/ >\ Kein Zeilenumbruch am Dateiende. >diff -Nru grub-0.97-r9/stage2/builtins.c grub-0.97-r10/stage2/builtins.c >--- grub-0.97-r9/stage2/builtins.c 2009-12-10 23:41:37.000000000 +0100 >+++ grub-0.97-r10/stage2/builtins.c 2009-12-10 23:41:15.000000000 +0100 >@@ -2370,6 +2370,16 @@ > 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; > } >@@ -4077,6 +4087,7 @@ > {"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 -Nru grub-0.97-r9/stage2/disk_io.c grub-0.97-r10/stage2/disk_io.c >--- grub-0.97-r9/stage2/disk_io.c 2009-12-10 23:41:37.000000000 +0100 >+++ grub-0.97-r10/stage2/disk_io.c 2009-12-11 00:50:51.555007247 +0100 >@@ -79,6 +79,9 @@ > # 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 -Nru grub-0.97-r9/stage2/filesys.h grub-0.97-r10/stage2/filesys.h >--- grub-0.97-r9/stage2/filesys.h 2004-05-14 21:36:43.000000000 +0200 >+++ grub-0.97-r10/stage2/filesys.h 2009-12-10 23:41:15.000000000 +0100 >@@ -77,6 +77,16 @@ > #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 @@ > #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 -Nru grub-0.97-r9/stage2/fsys_btrfs.c grub-0.97-r10/stage2/fsys_btrfs.c >--- grub-0.97-r9/stage2/fsys_btrfs.c 1970-01-01 01:00:00.000000000 +0100 >+++ grub-0.97-r10/stage2/fsys_btrfs.c 2009-12-11 01:08:03.156754722 +0100 >@@ -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 -Nru grub-0.97-r9/stage2/Makefile.am grub-0.97-r10/stage2/Makefile.am >--- grub-0.97-r9/stage2/Makefile.am 2009-12-10 23:41:35.000000000 +0100 >+++ grub-0.97-r10/stage2/Makefile.am 2009-12-10 23:41:15.000000000 +0100 >@@ -17,13 +17,13 @@ > 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 @@ > 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 @@ > 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 @@ > -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_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 -Nru grub-0.97-r9/stage2/shared.h grub-0.97-r10/stage2/shared.h >--- grub-0.97-r9/stage2/shared.h 2009-12-10 23:41:37.000000000 +0100 >+++ grub-0.97-r10/stage2/shared.h 2009-12-10 23:41:15.000000000 +0100 >@@ -209,11 +209,12 @@ > #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 >@@ -228,6 +229,8 @@ > # 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)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 283637
:
208666
| 212661