aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/relocation.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/relocation.c')
-rw-r--r--fs/btrfs/relocation.c90
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
2548static noinline_for_stack 2548static noinline_for_stack
2549int 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);
2587out:
2588 mutex_unlock(&inode->i_mutex);
2589 return ret;
2590}
2591
2592static noinline_for_stack
2549int setup_extent_mapping(struct inode *inode, u64 start, u64 end, 2593int 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);
2686out_unlock: 2727out:
2687 mutex_unlock(&inode->i_mutex);
2688 kfree(ra); 2728 kfree(ra);
2689 return ret; 2729 return ret;
2690} 2730}