diff options
author | Josef Bacik <josef@redhat.com> | 2010-06-21 14:48:16 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2010-10-28 15:59:09 -0400 |
commit | 0af3d00bad38d3bb9912a60928ad0669f17bdb76 (patch) | |
tree | abbf4c773138a33dcde483ac60f016c4b5e55dcc /fs/btrfs/inode.c | |
parent | f6f94e2ab1b33f0082ac22d71f66385a60d8157f (diff) |
Btrfs: create special free space cache inode
In order to save free space cache, we need an inode to hold the data, and we
need a special item to point at the right inode for the right block group. So
first, create a special item that will point to the right inode, and the number
of extent entries we will have and the number of bitmaps we will have. We
truncate and pre-allocate space everytime to make sure it's uptodate.
This feature will be turned on as soon as you mount with -o space_cache, however
it is safe to boot into old kernels, they will just generate the cache the old
fashion way. When you boot back into a newer kernel we will notice that we
modified and not the cache and automatically discard the cache.
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c03864406af3..1af1ea88e8a8 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1700,6 +1700,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1700 | ordered_extent->len); | 1700 | ordered_extent->len); |
1701 | BUG_ON(ret); | 1701 | BUG_ON(ret); |
1702 | } else { | 1702 | } else { |
1703 | BUG_ON(root == root->fs_info->tree_root); | ||
1703 | ret = insert_reserved_file_extent(trans, inode, | 1704 | ret = insert_reserved_file_extent(trans, inode, |
1704 | ordered_extent->file_offset, | 1705 | ordered_extent->file_offset, |
1705 | ordered_extent->start, | 1706 | ordered_extent->start, |
@@ -3196,7 +3197,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
3196 | 3197 | ||
3197 | BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); | 3198 | BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); |
3198 | 3199 | ||
3199 | if (root->ref_cows) | 3200 | if (root->ref_cows || root == root->fs_info->tree_root) |
3200 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); | 3201 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); |
3201 | 3202 | ||
3202 | path = btrfs_alloc_path(); | 3203 | path = btrfs_alloc_path(); |
@@ -3344,7 +3345,8 @@ delete: | |||
3344 | } else { | 3345 | } else { |
3345 | break; | 3346 | break; |
3346 | } | 3347 | } |
3347 | if (found_extent && root->ref_cows) { | 3348 | if (found_extent && (root->ref_cows || |
3349 | root == root->fs_info->tree_root)) { | ||
3348 | btrfs_set_path_blocking(path); | 3350 | btrfs_set_path_blocking(path); |
3349 | ret = btrfs_free_extent(trans, root, extent_start, | 3351 | ret = btrfs_free_extent(trans, root, extent_start, |
3350 | extent_num_bytes, 0, | 3352 | extent_num_bytes, 0, |
@@ -3675,7 +3677,8 @@ void btrfs_evict_inode(struct inode *inode) | |||
3675 | int ret; | 3677 | int ret; |
3676 | 3678 | ||
3677 | truncate_inode_pages(&inode->i_data, 0); | 3679 | truncate_inode_pages(&inode->i_data, 0); |
3678 | if (inode->i_nlink && btrfs_root_refs(&root->root_item) != 0) | 3680 | if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 || |
3681 | root == root->fs_info->tree_root)) | ||
3679 | goto no_delete; | 3682 | goto no_delete; |
3680 | 3683 | ||
3681 | if (is_bad_inode(inode)) { | 3684 | if (is_bad_inode(inode)) { |
@@ -3888,7 +3891,14 @@ static void inode_tree_del(struct inode *inode) | |||
3888 | } | 3891 | } |
3889 | spin_unlock(&root->inode_lock); | 3892 | spin_unlock(&root->inode_lock); |
3890 | 3893 | ||
3891 | if (empty && btrfs_root_refs(&root->root_item) == 0) { | 3894 | /* |
3895 | * Free space cache has inodes in the tree root, but the tree root has a | ||
3896 | * root_refs of 0, so this could end up dropping the tree root as a | ||
3897 | * snapshot, so we need the extra !root->fs_info->tree_root check to | ||
3898 | * make sure we don't drop it. | ||
3899 | */ | ||
3900 | if (empty && btrfs_root_refs(&root->root_item) == 0 && | ||
3901 | root != root->fs_info->tree_root) { | ||
3892 | synchronize_srcu(&root->fs_info->subvol_srcu); | 3902 | synchronize_srcu(&root->fs_info->subvol_srcu); |
3893 | spin_lock(&root->inode_lock); | 3903 | spin_lock(&root->inode_lock); |
3894 | empty = RB_EMPTY_ROOT(&root->inode_tree); | 3904 | empty = RB_EMPTY_ROOT(&root->inode_tree); |
@@ -4282,14 +4292,24 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
4282 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4292 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4283 | struct btrfs_trans_handle *trans; | 4293 | struct btrfs_trans_handle *trans; |
4284 | int ret = 0; | 4294 | int ret = 0; |
4295 | bool nolock = false; | ||
4285 | 4296 | ||
4286 | if (BTRFS_I(inode)->dummy_inode) | 4297 | if (BTRFS_I(inode)->dummy_inode) |
4287 | return 0; | 4298 | return 0; |
4288 | 4299 | ||
4300 | smp_mb(); | ||
4301 | nolock = (root->fs_info->closing && root == root->fs_info->tree_root); | ||
4302 | |||
4289 | if (wbc->sync_mode == WB_SYNC_ALL) { | 4303 | if (wbc->sync_mode == WB_SYNC_ALL) { |
4290 | trans = btrfs_join_transaction(root, 1); | 4304 | if (nolock) |
4305 | trans = btrfs_join_transaction_nolock(root, 1); | ||
4306 | else | ||
4307 | trans = btrfs_join_transaction(root, 1); | ||
4291 | btrfs_set_trans_block_group(trans, inode); | 4308 | btrfs_set_trans_block_group(trans, inode); |
4292 | ret = btrfs_commit_transaction(trans, root); | 4309 | if (nolock) |
4310 | ret = btrfs_end_transaction_nolock(trans, root); | ||
4311 | else | ||
4312 | ret = btrfs_commit_transaction(trans, root); | ||
4293 | } | 4313 | } |
4294 | return ret; | 4314 | return ret; |
4295 | } | 4315 | } |
@@ -6308,6 +6328,21 @@ void btrfs_destroy_inode(struct inode *inode) | |||
6308 | spin_unlock(&root->fs_info->ordered_extent_lock); | 6328 | spin_unlock(&root->fs_info->ordered_extent_lock); |
6309 | } | 6329 | } |
6310 | 6330 | ||
6331 | if (root == root->fs_info->tree_root) { | ||
6332 | struct btrfs_block_group_cache *block_group; | ||
6333 | |||
6334 | block_group = btrfs_lookup_block_group(root->fs_info, | ||
6335 | BTRFS_I(inode)->block_group); | ||
6336 | if (block_group && block_group->inode == inode) { | ||
6337 | spin_lock(&block_group->lock); | ||
6338 | block_group->inode = NULL; | ||
6339 | spin_unlock(&block_group->lock); | ||
6340 | btrfs_put_block_group(block_group); | ||
6341 | } else if (block_group) { | ||
6342 | btrfs_put_block_group(block_group); | ||
6343 | } | ||
6344 | } | ||
6345 | |||
6311 | spin_lock(&root->orphan_lock); | 6346 | spin_lock(&root->orphan_lock); |
6312 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { | 6347 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { |
6313 | printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n", | 6348 | printk(KERN_INFO "BTRFS: inode %lu still on the orphan list\n", |
@@ -6340,7 +6375,8 @@ int btrfs_drop_inode(struct inode *inode) | |||
6340 | { | 6375 | { |
6341 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6376 | struct btrfs_root *root = BTRFS_I(inode)->root; |
6342 | 6377 | ||
6343 | if (btrfs_root_refs(&root->root_item) == 0) | 6378 | if (btrfs_root_refs(&root->root_item) == 0 && |
6379 | root != root->fs_info->tree_root) | ||
6344 | return 1; | 6380 | return 1; |
6345 | else | 6381 | else |
6346 | return generic_drop_inode(inode); | 6382 | return generic_drop_inode(inode); |
@@ -6757,27 +6793,33 @@ out_unlock: | |||
6757 | return err; | 6793 | return err; |
6758 | } | 6794 | } |
6759 | 6795 | ||
6760 | int btrfs_prealloc_file_range(struct inode *inode, int mode, | 6796 | static int __btrfs_prealloc_file_range(struct inode *inode, int mode, |
6761 | u64 start, u64 num_bytes, u64 min_size, | 6797 | u64 start, u64 num_bytes, u64 min_size, |
6762 | loff_t actual_len, u64 *alloc_hint) | 6798 | loff_t actual_len, u64 *alloc_hint, |
6799 | struct btrfs_trans_handle *trans) | ||
6763 | { | 6800 | { |
6764 | struct btrfs_trans_handle *trans; | ||
6765 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6801 | struct btrfs_root *root = BTRFS_I(inode)->root; |
6766 | struct btrfs_key ins; | 6802 | struct btrfs_key ins; |
6767 | u64 cur_offset = start; | 6803 | u64 cur_offset = start; |
6768 | int ret = 0; | 6804 | int ret = 0; |
6805 | bool own_trans = true; | ||
6769 | 6806 | ||
6807 | if (trans) | ||
6808 | own_trans = false; | ||
6770 | while (num_bytes > 0) { | 6809 | while (num_bytes > 0) { |
6771 | trans = btrfs_start_transaction(root, 3); | 6810 | if (own_trans) { |
6772 | if (IS_ERR(trans)) { | 6811 | trans = btrfs_start_transaction(root, 3); |
6773 | ret = PTR_ERR(trans); | 6812 | if (IS_ERR(trans)) { |
6774 | break; | 6813 | ret = PTR_ERR(trans); |
6814 | break; | ||
6815 | } | ||
6775 | } | 6816 | } |
6776 | 6817 | ||
6777 | ret = btrfs_reserve_extent(trans, root, num_bytes, min_size, | 6818 | ret = btrfs_reserve_extent(trans, root, num_bytes, min_size, |
6778 | 0, *alloc_hint, (u64)-1, &ins, 1); | 6819 | 0, *alloc_hint, (u64)-1, &ins, 1); |
6779 | if (ret) { | 6820 | if (ret) { |
6780 | btrfs_end_transaction(trans, root); | 6821 | if (own_trans) |
6822 | btrfs_end_transaction(trans, root); | ||
6781 | break; | 6823 | break; |
6782 | } | 6824 | } |
6783 | 6825 | ||
@@ -6810,11 +6852,30 @@ int btrfs_prealloc_file_range(struct inode *inode, int mode, | |||
6810 | ret = btrfs_update_inode(trans, root, inode); | 6852 | ret = btrfs_update_inode(trans, root, inode); |
6811 | BUG_ON(ret); | 6853 | BUG_ON(ret); |
6812 | 6854 | ||
6813 | btrfs_end_transaction(trans, root); | 6855 | if (own_trans) |
6856 | btrfs_end_transaction(trans, root); | ||
6814 | } | 6857 | } |
6815 | return ret; | 6858 | return ret; |
6816 | } | 6859 | } |
6817 | 6860 | ||
6861 | int btrfs_prealloc_file_range(struct inode *inode, int mode, | ||
6862 | u64 start, u64 num_bytes, u64 min_size, | ||
6863 | loff_t actual_len, u64 *alloc_hint) | ||
6864 | { | ||
6865 | return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, | ||
6866 | min_size, actual_len, alloc_hint, | ||
6867 | NULL); | ||
6868 | } | ||
6869 | |||
6870 | int btrfs_prealloc_file_range_trans(struct inode *inode, | ||
6871 | struct btrfs_trans_handle *trans, int mode, | ||
6872 | u64 start, u64 num_bytes, u64 min_size, | ||
6873 | loff_t actual_len, u64 *alloc_hint) | ||
6874 | { | ||
6875 | return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, | ||
6876 | min_size, actual_len, alloc_hint, trans); | ||
6877 | } | ||
6878 | |||
6818 | static long btrfs_fallocate(struct inode *inode, int mode, | 6879 | static long btrfs_fallocate(struct inode *inode, int mode, |
6819 | loff_t offset, loff_t len) | 6880 | loff_t offset, loff_t len) |
6820 | { | 6881 | { |