diff options
Diffstat (limited to 'fs/ubifs/debug.c')
-rw-r--r-- | fs/ubifs/debug.c | 156 |
1 files changed, 156 insertions, 0 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) |