diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-12-21 16:27:24 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | edbd8d4efe4ddaf29a175ae504e2c9a05a96ebee (patch) | |
tree | c5156fe3a75e97972186c9a933a631b258490a7e /fs/btrfs/inode.c | |
parent | 5d4fb734b4cb89a3902d6de309af0f6f3e63fe73 (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.c | 105 |
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 | ||
2349 | static unsigned long force_ra(struct address_space *mapping, | 2349 | unsigned 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 | ||
2435 | static 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 | |||
2502 | printk("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 | |||
2511 | out_unlock: | ||
2512 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2513 | out: | ||
2514 | kfree(vol_args); | ||
2515 | return ret; | ||
2516 | } | ||
2517 | |||
2421 | static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) | 2518 | static 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; |