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