]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Merge branch 'master' into andrey/ext4_inline_data andrey/ext4_inline_data
authorAndrei Borzenkov <arvidjaar@gmail.com>
Mon, 11 Jul 2016 04:23:13 +0000 (07:23 +0300)
committerAndrei Borzenkov <arvidjaar@gmail.com>
Mon, 11 Jul 2016 04:23:13 +0000 (07:23 +0300)
Conflicts:
grub-core/fs/ext2.c

1  2 
grub-core/fs/ext2.c

index ca73421888c1d16c45c41f016f128b2a36b9427c,cdce63bcc9d57e82b7a4f6a644803a1d8320935d..841b8707cd4630a465d8cf6959e1088aa4286443
@@@ -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 \
 -                                       | EXT4_FEATURE_INCOMPAT_64BIT)
+                                        | EXT2_FEATURE_INCOMPAT_META_BG \
 +                                       | 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
  
  \f
  
+ /* 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