diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:49:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:53 -0400 |
commit | efa56464562991b8c24f965199888806bd8c4b38 (patch) | |
tree | e7c7e69e2931674ddf4f14ac08dfdf43b45de0f4 /fs/btrfs/relocation.c | |
parent | 4a500fd178c89b96fa166a2d9e7855df33429841 (diff) |
Btrfs: Pre-allocate space for data relocation
Pre-allocate space for data relocation. This can detect ENOPSC
condition caused by fragmentation of free space.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r-- | fs/btrfs/relocation.c | 90 |
1 files changed, 65 insertions, 25 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 145a468c300d..3943526b7348 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -2546,6 +2546,50 @@ out: | |||
2546 | } | 2546 | } |
2547 | 2547 | ||
2548 | static noinline_for_stack | 2548 | static noinline_for_stack |
2549 | int prealloc_file_extent_cluster(struct inode *inode, | ||
2550 | struct file_extent_cluster *cluster) | ||
2551 | { | ||
2552 | u64 alloc_hint = 0; | ||
2553 | u64 start; | ||
2554 | u64 end; | ||
2555 | u64 offset = BTRFS_I(inode)->index_cnt; | ||
2556 | u64 num_bytes; | ||
2557 | int nr = 0; | ||
2558 | int ret = 0; | ||
2559 | |||
2560 | BUG_ON(cluster->start != cluster->boundary[0]); | ||
2561 | mutex_lock(&inode->i_mutex); | ||
2562 | |||
2563 | ret = btrfs_check_data_free_space(inode, cluster->end + | ||
2564 | 1 - cluster->start); | ||
2565 | if (ret) | ||
2566 | goto out; | ||
2567 | |||
2568 | while (nr < cluster->nr) { | ||
2569 | start = cluster->boundary[nr] - offset; | ||
2570 | if (nr + 1 < cluster->nr) | ||
2571 | end = cluster->boundary[nr + 1] - 1 - offset; | ||
2572 | else | ||
2573 | end = cluster->end - offset; | ||
2574 | |||
2575 | lock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS); | ||
2576 | num_bytes = end + 1 - start; | ||
2577 | ret = btrfs_prealloc_file_range(inode, 0, start, | ||
2578 | num_bytes, num_bytes, | ||
2579 | end + 1, &alloc_hint); | ||
2580 | unlock_extent(&BTRFS_I(inode)->io_tree, start, end, GFP_NOFS); | ||
2581 | if (ret) | ||
2582 | break; | ||
2583 | nr++; | ||
2584 | } | ||
2585 | btrfs_free_reserved_data_space(inode, cluster->end + | ||
2586 | 1 - cluster->start); | ||
2587 | out: | ||
2588 | mutex_unlock(&inode->i_mutex); | ||
2589 | return ret; | ||
2590 | } | ||
2591 | |||
2592 | static noinline_for_stack | ||
2549 | int setup_extent_mapping(struct inode *inode, u64 start, u64 end, | 2593 | int setup_extent_mapping(struct inode *inode, u64 start, u64 end, |
2550 | u64 block_start) | 2594 | u64 block_start) |
2551 | { | 2595 | { |
@@ -2588,7 +2632,6 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2588 | u64 offset = BTRFS_I(inode)->index_cnt; | 2632 | u64 offset = BTRFS_I(inode)->index_cnt; |
2589 | unsigned long index; | 2633 | unsigned long index; |
2590 | unsigned long last_index; | 2634 | unsigned long last_index; |
2591 | unsigned int dirty_page = 0; | ||
2592 | struct page *page; | 2635 | struct page *page; |
2593 | struct file_ra_state *ra; | 2636 | struct file_ra_state *ra; |
2594 | int nr = 0; | 2637 | int nr = 0; |
@@ -2601,21 +2644,24 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2601 | if (!ra) | 2644 | if (!ra) |
2602 | return -ENOMEM; | 2645 | return -ENOMEM; |
2603 | 2646 | ||
2604 | index = (cluster->start - offset) >> PAGE_CACHE_SHIFT; | 2647 | ret = prealloc_file_extent_cluster(inode, cluster); |
2605 | last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT; | 2648 | if (ret) |
2649 | goto out; | ||
2606 | 2650 | ||
2607 | mutex_lock(&inode->i_mutex); | 2651 | file_ra_state_init(ra, inode->i_mapping); |
2608 | 2652 | ||
2609 | i_size_write(inode, cluster->end + 1 - offset); | ||
2610 | ret = setup_extent_mapping(inode, cluster->start - offset, | 2653 | ret = setup_extent_mapping(inode, cluster->start - offset, |
2611 | cluster->end - offset, cluster->start); | 2654 | cluster->end - offset, cluster->start); |
2612 | if (ret) | 2655 | if (ret) |
2613 | goto out_unlock; | 2656 | goto out; |
2614 | |||
2615 | file_ra_state_init(ra, inode->i_mapping); | ||
2616 | 2657 | ||
2617 | WARN_ON(cluster->start != cluster->boundary[0]); | 2658 | index = (cluster->start - offset) >> PAGE_CACHE_SHIFT; |
2659 | last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT; | ||
2618 | while (index <= last_index) { | 2660 | while (index <= last_index) { |
2661 | ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE); | ||
2662 | if (ret) | ||
2663 | goto out; | ||
2664 | |||
2619 | page = find_lock_page(inode->i_mapping, index); | 2665 | page = find_lock_page(inode->i_mapping, index); |
2620 | if (!page) { | 2666 | if (!page) { |
2621 | page_cache_sync_readahead(inode->i_mapping, | 2667 | page_cache_sync_readahead(inode->i_mapping, |
@@ -2623,8 +2669,10 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2623 | last_index + 1 - index); | 2669 | last_index + 1 - index); |
2624 | page = grab_cache_page(inode->i_mapping, index); | 2670 | page = grab_cache_page(inode->i_mapping, index); |
2625 | if (!page) { | 2671 | if (!page) { |
2672 | btrfs_delalloc_release_metadata(inode, | ||
2673 | PAGE_CACHE_SIZE); | ||
2626 | ret = -ENOMEM; | 2674 | ret = -ENOMEM; |
2627 | goto out_unlock; | 2675 | goto out; |
2628 | } | 2676 | } |
2629 | } | 2677 | } |
2630 | 2678 | ||
@@ -2640,8 +2688,10 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2640 | if (!PageUptodate(page)) { | 2688 | if (!PageUptodate(page)) { |
2641 | unlock_page(page); | 2689 | unlock_page(page); |
2642 | page_cache_release(page); | 2690 | page_cache_release(page); |
2691 | btrfs_delalloc_release_metadata(inode, | ||
2692 | PAGE_CACHE_SIZE); | ||
2643 | ret = -EIO; | 2693 | ret = -EIO; |
2644 | goto out_unlock; | 2694 | goto out; |
2645 | } | 2695 | } |
2646 | } | 2696 | } |
2647 | 2697 | ||
@@ -2660,10 +2710,9 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2660 | EXTENT_BOUNDARY, GFP_NOFS); | 2710 | EXTENT_BOUNDARY, GFP_NOFS); |
2661 | nr++; | 2711 | nr++; |
2662 | } | 2712 | } |
2663 | btrfs_set_extent_delalloc(inode, page_start, page_end, NULL); | ||
2664 | 2713 | ||
2714 | btrfs_set_extent_delalloc(inode, page_start, page_end, NULL); | ||
2665 | set_page_dirty(page); | 2715 | set_page_dirty(page); |
2666 | dirty_page++; | ||
2667 | 2716 | ||
2668 | unlock_extent(&BTRFS_I(inode)->io_tree, | 2717 | unlock_extent(&BTRFS_I(inode)->io_tree, |
2669 | page_start, page_end, GFP_NOFS); | 2718 | page_start, page_end, GFP_NOFS); |
@@ -2671,20 +2720,11 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
2671 | page_cache_release(page); | 2720 | page_cache_release(page); |
2672 | 2721 | ||
2673 | index++; | 2722 | index++; |
2674 | if (nr < cluster->nr && | 2723 | balance_dirty_pages_ratelimited(inode->i_mapping); |
2675 | page_end + 1 + offset == cluster->boundary[nr]) { | 2724 | btrfs_throttle(BTRFS_I(inode)->root); |
2676 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, | ||
2677 | dirty_page); | ||
2678 | dirty_page = 0; | ||
2679 | } | ||
2680 | } | ||
2681 | if (dirty_page) { | ||
2682 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, | ||
2683 | dirty_page); | ||
2684 | } | 2725 | } |
2685 | WARN_ON(nr != cluster->nr); | 2726 | WARN_ON(nr != cluster->nr); |
2686 | out_unlock: | 2727 | out: |
2687 | mutex_unlock(&inode->i_mutex); | ||
2688 | kfree(ra); | 2728 | kfree(ra); |
2689 | return ret; | 2729 | return ret; |
2690 | } | 2730 | } |