2010-08-29 19:47:30

by Andreas Rid

[permalink] [raw]
Subject: [patch] e4defrag: relevant file fragmentation with base_file

hi Kazuya Mio,

as I promised the implementation of the new interface
e4defrag -r base_file move_file..

Feel free to change.

Andreas

diff --git a/misc/e4defrag.c b/misc/e4defrag.c
index 6022758..b7813d7 100644
--- a/misc/e4defrag.c
+++ b/misc/e4defrag.c
@@ -125,7 +125,8 @@
#define MSG_USAGE \
"Usage : e4defrag [-v] file...| directory...| device...\n\
: e4defrag -c file...| directory...| device...\n\
- : e4defrag -r directory...| device...\n"
+ : e4defrag -r directory...| device...\n\
+ : e4defrag -r base_file move_file...\n"

#define NGMSG_EXT4 "Filesystem is not ext4 filesystem"
#define NGMSG_FILE_EXTENT "Failed to get file extents"
@@ -133,7 +134,6 @@
#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_FILE_UNDIR "Target is not directory"

/* Data type for filesystem-wide blocks number */
typedef unsigned long long ext4_fsblk_t;
@@ -1593,7 +1593,7 @@ static int call_defrag(int fd, int donor_fd, const char *file,
return 0;
}

-static unsigned long long get_dir_offset(const int fd, int *ret)
+static unsigned long long get_physical_offset(const int fd, int *ret)
{
struct fiemap *fiemap_buf;
char *fiebuf;
@@ -2129,13 +2129,6 @@ int main(int argc, char *argv[])
continue;
}

- /* -r mode can defrag only directory. */
- if ((mode_flag & RELEVANT) && arg_type == FILENAME) {
- PRINT_ERR_MSG(NGMSG_FILE_UNDIR);
- PRINT_FILE_NAME(argv[i]);
- continue;
- }
-
/* Set blocksize */
block_size = buf.st_blksize;

@@ -2223,7 +2216,7 @@ int main(int argc, char *argv[])
continue;
}

- r_pstart = get_dir_offset(fd, &ret);
+ r_pstart = get_physical_offset(fd, &ret);
if (ret < 0) {
if (mode_flag & DETAIL) {
perror("failed to fiemap\n");
@@ -2327,8 +2320,44 @@ int main(int argc, char *argv[])
} else
printf("ext4 defragmentation for %s\n",
argv[i]);
- /* Defrag single file process */
- file_defrag(argv[i], &buf, FTW_F, NULL);
+
+ if (mode_flag & RELEVANT && i == optind) {
+ if (i - argc == 1)
+ /* not enought arguemnts */
+ goto out;
+
+ /*
+ * call defrag for base_file
+ * don't move extents to r_pstart
+ */
+ mode_flag &= ~RELEVANT;
+ file_defrag(argv[i], &buf, FTW_F, NULL);
+ mode_flag |= RELEVANT;
+
+ /* get physical start of base_file for PA */
+ int fd, ret;
+ fd = open(argv[i], O_RDONLY);
+ if (fd < 0) {
+ if (mode_flag & DETAIL) {
+ PRINT_FILE_NAME(argv[i]);
+ STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
+ }
+ goto out;
+ }
+
+ r_pstart = get_physical_offset(fd, &ret);
+ if (ret < 0) {
+ if (mode_flag & DETAIL) {
+ perror("failed to fiemap\n");
+ PRINT_FILE_NAME(dir_name);
+ }
+ goto out;
+ }
+ close(fd);
+ } else
+ /* Defrag single file process */
+ file_defrag(argv[i], &buf, FTW_F, NULL);
+
if (succeed_cnt != 0)
printf(" Success:\t\t\t[1/1]\n");
else


2010-09-01 08:32:37

by Kazuya Mio

[permalink] [raw]
Subject: Re: [patch] e4defrag: relevant file fragmentation with base_file

2010/08/30 4:47, Andreas Rid wrote:
> @@ -2327,8 +2320,44 @@ int main(int argc, char *argv[])
> } else
> printf("ext4 defragmentation for %s\n",
> argv[i]);
> - /* Defrag single file process */
> - file_defrag(argv[i],&buf, FTW_F, NULL);
> +
> + if (mode_flag& RELEVANT&& i == optind) {
> + if (i - argc == 1)
> + /* not enought arguemnts */
> + goto out;

I think this condition should be "argc - optind == 1" because "i" is smaller
than argc at all times.

> + goto out;
> + }
> +
> + r_pstart = get_physical_offset(fd,&ret);

If e4defrag is executed with the following arguments, e4defrag will move the
extents of "move_file" near the "directory".
# e4defrag -r base_file directory move_file

To prevent this case, r_pstart should not be changed even if directories or
devices are set to the argument of e4defrag after the physical block number of
the "base_file" was assigned to r_pstart.

I will fix your patch in above way. Any comments?

Regards,
Kazuya Mio