Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / ext3-extents-sanity-checks.patch
1 Index: linux-2.6.9-42.0.10.EL_lustre.1.4.10/fs/ext3/extents.c
2 ===================================================================
3 --- linux-2.6.9-42.0.10.EL_lustre.1.4.10.orig/fs/ext3/extents.c 2007-07-17 22:14:08.000000000 +0200
4 +++ linux-2.6.9-42.0.10.EL_lustre.1.4.10/fs/ext3/extents.c      2007-07-17 22:40:57.000000000 +0200
5 @@ -44,26 +44,56 @@
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, 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         return 0;
57 +
58 +corrupted:
59 +       ext3_error(inode->i_sb, function,
60 +                       "bad header in inode #%lu: %s - magic %x, "
61 +                       "entries %u, max %u(%u), depth %u(%u)",
62 +                       inode->i_ino, error_msg, eh->eh_magic,
63 +                       eh->eh_entries, eh->eh_max, max,
64 +                       eh->eh_depth, depth);
65 +
66 +       return -EIO;
67  }
68  
69 +#define ext3_ext_check_header(inode,eh,depth,max)      \
70 +       __ext3_ext_check_header(__FUNCTION__,inode,eh,depth,max)
71 +
72 +
73  static handle_t *ext3_ext_journal_restart(handle_t *handle, int needed)
74  {
75         int err;
76 @@ -227,6 +257,26 @@ static inline int ext3_ext_space_root_id
77         return size;
78  }
79  
80 +static inline int
81 +ext3_ext_max_entries(struct ext3_extents_tree *tree, int root, int depth)
82 +{
83 +       int max;
84 +
85 +       if (root) {
86 +               if (depth == 0)
87 +                       max = ext3_ext_space_root(tree);
88 +               else
89 +                       max = ext3_ext_space_root_idx(tree);
90 +       } else {
91 +               if (depth == 0)
92 +                       max = ext3_ext_space_block(tree);
93 +               else
94 +                       max = ext3_ext_space_block_idx(tree);
95 +       }
96 +
97 +       return max;
98 +}
99 +
100  static void ext3_ext_show_path(struct ext3_extents_tree *tree,
101                                struct ext3_ext_path *path)
102  {
103 @@ -297,10 +347,6 @@ ext3_ext_binsearch_idx(struct ext3_exten
104         struct ext3_extent_idx *ix;
105         int l = 0, k, r;
106  
107 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
108 -       EXT_ASSERT(eh->eh_entries <= eh->eh_max);
109 -       EXT_ASSERT(eh->eh_entries > 0);
110 -
111         ext_debug(tree, "binsearch for %d(idx):  ", block);
112  
113         path->p_idx = ix = EXT_FIRST_INDEX(eh);
114 @@ -360,9 +406,6 @@ ext3_ext_binsearch(struct ext3_extents_t
115         struct ext3_extent *ex;
116         int l = 0, k, r;
117  
118 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
119 -       EXT_ASSERT(eh->eh_entries <= eh->eh_max);
120 -
121         if (eh->eh_entries == 0) {
122                 /*
123                  * this leaf is empty yet:
124 @@ -437,6 +480,7 @@ ext3_ext_find_extent(struct ext3_extents
125         struct ext3_extent_header *eh;
126         struct buffer_head *bh;
127         int depth, i, ppos = 0;
128 +       int max;
129  
130         EXT_ASSERT(tree);
131         EXT_ASSERT(tree->inode);
132 @@ -444,17 +488,15 @@ ext3_ext_find_extent(struct ext3_extents
133  
134         eh = EXT_ROOT_HDR(tree);
135         EXT_ASSERT(eh);
136 -       if (ext3_ext_check_header(eh)) {
137 +       i = depth = EXT_DEPTH(tree);
138 +       max = ext3_ext_max_entries(tree, 1, i);
139 +       if (ext3_ext_check_header(tree->inode, eh, i, max)) {
140                 /* don't free previously allocated path
141                  * -- caller should take care */
142                 path = NULL;
143                 goto err;
144         }
145  
146 -       i = depth = EXT_DEPTH(tree);
147 -       EXT_ASSERT(eh->eh_max);
148 -       EXT_ASSERT(eh->eh_magic == EXT3_EXT_MAGIC);
149 -       
150         /* account possible depth increase */
151         if (!path) {
152                 path = kmalloc(sizeof(struct ext3_ext_path) * (depth + 2),
153 @@ -485,7 +527,8 @@ ext3_ext_find_extent(struct ext3_extents
154                 path[ppos].p_hdr = eh;
155                 i--;
156  
157 -               if (ext3_ext_check_header(eh))
158 +               max = ext3_ext_max_entries(tree, 0, i);
159 +               if (ext3_ext_check_header(tree->inode, eh, i, max))
160                         goto err;
161         }
162  
163 @@ -494,9 +537,6 @@ ext3_ext_find_extent(struct ext3_extents
164         path[ppos].p_ext = NULL;
165         path[ppos].p_idx = NULL;
166  
167 -       if (ext3_ext_check_header(eh))
168 -               goto err;
169 -
170         /* find extent */
171         ext3_ext_binsearch(tree, path + ppos, block);
172  
173 @@ -993,7 +1033,7 @@ ext3_ext_search_right(struct ext3_extent
174         struct ext3_extent_idx *ix;
175         struct ext3_extent *ex;
176         unsigned long block;
177 -       int depth;
178 +       int depth, max;
179  
180         BUG_ON(path == NULL);
181         depth = path->p_depth;
182 @@ -1051,7 +1091,9 @@ ext3_ext_search_right(struct ext3_extent
183                 if (bh == NULL)
184                         return -EIO;
185                 eh = EXT_BLOCK_HDR(bh);
186 -               if (ext3_ext_check_header(eh)) {
187 +               max = ext3_ext_max_entries(tree, 0, depth);
188 +               if (ext3_ext_check_header(tree->inode, eh,
189 +                                         path->p_depth - depth, max)) {
190                         brelse(bh);
191                         return -EIO;
192                 }
193 @@ -1064,7 +1106,8 @@ ext3_ext_search_right(struct ext3_extent
194         if (bh == NULL)
195                 return -EIO;
196         eh = EXT_BLOCK_HDR(bh);
197 -       if (ext3_ext_check_header(eh)) {
198 +       max = ext3_ext_max_entries(tree, 0, depth);
199 +       if (ext3_ext_check_header(tree->inode, eh, 0, max)) {
200                 brelse(bh);
201                 return -EIO;
202         }
203 @@ -1694,6 +1737,8 @@ ext3_ext_rm_leaf(handle_t *handle, struc
204         ext_debug(tree, "remove [%lu:%lu] in leaf\n", start, end);
205         if (!path[depth].p_hdr)
206                 path[depth].p_hdr = EXT_BLOCK_HDR(path[depth].p_bh);
207 +
208 +       /* the header must be checked already in ext3_ext_remove_space() */
209         eh = path[depth].p_hdr;
210         EXT_ASSERT(eh);
211         EXT_ASSERT(eh->eh_entries <= eh->eh_max);
212 @@ -1856,7 +1901,7 @@ int ext3_ext_remove_space(struct ext3_ex
213         int depth = EXT_DEPTH(tree);
214         struct ext3_ext_path *path;
215         handle_t *handle;
216 -       int i = 0, err = 0;
217 +       int i = 0, err = 0, max;
218  
219         ext_debug(tree, "space to be removed: %lu:%lu\n", start, end);
220  
221 @@ -1879,7 +1924,13 @@ int ext3_ext_remove_space(struct ext3_ex
222         }
223         memset(path, 0, sizeof(struct ext3_ext_path) * (depth + 1));
224         path[i].p_hdr = EXT_ROOT_HDR(tree);
225 -       
226 +
227 +       max = ext3_ext_max_entries(tree, 1, depth);
228 +       if (ext3_ext_check_header(inode, path[i].p_hdr, depth, max)) {
229 +               err = -EIO;
230 +               goto out;
231 +       }
232 +
233         while (i >= 0 && err == 0) {
234                 if (i == depth) {
235                         /* this is leaf block */
236 @@ -1889,16 +1940,13 @@ int ext3_ext_remove_space(struct ext3_ex
237                         i--;
238                         continue;
239                 }
240 -               
241 +
242                 /* this is index block */
243                 if (!path[i].p_hdr) {
244                         ext_debug(tree, "initialize header\n");
245                         path[i].p_hdr = EXT_BLOCK_HDR(path[i].p_bh);
246                 }
247  
248 -               EXT_ASSERT(path[i].p_hdr->eh_entries <= path[i].p_hdr->eh_max);
249 -               EXT_ASSERT(path[i].p_hdr->eh_magic == EXT3_EXT_MAGIC);
250 -               
251                 if (!path[i].p_idx) {
252                         /* this level hasn't touched yet */
253                         path[i].p_idx =
254 @@ -1925,6 +1973,14 @@ int ext3_ext_remove_space(struct ext3_ex
255                                 err = -EIO;
256                                 break;
257                         }
258 +                       BUG_ON(i + 1 > depth);
259 +                       max = ext3_ext_max_entries(tree, 0, depth - i - 1);
260 +                       if (ext3_ext_check_header(inode,
261 +                                               EXT_BLOCK_HDR(path[i+1].p_bh),
262 +                                               depth - i - 1, max)) {
263 +                               err = -EIO;
264 +                               break;
265 +                       }
266                         /* put actual number of indexes to know is this
267                          * number got changed at the next iteration */
268                         path[i].p_block = path[i].p_hdr->eh_entries;
269 @@ -1945,7 +2001,7 @@ int ext3_ext_remove_space(struct ext3_ex
270         }
271  
272         /* TODO: flexible tree reduction should be here */
273 -       if (path->p_hdr->eh_entries == 0) {
274 +       if (err == 0 && path->p_hdr->eh_entries == 0) {
275                 /*
276                  * truncate to zero freed all the tree
277                  * so, we need to correct eh_depth
278 @@ -1959,6 +2015,7 @@ int ext3_ext_remove_space(struct ext3_ex
279         }
280         ext3_ext_tree_changed(tree);
281  
282 +out:
283         kfree(path);
284         ext3_journal_stop(handle);
285