diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:49:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:53 -0400 |
commit | efa56464562991b8c24f965199888806bd8c4b38 (patch) | |
tree | e7c7e69e2931674ddf4f14ac08dfdf43b45de0f4 /fs/btrfs/inode.c | |
parent | 4a500fd178c89b96fa166a2d9e7855df33429841 (diff) |
Btrfs: Pre-allocate space for data relocation
Pre-allocate space for data relocation. This can detect ENOPSC
condition caused by fragmentation of free space.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 44 |
1 files changed, 24 insertions, 20 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index bef69bedf3cf..460dd512eebd 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1175,6 +1175,13 @@ out_check: | |||
1175 | num_bytes, num_bytes, type); | 1175 | num_bytes, num_bytes, type); |
1176 | BUG_ON(ret); | 1176 | BUG_ON(ret); |
1177 | 1177 | ||
1178 | if (root->root_key.objectid == | ||
1179 | BTRFS_DATA_RELOC_TREE_OBJECTID) { | ||
1180 | ret = btrfs_reloc_clone_csums(inode, cur_offset, | ||
1181 | num_bytes); | ||
1182 | BUG_ON(ret); | ||
1183 | } | ||
1184 | |||
1178 | extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, | 1185 | extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree, |
1179 | cur_offset, cur_offset + num_bytes - 1, | 1186 | cur_offset, cur_offset + num_bytes - 1, |
1180 | locked_page, EXTENT_CLEAR_UNLOCK_PAGE | | 1187 | locked_page, EXTENT_CLEAR_UNLOCK_PAGE | |
@@ -6080,16 +6087,15 @@ out_unlock: | |||
6080 | return err; | 6087 | return err; |
6081 | } | 6088 | } |
6082 | 6089 | ||
6083 | static int prealloc_file_range(struct inode *inode, u64 start, u64 end, | 6090 | int btrfs_prealloc_file_range(struct inode *inode, int mode, |
6084 | u64 alloc_hint, int mode, loff_t actual_len) | 6091 | u64 start, u64 num_bytes, u64 min_size, |
6092 | loff_t actual_len, u64 *alloc_hint) | ||
6085 | { | 6093 | { |
6086 | struct btrfs_trans_handle *trans; | 6094 | struct btrfs_trans_handle *trans; |
6087 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6095 | struct btrfs_root *root = BTRFS_I(inode)->root; |
6088 | struct btrfs_key ins; | 6096 | struct btrfs_key ins; |
6089 | u64 cur_offset = start; | 6097 | u64 cur_offset = start; |
6090 | u64 num_bytes = end - start; | ||
6091 | int ret = 0; | 6098 | int ret = 0; |
6092 | u64 i_size; | ||
6093 | 6099 | ||
6094 | while (num_bytes > 0) { | 6100 | while (num_bytes > 0) { |
6095 | trans = btrfs_start_transaction(root, 3); | 6101 | trans = btrfs_start_transaction(root, 3); |
@@ -6098,9 +6104,8 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end, | |||
6098 | break; | 6104 | break; |
6099 | } | 6105 | } |
6100 | 6106 | ||
6101 | ret = btrfs_reserve_extent(trans, root, num_bytes, | 6107 | ret = btrfs_reserve_extent(trans, root, num_bytes, min_size, |
6102 | root->sectorsize, 0, alloc_hint, | 6108 | 0, *alloc_hint, (u64)-1, &ins, 1); |
6103 | (u64)-1, &ins, 1); | ||
6104 | if (ret) { | 6109 | if (ret) { |
6105 | btrfs_end_transaction(trans, root); | 6110 | btrfs_end_transaction(trans, root); |
6106 | break; | 6111 | break; |
@@ -6117,20 +6122,19 @@ static int prealloc_file_range(struct inode *inode, u64 start, u64 end, | |||
6117 | 6122 | ||
6118 | num_bytes -= ins.offset; | 6123 | num_bytes -= ins.offset; |
6119 | cur_offset += ins.offset; | 6124 | cur_offset += ins.offset; |
6120 | alloc_hint = ins.objectid + ins.offset; | 6125 | *alloc_hint = ins.objectid + ins.offset; |
6121 | 6126 | ||
6122 | inode->i_ctime = CURRENT_TIME; | 6127 | inode->i_ctime = CURRENT_TIME; |
6123 | BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; | 6128 | BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; |
6124 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | 6129 | if (!(mode & FALLOC_FL_KEEP_SIZE) && |
6125 | (actual_len > inode->i_size) && | 6130 | (actual_len > inode->i_size) && |
6126 | (cur_offset > inode->i_size)) { | 6131 | (cur_offset > inode->i_size)) { |
6127 | |||
6128 | if (cur_offset > actual_len) | 6132 | if (cur_offset > actual_len) |
6129 | i_size = actual_len; | 6133 | i_size_write(inode, actual_len); |
6130 | else | 6134 | else |
6131 | i_size = cur_offset; | 6135 | i_size_write(inode, cur_offset); |
6132 | i_size_write(inode, i_size); | 6136 | i_size_write(inode, cur_offset); |
6133 | btrfs_ordered_update_i_size(inode, i_size, NULL); | 6137 | btrfs_ordered_update_i_size(inode, cur_offset, NULL); |
6134 | } | 6138 | } |
6135 | 6139 | ||
6136 | ret = btrfs_update_inode(trans, root, inode); | 6140 | ret = btrfs_update_inode(trans, root, inode); |
@@ -6216,16 +6220,16 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
6216 | if (em->block_start == EXTENT_MAP_HOLE || | 6220 | if (em->block_start == EXTENT_MAP_HOLE || |
6217 | (cur_offset >= inode->i_size && | 6221 | (cur_offset >= inode->i_size && |
6218 | !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { | 6222 | !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { |
6219 | ret = prealloc_file_range(inode, | 6223 | ret = btrfs_prealloc_file_range(inode, 0, cur_offset, |
6220 | cur_offset, last_byte, | 6224 | last_byte - cur_offset, |
6221 | alloc_hint, mode, offset+len); | 6225 | 1 << inode->i_blkbits, |
6226 | offset + len, | ||
6227 | &alloc_hint); | ||
6222 | if (ret < 0) { | 6228 | if (ret < 0) { |
6223 | free_extent_map(em); | 6229 | free_extent_map(em); |
6224 | break; | 6230 | break; |
6225 | } | 6231 | } |
6226 | } | 6232 | } |
6227 | if (em->block_start <= EXTENT_MAP_LAST_BYTE) | ||
6228 | alloc_hint = em->block_start; | ||
6229 | free_extent_map(em); | 6233 | free_extent_map(em); |
6230 | 6234 | ||
6231 | cur_offset = last_byte; | 6235 | cur_offset = last_byte; |