diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:49:58 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:52 -0400 |
commit | 8929ecfa50f266163832eeacfbc3642ed5eb83b6 (patch) | |
tree | e0177748af36d49d5f652cff0e421a8268cf7194 /fs | |
parent | 0ca1f7ceb1991099ed5273885ebcf4323948c72e (diff) |
Btrfs: Introduce global metadata reservation
Reserve metadata space for extent tree, checksum tree and root tree
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 8 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 59 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 147 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 13 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 10 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 70 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 3 | ||||
-rw-r--r-- | fs/btrfs/tree-defrag.c | 7 |
8 files changed, 241 insertions, 76 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d4744192eada..504d5daf2f1c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -683,21 +683,15 @@ struct btrfs_space_info { | |||
683 | u64 bytes_reserved; /* total bytes the allocator has reserved for | 683 | u64 bytes_reserved; /* total bytes the allocator has reserved for |
684 | current allocations */ | 684 | current allocations */ |
685 | u64 bytes_readonly; /* total bytes that are read only */ | 685 | u64 bytes_readonly; /* total bytes that are read only */ |
686 | u64 bytes_super; /* total bytes reserved for the super blocks */ | 686 | |
687 | u64 bytes_root; /* the number of bytes needed to commit a | ||
688 | transaction */ | ||
689 | u64 bytes_may_use; /* number of bytes that may be used for | 687 | u64 bytes_may_use; /* number of bytes that may be used for |
690 | delalloc/allocations */ | 688 | delalloc/allocations */ |
691 | u64 bytes_delalloc; /* number of bytes currently reserved for | ||
692 | delayed allocation */ | ||
693 | u64 disk_used; /* total bytes used on disk */ | 689 | u64 disk_used; /* total bytes used on disk */ |
694 | 690 | ||
695 | int full; /* indicates that we cannot allocate any more | 691 | int full; /* indicates that we cannot allocate any more |
696 | chunks for this space */ | 692 | chunks for this space */ |
697 | int force_alloc; /* set if we need to force a chunk alloc for | 693 | int force_alloc; /* set if we need to force a chunk alloc for |
698 | this space */ | 694 | this space */ |
699 | int force_delalloc; /* make people start doing filemap_flush until | ||
700 | we're under a threshold */ | ||
701 | 695 | ||
702 | struct list_head list; | 696 | struct list_head list; |
703 | 697 | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 054b4475c757..309d8c08a640 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1463,10 +1463,6 @@ static int cleaner_kthread(void *arg) | |||
1463 | struct btrfs_root *root = arg; | 1463 | struct btrfs_root *root = arg; |
1464 | 1464 | ||
1465 | do { | 1465 | do { |
1466 | smp_mb(); | ||
1467 | if (root->fs_info->closing) | ||
1468 | break; | ||
1469 | |||
1470 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | 1466 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); |
1471 | 1467 | ||
1472 | if (!(root->fs_info->sb->s_flags & MS_RDONLY) && | 1468 | if (!(root->fs_info->sb->s_flags & MS_RDONLY) && |
@@ -1479,11 +1475,9 @@ static int cleaner_kthread(void *arg) | |||
1479 | if (freezing(current)) { | 1475 | if (freezing(current)) { |
1480 | refrigerator(); | 1476 | refrigerator(); |
1481 | } else { | 1477 | } else { |
1482 | smp_mb(); | ||
1483 | if (root->fs_info->closing) | ||
1484 | break; | ||
1485 | set_current_state(TASK_INTERRUPTIBLE); | 1478 | set_current_state(TASK_INTERRUPTIBLE); |
1486 | schedule(); | 1479 | if (!kthread_should_stop()) |
1480 | schedule(); | ||
1487 | __set_current_state(TASK_RUNNING); | 1481 | __set_current_state(TASK_RUNNING); |
1488 | } | 1482 | } |
1489 | } while (!kthread_should_stop()); | 1483 | } while (!kthread_should_stop()); |
@@ -1495,36 +1489,40 @@ static int transaction_kthread(void *arg) | |||
1495 | struct btrfs_root *root = arg; | 1489 | struct btrfs_root *root = arg; |
1496 | struct btrfs_trans_handle *trans; | 1490 | struct btrfs_trans_handle *trans; |
1497 | struct btrfs_transaction *cur; | 1491 | struct btrfs_transaction *cur; |
1492 | u64 transid; | ||
1498 | unsigned long now; | 1493 | unsigned long now; |
1499 | unsigned long delay; | 1494 | unsigned long delay; |
1500 | int ret; | 1495 | int ret; |
1501 | 1496 | ||
1502 | do { | 1497 | do { |
1503 | smp_mb(); | ||
1504 | if (root->fs_info->closing) | ||
1505 | break; | ||
1506 | |||
1507 | delay = HZ * 30; | 1498 | delay = HZ * 30; |
1508 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | 1499 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); |
1509 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | 1500 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
1510 | 1501 | ||
1511 | mutex_lock(&root->fs_info->trans_mutex); | 1502 | spin_lock(&root->fs_info->new_trans_lock); |
1512 | cur = root->fs_info->running_transaction; | 1503 | cur = root->fs_info->running_transaction; |
1513 | if (!cur) { | 1504 | if (!cur) { |
1514 | mutex_unlock(&root->fs_info->trans_mutex); | 1505 | spin_unlock(&root->fs_info->new_trans_lock); |
1515 | goto sleep; | 1506 | goto sleep; |
1516 | } | 1507 | } |
1517 | 1508 | ||
1518 | now = get_seconds(); | 1509 | now = get_seconds(); |
1519 | if (now < cur->start_time || now - cur->start_time < 30) { | 1510 | if (!cur->blocked && |
1520 | mutex_unlock(&root->fs_info->trans_mutex); | 1511 | (now < cur->start_time || now - cur->start_time < 30)) { |
1512 | spin_unlock(&root->fs_info->new_trans_lock); | ||
1521 | delay = HZ * 5; | 1513 | delay = HZ * 5; |
1522 | goto sleep; | 1514 | goto sleep; |
1523 | } | 1515 | } |
1524 | mutex_unlock(&root->fs_info->trans_mutex); | 1516 | transid = cur->transid; |
1525 | trans = btrfs_join_transaction(root, 1); | 1517 | spin_unlock(&root->fs_info->new_trans_lock); |
1526 | ret = btrfs_commit_transaction(trans, root); | ||
1527 | 1518 | ||
1519 | trans = btrfs_join_transaction(root, 1); | ||
1520 | if (transid == trans->transid) { | ||
1521 | ret = btrfs_commit_transaction(trans, root); | ||
1522 | BUG_ON(ret); | ||
1523 | } else { | ||
1524 | btrfs_end_transaction(trans, root); | ||
1525 | } | ||
1528 | sleep: | 1526 | sleep: |
1529 | wake_up_process(root->fs_info->cleaner_kthread); | 1527 | wake_up_process(root->fs_info->cleaner_kthread); |
1530 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); | 1528 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); |
@@ -1532,10 +1530,10 @@ sleep: | |||
1532 | if (freezing(current)) { | 1530 | if (freezing(current)) { |
1533 | refrigerator(); | 1531 | refrigerator(); |
1534 | } else { | 1532 | } else { |
1535 | if (root->fs_info->closing) | ||
1536 | break; | ||
1537 | set_current_state(TASK_INTERRUPTIBLE); | 1533 | set_current_state(TASK_INTERRUPTIBLE); |
1538 | schedule_timeout(delay); | 1534 | if (!kthread_should_stop() && |
1535 | !btrfs_transaction_blocked(root->fs_info)) | ||
1536 | schedule_timeout(delay); | ||
1539 | __set_current_state(TASK_RUNNING); | 1537 | __set_current_state(TASK_RUNNING); |
1540 | } | 1538 | } |
1541 | } while (!kthread_should_stop()); | 1539 | } while (!kthread_should_stop()); |
@@ -1917,17 +1915,18 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1917 | 1915 | ||
1918 | csum_root->track_dirty = 1; | 1916 | csum_root->track_dirty = 1; |
1919 | 1917 | ||
1918 | fs_info->generation = generation; | ||
1919 | fs_info->last_trans_committed = generation; | ||
1920 | fs_info->data_alloc_profile = (u64)-1; | ||
1921 | fs_info->metadata_alloc_profile = (u64)-1; | ||
1922 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; | ||
1923 | |||
1920 | ret = btrfs_read_block_groups(extent_root); | 1924 | ret = btrfs_read_block_groups(extent_root); |
1921 | if (ret) { | 1925 | if (ret) { |
1922 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); | 1926 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); |
1923 | goto fail_block_groups; | 1927 | goto fail_block_groups; |
1924 | } | 1928 | } |
1925 | 1929 | ||
1926 | fs_info->generation = generation; | ||
1927 | fs_info->last_trans_committed = generation; | ||
1928 | fs_info->data_alloc_profile = (u64)-1; | ||
1929 | fs_info->metadata_alloc_profile = (u64)-1; | ||
1930 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; | ||
1931 | fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, | 1930 | fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, |
1932 | "btrfs-cleaner"); | 1931 | "btrfs-cleaner"); |
1933 | if (IS_ERR(fs_info->cleaner_kthread)) | 1932 | if (IS_ERR(fs_info->cleaner_kthread)) |
@@ -2430,15 +2429,15 @@ int close_ctree(struct btrfs_root *root) | |||
2430 | fs_info->closing = 1; | 2429 | fs_info->closing = 1; |
2431 | smp_mb(); | 2430 | smp_mb(); |
2432 | 2431 | ||
2433 | kthread_stop(root->fs_info->transaction_kthread); | ||
2434 | kthread_stop(root->fs_info->cleaner_kthread); | ||
2435 | |||
2436 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { | 2432 | if (!(fs_info->sb->s_flags & MS_RDONLY)) { |
2437 | ret = btrfs_commit_super(root); | 2433 | ret = btrfs_commit_super(root); |
2438 | if (ret) | 2434 | if (ret) |
2439 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); | 2435 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); |
2440 | } | 2436 | } |
2441 | 2437 | ||
2438 | kthread_stop(root->fs_info->transaction_kthread); | ||
2439 | kthread_stop(root->fs_info->cleaner_kthread); | ||
2440 | |||
2442 | fs_info->closing = 2; | 2441 | fs_info->closing = 2; |
2443 | smp_mb(); | 2442 | smp_mb(); |
2444 | 2443 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b1822e752b4a..cb814a71800d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2895,10 +2895,9 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) | |||
2895 | again: | 2895 | again: |
2896 | /* make sure we have enough space to handle the data first */ | 2896 | /* make sure we have enough space to handle the data first */ |
2897 | spin_lock(&data_sinfo->lock); | 2897 | spin_lock(&data_sinfo->lock); |
2898 | used = data_sinfo->bytes_used + data_sinfo->bytes_delalloc + | 2898 | used = data_sinfo->bytes_used + data_sinfo->bytes_reserved + |
2899 | data_sinfo->bytes_reserved + data_sinfo->bytes_pinned + | 2899 | data_sinfo->bytes_pinned + data_sinfo->bytes_readonly + |
2900 | data_sinfo->bytes_readonly + data_sinfo->bytes_may_use + | 2900 | data_sinfo->bytes_may_use; |
2901 | data_sinfo->bytes_super; | ||
2902 | 2901 | ||
2903 | if (used + bytes > data_sinfo->total_bytes) { | 2902 | if (used + bytes > data_sinfo->total_bytes) { |
2904 | struct btrfs_trans_handle *trans; | 2903 | struct btrfs_trans_handle *trans; |
@@ -2922,7 +2921,7 @@ alloc: | |||
2922 | bytes + 2 * 1024 * 1024, | 2921 | bytes + 2 * 1024 * 1024, |
2923 | alloc_target, 0); | 2922 | alloc_target, 0); |
2924 | btrfs_end_transaction(trans, root); | 2923 | btrfs_end_transaction(trans, root); |
2925 | if (ret) | 2924 | if (ret < 0) |
2926 | return ret; | 2925 | return ret; |
2927 | 2926 | ||
2928 | if (!data_sinfo) { | 2927 | if (!data_sinfo) { |
@@ -2945,11 +2944,10 @@ alloc: | |||
2945 | goto again; | 2944 | goto again; |
2946 | } | 2945 | } |
2947 | 2946 | ||
2948 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" | 2947 | printk(KERN_ERR "no space left, need %llu, %llu bytes_used, " |
2949 | ", %llu bytes_used, %llu bytes_reserved, " | 2948 | "%llu bytes_reserved, " "%llu bytes_pinned, " |
2950 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use " | 2949 | "%llu bytes_readonly, %llu may use %llu total\n", |
2951 | "%llu total\n", (unsigned long long)bytes, | 2950 | (unsigned long long)bytes, |
2952 | (unsigned long long)data_sinfo->bytes_delalloc, | ||
2953 | (unsigned long long)data_sinfo->bytes_used, | 2951 | (unsigned long long)data_sinfo->bytes_used, |
2954 | (unsigned long long)data_sinfo->bytes_reserved, | 2952 | (unsigned long long)data_sinfo->bytes_reserved, |
2955 | (unsigned long long)data_sinfo->bytes_pinned, | 2953 | (unsigned long long)data_sinfo->bytes_pinned, |
@@ -3464,6 +3462,91 @@ void btrfs_block_rsv_release(struct btrfs_root *root, | |||
3464 | block_rsv_release_bytes(block_rsv, global_rsv, num_bytes); | 3462 | block_rsv_release_bytes(block_rsv, global_rsv, num_bytes); |
3465 | } | 3463 | } |
3466 | 3464 | ||
3465 | /* | ||
3466 | * helper to calculate size of global block reservation. | ||
3467 | * the desired value is sum of space used by extent tree, | ||
3468 | * checksum tree and root tree | ||
3469 | */ | ||
3470 | static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) | ||
3471 | { | ||
3472 | struct btrfs_space_info *sinfo; | ||
3473 | u64 num_bytes; | ||
3474 | u64 meta_used; | ||
3475 | u64 data_used; | ||
3476 | int csum_size = btrfs_super_csum_size(&fs_info->super_copy); | ||
3477 | #if 0 | ||
3478 | /* | ||
3479 | * per tree used space accounting can be inaccuracy, so we | ||
3480 | * can't rely on it. | ||
3481 | */ | ||
3482 | spin_lock(&fs_info->extent_root->accounting_lock); | ||
3483 | num_bytes = btrfs_root_used(&fs_info->extent_root->root_item); | ||
3484 | spin_unlock(&fs_info->extent_root->accounting_lock); | ||
3485 | |||
3486 | spin_lock(&fs_info->csum_root->accounting_lock); | ||
3487 | num_bytes += btrfs_root_used(&fs_info->csum_root->root_item); | ||
3488 | spin_unlock(&fs_info->csum_root->accounting_lock); | ||
3489 | |||
3490 | spin_lock(&fs_info->tree_root->accounting_lock); | ||
3491 | num_bytes += btrfs_root_used(&fs_info->tree_root->root_item); | ||
3492 | spin_unlock(&fs_info->tree_root->accounting_lock); | ||
3493 | #endif | ||
3494 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA); | ||
3495 | spin_lock(&sinfo->lock); | ||
3496 | data_used = sinfo->bytes_used; | ||
3497 | spin_unlock(&sinfo->lock); | ||
3498 | |||
3499 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | ||
3500 | spin_lock(&sinfo->lock); | ||
3501 | meta_used = sinfo->bytes_used; | ||
3502 | spin_unlock(&sinfo->lock); | ||
3503 | |||
3504 | num_bytes = (data_used >> fs_info->sb->s_blocksize_bits) * | ||
3505 | csum_size * 2; | ||
3506 | num_bytes += div64_u64(data_used + meta_used, 50); | ||
3507 | |||
3508 | if (num_bytes * 3 > meta_used) | ||
3509 | num_bytes = div64_u64(meta_used, 3); | ||
3510 | |||
3511 | return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10); | ||
3512 | } | ||
3513 | |||
3514 | static void update_global_block_rsv(struct btrfs_fs_info *fs_info) | ||
3515 | { | ||
3516 | struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | ||
3517 | struct btrfs_space_info *sinfo = block_rsv->space_info; | ||
3518 | u64 num_bytes; | ||
3519 | |||
3520 | num_bytes = calc_global_metadata_size(fs_info); | ||
3521 | |||
3522 | spin_lock(&block_rsv->lock); | ||
3523 | spin_lock(&sinfo->lock); | ||
3524 | |||
3525 | block_rsv->size = num_bytes; | ||
3526 | |||
3527 | num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + | ||
3528 | sinfo->bytes_reserved + sinfo->bytes_readonly; | ||
3529 | |||
3530 | if (sinfo->total_bytes > num_bytes) { | ||
3531 | num_bytes = sinfo->total_bytes - num_bytes; | ||
3532 | block_rsv->reserved += num_bytes; | ||
3533 | sinfo->bytes_reserved += num_bytes; | ||
3534 | } | ||
3535 | |||
3536 | if (block_rsv->reserved >= block_rsv->size) { | ||
3537 | num_bytes = block_rsv->reserved - block_rsv->size; | ||
3538 | sinfo->bytes_reserved -= num_bytes; | ||
3539 | block_rsv->reserved = block_rsv->size; | ||
3540 | block_rsv->full = 1; | ||
3541 | } | ||
3542 | #if 0 | ||
3543 | printk(KERN_INFO"global block rsv size %llu reserved %llu\n", | ||
3544 | block_rsv->size, block_rsv->reserved); | ||
3545 | #endif | ||
3546 | spin_unlock(&sinfo->lock); | ||
3547 | spin_unlock(&block_rsv->lock); | ||
3548 | } | ||
3549 | |||
3467 | static void init_global_block_rsv(struct btrfs_fs_info *fs_info) | 3550 | static void init_global_block_rsv(struct btrfs_fs_info *fs_info) |
3468 | { | 3551 | { |
3469 | struct btrfs_space_info *space_info; | 3552 | struct btrfs_space_info *space_info; |
@@ -3473,11 +3556,36 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info) | |||
3473 | fs_info->chunk_block_rsv.priority = 10; | 3556 | fs_info->chunk_block_rsv.priority = 10; |
3474 | 3557 | ||
3475 | space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | 3558 | space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); |
3559 | fs_info->global_block_rsv.space_info = space_info; | ||
3560 | fs_info->global_block_rsv.priority = 10; | ||
3561 | fs_info->global_block_rsv.refill_used = 1; | ||
3562 | fs_info->delalloc_block_rsv.space_info = space_info; | ||
3476 | fs_info->trans_block_rsv.space_info = space_info; | 3563 | fs_info->trans_block_rsv.space_info = space_info; |
3477 | fs_info->empty_block_rsv.space_info = space_info; | 3564 | fs_info->empty_block_rsv.space_info = space_info; |
3478 | fs_info->empty_block_rsv.priority = 10; | 3565 | fs_info->empty_block_rsv.priority = 10; |
3479 | 3566 | ||
3567 | fs_info->extent_root->block_rsv = &fs_info->global_block_rsv; | ||
3568 | fs_info->csum_root->block_rsv = &fs_info->global_block_rsv; | ||
3569 | fs_info->dev_root->block_rsv = &fs_info->global_block_rsv; | ||
3570 | fs_info->tree_root->block_rsv = &fs_info->global_block_rsv; | ||
3480 | fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; | 3571 | fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; |
3572 | |||
3573 | btrfs_add_durable_block_rsv(fs_info, &fs_info->global_block_rsv); | ||
3574 | |||
3575 | btrfs_add_durable_block_rsv(fs_info, &fs_info->delalloc_block_rsv); | ||
3576 | |||
3577 | update_global_block_rsv(fs_info); | ||
3578 | } | ||
3579 | |||
3580 | static void release_global_block_rsv(struct btrfs_fs_info *fs_info) | ||
3581 | { | ||
3582 | block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1); | ||
3583 | WARN_ON(fs_info->delalloc_block_rsv.size > 0); | ||
3584 | WARN_ON(fs_info->delalloc_block_rsv.reserved > 0); | ||
3585 | WARN_ON(fs_info->trans_block_rsv.size > 0); | ||
3586 | WARN_ON(fs_info->trans_block_rsv.reserved > 0); | ||
3587 | WARN_ON(fs_info->chunk_block_rsv.size > 0); | ||
3588 | WARN_ON(fs_info->chunk_block_rsv.reserved > 0); | ||
3481 | } | 3589 | } |
3482 | 3590 | ||
3483 | static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items) | 3591 | static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items) |
@@ -3826,6 +3934,8 @@ int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, | |||
3826 | fs_info->pinned_extents = &fs_info->freed_extents[0]; | 3934 | fs_info->pinned_extents = &fs_info->freed_extents[0]; |
3827 | 3935 | ||
3828 | up_write(&fs_info->extent_commit_sem); | 3936 | up_write(&fs_info->extent_commit_sem); |
3937 | |||
3938 | update_global_block_rsv(fs_info); | ||
3829 | return 0; | 3939 | return 0; |
3830 | } | 3940 | } |
3831 | 3941 | ||
@@ -4818,19 +4928,16 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes, | |||
4818 | printk(KERN_INFO "space_info has %llu free, is %sfull\n", | 4928 | printk(KERN_INFO "space_info has %llu free, is %sfull\n", |
4819 | (unsigned long long)(info->total_bytes - info->bytes_used - | 4929 | (unsigned long long)(info->total_bytes - info->bytes_used - |
4820 | info->bytes_pinned - info->bytes_reserved - | 4930 | info->bytes_pinned - info->bytes_reserved - |
4821 | info->bytes_super), | 4931 | info->bytes_readonly), |
4822 | (info->full) ? "" : "not "); | 4932 | (info->full) ? "" : "not "); |
4823 | printk(KERN_INFO "space_info total=%llu, pinned=%llu, delalloc=%llu," | 4933 | printk(KERN_INFO "space_info total=%llu, used=%llu, pinned=%llu, " |
4824 | " may_use=%llu, used=%llu, root=%llu, super=%llu, reserved=%llu" | 4934 | "reserved=%llu, may_use=%llu, readonly=%llu\n", |
4825 | "\n", | ||
4826 | (unsigned long long)info->total_bytes, | 4935 | (unsigned long long)info->total_bytes, |
4936 | (unsigned long long)info->bytes_used, | ||
4827 | (unsigned long long)info->bytes_pinned, | 4937 | (unsigned long long)info->bytes_pinned, |
4828 | (unsigned long long)info->bytes_delalloc, | 4938 | (unsigned long long)info->bytes_reserved, |
4829 | (unsigned long long)info->bytes_may_use, | 4939 | (unsigned long long)info->bytes_may_use, |
4830 | (unsigned long long)info->bytes_used, | 4940 | (unsigned long long)info->bytes_readonly); |
4831 | (unsigned long long)info->bytes_root, | ||
4832 | (unsigned long long)info->bytes_super, | ||
4833 | (unsigned long long)info->bytes_reserved); | ||
4834 | spin_unlock(&info->lock); | 4941 | spin_unlock(&info->lock); |
4835 | 4942 | ||
4836 | if (!dump_block_groups) | 4943 | if (!dump_block_groups) |
@@ -7727,6 +7834,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
7727 | */ | 7834 | */ |
7728 | synchronize_rcu(); | 7835 | synchronize_rcu(); |
7729 | 7836 | ||
7837 | release_global_block_rsv(info); | ||
7838 | |||
7730 | while(!list_empty(&info->space_info)) { | 7839 | while(!list_empty(&info->space_info)) { |
7731 | space_info = list_entry(info->space_info.next, | 7840 | space_info = list_entry(info->space_info.next, |
7732 | struct btrfs_space_info, | 7841 | struct btrfs_space_info, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6e54665d37f7..f9c40b839452 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4060,7 +4060,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
4060 | struct btrfs_trans_handle *trans; | 4060 | struct btrfs_trans_handle *trans; |
4061 | int ret = 0; | 4061 | int ret = 0; |
4062 | 4062 | ||
4063 | if (root->fs_info->btree_inode == inode) | 4063 | if (BTRFS_I(inode)->dummy_inode) |
4064 | return 0; | 4064 | return 0; |
4065 | 4065 | ||
4066 | if (wbc->sync_mode == WB_SYNC_ALL) { | 4066 | if (wbc->sync_mode == WB_SYNC_ALL) { |
@@ -4081,10 +4081,19 @@ void btrfs_dirty_inode(struct inode *inode) | |||
4081 | { | 4081 | { |
4082 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4082 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4083 | struct btrfs_trans_handle *trans; | 4083 | struct btrfs_trans_handle *trans; |
4084 | int ret; | ||
4085 | |||
4086 | if (BTRFS_I(inode)->dummy_inode) | ||
4087 | return; | ||
4084 | 4088 | ||
4085 | trans = btrfs_join_transaction(root, 1); | 4089 | trans = btrfs_join_transaction(root, 1); |
4086 | btrfs_set_trans_block_group(trans, inode); | 4090 | btrfs_set_trans_block_group(trans, inode); |
4087 | btrfs_update_inode(trans, root, inode); | 4091 | |
4092 | ret = btrfs_update_inode(trans, root, inode); | ||
4093 | if (ret) | ||
4094 | printk(KERN_ERR"btrfs: fail to dirty inode %lu error %d\n", | ||
4095 | inode->i_ino, ret); | ||
4096 | |||
4088 | btrfs_end_transaction(trans, root); | 4097 | btrfs_end_transaction(trans, root); |
4089 | } | 4098 | } |
4090 | 4099 | ||
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 6a706e691377..a0686658a3f6 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1341,8 +1341,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
1341 | ret = -EPERM; | 1341 | ret = -EPERM; |
1342 | goto out; | 1342 | goto out; |
1343 | } | 1343 | } |
1344 | btrfs_defrag_root(root, 0); | 1344 | ret = btrfs_defrag_root(root, 0); |
1345 | btrfs_defrag_root(root->fs_info->extent_root, 0); | 1345 | if (ret) |
1346 | goto out; | ||
1347 | ret = btrfs_defrag_root(root->fs_info->extent_root, 0); | ||
1346 | break; | 1348 | break; |
1347 | case S_IFREG: | 1349 | case S_IFREG: |
1348 | if (!(file->f_mode & FMODE_WRITE)) { | 1350 | if (!(file->f_mode & FMODE_WRITE)) { |
@@ -1372,9 +1374,11 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
1372 | /* the rest are all set to zero by kzalloc */ | 1374 | /* the rest are all set to zero by kzalloc */ |
1373 | range->len = (u64)-1; | 1375 | range->len = (u64)-1; |
1374 | } | 1376 | } |
1375 | btrfs_defrag_file(file, range); | 1377 | ret = btrfs_defrag_file(file, range); |
1376 | kfree(range); | 1378 | kfree(range); |
1377 | break; | 1379 | break; |
1380 | default: | ||
1381 | ret = -EINVAL; | ||
1378 | } | 1382 | } |
1379 | out: | 1383 | out: |
1380 | mnt_drop_write(file->f_path.mnt); | 1384 | mnt_drop_write(file->f_path.mnt); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2616491a5c5b..6217bb6d516a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -321,10 +321,36 @@ void btrfs_throttle(struct btrfs_root *root) | |||
321 | mutex_unlock(&root->fs_info->trans_mutex); | 321 | mutex_unlock(&root->fs_info->trans_mutex); |
322 | } | 322 | } |
323 | 323 | ||
324 | static int should_end_transaction(struct btrfs_trans_handle *trans, | ||
325 | struct btrfs_root *root) | ||
326 | { | ||
327 | int ret; | ||
328 | ret = btrfs_block_rsv_check(trans, root, | ||
329 | &root->fs_info->global_block_rsv, 0, 5); | ||
330 | return ret ? 1 : 0; | ||
331 | } | ||
332 | |||
333 | int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | ||
334 | struct btrfs_root *root) | ||
335 | { | ||
336 | struct btrfs_transaction *cur_trans = trans->transaction; | ||
337 | int updates; | ||
338 | |||
339 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) | ||
340 | return 1; | ||
341 | |||
342 | updates = trans->delayed_ref_updates; | ||
343 | trans->delayed_ref_updates = 0; | ||
344 | if (updates) | ||
345 | btrfs_run_delayed_refs(trans, root, updates); | ||
346 | |||
347 | return should_end_transaction(trans, root); | ||
348 | } | ||
349 | |||
324 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | 350 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, |
325 | struct btrfs_root *root, int throttle) | 351 | struct btrfs_root *root, int throttle) |
326 | { | 352 | { |
327 | struct btrfs_transaction *cur_trans; | 353 | struct btrfs_transaction *cur_trans = trans->transaction; |
328 | struct btrfs_fs_info *info = root->fs_info; | 354 | struct btrfs_fs_info *info = root->fs_info; |
329 | int count = 0; | 355 | int count = 0; |
330 | 356 | ||
@@ -350,9 +376,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
350 | 376 | ||
351 | btrfs_trans_release_metadata(trans, root); | 377 | btrfs_trans_release_metadata(trans, root); |
352 | 378 | ||
379 | if (!root->fs_info->open_ioctl_trans && | ||
380 | should_end_transaction(trans, root)) | ||
381 | trans->transaction->blocked = 1; | ||
382 | |||
383 | if (cur_trans->blocked && !cur_trans->in_commit) { | ||
384 | if (throttle) | ||
385 | return btrfs_commit_transaction(trans, root); | ||
386 | else | ||
387 | wake_up_process(info->transaction_kthread); | ||
388 | } | ||
389 | |||
353 | mutex_lock(&info->trans_mutex); | 390 | mutex_lock(&info->trans_mutex); |
354 | cur_trans = info->running_transaction; | 391 | WARN_ON(cur_trans != info->running_transaction); |
355 | WARN_ON(cur_trans != trans->transaction); | ||
356 | WARN_ON(cur_trans->num_writers < 1); | 392 | WARN_ON(cur_trans->num_writers < 1); |
357 | cur_trans->num_writers--; | 393 | cur_trans->num_writers--; |
358 | 394 | ||
@@ -664,30 +700,30 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
664 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | 700 | int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) |
665 | { | 701 | { |
666 | struct btrfs_fs_info *info = root->fs_info; | 702 | struct btrfs_fs_info *info = root->fs_info; |
667 | int ret; | ||
668 | struct btrfs_trans_handle *trans; | 703 | struct btrfs_trans_handle *trans; |
704 | int ret; | ||
669 | unsigned long nr; | 705 | unsigned long nr; |
670 | 706 | ||
671 | smp_mb(); | 707 | if (xchg(&root->defrag_running, 1)) |
672 | if (root->defrag_running) | ||
673 | return 0; | 708 | return 0; |
674 | trans = btrfs_start_transaction(root, 1); | 709 | |
675 | while (1) { | 710 | while (1) { |
676 | root->defrag_running = 1; | 711 | trans = btrfs_start_transaction(root, 0); |
712 | if (IS_ERR(trans)) | ||
713 | return PTR_ERR(trans); | ||
714 | |||
677 | ret = btrfs_defrag_leaves(trans, root, cacheonly); | 715 | ret = btrfs_defrag_leaves(trans, root, cacheonly); |
716 | |||
678 | nr = trans->blocks_used; | 717 | nr = trans->blocks_used; |
679 | btrfs_end_transaction(trans, root); | 718 | btrfs_end_transaction(trans, root); |
680 | btrfs_btree_balance_dirty(info->tree_root, nr); | 719 | btrfs_btree_balance_dirty(info->tree_root, nr); |
681 | cond_resched(); | 720 | cond_resched(); |
682 | 721 | ||
683 | trans = btrfs_start_transaction(root, 1); | ||
684 | if (root->fs_info->closing || ret != -EAGAIN) | 722 | if (root->fs_info->closing || ret != -EAGAIN) |
685 | break; | 723 | break; |
686 | } | 724 | } |
687 | root->defrag_running = 0; | 725 | root->defrag_running = 0; |
688 | smp_mb(); | 726 | return ret; |
689 | btrfs_end_transaction(trans, root); | ||
690 | return 0; | ||
691 | } | 727 | } |
692 | 728 | ||
693 | #if 0 | 729 | #if 0 |
@@ -924,6 +960,16 @@ int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | |||
924 | return ret; | 960 | return ret; |
925 | } | 961 | } |
926 | 962 | ||
963 | int btrfs_transaction_blocked(struct btrfs_fs_info *info) | ||
964 | { | ||
965 | int ret = 0; | ||
966 | spin_lock(&info->new_trans_lock); | ||
967 | if (info->running_transaction) | ||
968 | ret = info->running_transaction->blocked; | ||
969 | spin_unlock(&info->new_trans_lock); | ||
970 | return ret; | ||
971 | } | ||
972 | |||
927 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 973 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
928 | struct btrfs_root *root) | 974 | struct btrfs_root *root) |
929 | { | 975 | { |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 14b3841b75d5..e104986d0bfd 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -106,6 +106,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
106 | struct btrfs_root *root); | 106 | struct btrfs_root *root); |
107 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | 107 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, |
108 | struct btrfs_root *root); | 108 | struct btrfs_root *root); |
109 | int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | ||
110 | struct btrfs_root *root); | ||
109 | void btrfs_throttle(struct btrfs_root *root); | 111 | void btrfs_throttle(struct btrfs_root *root); |
110 | int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, | 112 | int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, |
111 | struct btrfs_root *root); | 113 | struct btrfs_root *root); |
@@ -115,5 +117,6 @@ int btrfs_write_marked_extents(struct btrfs_root *root, | |||
115 | struct extent_io_tree *dirty_pages, int mark); | 117 | struct extent_io_tree *dirty_pages, int mark); |
116 | int btrfs_wait_marked_extents(struct btrfs_root *root, | 118 | int btrfs_wait_marked_extents(struct btrfs_root *root, |
117 | struct extent_io_tree *dirty_pages, int mark); | 119 | struct extent_io_tree *dirty_pages, int mark); |
120 | int btrfs_transaction_blocked(struct btrfs_fs_info *info); | ||
118 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); | 121 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); |
119 | #endif | 122 | #endif |
diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index b10eacdb1620..f7ac8e013ed7 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c | |||
@@ -117,13 +117,14 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | |||
117 | path->nodes[1], 0, | 117 | path->nodes[1], 0, |
118 | cache_only, &last_ret, | 118 | cache_only, &last_ret, |
119 | &root->defrag_progress); | 119 | &root->defrag_progress); |
120 | WARN_ON(ret && ret != -EAGAIN); | 120 | if (ret) { |
121 | WARN_ON(ret == -EAGAIN); | ||
122 | goto out; | ||
123 | } | ||
121 | if (next_key_ret == 0) { | 124 | if (next_key_ret == 0) { |
122 | memcpy(&root->defrag_progress, &key, sizeof(key)); | 125 | memcpy(&root->defrag_progress, &key, sizeof(key)); |
123 | ret = -EAGAIN; | 126 | ret = -EAGAIN; |
124 | } | 127 | } |
125 | |||
126 | btrfs_release_path(root, path); | ||
127 | out: | 128 | out: |
128 | if (path) | 129 | if (path) |
129 | btrfs_free_path(path); | 130 | btrfs_free_path(path); |