06cd2c261b35561464489f00d450bffbe189517d
[openwrt.git] / package / grub / patches / 020-ext4_support.patch
1 --- a/stage2/fsys_ext2fs.c
2 +++ b/stage2/fsys_ext2fs.c
3 @@ -51,6 +51,9 @@ typedef unsigned int __u32;
4  #define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
5  #define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
6  
7 +/* Inode flags */
8 +#define EXT4_EXTENTS_FL                 0x00080000 /* Inode uses extents */
9 +
10  /* include/linux/ext2_fs.h */
11  struct ext2_super_block
12    {
13 @@ -191,6 +194,42 @@ struct ext2_dir_entry
14  #define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
15                                           ~EXT2_DIR_ROUND)
16  
17 +/* linux/ext4_fs_extents.h */
18 +/*
19 + * This is the extent on-disk structure.
20 + * It's used at the bottom of the tree.
21 + */
22 +struct ext4_extent {
23 +    __u32 ee_block;       /* first logical block extent covers */
24 +    __u16 ee_len;         /* number of blocks covered by extent */
25 +    __u16 ee_start_hi;    /* high 16 bits of physical block */
26 +    __u32 ee_start;       /* low 32 bits of physical block */
27 +};
28 +
29 +/*
30 + * This is index on-disk structure.
31 + * It's used at all the levels except the bottom.
32 + */
33 +struct ext4_extent_idx {
34 +    __u32 ei_block;       /* index covers logical blocks from 'block' */
35 +    __u32 ei_leaf;        /* pointer to the physical block of the next *
36 +                                 * level. leaf or next index could be there */
37 +    __u16 ei_leaf_hi;     /* high 16 bits of physical block */
38 +    __u16 ei_unused;
39 +};
40 +
41 +/*
42 + * Each block (leaves and indexes), even inode-stored has header.
43 + */
44 +struct ext4_extent_header {
45 +    __u16  eh_magic;       /* probably will support different formats */
46 +    __u16  eh_entries;     /* number of valid entries */
47 +    __u16  eh_max;         /* capacity of store in entries */
48 +    __u16  eh_depth;       /* has tree real underlying blocks? */
49 +    __u32  eh_generation;  /* generation of the tree */
50 +};
51 +
52 +#define EXT4_EXT_MAGIC          0xf30a
53  
54  /* ext2/super.c */
55  #define log2(n) ffz(~(n))
56 @@ -279,6 +318,27 @@ ext2_rdfsb (int fsblock, int buffer)
57                   EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
58  }
59  
60 +/* Walk through extents index tree to find the good leaf */
61 +static struct ext4_extent_header *
62 +ext4_recurse_extent_index(struct ext4_extent_header *extent_block, int logical_block)
63 +{
64 +  int i;
65 +  struct ext4_extent_idx *index = (struct ext4_extent_idx *) (extent_block + 1);
66 +  if (extent_block->eh_magic != EXT4_EXT_MAGIC)
67 +    return NULL;
68 +  if (extent_block->eh_depth == 0)
69 +    return extent_block;
70 +  for (i = 0; i < extent_block->eh_entries; i++)
71 +    {
72 +      if (logical_block < index[i].ei_block)
73 +        break;
74 +    }
75 +  if (i == 0 || !ext2_rdfsb(index[i-1].ei_leaf, DATABLOCK1))
76 +    return NULL;
77 +  return (ext4_recurse_extent_index((struct ext4_extent_header *) DATABLOCK1, logical_block));
78 +}
79 +
80 +
81  /* from
82    ext2/inode.c:ext2_bmap()
83  */
84 @@ -287,7 +347,6 @@ ext2_rdfsb (int fsblock, int buffer)
85  static int
86  ext2fs_block_map (int logical_block)
87  {
88 -
89  #ifdef E2DEBUG
90    unsigned char *i;
91    for (i = (unsigned char *) INODE;
92 @@ -308,82 +367,106 @@ ext2fs_block_map (int logical_block)
93    printf ("logical block %d\n", logical_block);
94  #endif /* E2DEBUG */
95  
96 -  /* if it is directly pointed to by the inode, return that physical addr */
97 -  if (logical_block < EXT2_NDIR_BLOCKS)
98 +  if (!(INODE->i_flags & EXT4_EXTENTS_FL))
99      {
100 -#ifdef E2DEBUG
101 -      printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
102 -      printf ("returning %d\n", INODE->i_block[logical_block]);
103 -#endif /* E2DEBUG */
104 -      return INODE->i_block[logical_block];
105 -    }
106 -  /* else */
107 -  logical_block -= EXT2_NDIR_BLOCKS;
108 -  /* try the indirect block */
109 -  if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
110 -    {
111 -      if (mapblock1 != 1
112 -         && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
113 -       {
114 -         errnum = ERR_FSYS_CORRUPT;
115 -         return -1;
116 -       }
117 -      mapblock1 = 1;
118 -      return ((__u32 *) DATABLOCK1)[logical_block];
119 -    }
120 -  /* else */
121 -  logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
122 -  /* now try the double indirect block */
123 -  if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
124 -    {
125 -      int bnum;
126 -      if (mapblock1 != 2
127 -         && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
128 -       {
129 -         errnum = ERR_FSYS_CORRUPT;
130 -         return -1;
131 -       }
132 -      mapblock1 = 2;
133 -      if ((bnum = (((__u32 *) DATABLOCK1)
134 -                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
135 -         != mapblock2
136 -         && !ext2_rdfsb (bnum, DATABLOCK2))
137 -       {
138 -         errnum = ERR_FSYS_CORRUPT;
139 -         return -1;
140 -       }
141 -      mapblock2 = bnum;
142 +      /* if it is directly pointed to by the inode, return that physical addr */
143 +      if (logical_block < EXT2_NDIR_BLOCKS)
144 +        {
145 +#ifdef E2DEBUG
146 +          printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
147 +          printf ("returning %d\n", INODE->i_block[logical_block]);
148 +#endif /* E2DEBUG */
149 +          return INODE->i_block[logical_block];
150 +        }
151 +      /* else */
152 +      logical_block -= EXT2_NDIR_BLOCKS;
153 +      /* try the indirect block */
154 +      if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
155 +        {
156 +          if (mapblock1 != 1 && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
157 +            {
158 +              errnum = ERR_FSYS_CORRUPT;
159 +              return -1;
160 +            }
161 +          mapblock1 = 1;
162 +          return ((__u32 *) DATABLOCK1)[logical_block];
163 +        }
164 +      /* else */
165 +      logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
166 +      /* now try the double indirect block */
167 +      if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
168 +        {
169 +          int bnum;
170 +          if (mapblock1 != 2 && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
171 +            {
172 +              errnum = ERR_FSYS_CORRUPT;
173 +              return -1;
174 +            }
175 +          mapblock1 = 2;
176 +          if ((bnum = (((__u32 *) DATABLOCK1)
177 +                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
178 +         != mapblock2
179 +         && !ext2_rdfsb (bnum, DATABLOCK2))
180 +           {
181 +             errnum = ERR_FSYS_CORRUPT;
182 +             return -1;
183 +           }
184 +          mapblock2 = bnum;
185 +          return ((__u32 *) DATABLOCK2)
186 +            [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
187 +        }
188 +      /* else */
189 +      mapblock2 = -1;
190 +      logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
191 +      if (mapblock1 != 3
192 +          && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
193 +        {
194 +          errnum = ERR_FSYS_CORRUPT;
195 +          return -1;
196 +        }
197 +      mapblock1 = 3;
198 +      if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
199 +                  [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
200 +                                     * 2)],
201 +                  DATABLOCK2))
202 +        {
203 +          errnum = ERR_FSYS_CORRUPT;
204 +          return -1;
205 +        }
206 +      if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
207 +                  [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
208 +                   & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
209 +                  DATABLOCK2))
210 +        {
211 +          errnum = ERR_FSYS_CORRUPT;
212 +          return -1;
213 +        }
214 +
215        return ((__u32 *) DATABLOCK2)
216 -       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
217 +       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
218      }
219 -  /* else */
220 -  mapblock2 = -1;
221 -  logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
222 -  if (mapblock1 != 3
223 -      && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
224 -    {
225 -      errnum = ERR_FSYS_CORRUPT;
226 -      return -1;
227 -    }
228 -  mapblock1 = 3;
229 -  if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
230 -                  [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
231 -                                     * 2)],
232 -                  DATABLOCK2))
233 -    {
234 -      errnum = ERR_FSYS_CORRUPT;
235 -      return -1;
236 -    }
237 -  if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
238 -                  [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
239 -                   & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
240 -                  DATABLOCK2))
241 +    /* inode is in extents format */
242 +    else
243      {
244 +      int i;
245 +      struct ext4_extent_header *extent_hdr =
246 +         ext4_recurse_extent_index((struct ext4_extent_header *) INODE->i_block, logical_block);
247 +      struct ext4_extent *extent = (struct ext4_extent *) (extent_hdr + 1);
248 +      if ( extent_hdr == NULL || extent_hdr->eh_magic != EXT4_EXT_MAGIC)
249 +        {
250 +          errnum = ERR_FSYS_CORRUPT;
251 +          return -1;
252 +        }
253 +      for (i = 0; i<extent_hdr->eh_entries; i++)
254 +        {
255 +          if (extent[i].ee_block <= logical_block && logical_block < extent[i].ee_block + extent[i].ee_len && !(extent[i].ee_len>>15))
256 +            return (logical_block - extent[i].ee_block + extent[i].ee_start);
257 +        }
258 +      /* We should not arrive here */
259 +
260        errnum = ERR_FSYS_CORRUPT;
261        return -1;
262      }
263 -  return ((__u32 *) DATABLOCK2)
264 -    [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
265  }
266  
267  /* preconditions: all preconds of ext2fs_block_map */