Patchwork [05/11,RESEND] e4defrag: Use get_fragment_score() for decision of whether to defrag

login
register
mail settings
Submitter Kazuya Mio
Date June 15, 2011, 6:36 a.m.
Message ID <4DF852EE.1090306@sx.jp.nec.com>
Download mbox | patch
Permalink /patch/100483/
State Superseded
Headers show

Comments

Kazuya Mio - June 15, 2011, 6:36 a.m.
This makes e4defrag use get_fragment_score() to calculate fragmentation
score. If fragmentation score of the target file is zero or less than the
destination file's one, e4defrag stops defragmentation.

The threshold that shows whether a fragment is good or not comes from
"blocksize * 8 - 2048". It's the same value as filefrag.

Signed-off-by: Kazuya Mio <k-mio@sx.jp.nec.com>
---
 misc/Makefile.in |    4 +--
 misc/e4defrag.c  |   64 +++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 60 insertions(+), 8 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/misc/Makefile.in b/misc/Makefile.in
index 19eaa43..681475b 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -196,9 +196,9 @@  e2undo.profiled: $(PROFILED_E2UNDO_OBJS) $(PROFILED_DEPLIBS)
 	$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \
 		$(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL)
 
-e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS)
+e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS) $(DEPLIBS_E2P)
 	$(E) "	LD $@"
-	$(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS)
+	$(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) $(LIBE2P)
 
 e4defrag.profiled: $(PROFILED_E4DEFRAG_OBJS) $(PROFILED_DEPLIBS)
 	$(E) "	LD $@"
diff --git a/misc/e4defrag.c b/misc/e4defrag.c
index b168700..891bad4 100644
--- a/misc/e4defrag.c
+++ b/misc/e4defrag.c
@@ -31,16 +31,18 @@ 
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <ext2fs/ext2_types.h>
 #include <linux/fs.h>
 #include <sys/ioctl.h>
-#include <ext2fs/fiemap.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/statfs.h>
 #include <sys/syscall.h>
 #include <sys/vfs.h>
 
+#include "e2p/e2p.h"
+#include "ext2fs/ext2_types.h"
+#include "ext2fs/fiemap.h"
+
 /* A relatively new ioctl interface ... */
 #ifndef EXT4_IOC_MOVE_EXT
 #define EXT4_IOC_MOVE_EXT      _IOWR('f', 15, struct move_extent)
@@ -107,6 +109,7 @@ 
 #define NGMSG_FILE_OPEN		"Failed to open"
 #define NGMSG_FILE_UNREG	"File is not regular file"
 #define NGMSG_LOST_FOUND	"Can not process \"lost+found\""
+#define NGMSG_EXT_FORMAT	"File is not extent format"
 
 /* Data type for filesystem-wide blocks number */
 typedef unsigned long long ext4_fsblk_t;
@@ -961,9 +964,11 @@  static int file_defrag(const char *file, const struct stat64 *buf,
 {
 	int	fd;
 	int	donor_fd = -1;
+	int	orig_score = 0, donor_score = 0;
 	int	ret;
 	int	file_frags_start, file_frags_end;
 	char	tmp_inode_name[PATH_MAX + 8];
+	size_t	threshold;
 	ext4_fsblk_t			blk_count = 0;
 	struct fiemap_extent_list	*orig_list = NULL;
 	struct fiemap_extent_list	*donor_list = NULL;
@@ -1046,16 +1051,26 @@  static int file_defrag(const char *file, const struct stat64 *buf,
 		goto out;
 	}
 
-	/* Combine extents to group */
-	ret = join_extents(orig_list, &orig_group_head);
-	if (ret < 0) {
+	/*
+	 * Calculate the threshold of perfection.
+	 * NOTE: 2048 means the maximum block region of mballoc.
+	 */
+	threshold = (block_size * 8 - 2048) * block_size;
+	orig_score = get_fragment_score(fd, threshold);
+	if (orig_score < 0) {
 		if (mode_flag & DETAIL) {
 			PRINT_FILE_NAME(file);
-			PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+			if (errno == EOPNOTSUPP)
+				PRINT_ERR_MSG_WITH_ERRNO(NGMSG_EXT_FORMAT);
+			else
+				PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
 		}
 		goto out;
 	}
 
+	if (!orig_score)
+		goto check_improvement;
+
 	/* Create donor inode */
 	memset(tmp_inode_name, 0, PATH_MAX + 8);
 	sprintf(tmp_inode_name, "%.*s.defrag",
@@ -1083,6 +1098,16 @@  static int file_defrag(const char *file, const struct stat64 *buf,
 		goto out;
 	}
 
+	/* Combine extents to group */
+	ret = join_extents(orig_list, &orig_group_head);
+	if (ret < 0) {
+		if (mode_flag & DETAIL) {
+			PRINT_FILE_NAME(file);
+			PRINT_ERR_MSG_WITH_ERRNO("Failed to allocate memory");
+		}
+		goto out;
+	}
+
 	/* Allocate space for donor inode */
 	orig_group_tmp = orig_group_head;
 	do {
@@ -1110,6 +1135,16 @@  static int file_defrag(const char *file, const struct stat64 *buf,
 		goto out;
 	}
 
+	donor_score = get_fragment_score(donor_fd, threshold);
+	if (donor_score < 0) {
+		if (mode_flag & DETAIL) {
+			PRINT_FILE_NAME(file);
+			PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
+		}
+		goto out;
+	}
+
+check_improvement:
 	if (mode_flag & DETAIL) {
 		if (file_frags_start != 1)
 			frag_files_before_defrag++;
@@ -1117,6 +1152,23 @@  static int file_defrag(const char *file, const struct stat64 *buf,
 		extents_before_defrag += file_frags_start;
 	}
 
+	if (!orig_score || orig_score <= donor_score) {
+		printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
+			defraged_file_count, total_count, file, 100);
+		if (mode_flag & DETAIL)
+			printf("  extents: %d -> %d",
+				file_frags_start, file_frags_start);
+
+		printf("\t[ OK ]\n");
+		succeed_cnt++;
+
+		if (file_frags_start != 1)
+			frag_files_after_defrag++;
+
+		extents_after_defrag += file_frags_start;
+		goto out;
+	}
+
 	/* Defrag the file */
 	ret = call_defrag(fd, donor_fd, file, buf, donor_list);