06cd2c261b35561464489f00d450bffbe189517d
[openwrt/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 */