From: Andrei Borzenkov Date: Mon, 11 Jul 2016 04:23:13 +0000 (+0300) Subject: Merge branch 'master' into andrey/ext4_inline_data X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e897f83635a9a8cc6824ae8c9b473f6773389224;p=thirdparty%2Fgrub.git Merge branch 'master' into andrey/ext4_inline_data Conflicts: grub-core/fs/ext2.c --- e897f83635a9a8cc6824ae8c9b473f6773389224 diff --cc grub-core/fs/ext2.c index ca7342188,cdce63bcc..841b8707c --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@@ -103,20 -100,16 +103,22 @@@ GRUB_MOD_LICENSE ("GPLv3+") #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */ #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 + #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 +#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ +#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ +#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ +#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ +#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ /* The set of back-incompatible features this driver DOES support. Add (OR) * flags here as the related features are implemented into the driver. */ #define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \ | EXT4_FEATURE_INCOMPAT_EXTENTS \ | EXT4_FEATURE_INCOMPAT_FLEX_BG \ + | EXT2_FEATURE_INCOMPAT_META_BG \ - | EXT4_FEATURE_INCOMPAT_64BIT) + | EXT4_FEATURE_INCOMPAT_64BIT \ + | EXT4_FEATURE_INCOMPAT_INLINE_DATA) /* List of rationales for the ignored "incompatible" features: * needs_recovery: Not really back-incompatible - was added as such to forbid * ext2 drivers from mounting an ext3 volume with a dirty @@@ -368,66 -338,35 +375,95 @@@ static grub_dl_t my_mod + /* Check is a = b^x for some x. */ + static inline int + is_power_of (grub_uint64_t a, grub_uint32_t b) + { + grub_uint64_t c; + /* Prevent overflow assuming b < 8. */ + if (a >= (1LL << 60)) + return 0; + for (c = 1; c <= a; c *= b); + return (c == a); + } + + + static inline int + group_has_super_block (struct grub_ext2_data *data, grub_uint64_t group) + { + if (!(data->sblock.feature_ro_compat + & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))) + return 1; + /* Algorithm looked up in Linux source. */ + if (group <= 1) + return 1; + /* Even number is never a power of odd number. */ + if (!(group & 1)) + return 0; + return (is_power_of(group, 7) || is_power_of(group, 5) || + is_power_of(group, 3)); + } + +/* Inline data is stored using inline extended attributes. Attributes consist + of entry and value. Entries start after inode proper, following 4 bytes + magic header. Each entry is 4 bytes aligned, end of list is marked with + 4 bytes zero. Values are stored after entries. + + Inline data is stored as system attribute with name "data". First part of + data is kept in space reserved for block pointers, so it is valid for value + size to be zero. Offset is apparently non-zero even in this case. + */ +inline static void +grub_ext2_find_inline_data (struct grub_fshelp_node *node, grub_size_t isize, + struct grub_ext2_inode *inode) +{ + grub_size_t extra; + grub_uint8_t *ihdr; + struct grub_ext4_xattr_entry *entry; + grub_uint8_t *iend = (grub_uint8_t *) inode + isize - sizeof (grub_uint32_t); + + node->inline_offs = 0; + + if (isize < EXT2_GOOD_OLD_INODE_SIZE + sizeof (grub_uint16_t)) + return; + extra = grub_le_to_cpu16 (*((grub_uint16_t *) inode + + (EXT2_GOOD_OLD_INODE_SIZE / 2))); + if (EXT2_GOOD_OLD_INODE_SIZE + extra + 4 > isize) + return; + ihdr = ((grub_uint8_t *) inode + + EXT2_GOOD_OLD_INODE_SIZE + extra); + if (grub_get_unaligned32 (ihdr) + != grub_cpu_to_le32_compile_time (EXT4_XATTR_MAGIC)) + return; + entry = (struct grub_ext4_xattr_entry *) (ihdr + 4); + for (; (grub_uint8_t *) entry < iend && !IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry)) + { + grub_size_t value_size; + grub_off_t value_offs; + + if (entry->value_block) + continue; + if (entry->name_index != EXT4_XATTR_INDEX_SYSTEM) + continue; + if (entry->name_len != sizeof (EXT4_XATTR_SYSTEM_DATA) - 1) + continue; + if (grub_memcmp (entry->name, EXT4_XATTR_SYSTEM_DATA, sizeof (EXT4_XATTR_SYSTEM_DATA) - 1)) + continue; + value_size = grub_le_to_cpu32 (entry->value_size); + value_offs = grub_le_to_cpu16 (entry->value_offs); + /* extra is additional size of base inode. Extended attributes start + after base inode, offset is calculated from the end of extended + attributes header. + */ + if (EXT2_GOOD_OLD_INODE_SIZE + extra + 4 + value_offs + value_size > isize) + continue; + node->inline_offs = EXT2_GOOD_OLD_INODE_SIZE + extra + 4 + value_offs; + node->inline_size = value_size; + return; + } +} + /* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of the mounted filesystem DATA. */ inline static grub_err_t