diff options
Diffstat (limited to 'fs/ocfs2/alloc.c')
-rw-r--r-- | fs/ocfs2/alloc.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 2e3898316468..fac1adb3880a 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -4139,6 +4139,373 @@ out: | |||
4139 | return ret; | 4139 | return ret; |
4140 | } | 4140 | } |
4141 | 4141 | ||
4142 | static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh, | ||
4143 | handle_t *handle, struct ocfs2_path *path, | ||
4144 | int index, u32 new_range, | ||
4145 | struct ocfs2_alloc_context *meta_ac) | ||
4146 | { | ||
4147 | int ret, depth, credits = handle->h_buffer_credits; | ||
4148 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
4149 | struct buffer_head *last_eb_bh = NULL; | ||
4150 | struct ocfs2_extent_block *eb; | ||
4151 | struct ocfs2_extent_list *rightmost_el, *el; | ||
4152 | struct ocfs2_extent_rec split_rec; | ||
4153 | struct ocfs2_extent_rec *rec; | ||
4154 | struct ocfs2_insert_type insert; | ||
4155 | |||
4156 | /* | ||
4157 | * Setup the record to split before we grow the tree. | ||
4158 | */ | ||
4159 | el = path_leaf_el(path); | ||
4160 | rec = &el->l_recs[index]; | ||
4161 | ocfs2_make_right_split_rec(inode->i_sb, &split_rec, new_range, rec); | ||
4162 | |||
4163 | depth = path->p_tree_depth; | ||
4164 | if (depth > 0) { | ||
4165 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | ||
4166 | le64_to_cpu(di->i_last_eb_blk), | ||
4167 | &last_eb_bh, OCFS2_BH_CACHED, inode); | ||
4168 | if (ret < 0) { | ||
4169 | mlog_errno(ret); | ||
4170 | goto out; | ||
4171 | } | ||
4172 | |||
4173 | eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; | ||
4174 | rightmost_el = &eb->h_list; | ||
4175 | } else | ||
4176 | rightmost_el = path_leaf_el(path); | ||
4177 | |||
4178 | credits += path->p_tree_depth + ocfs2_extend_meta_needed(di); | ||
4179 | ret = ocfs2_extend_trans(handle, credits); | ||
4180 | if (ret) { | ||
4181 | mlog_errno(ret); | ||
4182 | goto out; | ||
4183 | } | ||
4184 | |||
4185 | if (le16_to_cpu(rightmost_el->l_next_free_rec) == | ||
4186 | le16_to_cpu(rightmost_el->l_count)) { | ||
4187 | int old_depth = depth; | ||
4188 | |||
4189 | ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh, | ||
4190 | meta_ac); | ||
4191 | if (ret) { | ||
4192 | mlog_errno(ret); | ||
4193 | goto out; | ||
4194 | } | ||
4195 | |||
4196 | if (old_depth != depth) { | ||
4197 | eb = (struct ocfs2_extent_block *)last_eb_bh->b_data; | ||
4198 | rightmost_el = &eb->h_list; | ||
4199 | } | ||
4200 | } | ||
4201 | |||
4202 | memset(&insert, 0, sizeof(struct ocfs2_insert_type)); | ||
4203 | insert.ins_appending = APPEND_NONE; | ||
4204 | insert.ins_contig = CONTIG_NONE; | ||
4205 | insert.ins_split = SPLIT_RIGHT; | ||
4206 | insert.ins_free_records = le16_to_cpu(rightmost_el->l_count) | ||
4207 | - le16_to_cpu(rightmost_el->l_next_free_rec); | ||
4208 | insert.ins_tree_depth = depth; | ||
4209 | |||
4210 | ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert); | ||
4211 | if (ret) | ||
4212 | mlog_errno(ret); | ||
4213 | |||
4214 | out: | ||
4215 | brelse(last_eb_bh); | ||
4216 | return ret; | ||
4217 | } | ||
4218 | |||
4219 | static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle, | ||
4220 | struct ocfs2_path *path, int index, | ||
4221 | struct ocfs2_cached_dealloc_ctxt *dealloc, | ||
4222 | u32 cpos, u32 len) | ||
4223 | { | ||
4224 | int ret; | ||
4225 | u32 left_cpos, rec_range, trunc_range; | ||
4226 | int wants_rotate = 0, is_rightmost_tree_rec = 0; | ||
4227 | struct super_block *sb = inode->i_sb; | ||
4228 | struct ocfs2_path *left_path = NULL; | ||
4229 | struct ocfs2_extent_list *el = path_leaf_el(path); | ||
4230 | struct ocfs2_extent_rec *rec; | ||
4231 | struct ocfs2_extent_block *eb; | ||
4232 | |||
4233 | if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) { | ||
4234 | ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc); | ||
4235 | if (ret) { | ||
4236 | mlog_errno(ret); | ||
4237 | goto out; | ||
4238 | } | ||
4239 | |||
4240 | index--; | ||
4241 | } | ||
4242 | |||
4243 | if (index == (le16_to_cpu(el->l_next_free_rec) - 1) && | ||
4244 | path->p_tree_depth) { | ||
4245 | /* | ||
4246 | * Check whether this is the rightmost tree record. If | ||
4247 | * we remove all of this record or part of its right | ||
4248 | * edge then an update of the record lengths above it | ||
4249 | * will be required. | ||
4250 | */ | ||
4251 | eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data; | ||
4252 | if (eb->h_next_leaf_blk == 0) | ||
4253 | is_rightmost_tree_rec = 1; | ||
4254 | } | ||
4255 | |||
4256 | rec = &el->l_recs[index]; | ||
4257 | if (index == 0 && path->p_tree_depth && | ||
4258 | le32_to_cpu(rec->e_cpos) == cpos) { | ||
4259 | /* | ||
4260 | * Changing the leftmost offset (via partial or whole | ||
4261 | * record truncate) of an interior (or rightmost) path | ||
4262 | * means we have to update the subtree that is formed | ||
4263 | * by this leaf and the one to it's left. | ||
4264 | * | ||
4265 | * There are two cases we can skip: | ||
4266 | * 1) Path is the leftmost one in our inode tree. | ||
4267 | * 2) The leaf is rightmost and will be empty after | ||
4268 | * we remove the extent record - the rotate code | ||
4269 | * knows how to update the newly formed edge. | ||
4270 | */ | ||
4271 | |||
4272 | ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path, | ||
4273 | &left_cpos); | ||
4274 | if (ret) { | ||
4275 | mlog_errno(ret); | ||
4276 | goto out; | ||
4277 | } | ||
4278 | |||
4279 | if (left_cpos && le16_to_cpu(el->l_next_free_rec) > 1) { | ||
4280 | left_path = ocfs2_new_path(path_root_bh(path), | ||
4281 | path_root_el(path)); | ||
4282 | if (!left_path) { | ||
4283 | ret = -ENOMEM; | ||
4284 | mlog_errno(ret); | ||
4285 | goto out; | ||
4286 | } | ||
4287 | |||
4288 | ret = ocfs2_find_path(inode, left_path, left_cpos); | ||
4289 | if (ret) { | ||
4290 | mlog_errno(ret); | ||
4291 | goto out; | ||
4292 | } | ||
4293 | } | ||
4294 | } | ||
4295 | |||
4296 | ret = ocfs2_extend_rotate_transaction(handle, 0, | ||
4297 | handle->h_buffer_credits, | ||
4298 | path); | ||
4299 | if (ret) { | ||
4300 | mlog_errno(ret); | ||
4301 | goto out; | ||
4302 | } | ||
4303 | |||
4304 | ret = ocfs2_journal_access_path(inode, handle, path); | ||
4305 | if (ret) { | ||
4306 | mlog_errno(ret); | ||
4307 | goto out; | ||
4308 | } | ||
4309 | |||
4310 | ret = ocfs2_journal_access_path(inode, handle, left_path); | ||
4311 | if (ret) { | ||
4312 | mlog_errno(ret); | ||
4313 | goto out; | ||
4314 | } | ||
4315 | |||
4316 | rec_range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); | ||
4317 | trunc_range = cpos + len; | ||
4318 | |||
4319 | if (le32_to_cpu(rec->e_cpos) == cpos && rec_range == trunc_range) { | ||
4320 | int next_free; | ||
4321 | |||
4322 | memset(rec, 0, sizeof(*rec)); | ||
4323 | ocfs2_cleanup_merge(el, index); | ||
4324 | wants_rotate = 1; | ||
4325 | |||
4326 | next_free = le16_to_cpu(el->l_next_free_rec); | ||
4327 | if (is_rightmost_tree_rec && next_free > 1) { | ||
4328 | /* | ||
4329 | * We skip the edge update if this path will | ||
4330 | * be deleted by the rotate code. | ||
4331 | */ | ||
4332 | rec = &el->l_recs[next_free - 1]; | ||
4333 | ocfs2_adjust_rightmost_records(inode, handle, path, | ||
4334 | rec); | ||
4335 | } | ||
4336 | } else if (le32_to_cpu(rec->e_cpos) == cpos) { | ||
4337 | /* Remove leftmost portion of the record. */ | ||
4338 | le32_add_cpu(&rec->e_cpos, len); | ||
4339 | le64_add_cpu(&rec->e_blkno, ocfs2_clusters_to_blocks(sb, len)); | ||
4340 | le16_add_cpu(&rec->e_leaf_clusters, -len); | ||
4341 | } else if (rec_range == trunc_range) { | ||
4342 | /* Remove rightmost portion of the record */ | ||
4343 | le16_add_cpu(&rec->e_leaf_clusters, -len); | ||
4344 | if (is_rightmost_tree_rec) | ||
4345 | ocfs2_adjust_rightmost_records(inode, handle, path, rec); | ||
4346 | } else { | ||
4347 | /* Caller should have trapped this. */ | ||
4348 | mlog(ML_ERROR, "Inode %llu: Invalid record truncate: (%u, %u) " | ||
4349 | "(%u, %u)\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
4350 | le32_to_cpu(rec->e_cpos), | ||
4351 | le16_to_cpu(rec->e_leaf_clusters), cpos, len); | ||
4352 | BUG(); | ||
4353 | } | ||
4354 | |||
4355 | if (left_path) { | ||
4356 | int subtree_index; | ||
4357 | |||
4358 | subtree_index = ocfs2_find_subtree_root(inode, left_path, path); | ||
4359 | ocfs2_complete_edge_insert(inode, handle, left_path, path, | ||
4360 | subtree_index); | ||
4361 | } | ||
4362 | |||
4363 | ocfs2_journal_dirty(handle, path_leaf_bh(path)); | ||
4364 | |||
4365 | ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc); | ||
4366 | if (ret) { | ||
4367 | mlog_errno(ret); | ||
4368 | goto out; | ||
4369 | } | ||
4370 | |||
4371 | out: | ||
4372 | ocfs2_free_path(left_path); | ||
4373 | return ret; | ||
4374 | } | ||
4375 | |||
4376 | static int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh, | ||
4377 | u32 cpos, u32 len, handle_t *handle, | ||
4378 | struct ocfs2_alloc_context *meta_ac, | ||
4379 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
4380 | { | ||
4381 | int ret, index; | ||
4382 | u32 rec_range, trunc_range; | ||
4383 | struct ocfs2_extent_rec *rec; | ||
4384 | struct ocfs2_extent_list *el; | ||
4385 | struct ocfs2_path *path; | ||
4386 | |||
4387 | ocfs2_extent_map_trunc(inode, 0); | ||
4388 | |||
4389 | path = ocfs2_new_inode_path(di_bh); | ||
4390 | if (!path) { | ||
4391 | ret = -ENOMEM; | ||
4392 | mlog_errno(ret); | ||
4393 | goto out; | ||
4394 | } | ||
4395 | |||
4396 | ret = ocfs2_find_path(inode, path, cpos); | ||
4397 | if (ret) { | ||
4398 | mlog_errno(ret); | ||
4399 | goto out; | ||
4400 | } | ||
4401 | |||
4402 | el = path_leaf_el(path); | ||
4403 | index = ocfs2_search_extent_list(el, cpos); | ||
4404 | if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) { | ||
4405 | ocfs2_error(inode->i_sb, | ||
4406 | "Inode %llu has an extent at cpos %u which can no " | ||
4407 | "longer be found.\n", | ||
4408 | (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos); | ||
4409 | ret = -EROFS; | ||
4410 | goto out; | ||
4411 | } | ||
4412 | |||
4413 | /* | ||
4414 | * We have 3 cases of extent removal: | ||
4415 | * 1) Range covers the entire extent rec | ||
4416 | * 2) Range begins or ends on one edge of the extent rec | ||
4417 | * 3) Range is in the middle of the extent rec (no shared edges) | ||
4418 | * | ||
4419 | * For case 1 we remove the extent rec and left rotate to | ||
4420 | * fill the hole. | ||
4421 | * | ||
4422 | * For case 2 we just shrink the existing extent rec, with a | ||
4423 | * tree update if the shrinking edge is also the edge of an | ||
4424 | * extent block. | ||
4425 | * | ||
4426 | * For case 3 we do a right split to turn the extent rec into | ||
4427 | * something case 2 can handle. | ||
4428 | */ | ||
4429 | rec = &el->l_recs[index]; | ||
4430 | rec_range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec); | ||
4431 | trunc_range = cpos + len; | ||
4432 | |||
4433 | BUG_ON(cpos < le32_to_cpu(rec->e_cpos) || trunc_range > rec_range); | ||
4434 | |||
4435 | mlog(0, "Inode %llu, remove (cpos %u, len %u). Existing index %d " | ||
4436 | "(cpos %u, len %u)\n", | ||
4437 | (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos, len, index, | ||
4438 | le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); | ||
4439 | |||
4440 | if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) { | ||
4441 | ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, | ||
4442 | cpos, len); | ||
4443 | if (ret) { | ||
4444 | mlog_errno(ret); | ||
4445 | goto out; | ||
4446 | } | ||
4447 | } else { | ||
4448 | ret = ocfs2_split_tree(inode, di_bh, handle, path, index, | ||
4449 | trunc_range, meta_ac); | ||
4450 | if (ret) { | ||
4451 | mlog_errno(ret); | ||
4452 | goto out; | ||
4453 | } | ||
4454 | |||
4455 | /* | ||
4456 | * The split could have manipulated the tree enough to | ||
4457 | * move the record location, so we have to look for it again. | ||
4458 | */ | ||
4459 | ocfs2_reinit_path(path, 1); | ||
4460 | |||
4461 | ret = ocfs2_find_path(inode, path, cpos); | ||
4462 | if (ret) { | ||
4463 | mlog_errno(ret); | ||
4464 | goto out; | ||
4465 | } | ||
4466 | |||
4467 | el = path_leaf_el(path); | ||
4468 | index = ocfs2_search_extent_list(el, cpos); | ||
4469 | if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) { | ||
4470 | ocfs2_error(inode->i_sb, | ||
4471 | "Inode %llu: split at cpos %u lost record.", | ||
4472 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
4473 | cpos); | ||
4474 | ret = -EROFS; | ||
4475 | goto out; | ||
4476 | } | ||
4477 | |||
4478 | /* | ||
4479 | * Double check our values here. If anything is fishy, | ||
4480 | * it's easier to catch it at the top level. | ||
4481 | */ | ||
4482 | rec = &el->l_recs[index]; | ||
4483 | rec_range = le32_to_cpu(rec->e_cpos) + | ||
4484 | ocfs2_rec_clusters(el, rec); | ||
4485 | if (rec_range != trunc_range) { | ||
4486 | ocfs2_error(inode->i_sb, | ||
4487 | "Inode %llu: error after split at cpos %u" | ||
4488 | "trunc len %u, existing record is (%u,%u)", | ||
4489 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
4490 | cpos, len, le32_to_cpu(rec->e_cpos), | ||
4491 | ocfs2_rec_clusters(el, rec)); | ||
4492 | ret = -EROFS; | ||
4493 | goto out; | ||
4494 | } | ||
4495 | |||
4496 | ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc, | ||
4497 | cpos, len); | ||
4498 | if (ret) { | ||
4499 | mlog_errno(ret); | ||
4500 | goto out; | ||
4501 | } | ||
4502 | } | ||
4503 | |||
4504 | out: | ||
4505 | ocfs2_free_path(path); | ||
4506 | return ret; | ||
4507 | } | ||
4508 | |||
4142 | static inline int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb) | 4509 | static inline int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb) |
4143 | { | 4510 | { |
4144 | struct buffer_head *tl_bh = osb->osb_tl_bh; | 4511 | struct buffer_head *tl_bh = osb->osb_tl_bh; |