diff options
| -rw-r--r-- | fs/ocfs2/move_extents.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 390354a4ecb4..ae15c998a82a 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c | |||
| @@ -632,3 +632,168 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle, | |||
| 632 | bail: | 632 | bail: |
| 633 | return status; | 633 | return status; |
| 634 | } | 634 | } |
| 635 | |||
| 636 | static int ocfs2_move_extent(struct ocfs2_move_extents_context *context, | ||
| 637 | u32 cpos, u32 phys_cpos, u32 *new_phys_cpos, | ||
| 638 | u32 len, int ext_flags) | ||
| 639 | { | ||
| 640 | int ret, credits = 0, extra_blocks = 0, goal_bit = 0; | ||
| 641 | handle_t *handle; | ||
| 642 | struct inode *inode = context->inode; | ||
| 643 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
| 644 | struct inode *tl_inode = osb->osb_tl_inode; | ||
| 645 | struct inode *gb_inode = NULL; | ||
| 646 | struct buffer_head *gb_bh = NULL; | ||
| 647 | struct buffer_head *gd_bh = NULL; | ||
| 648 | struct ocfs2_group_desc *gd; | ||
| 649 | struct ocfs2_refcount_tree *ref_tree = NULL; | ||
| 650 | u32 move_max_hop = ocfs2_blocks_to_clusters(inode->i_sb, | ||
| 651 | context->range->me_threshold); | ||
| 652 | u64 phys_blkno, new_phys_blkno; | ||
| 653 | |||
| 654 | phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); | ||
| 655 | |||
| 656 | if ((ext_flags & OCFS2_EXT_REFCOUNTED) && len) { | ||
| 657 | |||
| 658 | BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & | ||
| 659 | OCFS2_HAS_REFCOUNT_FL)); | ||
| 660 | |||
| 661 | BUG_ON(!context->refcount_loc); | ||
| 662 | |||
| 663 | ret = ocfs2_lock_refcount_tree(osb, context->refcount_loc, 1, | ||
| 664 | &ref_tree, NULL); | ||
| 665 | if (ret) { | ||
| 666 | mlog_errno(ret); | ||
| 667 | return ret; | ||
| 668 | } | ||
| 669 | |||
| 670 | ret = ocfs2_prepare_refcount_change_for_del(inode, | ||
| 671 | context->refcount_loc, | ||
| 672 | phys_blkno, | ||
| 673 | len, | ||
| 674 | &credits, | ||
| 675 | &extra_blocks); | ||
| 676 | if (ret) { | ||
| 677 | mlog_errno(ret); | ||
| 678 | goto out; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 682 | ret = ocfs2_lock_allocators_move_extents(inode, &context->et, len, 1, | ||
| 683 | &context->meta_ac, | ||
| 684 | NULL, extra_blocks, &credits); | ||
| 685 | if (ret) { | ||
| 686 | mlog_errno(ret); | ||
| 687 | goto out; | ||
| 688 | } | ||
| 689 | |||
| 690 | /* | ||
| 691 | * need to count 2 extra credits for global_bitmap inode and | ||
| 692 | * group descriptor. | ||
| 693 | */ | ||
| 694 | credits += OCFS2_INODE_UPDATE_CREDITS + 1; | ||
| 695 | |||
| 696 | /* | ||
| 697 | * ocfs2_move_extent() didn't reserve any clusters in lock_allocators() | ||
| 698 | * logic, while we still need to lock the global_bitmap. | ||
| 699 | */ | ||
| 700 | gb_inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE, | ||
| 701 | OCFS2_INVALID_SLOT); | ||
| 702 | if (!gb_inode) { | ||
| 703 | mlog(ML_ERROR, "unable to get global_bitmap inode\n"); | ||
| 704 | ret = -EIO; | ||
| 705 | goto out; | ||
| 706 | } | ||
| 707 | |||
| 708 | mutex_lock(&gb_inode->i_mutex); | ||
| 709 | |||
| 710 | ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1); | ||
| 711 | if (ret) { | ||
| 712 | mlog_errno(ret); | ||
| 713 | goto out_unlock_gb_mutex; | ||
| 714 | } | ||
| 715 | |||
| 716 | mutex_lock(&tl_inode->i_mutex); | ||
| 717 | |||
| 718 | handle = ocfs2_start_trans(osb, credits); | ||
| 719 | if (IS_ERR(handle)) { | ||
| 720 | ret = PTR_ERR(handle); | ||
| 721 | mlog_errno(ret); | ||
| 722 | goto out_unlock_tl_inode; | ||
| 723 | } | ||
| 724 | |||
| 725 | new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos); | ||
| 726 | ret = ocfs2_find_victim_alloc_group(inode, new_phys_blkno, | ||
| 727 | GLOBAL_BITMAP_SYSTEM_INODE, | ||
| 728 | OCFS2_INVALID_SLOT, | ||
| 729 | &goal_bit, &gd_bh); | ||
| 730 | if (ret) { | ||
| 731 | mlog_errno(ret); | ||
| 732 | goto out_commit; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* | ||
| 736 | * probe the victim cluster group to find a proper | ||
| 737 | * region to fit wanted movement, it even will perfrom | ||
| 738 | * a best-effort attempt by compromising to a threshold | ||
| 739 | * around the goal. | ||
| 740 | */ | ||
| 741 | ocfs2_probe_alloc_group(inode, gd_bh, &goal_bit, len, move_max_hop, | ||
| 742 | new_phys_cpos); | ||
| 743 | if (!new_phys_cpos) { | ||
| 744 | ret = -ENOSPC; | ||
| 745 | goto out_commit; | ||
| 746 | } | ||
| 747 | |||
| 748 | ret = __ocfs2_move_extent(handle, context, cpos, len, phys_cpos, | ||
| 749 | *new_phys_cpos, ext_flags); | ||
| 750 | if (ret) { | ||
| 751 | mlog_errno(ret); | ||
| 752 | goto out_commit; | ||
| 753 | } | ||
| 754 | |||
| 755 | gd = (struct ocfs2_group_desc *)gd_bh->b_data; | ||
| 756 | ret = ocfs2_alloc_dinode_update_counts(gb_inode, handle, gb_bh, len, | ||
| 757 | le16_to_cpu(gd->bg_chain)); | ||
| 758 | if (ret) { | ||
| 759 | mlog_errno(ret); | ||
| 760 | goto out_commit; | ||
| 761 | } | ||
| 762 | |||
| 763 | ret = ocfs2_block_group_set_bits(handle, gb_inode, gd, gd_bh, | ||
| 764 | goal_bit, len); | ||
| 765 | if (ret) | ||
| 766 | mlog_errno(ret); | ||
| 767 | |||
| 768 | /* | ||
| 769 | * Here we should write the new page out first if we are | ||
| 770 | * in write-back mode. | ||
| 771 | */ | ||
| 772 | ret = ocfs2_cow_sync_writeback(inode->i_sb, context->inode, cpos, len); | ||
| 773 | if (ret) | ||
| 774 | mlog_errno(ret); | ||
| 775 | |||
| 776 | out_commit: | ||
| 777 | ocfs2_commit_trans(osb, handle); | ||
| 778 | brelse(gd_bh); | ||
| 779 | |||
| 780 | out_unlock_tl_inode: | ||
| 781 | mutex_unlock(&tl_inode->i_mutex); | ||
| 782 | |||
| 783 | ocfs2_inode_unlock(gb_inode, 1); | ||
| 784 | out_unlock_gb_mutex: | ||
| 785 | mutex_unlock(&gb_inode->i_mutex); | ||
| 786 | brelse(gb_bh); | ||
| 787 | iput(gb_inode); | ||
| 788 | |||
| 789 | out: | ||
| 790 | if (context->meta_ac) { | ||
| 791 | ocfs2_free_alloc_context(context->meta_ac); | ||
| 792 | context->meta_ac = NULL; | ||
| 793 | } | ||
| 794 | |||
| 795 | if (ref_tree) | ||
| 796 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | ||
| 797 | |||
| 798 | return ret; | ||
| 799 | } | ||
