aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTristan Ye <tristan.ye@oracle.com>2011-05-24 05:35:19 -0400
committerTristan Ye <tristan.ye@oracle.com>2011-05-25 03:17:11 -0400
commite08477176d5575493ba4c30041245c34f2737ad4 (patch)
treeaedeb0f25df0c5a5ba926cbd0372626d8d0b755f /fs/ocfs2
parent8473aa8a2b5857b1bdfb57d860594d2eb2b4a0d6 (diff)
Ocfs2/move_extents: move entire/partial extent.
ocfs2_move_extent() logic will validate the goal_offset_in_block, where extents to be moved, what's more, it also compromises a bit to probe the appropriate region around given goal_offset when the original goal is not able to fit the movement. Signed-off-by: Tristan Ye <tristan.ye@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/move_extents.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 390354a4ecb..ae15c998a82 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,
632bail: 632bail:
633 return status; 633 return status;
634} 634}
635
636static 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
776out_commit:
777 ocfs2_commit_trans(osb, handle);
778 brelse(gd_bh);
779
780out_unlock_tl_inode:
781 mutex_unlock(&tl_inode->i_mutex);
782
783 ocfs2_inode_unlock(gb_inode, 1);
784out_unlock_gb_mutex:
785 mutex_unlock(&gb_inode->i_mutex);
786 brelse(gb_bh);
787 iput(gb_inode);
788
789out:
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}