diff options
Diffstat (limited to 'fs/ocfs2/alloc.c')
-rw-r--r-- | fs/ocfs2/alloc.c | 150 |
1 files changed, 100 insertions, 50 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 75e65df34b69..14b9106849ca 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -5032,9 +5032,8 @@ out: | |||
5032 | } | 5032 | } |
5033 | 5033 | ||
5034 | /* | 5034 | /* |
5035 | * Mark part or all of the extent record at split_index in the leaf | 5035 | * Split part or all of the extent record at split_index in the leaf |
5036 | * pointed to by path as written. This removes the unwritten | 5036 | * pointed to by path. Merge with the contiguous extent record if needed. |
5037 | * extent flag. | ||
5038 | * | 5037 | * |
5039 | * Care is taken to handle contiguousness so as to not grow the tree. | 5038 | * Care is taken to handle contiguousness so as to not grow the tree. |
5040 | * | 5039 | * |
@@ -5051,13 +5050,13 @@ out: | |||
5051 | * have been brought into cache (and pinned via the journal), so the | 5050 | * have been brought into cache (and pinned via the journal), so the |
5052 | * extra overhead is not expressed in terms of disk reads. | 5051 | * extra overhead is not expressed in terms of disk reads. |
5053 | */ | 5052 | */ |
5054 | static int __ocfs2_mark_extent_written(handle_t *handle, | 5053 | static int __ocfs2_split_extent(handle_t *handle, |
5055 | struct ocfs2_extent_tree *et, | 5054 | struct ocfs2_extent_tree *et, |
5056 | struct ocfs2_path *path, | 5055 | struct ocfs2_path *path, |
5057 | int split_index, | 5056 | int split_index, |
5058 | struct ocfs2_extent_rec *split_rec, | 5057 | struct ocfs2_extent_rec *split_rec, |
5059 | struct ocfs2_alloc_context *meta_ac, | 5058 | struct ocfs2_alloc_context *meta_ac, |
5060 | struct ocfs2_cached_dealloc_ctxt *dealloc) | 5059 | struct ocfs2_cached_dealloc_ctxt *dealloc) |
5061 | { | 5060 | { |
5062 | int ret = 0; | 5061 | int ret = 0; |
5063 | struct ocfs2_extent_list *el = path_leaf_el(path); | 5062 | struct ocfs2_extent_list *el = path_leaf_el(path); |
@@ -5066,12 +5065,6 @@ static int __ocfs2_mark_extent_written(handle_t *handle, | |||
5066 | struct ocfs2_merge_ctxt ctxt; | 5065 | struct ocfs2_merge_ctxt ctxt; |
5067 | struct ocfs2_extent_list *rightmost_el; | 5066 | struct ocfs2_extent_list *rightmost_el; |
5068 | 5067 | ||
5069 | if (!(rec->e_flags & OCFS2_EXT_UNWRITTEN)) { | ||
5070 | ret = -EIO; | ||
5071 | mlog_errno(ret); | ||
5072 | goto out; | ||
5073 | } | ||
5074 | |||
5075 | if (le32_to_cpu(rec->e_cpos) > le32_to_cpu(split_rec->e_cpos) || | 5068 | if (le32_to_cpu(rec->e_cpos) > le32_to_cpu(split_rec->e_cpos) || |
5076 | ((le32_to_cpu(rec->e_cpos) + le16_to_cpu(rec->e_leaf_clusters)) < | 5069 | ((le32_to_cpu(rec->e_cpos) + le16_to_cpu(rec->e_leaf_clusters)) < |
5077 | (le32_to_cpu(split_rec->e_cpos) + le16_to_cpu(split_rec->e_leaf_clusters)))) { | 5070 | (le32_to_cpu(split_rec->e_cpos) + le16_to_cpu(split_rec->e_leaf_clusters)))) { |
@@ -5141,42 +5134,31 @@ out: | |||
5141 | } | 5134 | } |
5142 | 5135 | ||
5143 | /* | 5136 | /* |
5144 | * Mark the already-existing extent at cpos as written for len clusters. | 5137 | * Change the flags of the already-existing extent at cpos for len clusters. |
5138 | * | ||
5139 | * new_flags: the flags we want to set. | ||
5140 | * clear_flags: the flags we want to clear. | ||
5141 | * phys: the new physical offset we want this new extent starts from. | ||
5145 | * | 5142 | * |
5146 | * If the existing extent is larger than the request, initiate a | 5143 | * If the existing extent is larger than the request, initiate a |
5147 | * split. An attempt will be made at merging with adjacent extents. | 5144 | * split. An attempt will be made at merging with adjacent extents. |
5148 | * | 5145 | * |
5149 | * The caller is responsible for passing down meta_ac if we'll need it. | 5146 | * The caller is responsible for passing down meta_ac if we'll need it. |
5150 | */ | 5147 | */ |
5151 | int ocfs2_mark_extent_written(struct inode *inode, | 5148 | static int ocfs2_change_extent_flag(handle_t *handle, |
5152 | struct ocfs2_extent_tree *et, | 5149 | struct ocfs2_extent_tree *et, |
5153 | handle_t *handle, u32 cpos, u32 len, u32 phys, | 5150 | u32 cpos, u32 len, u32 phys, |
5154 | struct ocfs2_alloc_context *meta_ac, | 5151 | struct ocfs2_alloc_context *meta_ac, |
5155 | struct ocfs2_cached_dealloc_ctxt *dealloc) | 5152 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
5153 | int new_flags, int clear_flags) | ||
5156 | { | 5154 | { |
5157 | int ret, index; | 5155 | int ret, index; |
5158 | u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); | 5156 | struct super_block *sb = ocfs2_metadata_cache_get_super(et->et_ci); |
5157 | u64 start_blkno = ocfs2_clusters_to_blocks(sb, phys); | ||
5159 | struct ocfs2_extent_rec split_rec; | 5158 | struct ocfs2_extent_rec split_rec; |
5160 | struct ocfs2_path *left_path = NULL; | 5159 | struct ocfs2_path *left_path = NULL; |
5161 | struct ocfs2_extent_list *el; | 5160 | struct ocfs2_extent_list *el; |
5162 | 5161 | struct ocfs2_extent_rec *rec; | |
5163 | mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n", | ||
5164 | inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno); | ||
5165 | |||
5166 | if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { | ||
5167 | ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " | ||
5168 | "that are being written to, but the feature bit " | ||
5169 | "is not set in the super block.", | ||
5170 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
5171 | ret = -EROFS; | ||
5172 | goto out; | ||
5173 | } | ||
5174 | |||
5175 | /* | ||
5176 | * XXX: This should be fixed up so that we just re-insert the | ||
5177 | * next extent records. | ||
5178 | */ | ||
5179 | ocfs2_et_extent_map_truncate(et, 0); | ||
5180 | 5162 | ||
5181 | left_path = ocfs2_new_path_from_et(et); | 5163 | left_path = ocfs2_new_path_from_et(et); |
5182 | if (!left_path) { | 5164 | if (!left_path) { |
@@ -5194,30 +5176,98 @@ int ocfs2_mark_extent_written(struct inode *inode, | |||
5194 | 5176 | ||
5195 | index = ocfs2_search_extent_list(el, cpos); | 5177 | index = ocfs2_search_extent_list(el, cpos); |
5196 | if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) { | 5178 | if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) { |
5197 | ocfs2_error(inode->i_sb, | 5179 | ocfs2_error(sb, |
5198 | "Inode %llu has an extent at cpos %u which can no " | 5180 | "Owner %llu has an extent at cpos %u which can no " |
5199 | "longer be found.\n", | 5181 | "longer be found.\n", |
5200 | (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos); | 5182 | (unsigned long long) |
5183 | ocfs2_metadata_cache_owner(et->et_ci), cpos); | ||
5201 | ret = -EROFS; | 5184 | ret = -EROFS; |
5202 | goto out; | 5185 | goto out; |
5203 | } | 5186 | } |
5204 | 5187 | ||
5188 | ret = -EIO; | ||
5189 | rec = &el->l_recs[index]; | ||
5190 | if (new_flags && (rec->e_flags & new_flags)) { | ||
5191 | mlog(ML_ERROR, "Owner %llu tried to set %d flags on an " | ||
5192 | "extent that already had them", | ||
5193 | (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), | ||
5194 | new_flags); | ||
5195 | goto out; | ||
5196 | } | ||
5197 | |||
5198 | if (clear_flags && !(rec->e_flags & clear_flags)) { | ||
5199 | mlog(ML_ERROR, "Owner %llu tried to clear %d flags on an " | ||
5200 | "extent that didn't have them", | ||
5201 | (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), | ||
5202 | clear_flags); | ||
5203 | goto out; | ||
5204 | } | ||
5205 | |||
5205 | memset(&split_rec, 0, sizeof(struct ocfs2_extent_rec)); | 5206 | memset(&split_rec, 0, sizeof(struct ocfs2_extent_rec)); |
5206 | split_rec.e_cpos = cpu_to_le32(cpos); | 5207 | split_rec.e_cpos = cpu_to_le32(cpos); |
5207 | split_rec.e_leaf_clusters = cpu_to_le16(len); | 5208 | split_rec.e_leaf_clusters = cpu_to_le16(len); |
5208 | split_rec.e_blkno = cpu_to_le64(start_blkno); | 5209 | split_rec.e_blkno = cpu_to_le64(start_blkno); |
5209 | split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags; | 5210 | split_rec.e_flags = rec->e_flags; |
5210 | split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN; | 5211 | if (new_flags) |
5211 | 5212 | split_rec.e_flags |= new_flags; | |
5212 | ret = __ocfs2_mark_extent_written(handle, et, left_path, | 5213 | if (clear_flags) |
5213 | index, &split_rec, meta_ac, | 5214 | split_rec.e_flags &= ~clear_flags; |
5214 | dealloc); | 5215 | |
5216 | ret = __ocfs2_split_extent(handle, et, left_path, | ||
5217 | index, &split_rec, meta_ac, | ||
5218 | dealloc); | ||
5215 | if (ret) | 5219 | if (ret) |
5216 | mlog_errno(ret); | 5220 | mlog_errno(ret); |
5217 | 5221 | ||
5218 | out: | 5222 | out: |
5219 | ocfs2_free_path(left_path); | 5223 | ocfs2_free_path(left_path); |
5220 | return ret; | 5224 | return ret; |
5225 | |||
5226 | } | ||
5227 | |||
5228 | /* | ||
5229 | * Mark the already-existing extent at cpos as written for len clusters. | ||
5230 | * This removes the unwritten extent flag. | ||
5231 | * | ||
5232 | * If the existing extent is larger than the request, initiate a | ||
5233 | * split. An attempt will be made at merging with adjacent extents. | ||
5234 | * | ||
5235 | * The caller is responsible for passing down meta_ac if we'll need it. | ||
5236 | */ | ||
5237 | int ocfs2_mark_extent_written(struct inode *inode, | ||
5238 | struct ocfs2_extent_tree *et, | ||
5239 | handle_t *handle, u32 cpos, u32 len, u32 phys, | ||
5240 | struct ocfs2_alloc_context *meta_ac, | ||
5241 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
5242 | { | ||
5243 | int ret; | ||
5244 | |||
5245 | mlog(0, "Inode %lu cpos %u, len %u, phys clusters %u\n", | ||
5246 | inode->i_ino, cpos, len, phys); | ||
5247 | |||
5248 | if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { | ||
5249 | ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " | ||
5250 | "that are being written to, but the feature bit " | ||
5251 | "is not set in the super block.", | ||
5252 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
5253 | ret = -EROFS; | ||
5254 | goto out; | ||
5255 | } | ||
5256 | |||
5257 | /* | ||
5258 | * XXX: This should be fixed up so that we just re-insert the | ||
5259 | * next extent records. | ||
5260 | */ | ||
5261 | ocfs2_et_extent_map_truncate(et, 0); | ||
5262 | |||
5263 | ret = ocfs2_change_extent_flag(handle, et, cpos, | ||
5264 | len, phys, meta_ac, dealloc, | ||
5265 | 0, OCFS2_EXT_UNWRITTEN); | ||
5266 | if (ret) | ||
5267 | mlog_errno(ret); | ||
5268 | |||
5269 | out: | ||
5270 | return ret; | ||
5221 | } | 5271 | } |
5222 | 5272 | ||
5223 | static int ocfs2_split_tree(handle_t *handle, struct ocfs2_extent_tree *et, | 5273 | static int ocfs2_split_tree(handle_t *handle, struct ocfs2_extent_tree *et, |