[RFC][PATCH 5/8]ext4: defragmentation for the relevant files (-r mode)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ext4: online defrag-- Defragmentation for the relevant files (-r mode)

From: Akira Fujita <a-fujita@xxxxxxxxxxxxx>

Relevant file fragmentation could be solved by moving
the files under the specified directory close together with
the block containing the directory data.

Signed-off-by: Akira Fujita <a-fujita@xxxxxxxxxxxxx>
Signed-off-by: Takashi Sato <t-sato@xxxxxxxxxxxxx>
---
 fs/ext4/defrag.c |   48 +++++++++++++++++++++++++++++++++++-------------
 fs/ext4/ext4.h   |    4 +++-
 fs/ext4/inode.c  |    2 +-
 fs/ext4/ioctl.c  |    1 +
 4 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/fs/ext4/defrag.c b/fs/ext4/defrag.c
index 8ae5a48..61f577b 100644
--- a/fs/ext4/defrag.c
+++ b/fs/ext4/defrag.c
@@ -95,13 +95,26 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 {
 	int err = 0;

-	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) {
+	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL ||
+					cmd == EXT4_IOC_FIBMAP)) {
 		printk(KERN_ERR "ext4 defrag: ino[%lu] is not extents "
 					"based file\n", inode->i_ino);
 		return -EOPNOTSUPP;
 	}

-	if (cmd == EXT4_IOC_DEFRAG) {
+	if (cmd == EXT4_IOC_FIBMAP) {
+		ext4_fsblk_t __user *p = (ext4_fsblk_t __user *)arg;
+		ext4_fsblk_t block = 0;
+		struct address_space *mapping = filp->f_mapping;
+
+		if (copy_from_user(&block, (ext4_fsblk_t __user *)arg,
+					sizeof(block)))
+			return -EFAULT;
+
+		block = ext4_bmap(mapping, block);
+
+		return put_user(block, p);
+	} else if (cmd == EXT4_IOC_DEFRAG) {
 		struct ext4_ext_defrag_data defrag;
 		struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;

@@ -127,7 +140,7 @@ int ext4_defrag_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 		}

 		err = ext4_defrag(filp, defrag.start_offset,
-				defrag.defrag_size);
+				defrag.defrag_size, defrag.goal);
 	}

 	return err;
@@ -745,6 +758,7 @@ out:
  * @dest_path:		indicating the temporary inode's extent
  * @req_blocks:		contiguous blocks count we need
  * @iblock:		target file offset
+ * @goal:		goal offset
  *
  */
 static void
