aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ocfs2/ioctl.c5
-rw-r--r--fs/ocfs2/move_extents.c308
-rw-r--r--fs/ocfs2/move_extents.h2
3 files changed, 315 insertions, 0 deletions
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index fd248ed53df..59100598b0c 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -26,6 +26,7 @@
26#include "dir.h" 26#include "dir.h"
27#include "buffer_head_io.h" 27#include "buffer_head_io.h"
28#include "suballoc.h" 28#include "suballoc.h"
29#include "move_extents.h"
29 30
30#include <linux/ext2_fs.h> 31#include <linux/ext2_fs.h>
31 32
@@ -951,6 +952,8 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
951 return -EFAULT; 952 return -EFAULT;
952 953
953 return ocfs2_info_handle(inode, &info, 0); 954 return ocfs2_info_handle(inode, &info, 0);
955 case OCFS2_IOC_MOVE_EXT:
956 return ocfs2_ioctl_move_extents(filp, (void __user *)arg);
954 default: 957 default:
955 return -ENOTTY; 958 return -ENOTTY;
956 } 959 }
@@ -993,6 +996,8 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
993 return -EFAULT; 996 return -EFAULT;
994 997
995 return ocfs2_info_handle(inode, &info, 1); 998 return ocfs2_info_handle(inode, &info, 1);
999 case OCFS2_IOC_MOVE_EXT:
1000 break;
996 default: 1001 default:
997 return -ENOIOCTLCMD; 1002 return -ENOIOCTLCMD;
998 } 1003 }
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 1c822e08fea..800552168d8 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -827,3 +827,311 @@ static void ocfs2_calc_extent_defrag_len(u32 *alloc_size, u32 *len_defraged,
827 *len_defraged = 0; 827 *len_defraged = 0;
828 } 828 }
829} 829}
830
831static int __ocfs2_move_extents_range(struct buffer_head *di_bh,
832 struct ocfs2_move_extents_context *context)
833{
834 int ret = 0, flags, do_defrag, skip = 0;
835 u32 cpos, phys_cpos, move_start, len_to_move, alloc_size;
836 u32 len_defraged = 0, defrag_thresh = 0, new_phys_cpos = 0;
837
838 struct inode *inode = context->inode;
839 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
840 struct ocfs2_move_extents *range = context->range;
841 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
842
843 if ((inode->i_size == 0) || (range->me_len == 0))
844 return 0;
845
846 if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
847 return 0;
848
849 context->refcount_loc = le64_to_cpu(di->i_refcount_loc);
850
851 ocfs2_init_dinode_extent_tree(&context->et, INODE_CACHE(inode), di_bh);
852 ocfs2_init_dealloc_ctxt(&context->dealloc);
853
854 /*
855 * TO-DO XXX:
856 *
857 * - xattr extents.
858 */
859
860 do_defrag = context->auto_defrag;
861
862 /*
863 * extents moving happens in unit of clusters, for the sake
864 * of simplicity, we may ignore two clusters where 'byte_start'
865 * and 'byte_start + len' were within.
866 */
867 move_start = ocfs2_clusters_for_bytes(osb->sb, range->me_start);
868 len_to_move = (range->me_start + range->me_len) >>
869 osb->s_clustersize_bits;
870 if (len_to_move >= move_start)
871 len_to_move -= move_start;
872 else
873 len_to_move = 0;
874
875 if (do_defrag)
876 defrag_thresh = range->me_threshold >> osb->s_clustersize_bits;
877 else
878 new_phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
879 range->me_goal);
880
881 mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u, "
882 "thresh: %u\n",
883 (unsigned long long)OCFS2_I(inode)->ip_blkno,
884 (unsigned long long)range->me_start,
885 (unsigned long long)range->me_len,
886 move_start, len_to_move, defrag_thresh);
887
888 cpos = move_start;
889 while (len_to_move) {
890 ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &alloc_size,
891 &flags);
892 if (ret) {
893 mlog_errno(ret);
894 goto out;
895 }
896
897 if (alloc_size > len_to_move)
898 alloc_size = len_to_move;
899
900 /*
901 * XXX: how to deal with a hole:
902 *
903 * - skip the hole of course
904 * - force a new defragmentation
905 */
906 if (!phys_cpos) {
907 if (do_defrag)
908 len_defraged = 0;
909
910 goto next;
911 }
912
913 if (do_defrag) {
914 ocfs2_calc_extent_defrag_len(&alloc_size, &len_defraged,
915 defrag_thresh, &skip);
916 /*
917 * skip large extents
918 */
919 if (skip) {
920 skip = 0;
921 goto next;
922 }
923
924 mlog(0, "#Defrag: cpos: %u, phys_cpos: %u, "
925 "alloc_size: %u, len_defraged: %u\n",
926 cpos, phys_cpos, alloc_size, len_defraged);
927
928 ret = ocfs2_defrag_extent(context, cpos, phys_cpos,
929 alloc_size, flags);
930 } else {
931 ret = ocfs2_move_extent(context, cpos, phys_cpos,
932 &new_phys_cpos, alloc_size,
933 flags);
934
935 new_phys_cpos += alloc_size;
936 }
937
938 if (ret < 0) {
939 mlog_errno(ret);
940 goto out;
941 }
942
943 context->clusters_moved += alloc_size;
944next:
945 cpos += alloc_size;
946 len_to_move -= alloc_size;
947 }
948
949 range->me_flags |= OCFS2_MOVE_EXT_FL_COMPLETE;
950
951out:
952 range->me_moved_len = ocfs2_clusters_to_bytes(osb->sb,
953 context->clusters_moved);
954 range->me_new_offset = ocfs2_clusters_to_bytes(osb->sb,
955 context->new_phys_cpos);
956
957 ocfs2_schedule_truncate_log_flush(osb, 1);
958 ocfs2_run_deallocs(osb, &context->dealloc);
959
960 return ret;
961}
962
963static int ocfs2_move_extents(struct ocfs2_move_extents_context *context)
964{
965 int status;
966 handle_t *handle;
967 struct inode *inode = context->inode;
968 struct ocfs2_dinode *di;
969 struct buffer_head *di_bh = NULL;
970 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
971
972 if (!inode)
973 return -ENOENT;
974
975 if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
976 return -EROFS;
977
978 mutex_lock(&inode->i_mutex);
979
980 /*
981 * This prevents concurrent writes from other nodes
982 */
983 status = ocfs2_rw_lock(inode, 1);
984 if (status) {
985 mlog_errno(status);
986 goto out;
987 }
988
989 status = ocfs2_inode_lock(inode, &di_bh, 1);
990 if (status) {
991 mlog_errno(status);
992 goto out_rw_unlock;
993 }
994
995 /*
996 * rememer ip_xattr_sem also needs to be held if necessary
997 */
998 down_write(&OCFS2_I(inode)->ip_alloc_sem);
999
1000 status = __ocfs2_move_extents_range(di_bh, context);
1001
1002 up_write(&OCFS2_I(inode)->ip_alloc_sem);
1003 if (status) {
1004 mlog_errno(status);
1005 goto out_inode_unlock;
1006 }
1007
1008 /*