aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-22 11:54:27 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:38 -0400
commit110a045aca62f6f564e3b68f89af2a3a5a6ecff2 (patch)
treed7c2df9a59e527eb14add4daf1c0107e486715f4 /fs
parent37f8a2bfaa8364dd3644cccee8824bb8f5e409a5 (diff)
ocfs2: Add normal functions for reflink a normal file's extents.
2 major functions are added in this patch. ocfs2_attach_refcount_tree will create a new refcount tree to the old file if it doesn't have one and insert all the extent records to the tree if they are not refcounted. ocfs2_create_reflink_node will: 1. set the refcount tree to the new file. 2. call ocfs2_duplicate_extent_list which will iterate all the extents for the old file, insert it to the new file and increase the corresponding referennce count. Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/refcounttree.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 37aa0c8696d6..e3171c483685 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -3282,3 +3282,289 @@ int ocfs2_refcount_cow(struct inode *inode,
3282 3282
3283 return ret; 3283 return ret;
3284} 3284}
3285
3286/*
3287 * Insert a new extent into refcount tree and mark a extent rec
3288 * as refcounted in the dinode tree.
3289 */
3290int ocfs2_add_refcount_flag(struct inode *inode,
3291 struct ocfs2_extent_tree *data_et,
3292 struct ocfs2_caching_info *ref_ci,
3293 struct buffer_head *ref_root_bh,
3294 u32 cpos, u32 p_cluster, u32 num_clusters,
3295 struct ocfs2_cached_dealloc_ctxt *dealloc)
3296{
3297 int ret;
3298 handle_t *handle;
3299 int credits = 1, ref_blocks = 0;
3300 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3301 struct ocfs2_alloc_context *meta_ac = NULL;
3302
3303 ret = ocfs2_calc_refcount_meta_credits(inode->i_sb,
3304 ref_ci, ref_root_bh,
3305 p_cluster, num_clusters,
3306 &ref_blocks, &credits);
3307 if (ret) {
3308 mlog_errno(ret);
3309 goto out;
3310 }
3311
3312 mlog(0, "reserve new metadata %d, credits = %d\n",
3313 ref_blocks, credits);
3314
3315 if (ref_blocks) {
3316 ret = ocfs2_reserve_new_metadata_blocks(OCFS2_SB(inode->i_sb),
3317 ref_blocks, &meta_ac);
3318 if (ret) {
3319 mlog_errno(ret);
3320 goto out;
3321 }
3322 }
3323
3324 handle = ocfs2_start_trans(osb, credits);
3325 if (IS_ERR(handle)) {
3326 ret = PTR_ERR(handle);
3327 mlog_errno(ret);
3328 goto out;
3329 }
3330
3331 ret = ocfs2_mark_extent_refcounted(inode, data_et, handle,
3332 cpos, num_clusters, p_cluster,
3333 meta_ac, dealloc);
3334 if (ret) {
3335 mlog_errno(ret);
3336 goto out_commit;
3337 }
3338
3339 ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh,
3340 p_cluster, num_clusters,
3341 meta_ac, dealloc);
3342 if (ret)
3343 mlog_errno(ret);
3344
3345out_commit:
3346 ocfs2_commit_trans(osb, handle);
3347out:
3348 if (meta_ac)
3349 ocfs2_free_alloc_context(meta_ac);
3350 return ret;
3351}
3352
3353static int ocfs2_attach_refcount_tree(struct inode *inode,
3354 struct buffer_head *di_bh)
3355{
3356 int ret;
3357 struct buffer_head *ref_root_bh = NULL;
3358 struct ocfs2_inode_info *oi = OCFS2_I(inode);
3359 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
3360 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3361 struct ocfs2_refcount_tree *ref_tree;
3362 unsigned int ext_flags;
3363 loff_t size;
3364 u32 cpos, num_clusters, clusters, p_cluster;
3365 struct ocfs2_cached_dealloc_ctxt dealloc;
3366 struct ocfs2_extent_tree di_et;
3367
3368 ocfs2_init_dealloc_ctxt(&dealloc);
3369
3370 if (!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)) {
3371 ret = ocfs2_create_refcount_tree(inode, di_bh);
3372 if (ret) {
3373 mlog_errno(ret);
3374 goto out;
3375 }
3376 }
3377
3378 BUG_ON(!di->i_refcount_loc);
3379 ret = ocfs2_lock_refcount_tree(osb,
3380 le64_to_cpu(di->i_refcount_loc), 1,
3381 &ref_tree, &ref_root_bh);
3382 if (ret) {
3383 mlog_errno(ret);
3384 goto out;
3385 }
3386
3387 ocfs2_init_dinode_extent_tree(&di_et, INODE_CACHE(inode), di_bh);
3388
3389 size = i_size_read(inode);
3390 clusters = ocfs2_clusters_for_bytes(inode->i_sb, size);
3391
3392 cpos = 0;
3393 while (cpos < clusters) {
3394 ret = ocfs2_get_clusters(inode, cpos, &p_cluster,
3395 &num_clusters, &ext_flags);
3396
3397 if (p_cluster && !(ext_flags & OCFS2_EXT_REFCOUNTED)) {
3398 ret = ocfs2_add_refcount_flag(inode, &di_et,
3399 &ref_tree->rf_ci,
3400 ref_root_bh, cpos,
3401 p_cluster, num_clusters,
3402 &dealloc);
3403 if (ret) {
3404 mlog_errno(ret);
3405 break;
3406 }
3407 }
3408 cpos += num_clusters;
3409 }
3410
3411 ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
3412 brelse(ref_root_bh);
3413
3414 if (!ret && ocfs2_dealloc_has_cluster(&dealloc)) {
3415 ocfs2_schedule_truncate_log_flush(osb, 1);
3416 ocfs2_run_deallocs(osb, &dealloc);
3417 }
3418out:
3419 /*
3420 * Empty the extent map so that we may get the right extent
3421 * record from the disk.
3422 */
3423 ocfs2_extent_map_trunc(inode, 0);
3424
3425 return ret;
3426}
3427
3428static int ocfs2_add_refcounted_extent(struct inode *inode,
3429 struct ocfs2_extent_tree *et,
3430 struct ocfs2_caching_info *ref_ci,
3431 struct buffer_head *ref_root_bh,
3432 u32 cpos, u32 p_cluster, u32 num_clusters,
3433 unsigned int ext_flags,
3434 struct ocfs2_cached_dealloc_ctxt *dealloc)
3435{
3436 int ret;
3437 handle_t *handle;
3438 int credits = 0;
3439 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
3440 struct ocfs2_alloc_context *meta_ac = NULL;
3441
3442 ret = ocfs2_lock_refcount_allocators(inode->i_sb,
3443 p_cluster, num_clusters,
3444 et, ref_ci,
3445 ref_root_bh, &meta_ac,
3446 NULL, &credits);
3447 if (ret) {
3448 mlog_errno(ret);
3449 goto out;
3450 }
3451
3452 handle = ocfs2_start_trans(osb, credits);
3453 if (IS_ERR(handle)) {
3454 ret = PTR_ERR(handle);
3455 mlog_errno(ret);
3456 goto out;
3457 }
3458
3459 ret = ocfs2_insert_extent(handle, et, cpos,
3460 cpu_to_le64(ocfs2_clusters_to_blocks(inode->i_sb,
3461 p_cluster)),
3462 num_clusters, ext_flags, meta_ac);
3463 if (ret) {
3464 mlog_errno(ret);
3465 goto out_commit;
3466 }
3467
3468 ret = __ocfs2_increase_refcount(handle, ref_ci, ref_root_bh,
3469 p_cluster, num_clusters,
3470 meta_ac, dealloc);
3471 if (ret)
3472 mlog_errno(ret);
3473
3474out_commit:
3475 ocfs2_commit_trans(osb, handle);
3476out:
3477 if (meta_ac)
3478 ocfs2_free_alloc_context(meta_ac);
3479 return ret;
3480}
3481
3482static int ocfs2_duplicate_extent_list(struct inode *s_inode,
3483 struct inode *t_inode,
3484 struct buffer_head *t_bh,
3485 struct ocfs2_caching_info *ref_ci,
3486 struct buffer_head *ref_root_bh,
3487 struct ocfs2_cached_dealloc_ctxt *dealloc)
3488{
3489 int ret = 0;
3490 u32 p_cluster, num_clusters, clusters, cpos;
3491 loff_t size;
3492 unsigned int ext_flags;
3493 struct ocfs2_extent_tree et;
3494
3495 ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(t_inode), t_bh);
3496
3497 size = i_size_read(s_inode);
3498 clusters = ocfs2_clusters_for_bytes(s_inode->i_sb, size);
3499
3500 cpos = 0;
3501 while (cpos < clusters) {
3502 ret = ocfs2_get_clusters(s_inode, cpos, &p_cluster,
3503 &num_clusters, &ext_flags);
3504
3505 if (p_cluster) {
3506 ret = ocfs2_add_refcounted_extent(t_inode, &et,
3507 ref_ci, ref_root_bh,
3508 cpos, p_cluster,
3509 num_clusters,
3510 ext_flags,
3511 dealloc);
3512 if (ret) {
3513 mlog_errno(ret);
3514 goto out;
3515 }
3516 }
3517
3518 cpos += num_clusters;
3519 }
3520
3521out:
3522 return ret;
3523}
3524
3525static int ocfs2_create_reflink_node(struct inode *s_inode,
3526 struct buffer_head *s_bh,
3527 struct inode *t_inode,
3528 struct buffer_head *t_bh)
3529{
3530 int ret;
3531 struct buffer_head *ref_root_bh = NULL;
3532 struct ocfs2_cached_dealloc_ctxt dealloc;
3533 struct ocfs2_super *osb = OCFS2_SB(s_inode->i_sb);
3534 struct ocfs2_refcount_block *rb;
3535 struct ocfs2_dinode *di = (struct ocfs2_dinode *)s_bh->b_data;
3536 struct ocfs2_refcount_tree *ref_tree;
3537
3538 ocfs2_init_dealloc_ctxt(&dealloc);
3539
3540 ret = ocfs2_set_refcount_tree(t_inode, t_bh,
3541 le64_to_cpu(di->i_refcount_loc));
3542 if (ret) {
3543 mlog_errno(ret);
3544 goto out;
3545 }
3546
3547 ret = ocfs2_lock_refcount_tree(osb, le64_to_cpu(di->i_refcount_loc),
3548 1, &ref_tree, &ref_root_bh);
3549 if (ret) {
3550 mlog_errno(ret);
3551 goto out;
3552 }
3553 rb = (struct ocfs2_refcount_block *)ref_root_bh->b_data;
3554
3555 ret = ocfs2_duplicate_extent_list(s_inode, t_inode, t_bh,
3556 &ref_tree->rf_ci, ref_root_bh,
3557 &dealloc);
3558 if (ret)
3559 mlog_errno(ret);
3560
3561 ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
3562 brelse(ref_root_bh);
3563out:
3564 if (ocfs2_dealloc_has_cluster(&dealloc)) {
3565 ocfs2_schedule_truncate_log_flush(osb, 1);
3566 ocfs2_run_deallocs(osb, &dealloc);
3567 }
3568
3569 return ret;
3570}