@@ -752,7 +766,8 @@ ext4_defrag_fill_ar(struct inode *org_inode, struct inode *dest_inode,
 			struct ext4_allocation_request *ar,
 			struct ext4_ext_path *org_path,
 			struct ext4_ext_path *dest_path,
-			ext4_fsblk_t req_blocks, ext4_lblk_t iblock)
+			ext4_fsblk_t req_blocks, ext4_lblk_t iblock,
+			ext4_fsblk_t goal)
 {
 	ar->inode = dest_inode;
 	ar->len = req_blocks;
@@ -764,7 +779,10 @@ ext4_defrag_fill_ar(struct inode *org_inode, struct inode *dest_inode,
 	ar->lright = 0;
 	ar->pright = 0;

-	ar->goal = ext4_ext_find_goal(dest_inode, dest_path, iblock);
+	if (goal)
+		ar->goal = goal;
+	else
+		ar->goal = ext4_ext_find_goal(dest_inode, dest_path, iblock);
 }

 /**
@@ -941,6 +959,7 @@ out:
  *			original extent tree
  * @tar_end:		the last block number of the allocated blocks
  * @sum_tmp:		the extents count  in the allocated blocks
+ * @goal:		block offset for allocaton
  *
  *
  * This function returns the values as below.
@@ -951,7 +970,7 @@ out:
 static int
 ext4_defrag_comp_ext_count(struct inode *org_inode,
 			struct ext4_ext_path *org_path, ext4_lblk_t tar_end,
-			int sum_tmp)
+			int sum_tmp, ext4_fsblk_t goal)
 {
 	struct ext4_extent *ext = NULL;
 	int depth = ext_depth(org_inode);
@@ -975,7 +994,7 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,
 			 * Fail if goal is not set and the fragmentation
 			 * is not improved.
 			 */
-			if (sum_org == sum_tmp) {
+			if (sum_org == sum_tmp && !goal) {
 				/* Not improved */
 				ret = 1;
 			} else if (sum_org < sum_tmp) {
@@ -1006,6 +1025,7 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,
  * @tar_start:		starting offset to allocate in blocks
  * @tar_blocks:		the number of blocks to allocate
  * @iblock:		file related offset
+ * @goal:		block offset for allocaton
  *
  *
  * This function returns the value as below:
@@ -1016,7 +1036,8 @@ ext4_defrag_comp_ext_count(struct inode *org_inode,
 static int
 ext4_defrag_new_extent_tree(struct inode *org_inode, struct inode *tmp_inode,
 			struct ext4_ext_path *org_path, ext4_lblk_t tar_start,
-			ext4_lblk_t tar_blocks, ext4_lblk_t iblock)
+			ext4_lblk_t tar_blocks, ext4_lblk_t iblock,
+			ext4_fsblk_t goal)
 {
 	handle_t *handle;
 	struct ext4_extent_header *eh = NULL;
@@ -1042,7 +1063,7 @@ ext4_defrag_new_extent_tree(struct inode *org_inode, struct inode *tmp_inode,

 	/* Fill struct ext4_allocation_request with necessary info */
 	ext4_defrag_fill_ar(org_inode, tmp_inode, &ar, org_path,
-				dest_path, tar_blocks, iblock);
+				dest_path, tar_blocks, iblock, goal);

 	handle = ext4_journal_start(tmp_inode, 0);
 	if (IS_ERR(handle)) {
@@ -1074,7 +1095,7 @@ ext4_defrag_new_extent_tree(struct inode *org_inode, struct inode *tmp_inode,
 	}

 	ret = ext4_defrag_comp_ext_count(org_inode, org_path, tar_end,
-					sum_tmp);
+					sum_tmp, goal);

 out:
 	if (ret < 0 || ret == 1) {
@@ -1204,13 +1225,14 @@ out:
  * @filp:		pointer to file
  * @block_start:	starting offset to defrag in blocks
  * @defrag_size:	size of defrag in blocks
+ * @goal:		block offset for allocation
  *
  * This function returns the number of blocks if succeed, otherwise
  * returns error value.
  */
 int
 ext4_defrag(struct file *filp, ext4_lblk_t block_start,
-		ext4_lblk_t defrag_size)
+		ext4_lblk_t defrag_size, ext4_fsblk_t goal)
 {
 	struct inode *org_inode = filp->f_dentry->d_inode, *tmp_inode = NULL;
 	struct ext4_ext_path *org_path = NULL, *holecheck_path = NULL;
@@ -1329,14 +1351,14 @@ ext4_defrag(struct file *filp, ext4_lblk_t block_start,
 		}

 		/* Found an isolated block */
-		if (seq_extents == 1) {
+		if (seq_extents == 1 && !goal) {
 			seq_start = le32_to_cpu(ext_cur->ee_block);
 			goto CLEANUP;
 		}

 		ret = ext4_defrag_new_extent_tree(org_inode, tmp_inode,
 					org_path, seq_start, seq_blocks,
-					block_start);
+					block_start, goal);

 		if (ret < 0) {
 			break;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 1e9ce39..12b3fea 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -298,6 +298,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_GETRSVSZ		_IOR('f', 5, long)
 #define EXT4_IOC_SETRSVSZ		_IOW('f', 6, long)
 #define EXT4_IOC_MIGRATE		_IO('f', 7)
+#define EXT4_IOC_FIBMAP			_IOW('f', 9, ext4_fsblk_t)
 #define EXT4_IOC_DEFRAG		_IOW('f', 10, struct ext4_ext_defrag_data)

 /*
@@ -1018,6 +1019,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 				    __u32 minor_hash,
 				    struct ext4_dir_entry_2 *dirent);
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
+extern sector_t ext4_bmap(struct address_space *mapping, sector_t block);

 /* fsync.c */
 extern int ext4_sync_file (struct file *, struct dentry *, int);
@@ -1133,7 +1135,7 @@ extern void ext4_inode_table_set(struct super_block *sb,
 extern handle_t *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_lblk_t defrag_size, ext4_fsblk_t goal);
 extern int ext4_defrag_ioctl(struct inode *, struct file *, unsigned int,
 				unsigned long);

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index a30f56c..27f3d2c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1648,7 +1648,7 @@ out:
  * So, if we see any bmap calls here on a modified, data-journaled file,
  * take extra steps to flush any blocks which might be in the cache.
  */
-static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
+sector_t ext4_bmap(struct address_space *mapping, sector_t block)
 {
 	struct inode *inode = mapping->host;
 	journal_t *journal;
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 4c7fca1..e1b9c10 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -241,6 +241,7 @@ setversion_out:

 		return err;
 	}
+	case EXT4_IOC_FIBMAP:
 	case EXT4_IOC_DEFRAG: {
 		return ext4_defrag_ioctl(inode, filp, cmd, arg);
 	}

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux