Skip to contentSkip to conversation

ext4: Add the EXT4_IOC_MOVE_VICTIM ioctl

RFC PATCH In review Akira Fujita 1 participant 1 message Oct 24, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 8/9 ext4: Add the EXT4_IOC_MOVE_VICTIM ioctl

ext4: online defrag -- Add the EXT4_IOC_MOVE_VICTIM ioctl.

From: Akira Fujita <[email protected]>

The EXT4_IOC_MOVE_VICTIM moves the victim extents into other block group. Therefore the contiguous free space is made in the target block group. This ioctl is used only in the force defrag (-f).

---
 fs/ext4/balloc.c       |    1 +
 fs/ext4/defrag.c       |  264 ++++++++++++++++++++++++++++++++++++++++++-----
 fs/ext4/ext4.h         |   20 ++++-
 fs/ext4/ext4_extents.h |    3 +
 fs/ext4/extents.c      |   52 ++++++++--
 fs/ext4/ioctl.c        |   16 +++-
 fs/ext4/mballoc.c      |    5 +
 fs/ext4/mballoc.h      |    1 +
 8 files changed, 322 insertions(+), 40 deletions(-)
fs/ext4/balloc.c +1 -0
index b9821be..e791484 100644
@@ -705,6 +705,7 @@ static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
 	ar.goal = goal;
 	ar.len = *count;
 	ar.logical = iblock;
+	ar.excepted_group = -1;
 
 	if (S_ISREG(inode->i_mode) && !(flags & EXT4_META_BLOCK))
 		/* enable in-core preallocation for data block allocation */
fs/ext4/defrag.c +236 -28

517 lines not on this page · raw message

fs/ext4/ext4.h +19 -1
index c72703f..e0b09dc 100644
@@ -97,6 +97,11 @@ struct ext4_allocation_request {
 	unsigned long len;
 	/* flags. see above EXT4_MB_HINT_* */
 	unsigned long flags;
+	/*
+	 * for ext4 online defrag:
+	 * the block group which is excepted from allocation target
+	 */
+	long long excepted_group;
 };
 
 /*
@@ -306,6 +311,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_SUPER_INFO		_IOR('f', 16, struct ext4_super_block)
 #define EXT4_IOC_FREE_BLOCKS_INFO	_IOWR('f', 17, struct ext4_extents_info)
 #define EXT4_IOC_FIEMAP_INO		_IOWR('f', 18, struct fiemap_ino)
+#define EXT4_IOC_MOVE_VICTIM		_IOW('f', 19, struct ext4_extents_info)
 
 /*
  * ioctl commands in 32 bit emulation
@@ -328,8 +334,15 @@ struct ext4_new_group_data {
  *
  * DEFRAG_MAX_ENT:	the maximum number of extents for exchanging between
  *			kernel-space and user-space per an ioctl
+ * DEFRAG_FORCE_TRY:	check whether we have free space fragmentation or not
+ * DEFRAG_FORCE_VICTIM:	move victim extents to make sufficient space
+ * DEFRAG_FORCE_GATHER:	move the target file into the free space made in the
+ *			DEFRAG_FORCE_VICTIM phase
  */
 #define DEFRAG_MAX_ENT		32
+#define DEFRAG_FORCE_TRY	1
+#define DEFRAG_FORCE_VICTIM	2
+#define DEFRAG_FORCE_GATHER	3
 
 struct ext4_extent_data {
 	ext4_lblk_t block;		/* start logical block number */
@@ -341,6 +354,8 @@ struct ext4_ext_defrag_data {
 	ext4_lblk_t start_offset;	/* start offset to defrag in blocks */
 	ext4_lblk_t defrag_size;	/* size of defrag in blocks */
 	ext4_fsblk_t goal;		/* block offset for allocation */
+	int flag;			/* free space mode flag */
+	struct ext4_extent_data ext;
 };
 
 struct ext4_extents_info {
@@ -1190,8 +1205,11 @@ extern void ext4_inode_table_set(struct super_block *sb,
 extern int ext4_ext_journal_restart(handle_t *handle, int needed);
 /* defrag.c */
 extern int ext4_defrag(struct file *filp, ext4_lblk_t block_start,
-			ext4_lblk_t defrag_size, ext4_fsblk_t goal);
+			ext4_lblk_t defrag_size, ext4_fsblk_t goal,
+			int flag, struct ext4_extent_data *ext);
 extern int ext4_defrag_fiemap_ino(struct file *filp, unsigned long arg);
+extern int ext4_defrag_move_victim(struct file *target_filp,
+				struct ext4_extents_info *ext_info);
 
 static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
 {
fs/ext4/ext4_extents.h +3 -0
index 39e043b..9b9dee9 100644
@@ -250,6 +250,9 @@ extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex);
 extern ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
 					struct ext4_ext_path *path,
 					ext4_lblk_t block);
+extern int ext4_ext_insert_extent_defrag(handle_t *handle, struct inode *inode,
+					struct ext4_ext_path *path,
+					struct ext4_extent *newext, int defrag);
 
 #endif /* _EXT4_EXTENTS */
 
fs/ext4/extents.c +42 -10

131 lines not on this page · raw message

fs/ext4/ioctl.c +15 -1
index b69b54a..15050d3 100644
@@ -242,7 +242,8 @@ setversion_out:
 		}
 
 		err = ext4_defrag(filp, defrag.start_offset,
-			defrag.defrag_size, defrag.goal);
+			defrag.defrag_size, defrag.goal, defrag.flag,
+			&defrag.ext);
 		return err;
 	}
 
@@ -283,6 +284,19 @@ setversion_out:
 		return err;
 	}
 
+	case EXT4_IOC_MOVE_VICTIM: {
+		struct ext4_extents_info ext_info;
+		int err;
+
+		if (copy_from_user(&ext_info,
+			(struct ext4_extents_info __user *)arg,
+						sizeof(ext_info)))
+			return -EFAULT;
+
+		err = ext4_defrag_move_victim(filp, &ext_info);
+		return err;
+	}
+
 	case EXT4_IOC_GROUP_ADD: {
 		struct ext4_new_group_data input;
 		struct super_block *sb = inode->i_sb;
fs/ext4/mballoc.c +5 -0
index eebcf7c..d523e42 100644
@@ -1774,6 +1774,10 @@ repeat:
 			if (group == EXT4_SB(sb)->s_groups_count)
 				group = 0;
 
+			if (ac->ac_excepted_group != -1 &&
+			    group == ac->ac_excepted_group)
+				continue;
+
 			/* quick check to skip empty groups */
 			grp = ext4_get_group_info(ac->ac_sb, group);
 			if (grp->bb_free == 0)
@@ -4069,6 +4073,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
 	ac->ac_bitmap_page = NULL;
 	ac->ac_buddy_page = NULL;
 	ac->ac_lg = NULL;
+	ac->ac_excepted_group = ar->excepted_group;
 
 	/* we have to define context: we'll we work with a file or
 	 * locality group. this is a policy, actually */
fs/ext4/mballoc.h +1 -0
index b5dff1f..557308a 100644
@@ -219,6 +219,7 @@ struct ext4_allocation_context {
 	struct page *ac_buddy_page;
 	struct ext4_prealloc_space *ac_pa;
 	struct ext4_locality_group *ac_lg;
+	long long ac_excepted_group;
 };
 
 #define AC_STATUS_CONTINUE	1