Whamcloud - gitweb
Branch b1_8
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / ext3-extents-sanity-checks.patch
1 Index: linux-2.6.16.54-0.2.5/fs/ext3/extents.c
2 ===================================================================
3 --- linux-2.6.16.54-0.2.5.orig/fs/ext3/extents.c
4 +++ linux-2.6.16.54-0.2.5/fs/ext3/extents.c
5 @@ -44,26 +44,60 @@
6  #include <asm/uaccess.h>
7  
8  
9 -static inline int ext3_ext_check_header(struct ext3_extent_header *eh)
10 -{
11 -       if (eh->eh_magic != EXT3_EXT_MAGIC) {
12 -               printk(KERN_ERR "EXT3-fs: invalid magic = 0x%x\n",
13 -                      (unsigned)eh->eh_magic);
14 -               return -EIO;
15 +static int __ext3_ext_check_header(const char *function, int line, struct inode *inode,
16 +                               struct ext3_extent_header *eh, int depth,
17 +                               int max)
18 +{
19 +       const char *error_msg = NULL;
20 +
21 +       if (unlikely(eh->eh_magic != EXT3_EXT_MAGIC)) {
22 +               error_msg = "invalid magic";
23 +               goto corrupted;
24 +       }
25 +       if (unlikely(eh->eh_depth != depth)) {
26 +               error_msg = "unexpected eh_depth";
27 +               goto corrupted;
28 +       }
29 +       if (unlikely(eh->eh_max == 0)) {
30 +               error_msg = "too small eh_max";
31 +               goto corrupted;
32         }
33 -       if (eh->eh_max == 0) {
34 -               printk(KERN_ERR "EXT3-fs: invalid eh_max = %u\n",
35 -                      (unsigned)eh->eh_max);
36 -               return -EIO;
37 +#ifdef AGRESSIVE_TEST
38 +       if (eh->eh_max > 3) {
39 +               /* inode probably got its extent without defining
40 +                * AGRESSIVE_TEST */
41 +               max = eh->eh_max;
42         }
43 -       if (eh->eh_entries > eh->eh_max) {
44 -               printk(KERN_ERR "EXT3-fs: invalid eh_entries = %u\n",
45 -                      (unsigned)eh->eh_entries);
46 -               return -EIO;
47 +#endif
48 +       if (unlikely(eh->eh_max > max)) {
49 +               error_msg = "too large eh_max";
50 +               goto corrupted;
51 +       }
52 +       if (unlikely(eh->eh_entries > eh->eh_max)) {
53 +               error_msg = "invalid eh_entries";
54 +               goto corrupted;
55 +       }
56 +       if (unlikely((eh->eh_entries == 0) && (eh->eh_depth != 0))) {
57 +               error_msg = "invalid index, eh_entries=0 && eh_depth != 0";
58 +               goto corrupted;
59         }
60         return 0;
61 +
62 +corrupted:
63 +       ext3_error(inode->i_sb, function,
64 +                       ":%d: bad header in inode #%lu: %s - magic %x, "
65 +                       "entries %u, max %u(%u), depth %u(%u)", line,
66 +                       inode->i_ino, error_msg, eh->eh_magic,
67 +                       eh->eh_entries, eh->eh_max, max,
68 +                       eh->eh_depth, depth);
69 +
70 +       return -EIO;
71  }
72  
73 +#define ext3_ext_check_header(inode,eh,depth,max)      \
74 +       __ext3_ext_check_header(__FUNCTION__,__LINE__,inode,eh,depth,max)
75 +
76 +
77  static handle_t *ext3_ext_journal_restart(handle_t *handle, int needed)
78  {
79         int err;
80 @@ -226,6 +260,26 @@ static inline int ext3_ext_space_root_id
81         return size;
82  }
83  
84 +static inline int
85 +ext3_ext_max_entries(struct ext3_extents_tree *tree, int root, int depth)
86 +{
87 +       int max;
88 +
89 +       if (root) {
90 +               if (depth == 0)
91 +                       max = ext3_ext_space_root(tree);
92 +               else
93 +                       max = ext3_ext_space_root_idx(tree);
94 +       } else {
95 +               if (depth == 0)
96 +                       max = ext3_ext_space_block(tree);
97 +               else
98 +                       max = ext3_ext_space_block_idx(tree);
99 +       }
100 +
101 +       return max;
102 +}
103 +
104  static void ext3_ext_show_path(struct ext3_extents_tree *tree,
105                                struct ext3_ext_path *path)
106  {
107 @@ -296,10 +350,6 @@ ext3_ext_binsearch_idx(struct ext3_exten
108         struct ext3_extent_idx *ix;
109         int l = 0, k, r;
110  
111 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
112 -       EXT_ASSERT(eh->eh_entries <= eh->eh_max);
113 -       EXT_ASSERT(eh->eh_entries > 0);
114 -
115         ext_debug(tree, "binsearch for %d(idx):  ", block);
116  
117         path->p_idx = ix = EXT_FIRST_INDEX(eh);
118 @@ -359,9 +409,6 @@ ext3_ext_binsearch(struct ext3_extents_t
119         struct ext3_extent *ex;
120         int l = 0, k, r;
121  
122 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
123 -       EXT_ASSERT(eh->eh_entries <= eh->eh_max);
124 -
125         if (eh->eh_entries == 0) {
126                 /*
127                  * this leaf is empty yet:
128 @@ -436,6 +483,7 @@ ext3_ext_find_extent(struct ext3_extents
129         struct ext3_extent_header *eh;
130         struct buffer_head *bh;
131         int depth, i, ppos = 0;
132 +       int max;
133  
134         EXT_ASSERT(tree);
135         EXT_ASSERT(tree->inode);
136 @@ -443,17 +491,15 @@ ext3_ext_find_extent(struct ext3_extents
137  
138         eh = EXT_ROOT_HDR(tree);
139         EXT_ASSERT(eh);
140 -       if (ext3_ext_check_header(eh)) {
141 +       i = depth = EXT_DEPTH(tree);
142 +       max = ext3_ext_max_entries(tree, 1, i);
143 +       if (ext3_ext_check_header(tree->inode, eh, i, max)) {
144                 /* don't free previously allocated path
145                  * -- caller should take care */
146                 path = NULL;
147                 goto err;
148         }
149  
150 -       i = depth = EXT_DEPTH(tree);
151 -       EXT_ASSERT(eh->eh_max);
152 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
153 -       
154         /* account possible depth increase */
155         if (!path) {
156                 path = kmalloc(sizeof(struct ext3_ext_path) * (depth + 2),
157 @@ -484,7 +530,8 @@ ext3_ext_find_extent(struct ext3_extents
158                 path[ppos].p_hdr = eh;
159                 i--;
160  
161 -               if (ext3_ext_check_header(eh))
162 +               max = ext3_ext_max_entries(tree, 0, i);
163 +               if (ext3_ext_check_header(tree->inode, eh, i, max))
164                         goto err;
165         }
166  
167 @@ -493,9 +540,6 @@ ext3_ext_find_extent(struct ext3_extents
168         path[ppos].p_ext = NULL;
169         path[ppos].p_idx = NULL;
170  
171 -       if (ext3_ext_check_header(eh))
172 -               goto err;
173 -
174         /* find extent */
175         ext3_ext_binsearch(tree, path + ppos, block);
176  
177 @@ -992,7 +1036,7 @@ ext3_ext_search_right(struct ext3_extent
178         struct ext3_extent_idx *ix;
179         struct ext3_extent *ex;
180         unsigned long block;
181 -       int depth;
182 +       int depth, max;
183  
184         BUG_ON(path == NULL);
185         depth = path->p_depth;
186 @@ -1050,7 +1094,9 @@ ext3_ext_search_right(struct ext3_extent
187                 if (bh == NULL)
188                         return -EIO;
189                 eh = EXT_BLOCK_HDR(bh);
190 -               if (ext3_ext_check_header(eh)) {
191 +               max = ext3_ext_max_entries(tree, 0, depth);
192 +               if (ext3_ext_check_header(tree->inode, eh,
193 +                                         path->p_depth - depth, max)) {
194                         brelse(bh);
195                         return -EIO;
196                 }
197 @@ -1063,7 +1109,8 @@ ext3_ext_search_right(struct ext3_extent
198         if (bh == NULL)
199                 return -EIO;
200         eh = EXT_BLOCK_HDR(bh);
201 -       if (ext3_ext_check_header(eh)) {
202 +       max = ext3_ext_max_entries(tree, 0, depth);
203 +       if (ext3_ext_check_header(tree->inode, eh, 0, max)) {
204                 brelse(bh);
205                 return -EIO;
206         }
207 @@ -1693,6 +1740,8 @@ ext3_ext_rm_leaf(handle_t *handle, struc
208         ext_debug(tree, "remove [%lu:%lu] in leaf\n", start, end);
209         if (!path[depth].p_hdr)
210                 path[depth].p_hdr = EXT_BLOCK_HDR(path[depth].p_bh);
211 +
212 +       /* the header must be checked already in ext3_ext_remove_space() */
213         eh = path[depth].p_hdr;
214         EXT_ASSERT(eh);
215         EXT_ASSERT(eh->eh_entries <= eh->eh_max);
216 @@ -1855,7 +1904,7 @@ int ext3_ext_remove_space(struct ext3_ex
217         int depth = EXT_DEPTH(tree);
218         struct ext3_ext_path *path;
219         handle_t *handle;
220 -       int i = 0, err = 0;
221 +       int i = 0, err = 0, max;
222  
223         ext_debug(tree, "space to be removed: %lu:%lu\n", start, end);
224  
225 @@ -1878,7 +1927,13 @@ int ext3_ext_remove_space(struct ext3_ex
226         }
227         memset(path, 0, sizeof(struct ext3_ext_path) * (depth + 1));
228         path[i].p_hdr = EXT_ROOT_HDR(tree);
229 -       
230 +
231 +       max = ext3_ext_max_entries(tree, 1, depth);
232 +       if (ext3_ext_check_header(inode, path[i].p_hdr, depth, max)) {
233 +               err = -EIO;
234 +               goto out;
235 +       }
236 +
237         while (i >= 0 && err == 0) {
238                 if (i == depth) {
239                         /* this is leaf block */
240 @@ -1888,16 +1943,13 @@ int ext3_ext_remove_space(struct ext3_ex
241                         i--;
242                         continue;
243                 }
244 -               
245 +
246                 /* this is index block */
247                 if (!path[i].p_hdr) {
248                         ext_debug(tree, "initialize header\n");
249                         path[i].p_hdr = EXT_BLOCK_HDR(path[i].p_bh);
250                 }
251  
252 -               EXT_ASSERT(path[i].p_hdr->eh_entries <= path[i].p_hdr->eh_max);
253 -               EXT_ASSERT(path[i].p_hdr->eh_magic == EXT3_EXT_MAGIC);
254 -               
255                 if (!path[i].p_idx) {
256                         /* this level hasn't touched yet */
257                         path[i].p_idx =
258 @@ -1924,6 +1976,14 @@ int ext3_ext_remove_space(struct ext3_ex
259                                 err = -EIO;
260                                 break;
261                         }
262 +                       BUG_ON(i + 1 > depth);
263 +                       max = ext3_ext_max_entries(tree, 0, depth - i - 1);
264 +                       if (ext3_ext_check_header(inode,
265 +                                               EXT_BLOCK_HDR(path[i+1].p_bh),
266 +                                               depth - i - 1, max)) {
267 +                               err = -EIO;
268 +                               break;
269 +                       }
270                         /* put actual number of indexes to know is this
271                          * number got changed at the next iteration */
272                         path[i].p_block = path[i].p_hdr->eh_entries;
273 @@ -1944,7 +2004,7 @@ int ext3_ext_remove_space(struct ext3_ex
274         }
275  
276         /* TODO: flexible tree reduction should be here */
277 -       if (path->p_hdr->eh_entries == 0) {
278 +       if (err == 0 && path->p_hdr->eh_entries == 0) {
279                 /*
280                  * truncate to zero freed all the tree
281                  * so, we need to correct eh_depth
282 @@ -1958,6 +2018,7 @@ int ext3_ext_remove_space(struct ext3_ex
283         }
284         ext3_ext_tree_changed(tree);
285  
286 +out:
287         kfree(path);
288         ext3_journal_stop(handle);
289