diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2013-10-28 22:45:05 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-11-11 22:11:00 -0500 |
commit | 6f519564d7d978c00351d9ab6abac3deeac31621 (patch) | |
tree | ad6219309aee3a44248fb7f7eb9756fc76423d79 | |
parent | 269d040ff2f340e1ed517dab8b66b2f133c83a77 (diff) |
Btrfs: do not run snapshot-aware defragment on error
If something wrong happens in write endio, running snapshot-aware defragment
can end up with undefined results, maybe a crash, so we should avoid it.
In order to share similar code, this also adds a helper to free the struct for
snapshot-aware defrag.
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
-rw-r--r-- | fs/btrfs/inode.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c84adde53023..17800221978f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2365,10 +2365,23 @@ out_unlock: | |||
2365 | return ret; | 2365 | return ret; |
2366 | } | 2366 | } |
2367 | 2367 | ||
2368 | static void free_sa_defrag_extent(struct new_sa_defrag_extent *new) | ||
2369 | { | ||
2370 | struct old_sa_defrag_extent *old, *tmp; | ||
2371 | |||
2372 | if (!new) | ||
2373 | return; | ||
2374 | |||
2375 | list_for_each_entry_safe(old, tmp, &new->head, list) { | ||
2376 | list_del(&old->list); | ||
2377 | kfree(old); | ||
2378 | } | ||
2379 | kfree(new); | ||
2380 | } | ||
2381 | |||
2368 | static void relink_file_extents(struct new_sa_defrag_extent *new) | 2382 | static void relink_file_extents(struct new_sa_defrag_extent *new) |
2369 | { | 2383 | { |
2370 | struct btrfs_path *path; | 2384 | struct btrfs_path *path; |
2371 | struct old_sa_defrag_extent *old, *tmp; | ||
2372 | struct sa_defrag_extent_backref *backref; | 2385 | struct sa_defrag_extent_backref *backref; |
2373 | struct sa_defrag_extent_backref *prev = NULL; | 2386 | struct sa_defrag_extent_backref *prev = NULL; |
2374 | struct inode *inode; | 2387 | struct inode *inode; |
@@ -2411,16 +2424,11 @@ static void relink_file_extents(struct new_sa_defrag_extent *new) | |||
2411 | kfree(prev); | 2424 | kfree(prev); |
2412 | 2425 | ||
2413 | btrfs_free_path(path); | 2426 | btrfs_free_path(path); |
2414 | |||
2415 | list_for_each_entry_safe(old, tmp, &new->head, list) { | ||
2416 | list_del(&old->list); | ||
2417 | kfree(old); | ||
2418 | } | ||
2419 | out: | 2427 | out: |
2428 | free_sa_defrag_extent(new); | ||
2429 | |||
2420 | atomic_dec(&root->fs_info->defrag_running); | 2430 | atomic_dec(&root->fs_info->defrag_running); |
2421 | wake_up(&root->fs_info->transaction_wait); | 2431 | wake_up(&root->fs_info->transaction_wait); |
2422 | |||
2423 | kfree(new); | ||
2424 | } | 2432 | } |
2425 | 2433 | ||
2426 | static struct new_sa_defrag_extent * | 2434 | static struct new_sa_defrag_extent * |
@@ -2430,7 +2438,7 @@ record_old_file_extents(struct inode *inode, | |||
2430 | struct btrfs_root *root = BTRFS_I(inode)->root; | 2438 | struct btrfs_root *root = BTRFS_I(inode)->root; |
2431 | struct btrfs_path *path; | 2439 | struct btrfs_path *path; |
2432 | struct btrfs_key key; | 2440 | struct btrfs_key key; |
2433 | struct old_sa_defrag_extent *old, *tmp; | 2441 | struct old_sa_defrag_extent *old; |
2434 | struct new_sa_defrag_extent *new; | 2442 | struct new_sa_defrag_extent *new; |
2435 | int ret; | 2443 | int ret; |
2436 | 2444 | ||
@@ -2478,7 +2486,7 @@ record_old_file_extents(struct inode *inode, | |||
2478 | if (slot >= btrfs_header_nritems(l)) { | 2486 | if (slot >= btrfs_header_nritems(l)) { |
2479 | ret = btrfs_next_leaf(root, path); | 2487 | ret = btrfs_next_leaf(root, path); |
2480 | if (ret < 0) | 2488 | if (ret < 0) |
2481 | goto out_free_list; | 2489 | goto out_free_path; |
2482 | else if (ret > 0) | 2490 | else if (ret > 0) |
2483 | break; | 2491 | break; |
2484 | continue; | 2492 | continue; |
@@ -2507,7 +2515,7 @@ record_old_file_extents(struct inode *inode, | |||
2507 | 2515 | ||
2508 | old = kmalloc(sizeof(*old), GFP_NOFS); | 2516 | old = kmalloc(sizeof(*old), GFP_NOFS); |
2509 | if (!old) | 2517 | if (!old) |
2510 | goto out_free_list; | 2518 | goto out_free_path; |
2511 | 2519 | ||
2512 | offset = max(new->file_pos, key.offset); | 2520 | offset = max(new->file_pos, key.offset); |
2513 | end = min(new->file_pos + new->len, key.offset + num_bytes); | 2521 | end = min(new->file_pos + new->len, key.offset + num_bytes); |
@@ -2529,15 +2537,10 @@ next: | |||
2529 | 2537 | ||
2530 | return new; | 2538 | return new; |
2531 | 2539 | ||
2532 | out_free_list: | ||
2533 | list_for_each_entry_safe(old, tmp, &new->head, list) { | ||
2534 | list_del(&old->list); | ||
2535 | kfree(old); | ||
2536 | } | ||
2537 | out_free_path: | 2540 | out_free_path: |
2538 | btrfs_free_path(path); | 2541 | btrfs_free_path(path); |
2539 | out_kfree: | 2542 | out_kfree: |
2540 | kfree(new); | 2543 | free_sa_defrag_extent(new); |
2541 | return NULL; | 2544 | return NULL; |
2542 | } | 2545 | } |
2543 | 2546 | ||
@@ -2708,8 +2711,14 @@ out: | |||
2708 | btrfs_remove_ordered_extent(inode, ordered_extent); | 2711 | btrfs_remove_ordered_extent(inode, ordered_extent); |
2709 | 2712 | ||
2710 | /* for snapshot-aware defrag */ | 2713 | /* for snapshot-aware defrag */ |
2711 | if (new) | 2714 | if (new) { |
2712 | relink_file_extents(new); | 2715 | if (ret) { |
2716 | free_sa_defrag_extent(new); | ||
2717 | atomic_dec(&root->fs_info->defrag_running); | ||
2718 | } else { | ||
2719 | relink_file_extents(new); | ||
2720 | } | ||
2721 | } | ||
2713 | 2722 | ||
2714 | /* once for us */ | 2723 | /* once for us */ |
2715 | btrfs_put_ordered_extent(ordered_extent); | 2724 | btrfs_put_ordered_extent(ordered_extent); |