diff options
| -rw-r--r-- | fs/ubifs/debug.c | 156 | ||||
| -rw-r--r-- | fs/ubifs/debug.h | 4 | ||||
| -rw-r--r-- | fs/ubifs/gc.c | 10 |
3 files changed, 168 insertions, 2 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index c2a68baa782f..c664f10aec6c 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
| @@ -2239,6 +2239,162 @@ out_free: | |||
| 2239 | return err; | 2239 | return err; |
| 2240 | } | 2240 | } |
| 2241 | 2241 | ||
| 2242 | /** | ||
| 2243 | * dbg_check_data_nodes_order - check that list of data nodes is sorted. | ||
| 2244 | * @c: UBIFS file-system description object | ||
| 2245 | * @head: the list of nodes ('struct ubifs_scan_node' objects) | ||
| 2246 | * | ||
| 2247 | * This function returns zero if the list of data nodes is sorted correctly, | ||
| 2248 | * and %-EINVAL if not. | ||
| 2249 | */ | ||
| 2250 | int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head) | ||
| 2251 | { | ||
| 2252 | struct list_head *cur; | ||
| 2253 | struct ubifs_scan_node *sa, *sb; | ||
| 2254 | |||
| 2255 | if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) | ||
| 2256 | return 0; | ||
| 2257 | |||
| 2258 | for (cur = head->next; cur->next != head; cur = cur->next) { | ||
| 2259 | ino_t inuma, inumb; | ||
| 2260 | uint32_t blka, blkb; | ||
| 2261 | |||
| 2262 | cond_resched(); | ||
| 2263 | sa = container_of(cur, struct ubifs_scan_node, list); | ||
| 2264 | sb = container_of(cur->next, struct ubifs_scan_node, list); | ||
| 2265 | |||
| 2266 | if (sa->type != UBIFS_DATA_NODE) { | ||
| 2267 | ubifs_err("bad node type %d", sa->type); | ||
| 2268 | dbg_dump_node(c, sa->node); | ||
| 2269 | return -EINVAL; | ||
| 2270 | } | ||
| 2271 | if (sb->type != UBIFS_DATA_NODE) { | ||
| 2272 | ubifs_err("bad node type %d", sb->type); | ||
| 2273 | dbg_dump_node(c, sb->node); | ||
| 2274 | return -EINVAL; | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | inuma = key_inum(c, &sa->key); | ||
| 2278 | inumb = key_inum(c, &sb->key); | ||
| 2279 | |||
| 2280 | if (inuma < inumb) | ||
| 2281 | continue; | ||
| 2282 | if (inuma > inumb) { | ||
| 2283 | ubifs_err("larger inum %lu goes before inum %lu", | ||
| 2284 | (unsigned long)inuma, (unsigned long)inumb); | ||
| 2285 | goto error_dump; | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | blka = key_block(c, &sa->key); | ||
| 2289 | blkb = key_block(c, &sb->key); | ||
| 2290 | |||
| 2291 | if (blka > blkb) { | ||
| 2292 | ubifs_err("larger block %u goes before %u", blka, blkb); | ||
| 2293 | goto error_dump; | ||
| 2294 | } | ||
| 2295 | if (blka == blkb) { | ||
| 2296 | ubifs_err("two data nodes for the same block"); | ||
| 2297 | goto error_dump; | ||
| 2298 | } | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | return 0; | ||
| 2302 | |||
| 2303 | error_dump: | ||
| 2304 | dbg_dump_node(c, sa->node); | ||
| 2305 | dbg_dump_node(c, sb->node); | ||
| 2306 | return -EINVAL; | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | /** | ||
| 2310 | * dbg_check_nondata_nodes_order - check that list of data nodes is sorted. | ||
| 2311 | * @c: UBIFS file-system description object | ||
| 2312 | * @head: the list of nodes ('struct ubifs_scan_node' objects) | ||
| 2313 | * | ||
| 2314 | * This function returns zero if the list of non-data nodes is sorted correctly, | ||
| 2315 | * and %-EINVAL if not. | ||
| 2316 | */ | ||
| 2317 | int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) | ||
| 2318 | { | ||
| 2319 | struct list_head *cur; | ||
| 2320 | struct ubifs_scan_node *sa, *sb; | ||
| 2321 | |||
| 2322 | if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) | ||
| 2323 | return 0; | ||
| 2324 | |||
| 2325 | for (cur = head->next; cur->next != head; cur = cur->next) { | ||
| 2326 | ino_t inuma, inumb; | ||
| 2327 | uint32_t hasha, hashb; | ||
| 2328 | |||
| 2329 | cond_resched(); | ||
| 2330 | sa = container_of(cur, struct ubifs_scan_node, list); | ||
| 2331 | sb = container_of(cur->next, struct ubifs_scan_node, list); | ||
| 2332 | |||
| 2333 | if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE && | ||
| 2334 | sa->type != UBIFS_XENT_NODE) { | ||
| 2335 | ubifs_err("bad node type %d", sa->type); | ||
| 2336 | dbg_dump_node(c, sa->node); | ||
| 2337 | return -EINVAL; | ||
| 2338 | } | ||
| 2339 | if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE && | ||
| 2340 | sa->type != UBIFS_XENT_NODE) { | ||
| 2341 | ubifs_err("bad node type %d", sb->type); | ||
| 2342 | dbg_dump_node(c, sb->node); | ||
| 2343 | return -EINVAL; | ||
| 2344 | } | ||
| 2345 | |||
| 2346 | if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) { | ||
| 2347 | ubifs_err("non-inode node goes before inode node"); | ||
| 2348 | goto error_dump; | ||
| 2349 | } | ||
| 2350 | |||
| 2351 | if (sa->type == UBIFS_INO_NODE && sb->type != UBIFS_INO_NODE) | ||
| 2352 | continue; | ||
| 2353 | |||
| 2354 | if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) { | ||
| 2355 | /* Inode nodes are sorted in descending size order */ | ||
| 2356 | if (sa->len < sb->len) { | ||
| 2357 | ubifs_err("smaller inode node goes first"); | ||
| 2358 | goto error_dump; | ||
| 2359 | } | ||
| 2360 | continue; | ||
| 2361 | } | ||
| 2362 | |||
| 2363 | /* | ||
| 2364 | * This is either a dentry or xentry, which should be sorted in | ||
| 2365 | * ascending (parent ino, hash) order. | ||
| 2366 | */ | ||
| 2367 | inuma = key_inum(c, &sa->key); | ||
| 2368 | inumb = key_inum(c, &sb->key); | ||
| 2369 | |||
| 2370 | if (inuma < inumb) | ||
| 2371 | continue; | ||
| 2372 | if (inuma > inumb) { | ||
| 2373 | ubifs_err("larger inum %lu goes before inum %lu", | ||
| 2374 | (unsigned long)inuma, (unsigned long)inumb); | ||
| 2375 | goto error_dump; | ||
| 2376 | } | ||
| 2377 | |||
| 2378 | hasha = key_block(c, &sa->key); | ||
| 2379 | hashb = key_block(c, &sb->key); | ||
| 2380 | |||
| 2381 | if (hasha > hashb) { | ||
| 2382 | ubifs_err("larger hash %u goes before %u", hasha, hashb); | ||
| 2383 | goto error_dump; | ||
| 2384 | } | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | return 0; | ||
| 2388 | |||
| 2389 | error_dump: | ||
| 2390 | ubifs_msg("dumping first node"); | ||
| 2391 | dbg_dump_node(c, sa->node); | ||
| 2392 | ubifs_msg("dumping second node"); | ||
| 2393 | dbg_dump_node(c, sb->node); | ||
| 2394 | return -EINVAL; | ||
| 2395 | return 0; | ||
| 2396 | } | ||
| 2397 | |||
| 2242 | static int invocation_cnt; | 2398 | static int invocation_cnt; |
| 2243 | 2399 | ||
| 2244 | int dbg_force_in_the_gaps(void) | 2400 | int dbg_force_in_the_gaps(void) |
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 29d960101ea6..69ebe4729151 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h | |||
| @@ -324,6 +324,8 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, | |||
| 324 | int row, int col); | 324 | int row, int col); |
| 325 | int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, | 325 | int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, |
| 326 | loff_t size); | 326 | loff_t size); |
| 327 | int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head); | ||
| 328 | int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head); | ||
| 327 | 329 | ||
| 328 | /* Force the use of in-the-gaps method for testing */ | 330 | /* Force the use of in-the-gaps method for testing */ |
| 329 | 331 | ||
| @@ -465,6 +467,8 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); | |||
| 465 | #define dbg_check_lprops(c) 0 | 467 | #define dbg_check_lprops(c) 0 |
| 466 | #define dbg_check_lpt_nodes(c, cnode, row, col) 0 | 468 | #define dbg_check_lpt_nodes(c, cnode, row, col) 0 |
| 467 | #define dbg_check_inode_size(c, inode, size) 0 | 469 | #define dbg_check_inode_size(c, inode, size) 0 |
| 470 | #define dbg_check_data_nodes_order(c, head) 0 | ||
| 471 | #define dbg_check_nondata_nodes_order(c, head) 0 | ||
| 468 | #define dbg_force_in_the_gaps_enabled 0 | 472 | #define dbg_force_in_the_gaps_enabled 0 |
| 469 | #define dbg_force_in_the_gaps() 0 | 473 | #define dbg_force_in_the_gaps() 0 |
| 470 | #define dbg_failure_mode 0 | 474 | #define dbg_failure_mode 0 |
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index 4fc31ca0e3b1..396f24a30af9 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c | |||
| @@ -242,14 +242,13 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b) | |||
| 242 | static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, | 242 | static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, |
| 243 | struct list_head *nondata, int *min) | 243 | struct list_head *nondata, int *min) |
| 244 | { | 244 | { |
| 245 | int err; | ||
| 245 | struct ubifs_scan_node *snod, *tmp; | 246 | struct ubifs_scan_node *snod, *tmp; |
| 246 | 247 | ||
| 247 | *min = INT_MAX; | 248 | *min = INT_MAX; |
