Beginning with kernel version 2.6.23, extents are by default enabled when
mounting ext4 filesystem, which makes grub unable to read any new file
created since the mount.

The following patch adds support for ext4 extents.

---
Signed-Off-By: Quentin Godfroy <[EMAIL PROTECTED]>
---
diff -ruNp grub-0.97/stage2/fsys_ext2fs.c grub-0.97-patch/stage2/fsys_ext2fs.c
--- grub-0.97/stage2/fsys_ext2fs.c      2004-08-08 20:19:18.000000000 +0200
+++ grub-0.97-patch/stage2/fsys_ext2fs.c        2007-12-29 16:25:19.000000000 
+0100
@@ -51,6 +51,9 @@ typedef unsigned int __u32;
 #define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
 #define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
 
+/* Inode flags */
+#define EXT4_EXTENTS_FL                 0x00080000 /* Inode uses extents */
+
 /* include/linux/ext2_fs.h */
 struct ext2_super_block
   {
@@ -191,6 +194,42 @@ struct ext2_dir_entry
 #define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
                                          ~EXT2_DIR_ROUND)
 
+/* 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;       /* 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;        /* 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
 
 /* ext2/super.c */
 #define log2(n) ffz(~(n))
@@ -279,6 +318,26 @@ ext2_rdfsb (int fsblock, int buffer)
                  EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
 }
 
+/* Walk through extents index tree to find the good leaf */
+static struct ext4_extent_header * 
+ext4_recurse_extent_index(struct ext4_extent_header *extent_block, int 
logical_block)
+{
+  int i;
+  struct ext4_extent_idx *index = (struct ext4_extent_idx *) (extent_block + 
1);
+  if (extent_block->eh_magic != EXT4_EXT_MAGIC)
+    return NULL;
+  if (extent_block->eh_depth == 0)
+    return extent_block;
+  for (i = 0; i < extent_block->eh_entries; i++)
+    {
+      if (logical_block < index[i].ei_block)
+        break;
+    }
+  if (i == 0 || !ext2_rdfsb(index[i-1].ei_leaf, DATABLOCK1))
+    return NULL;
+  return (ext4_recurse_extent_index((struct ext4_extent_header *) DATABLOCK1, 
logical_block));
+}
+
 /* from
   ext2/inode.c:ext2_bmap()
 */
@@ -307,83 +366,106 @@ ext2fs_block_map (int logical_block)
     }
   printf ("logical block %d\n", logical_block);
 #endif /* E2DEBUG */
-
-  /* if it is directly pointed to by the inode, return that physical addr */
-  if (logical_block < EXT2_NDIR_BLOCKS)
-    {
-#ifdef E2DEBUG
-      printf ("returning %d\n", (unsigned char *) 
(INODE->i_block[logical_block]));
-      printf ("returning %d\n", INODE->i_block[logical_block]);
-#endif /* E2DEBUG */
-      return INODE->i_block[logical_block];
-    }
-  /* else */
-  logical_block -= EXT2_NDIR_BLOCKS;
-  /* try the indirect block */
-  if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+  /* standard ext2 inode */
+  if (!(INODE->i_flags & EXT4_EXTENTS_FL))
     {
-      if (mapblock1 != 1
-         && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
-       {
-         errnum = ERR_FSYS_CORRUPT;
-         return -1;
-       }
-      mapblock1 = 1;
-      return ((__u32 *) DATABLOCK1)[logical_block];
-    }
-  /* else */
-  logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
-  /* now try the double indirect block */
-  if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
-    {
-      int bnum;
-      if (mapblock1 != 2
-         && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
-       {
-         errnum = ERR_FSYS_CORRUPT;
-         return -1;
-       }
-      mapblock1 = 2;
-      if ((bnum = (((__u32 *) DATABLOCK1)
-                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
-         != mapblock2
-         && !ext2_rdfsb (bnum, DATABLOCK2))
-       {
-         errnum = ERR_FSYS_CORRUPT;
-         return -1;
-       }
-      mapblock2 = bnum;
+      /* if it is directly pointed to by the inode, return that physical addr 
*/
+      if (logical_block < EXT2_NDIR_BLOCKS)
+        {
+#ifdef E2DEBUG
+          printf ("returning %d\n", (unsigned char *) 
(INODE->i_block[logical_block]));
+          printf ("returning %d\n", INODE->i_block[logical_block]);
+#endif /* E2DEBUG */
+          return INODE->i_block[logical_block];
+        }
+      /* else */
+      logical_block -= EXT2_NDIR_BLOCKS;
+      /* try the indirect block */
+      if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+        {
+          if (mapblock1 != 1
+         && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+          mapblock1 = 1;
+          return ((__u32 *) DATABLOCK1)[logical_block];
+        }
+      /* else */
+      logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
+      /* now try the double indirect block */
+      if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
+        {
+          int bnum;
+          if (mapblock1 != 2
+         && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+          mapblock1 = 2;
+          if ((bnum = (((__u32 *) DATABLOCK1)
+                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
+         != mapblock2
+         && !ext2_rdfsb (bnum, DATABLOCK2))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+          mapblock2 = bnum;
+          return ((__u32 *) DATABLOCK2)
+            [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+        }
+      /* else */
+      mapblock2 = -1;
+      logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
+      if (mapblock1 != 3
+          && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
+        {
+          errnum = ERR_FSYS_CORRUPT;
+          return -1;
+        }
+      mapblock1 = 3;
+      if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
+                  [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
+                                     * 2)],
+                  DATABLOCK2))
+        {
+          errnum = ERR_FSYS_CORRUPT;
+          return -1;
+        }
+      if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
+                  [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
+                   & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
+                  DATABLOCK2))
+        {
+          errnum = ERR_FSYS_CORRUPT;
+          return -1;
+        }
       return ((__u32 *) DATABLOCK2)
-       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
-    }
-  /* else */
-  mapblock2 = -1;
-  logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
-  if (mapblock1 != 3
-      && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
-    {
-      errnum = ERR_FSYS_CORRUPT;
-      return -1;
+       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
     }
-  mapblock1 = 3;
-  if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
-                  [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
-                                     * 2)],
-                  DATABLOCK2))
-    {
-      errnum = ERR_FSYS_CORRUPT;
-      return -1;
-    }
-  if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
-                  [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
-                   & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
-                  DATABLOCK2))
+  /* inode is in extents format */
+  else
     {
+      int i;
+      struct ext4_extent_header *extent_hdr = 
ext4_recurse_extent_index((struct ext4_extent_header *) INODE->i_block, 
logical_block);
+      struct ext4_extent *extent = (struct ext4_extent *) (extent_hdr + 1);
+      if ( extent_hdr == NULL || extent_hdr->eh_magic != EXT4_EXT_MAGIC)
+      {
+        errnum = ERR_FSYS_CORRUPT;
+        return -1;
+      }
+      for (i = 0; i<extent_hdr->eh_entries; i++)
+        {
+          if (extent[i].ee_block <= logical_block && logical_block < 
extent[i].ee_block + extent[i].ee_len && !(extent[i].ee_len>>15))
+            return (logical_block - extent[i].ee_block + extent[i].ee_start);
+        }
+      /* We should not arrive here */
       errnum = ERR_FSYS_CORRUPT;
       return -1;
     }
-  return ((__u32 *) DATABLOCK2)
-    [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
 }
 
 /* preconditions: all preconds of ext2fs_block_map */


_______________________________________________
Bug-grub mailing list
Bug-grub@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-grub

Reply via email to