aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-28 15:29:52 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commitec44a35cbeb26ab2da84cb280d778260f2312feb (patch)
treeafd48a9769125095922c931e3ad77f207c8fb025 /fs/btrfs/extent-tree.c
parent788f20eb5affef584e75ea84bb80a4c3352a2c0e (diff)
Btrfs: Add balance ioctl to restripe the chunks
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c106
1 files changed, 89 insertions, 17 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index fe4fe709c31..95aee5a2937 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -17,6 +17,7 @@
17 */ 17 */
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/pagemap.h> 19#include <linux/pagemap.h>
20#include <linux/writeback.h>
20#include "hash.h" 21#include "hash.h"
21#include "crc32c.h" 22#include "crc32c.h"
22#include "ctree.h" 23#include "ctree.h"
@@ -1058,6 +1059,26 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
1058 } 1059 }
1059} 1060}
1060 1061
1062static u64 reduce_alloc_profile(u64 flags)
1063{
1064 if ((flags & BTRFS_BLOCK_GROUP_DUP) &&
1065 (flags & (BTRFS_BLOCK_GROUP_RAID1 |
1066 BTRFS_BLOCK_GROUP_RAID10)))
1067 flags &= ~BTRFS_BLOCK_GROUP_DUP;
1068
1069 if ((flags & BTRFS_BLOCK_GROUP_RAID1) &&
1070 (flags & BTRFS_BLOCK_GROUP_RAID10))
1071 flags &= ~BTRFS_BLOCK_GROUP_RAID1;
1072
1073 if ((flags & BTRFS_BLOCK_GROUP_RAID0) &&
1074 ((flags & BTRFS_BLOCK_GROUP_RAID1) |
1075 (flags & BTRFS_BLOCK_GROUP_RAID10) |
1076 (flags & BTRFS_BLOCK_GROUP_DUP)))
1077 flags &= ~BTRFS_BLOCK_GROUP_RAID0;
1078 return flags;
1079}
1080
1081
1061static int do_chunk_alloc(struct btrfs_trans_handle *trans, 1082static int do_chunk_alloc(struct btrfs_trans_handle *trans,
1062 struct btrfs_root *extent_root, u64 alloc_bytes, 1083 struct btrfs_root *extent_root, u64 alloc_bytes,
1063 u64 flags) 1084 u64 flags)
@@ -1068,6 +1089,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
1068 u64 num_bytes; 1089 u64 num_bytes;
1069 int ret; 1090 int ret;
1070 1091
1092 flags = reduce_alloc_profile(flags);
1093
1071 space_info = __find_space_info(extent_root->fs_info, flags); 1094 space_info = __find_space_info(extent_root->fs_info, flags);
1072 if (!space_info) { 1095 if (!space_info) {
1073 ret = update_space_info(extent_root->fs_info, flags, 1096 ret = update_space_info(extent_root->fs_info, flags,
@@ -1684,6 +1707,7 @@ enospc:
1684error: 1707error:
1685 return ret; 1708 return ret;
1686} 1709}
1710
1687/* 1711/*
1688 * finds a free extent and does all the dirty work required for allocation 1712 * finds a free extent and does all the dirty work required for allocation
1689 * returns the key for the extent through ins, and a tree buffer for 1713 * returns the key for the extent through ins, and a tree buffer for
@@ -1697,7 +1721,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
1697 u64 root_objectid, u64 ref_generation, 1721 u64 root_objectid, u64 ref_generation,
1698 u64 owner, u64 owner_offset, 1722 u64 owner, u64 owner_offset,
1699 u64 empty_size, u64 hint_byte, 1723 u64 empty_size, u64 hint_byte,
1700 u64 search_end, struct btrfs_key *ins, int data) 1724 u64 search_end, struct btrfs_key *ins, u64 data)
1701{ 1725{
1702 int ret; 1726 int ret;
1703 int pending_ret; 1727 int pending_ret;
@@ -1727,6 +1751,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
1727 data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; 1751 data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
1728 } 1752 }
1729again: 1753again:
1754 data = reduce_alloc_profile(data);
1730 if (root->ref_cows) { 1755 if (root->ref_cows) {
1731 if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { 1756 if (!(data & BTRFS_BLOCK_GROUP_METADATA)) {
1732 ret = do_chunk_alloc(trans, root->fs_info->extent_root, 1757 ret = do_chunk_alloc(trans, root->fs_info->extent_root,
@@ -1752,6 +1777,9 @@ again:
1752 num_bytes = max(num_bytes, min_alloc_size); 1777 num_bytes = max(num_bytes, min_alloc_size);
1753 goto again; 1778 goto again;
1754 } 1779 }
1780 if (ret) {
1781 printk("allocation failed flags %Lu\n", data);
1782 }
1755 BUG_ON(ret); 1783 BUG_ON(ret);
1756 if (ret) 1784 if (ret)
1757 return ret; 1785 return ret;
@@ -2274,8 +2302,6 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
2274{ 2302{
2275 u64 page_start; 2303 u64 page_start;
2276 u64 page_end; 2304 u64 page_end;
2277 u64 delalloc_start;
2278 u64 existing_delalloc;
2279 unsigned long last_index; 2305 unsigned long last_index;
2280 unsigned long i; 2306 unsigned long i;
2281 struct page *page; 2307 struct page *page;
@@ -2293,7 +2319,6 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
2293 ra_pages = BTRFS_I(inode)->root->fs_info->bdi.ra_pages; 2319 ra_pages = BTRFS_I(inode)->root->fs_info->bdi.ra_pages;
2294 2320
2295 file_ra_state_init(ra, inode->i_mapping); 2321 file_ra_state_init(ra, inode->i_mapping);
2296 kfree(ra);
2297 2322
2298 for (; i <= last_index; i++) { 2323 for (; i <= last_index; i++) {
2299 if (total_read % ra_pages == 0) { 2324 if (total_read % ra_pages == 0) {
@@ -2313,26 +2338,30 @@ static int noinline relocate_inode_pages(struct inode *inode, u64 start,
2313 goto out_unlock; 2338 goto out_unlock;
2314 } 2339 }
2315 } 2340 }
2341#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
2342 ClearPageDirty(page);
2343#else
2344 cancel_dirty_page(page, PAGE_CACHE_SIZE);
2345#endif
2346 wait_on_page_writeback(page);
2347 set_page_extent_mapped(page);
2316 page_start = (u64)page->index << PAGE_CACHE_SHIFT; 2348 page_start = (u64)page->index << PAGE_CACHE_SHIFT;
2317 page_end = page_start + PAGE_CACHE_SIZE - 1; 2349 page_end = page_start + PAGE_CACHE_SIZE - 1;
2318 2350
2319 lock_extent(io_tree, page_start, page_end, GFP_NOFS); 2351 lock_extent(io_tree, page_start, page_end, GFP_NOFS);
2320 2352
2321 delalloc_start = page_start; 2353 set_page_dirty(page);
2322 existing_delalloc = count_range_bits(io_tree,
2323 &delalloc_start, page_end,
2324 PAGE_CACHE_SIZE, EXTENT_DELALLOC);
2325
2326 set_extent_delalloc(io_tree, page_start, 2354 set_extent_delalloc(io_tree, page_start,
2327 page_end, GFP_NOFS); 2355 page_end, GFP_NOFS);
2328 2356
2329 unlock_extent(io_tree, page_start, page_end, GFP_NOFS); 2357 unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
2330 set_page_dirty(page);
2331 unlock_page(page); 2358 unlock_page(page);
2332 page_cache_release(page); 2359 page_cache_release(page);
2360 balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
2333 } 2361 }
2334 2362
2335out_unlock: 2363out_unlock:
2364 kfree(ra);
2336 mutex_unlock(&inode->i_mutex); 2365 mutex_unlock(&inode->i_mutex);
2337 return 0; 2366 return 0;
2338} 2367}
@@ -2397,8 +2426,6 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root,
2397 goto out; 2426 goto out;
2398 } 2427 }
2399 relocate_inode_pages(inode, ref_offset, extent_key->offset); 2428 relocate_inode_pages(inode, ref_offset, extent_key->offset);
2400 /* FIXME, data=ordered will help get rid of this */
2401 filemap_fdatawrite(inode->i_mapping);
2402 iput(inode); 2429 iput(inode);
2403 mutex_lock(&extent_root->fs_info->fs_mutex); 2430 mutex_lock(&extent_root->fs_info->fs_mutex);
2404 } else { 2431 } else {
@@ -2486,6 +2513,47 @@ out:
2486 return ret; 2513 return ret;
2487} 2514}
2488 2515
2516static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
2517{
2518 u64 num_devices;
2519 u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
2520 BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
2521
2522 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy);
2523 if (num_devices == 1) {
2524 stripped |= BTRFS_BLOCK_GROUP_DUP;
2525 stripped = flags & ~stripped;
2526
2527 /* turn raid0 into single device chunks */
2528 if (flags & BTRFS_BLOCK_GROUP_RAID0)
2529 return stripped;
2530
2531 /* turn mirroring into duplication */
2532 if (flags & (BTRFS_BLOCK_GROUP_RAID1 |
2533 BTRFS_BLOCK_GROUP_RAID10))
2534 return stripped | BTRFS_BLOCK_GROUP_DUP;
2535 return flags;
2536 } else {
2537 /* they already had raid on here, just return */
2538 if ((flags & BTRFS_BLOCK_GROUP_DUP) &&
2539 (flags & BTRFS_BLOCK_GROUP_RAID1)) {
2540 }
2541 if (flags & stripped)
2542 return flags;
2543
2544 stripped |= BTRFS_BLOCK_GROUP_DUP;
2545 stripped = flags & ~stripped;
2546
2547 /* switch duplicated blocks with raid1 */
2548 if (flags & BTRFS_BLOCK_GROUP_DUP)
2549 return stripped | BTRFS_BLOCK_GROUP_RAID1;
2550
2551 /* turn single device chunks into raid0 */
2552 return stripped | BTRFS_BLOCK_GROUP_RAID0;
2553 }
2554 return flags;
2555}
2556
2489int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) 2557int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
2490{ 2558{
2491 struct btrfs_trans_handle *trans; 2559 struct btrfs_trans_handle *trans;
@@ -2494,6 +2562,7 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
2494 u64 cur_byte; 2562 u64 cur_byte;
2495 u64 total_found; 2563 u64 total_found;
2496 u64 shrink_last_byte; 2564 u64 shrink_last_byte;
2565 u64 new_alloc_flags;
2497 struct btrfs_block_group_cache *shrink_block_group; 2566 struct btrfs_block_group_cache *shrink_block_group;
2498 struct btrfs_fs_info *info = root->fs_info; 2567 struct btrfs_fs_info *info = root->fs_info;
2499 struct btrfs_key key; 2568 struct btrfs_key key;
@@ -2511,17 +2580,20 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start)
2511 2580
2512 shrink_block_group->space_info->total_bytes -= 2581 shrink_block_group->space_info->total_bytes -=
2513 shrink_block_group->key.offset; 2582 shrink_block_group->key.offset;
2514printk("shrink_extent_tree %Lu -> %Lu type %Lu\n", shrink_start, shrink_last_byte, shrink_block_group->flags);
2515 path = btrfs_alloc_path(); 2583 path = btrfs_alloc_path();
2516 root = root->fs_info->extent_root; 2584 root = root->fs_info->extent_root;
2517 path->reada = 2; 2585 path->reada = 2;
2518 2586
2519again: 2587again:
2520 trans = btrfs_start_transaction(root, 1); 2588 if (btrfs_block_group_used(&shrink_block_group->item) > 0) {
2521 do_chunk_alloc(trans, root->fs_info->extent_root, 2589 trans = btrfs_start_transaction(root, 1);
2590 new_alloc_flags = update_block_group_flags(root,
2591 shrink_block_group->flags);
2592 do_chunk_alloc(trans, root->fs_info->extent_root,
2522 btrfs_block_group_used(&shrink_block_group->item) + 2593 btrfs_block_group_used(&shrink_block_group->item) +
2523 2 * 1024 * 1024, shrink_block_group->flags); 2594 2 * 1024 * 1024, new_alloc_flags);
2524 btrfs_end_transaction(trans, root); 2595 btrfs_end_transaction(trans, root);
2596 }
2525 shrink_block_group->ro = 1; 2597 shrink_block_group->ro = 1;
2526 2598
2527 total_found = 0; 2599 total_found = 0;