diff options
Diffstat (limited to 'fs')
| -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; |
