aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-12-21 16:27:24 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:58 -0400
commitedbd8d4efe4ddaf29a175ae504e2c9a05a96ebee (patch)
treec5156fe3a75e97972186c9a933a631b258490a7e /fs/btrfs/inode.c
parent5d4fb734b4cb89a3902d6de309af0f6f3e63fe73 (diff)
Btrfs: Support for online FS resize (grow and shrink)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c105
1 files changed, 102 insertions, 3 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 5f5b7b89b144..f6a20112d9e7 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2346,7 +2346,7 @@ fail_unlock:
2346 return ret; 2346 return ret;
2347} 2347}
2348 2348
2349static unsigned long force_ra(struct address_space *mapping, 2349unsigned long btrfs_force_ra(struct address_space *mapping,
2350 struct file_ra_state *ra, struct file *file, 2350 struct file_ra_state *ra, struct file *file,
2351 pgoff_t offset, pgoff_t last_index) 2351 pgoff_t offset, pgoff_t last_index)
2352{ 2352{
@@ -2372,6 +2372,8 @@ int btrfs_defrag_file(struct file *file) {
2372 unsigned long ra_index = 0; 2372 unsigned long ra_index = 0;
2373 u64 page_start; 2373 u64 page_start;
2374 u64 page_end; 2374 u64 page_end;
2375 u64 delalloc_start;
2376 u64 existing_delalloc;
2375 unsigned long i; 2377 unsigned long i;
2376 int ret; 2378 int ret;
2377 2379
@@ -2385,8 +2387,9 @@ int btrfs_defrag_file(struct file *file) {
2385 last_index = inode->i_size >> PAGE_CACHE_SHIFT; 2387 last_index = inode->i_size >> PAGE_CACHE_SHIFT;
2386 for (i = 0; i <= last_index; i++) { 2388 for (i = 0; i <= last_index; i++) {
2387 if (i == ra_index) { 2389 if (i == ra_index) {
2388 ra_index = force_ra(inode->i_mapping, &file->f_ra, 2390 ra_index = btrfs_force_ra(inode->i_mapping,
2389 file, ra_index, last_index); 2391 &file->f_ra,
2392 file, ra_index, last_index);
2390 } 2393 }
2391 page = grab_cache_page(inode->i_mapping, i); 2394 page = grab_cache_page(inode->i_mapping, i);
2392 if (!page) 2395 if (!page)
@@ -2404,8 +2407,19 @@ int btrfs_defrag_file(struct file *file) {
2404 page_end = page_start + PAGE_CACHE_SIZE - 1; 2407 page_end = page_start + PAGE_CACHE_SIZE - 1;
2405 2408
2406 lock_extent(em_tree, page_start, page_end, GFP_NOFS); 2409 lock_extent(em_tree, page_start, page_end, GFP_NOFS);
2410 delalloc_start = page_start;
2411 existing_delalloc =
2412 count_range_bits(&BTRFS_I(inode)->extent_tree,
2413 &delalloc_start, page_end,
2414 PAGE_CACHE_SIZE, EXTENT_DELALLOC);
2407 set_extent_delalloc(em_tree, page_start, 2415 set_extent_delalloc(em_tree, page_start,
2408 page_end, GFP_NOFS); 2416 page_end, GFP_NOFS);
2417
2418 spin_lock(&root->fs_info->delalloc_lock);
2419 root->fs_info->delalloc_bytes += PAGE_CACHE_SIZE -
2420 existing_delalloc;
2421 spin_unlock(&root->fs_info->delalloc_lock);
2422
2409 unlock_extent(em_tree, page_start, page_end, GFP_NOFS); 2423 unlock_extent(em_tree, page_start, page_end, GFP_NOFS);
2410 set_page_dirty(page); 2424 set_page_dirty(page);
2411 unlock_page(page); 2425 unlock_page(page);
@@ -2418,6 +2432,89 @@ out_unlock:
2418 return 0; 2432 return 0;
2419} 2433}
2420 2434
2435static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
2436{
2437 u64 new_size;
2438 u64 old_size;
2439 struct btrfs_ioctl_vol_args *vol_args;
2440 struct btrfs_trans_handle *trans;
2441 char *sizestr;
2442 int ret = 0;
2443 int namelen;
2444 int mod = 0;
2445
2446 vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
2447
2448 if (!vol_args)
2449 return -ENOMEM;
2450
2451 if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
2452 ret = -EFAULT;
2453 goto out;
2454 }
2455 namelen = strlen(vol_args->name);
2456 if (namelen > BTRFS_VOL_NAME_MAX) {
2457 ret = -EINVAL;
2458 goto out;
2459 }
2460
2461 sizestr = vol_args->name;
2462 if (!strcmp(sizestr, "max"))
2463 new_size = root->fs_info->sb->s_bdev->bd_inode->i_size;
2464 else {
2465 if (sizestr[0] == '-') {
2466 mod = -1;
2467 sizestr++;
2468 } else if (sizestr[0] == '+') {
2469 mod = 1;
2470 sizestr++;
2471 }
2472 new_size = btrfs_parse_size(sizestr);
2473 if (new_size == 0) {
2474 ret = -EINVAL;
2475 goto out;
2476 }
2477 }
2478
2479 mutex_lock(&root->fs_info->fs_mutex);
2480 old_size = btrfs_super_total_bytes(&root->fs_info->super_copy);
2481
2482 if (mod < 0) {
2483 if (new_size > old_size) {
2484 ret = -EINVAL;
2485 goto out_unlock;
2486 }
2487 new_size = old_size - new_size;
2488 } else if (mod > 0) {
2489 new_size = old_size + new_size;
2490 }
2491
2492 if (new_size < 256 * 1024 * 1024) {
2493 ret = -EINVAL;
2494 goto out_unlock;
2495 }
2496 if (new_size > root->fs_info->sb->s_bdev->bd_inode->i_size) {
2497 ret = -EFBIG;
2498 goto out_unlock;
2499 }
2500 new_size = (new_size / root->sectorsize) * root->sectorsize;
2501
2502printk("new size is %Lu\n", new_size);
2503 if (new_size > old_size) {
2504 trans = btrfs_start_transaction(root, 1);
2505 ret = btrfs_grow_extent_tree(trans, root, new_size);
2506 btrfs_commit_transaction(trans, root);
2507 } else {
2508 ret = btrfs_shrink_extent_tree(root, new_size);
2509 }
2510
2511out_unlock:
2512 mutex_unlock(&root->fs_info->fs_mutex);
2513out:
2514 kfree(vol_args);
2515 return ret;
2516}
2517
2421static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) 2518static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg)
2422{ 2519{
2423 struct btrfs_ioctl_vol_args *vol_args; 2520 struct btrfs_ioctl_vol_args *vol_args;
@@ -2510,6 +2607,8 @@ long btrfs_ioctl(struct file *file, unsigned int
2510 return btrfs_ioctl_snap_create(root, (void __user *)arg); 2607 return btrfs_ioctl_snap_create(root, (void __user *)arg);
2511 case BTRFS_IOC_DEFRAG: 2608 case BTRFS_IOC_DEFRAG:
2512 return btrfs_ioctl_defrag(file); 2609 return btrfs_ioctl_defrag(file);
2610 case BTRFS_IOC_RESIZE:
2611 return btrfs_ioctl_resize(root, (void __user *)arg);
2513 } 2612 }
2514 2613
2515 return -ENOTTY; 2614 return -ENOTTY;