Whamcloud - gitweb
Shorten compile commands run by the build system
[tools/e2fsprogs.git] / misc / e4defrag.c
1 /*
2  * e4defrag.c - ext4 filesystem defragmenter
3  *
4  * Copyright (C) 2009 NEC Software Tohoku, Ltd.
5  *
6  * Author: Akira Fujita <a-fujita@rs.jp.nec.com>
7  *         Takashi Sato <t-sato@yk.jp.nec.com>
8  */
9
10 #ifndef _LARGEFILE_SOURCE
11 #define _LARGEFILE_SOURCE
12 #endif
13
14 #ifndef _LARGEFILE64_SOURCE
15 #define _LARGEFILE64_SOURCE
16 #endif
17
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21
22 #include "config.h"
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <endian.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <ftw.h>
29 #include <limits.h>
30 #include <mntent.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <ext2fs/ext2_types.h>
36 #include <ext2fs/ext2fs.h>
37 #include <linux/fs.h>
38 #include <sys/ioctl.h>
39 #include <ext2fs/fiemap.h>
40 #include <sys/mman.h>
41 #include <sys/stat.h>
42 #include <sys/statfs.h>
43 #include <sys/syscall.h>
44 #include <sys/vfs.h>
45
46 /* A relatively new ioctl interface ... */
47 #ifndef EXT4_IOC_MOVE_EXT
48 #define EXT4_IOC_MOVE_EXT      _IOWR('f', 15, struct move_extent)
49 #endif
50
51 /* Macro functions */
52 #define PRINT_ERR_MSG(msg)      fprintf(stderr, "%s\n", (msg))
53 #define IN_FTW_PRINT_ERR_MSG(msg)       \
54         fprintf(stderr, "\t%s\t\t[ NG ]\n", (msg))
55 #define PRINT_FILE_NAME(file)   fprintf(stderr, " \"%s\"\n", (file))
56 #define PRINT_ERR_MSG_WITH_ERRNO(msg)   \
57         fprintf(stderr, "\t%s:%s\t[ NG ]\n", (msg), strerror(errno))
58 #define STATISTIC_ERR_MSG(msg)  \
59         fprintf(stderr, "\t%s\n", (msg))
60 #define STATISTIC_ERR_MSG_WITH_ERRNO(msg)       \
61         fprintf(stderr, "\t%s:%s\n", (msg), strerror(errno))
62 #define min(x, y) (((x) > (y)) ? (y) : (x))
63 #define CALC_SCORE(ratio) \
64         ((ratio) > 10 ? (80 + 20 * (ratio) / 100) : (8 * (ratio)))
65 /* Wrap up the free function */
66 #define FREE(tmp)                               \
67         do {                                    \
68                 if ((tmp) != NULL)              \
69                         free(tmp);              \
70         } while (0)                             \
71 /* Insert list2 after list1 */
72 #define insert(list1, list2)                    \
73         do {                                    \
74                 list2->next = list1->next;      \
75                 list1->next->prev = list2;      \
76                 list2->prev = list1;            \
77                 list1->next = list2;            \
78         } while (0)
79
80 /* To delete unused warning */
81 #ifdef __GNUC__
82 #define EXT2FS_ATTR(x) __attribute__(x)
83 #else
84 #define EXT2FS_ATTR(x)
85 #endif
86
87 /* The mode of defrag */
88 #define DETAIL                  0x01
89 #define STATISTIC               0x02
90
91 #define DEVNAME                 0
92 #define DIRNAME                 1
93 #define FILENAME                2
94
95 #define FTW_OPEN_FD             2000
96
97 #define FS_EXT4                 "ext4"
98 #define ROOT_UID                0
99
100 #define BOUND_SCORE             55
101 #define SHOW_FRAG_FILES 5
102
103 /* Magic number for ext4 */
104 #define EXT4_SUPER_MAGIC        0xEF53
105
106 /* Definition of flex_bg */
107 #define EXT4_FEATURE_INCOMPAT_FLEX_BG           0x0200
108
109 /* The following macro is used for ioctl FS_IOC_FIEMAP
110  * EXTENT_MAX_COUNT:    the maximum number of extents for exchanging between
111  *                      kernel-space and user-space per ioctl
112  */
113 #define EXTENT_MAX_COUNT        512
114
115 /* The following macros are error message */
116 #define MSG_USAGE               \
117 "Usage  : e4defrag [-v] file...| directory...| device...\n\
118         : e4defrag  -c  file...| directory...| device...\n"
119
120 #define NGMSG_EXT4              "Filesystem is not ext4 filesystem"
121 #define NGMSG_FILE_EXTENT       "Failed to get file extents"
122 #define NGMSG_FILE_INFO         "Failed to get file information"
123 #define NGMSG_FILE_OPEN         "Failed to open"
124 #define NGMSG_FILE_UNREG        "File is not regular file"
125 #define NGMSG_LOST_FOUND        "Can not process \"lost+found\""
126
127 /* Data type for filesystem-wide blocks number */
128 typedef unsigned long long ext4_fsblk_t;
129
130 struct fiemap_extent_data {
131         __u64 len;                      /* blocks count */
132         __u64 logical;          /* start logical block number */
133         ext4_fsblk_t physical;          /* start physical block number */
134 };
135
136 struct fiemap_extent_list {
137         struct fiemap_extent_list *prev;
138         struct fiemap_extent_list *next;
139         struct fiemap_extent_data data; /* extent belong to file */
140 };
141
142 struct fiemap_extent_group {
143         struct fiemap_extent_group *prev;
144         struct fiemap_extent_group *next;
145         __u64 len;      /* length of this continuous region */
146         struct fiemap_extent_list *start;       /* start ext */
147         struct fiemap_extent_list *end;         /* end ext */
148 };
149
150 struct move_extent {
151         __s32 reserved; /* original file descriptor */
152         __u32 donor_fd; /* donor file descriptor */
153         __u64 orig_start;       /* logical start offset in block for orig */
154         __u64 donor_start;      /* logical start offset in block for donor */
155         __u64 len;      /* block length to be moved */
156         __u64 moved_len;        /* moved block length */
157 };
158
159 struct frag_statistic_ino {
160         int now_count;  /* the file's extents count of before defrag */
161         int best_count; /* the best file's extents count */
162         __u64 size_per_ext;     /* size(KB) per extent */
163         float ratio;    /* the ratio of fragmentation */
164         char msg_buffer[PATH_MAX + 1];  /* pathname of the file */
165 };
166
167 char    lost_found_dir[PATH_MAX + 1];
168 int     block_size;
169 int     extents_before_defrag;
170 int     extents_after_defrag;
171 int     mode_flag;
172 unsigned int    current_uid;
173 unsigned int    defraged_file_count;
174 unsigned int    frag_files_before_defrag;
175 unsigned int    frag_files_after_defrag;
176 unsigned int    regular_count;
177 unsigned int    succeed_cnt;
178 unsigned int    total_count;
179 __u8 log_groups_per_flex;
180 __u32 blocks_per_group;
181 __u32 feature_incompat;
182 ext4_fsblk_t    files_block_count;
183 struct frag_statistic_ino       frag_rank[SHOW_FRAG_FILES];
184
185
186 /* Local definitions of some syscalls glibc may not yet have */
187
188 #ifndef HAVE_POSIX_FADVISE
189 #warning Using locally defined posix_fadvise interface.
190
191 #ifndef __NR_fadvise64_64
192 #error Your kernel headers dont define __NR_fadvise64_64
193 #endif
194
195 /*
196  * fadvise() -          Give advice about file access.
197  *
198  * @fd:                 defrag target file's descriptor.
199  * @offset:             file offset.
200  * @len:                area length.
201  * @advise:             process flag.
202  */
203 static int posix_fadvise(int fd, loff_t offset, size_t len, int advise)
204 {
205         return syscall(__NR_fadvise64_64, fd, offset, len, advise);
206 }
207 #endif /* ! HAVE_FADVISE64_64 */
208
209 #ifndef HAVE_SYNC_FILE_RANGE
210 #warning Using locally defined sync_file_range interface.
211
212 #ifndef __NR_sync_file_range
213 #ifndef __NR_sync_file_range2 /* ppc */
214 #error Your kernel headers dont define __NR_sync_file_range
215 #endif
216 #endif
217
218 /*
219  * sync_file_range() -  Sync file region.
220  *
221  * @fd:                 defrag target file's descriptor.
222  * @offset:             file offset.
223  * @length:             area length.
224  * @flag:               process flag.
225  */
226 int sync_file_range(int fd, loff_t offset, loff_t length, unsigned int flag)
227 {
228 #ifdef __NR_sync_file_range
229         return syscall(__NR_sync_file_range, fd, offset, length, flag);
230 #else
231         return syscall(__NR_sync_file_range2, fd, flag, offset, length);
232 #endif
233 }
234 #endif /* ! HAVE_SYNC_FILE_RANGE */
235
236 #ifndef HAVE_FALLOCATE64
237 #warning Using locally defined fallocate syscall interface.
238
239 #ifndef __NR_fallocate
240 #error Your kernel headers dont define __NR_fallocate
241 #endif
242
243 /*
244  * fallocate64() -      Manipulate file space.
245  *
246  * @fd:                 defrag target file's descriptor.
247  * @mode:               process flag.
248  * @offset:             file offset.
249  * @len:                file size.
250  */
251 static int fallocate64(int fd, int mode, loff_t offset, loff_t len)
252 {
253         return syscall(__NR_fallocate, fd, mode, offset, len);
254 }
255 #endif /* ! HAVE_FALLOCATE */
256
257 /*
258  * get_mount_point() -  Get device's mount point.
259  *
260  * @devname:            the device's name.
261  * @mount_point:        the mount point.
262  * @dir_path_len:       the length of directory.
263  */
264 static int get_mount_point(const char *devname, char *mount_point,
265                                                         int dir_path_len)
266 {
267         /* Refer to /etc/mtab */
268         const char      *mtab = MOUNTED;
269         FILE    *fp = NULL;
270         struct mntent   *mnt = NULL;
271
272         fp = setmntent(mtab, "r");
273         if (fp == NULL) {
274                 perror("Couldn't access /etc/mtab");
275                 return -1;
276         }
277
278         while ((mnt = getmntent(fp)) != NULL) {
279                 if (strcmp(devname, mnt->mnt_fsname) != 0)
280                         continue;
281
282                 endmntent(fp);
283                 if (strcmp(mnt->mnt_type, FS_EXT4) == 0) {
284                         strncpy(mount_point, mnt->mnt_dir,
285                                 dir_path_len);
286                         return 0;
287                 }
288                 PRINT_ERR_MSG(NGMSG_EXT4);
289                 return -1;
290         }
291         endmntent(fp);
292         PRINT_ERR_MSG("Filesystem is not mounted");
293         return -1;
294 }
295
296 /*
297  * is_ext4() -          Whether on an ext4 filesystem.
298  *
299  * @file:               the file's name.
300  */
301 static int is_ext4(const char *file, char *devname)
302 {
303         int     maxlen = 0;
304         int     len, ret;
305         FILE    *fp = NULL;
306         char    *mnt_type = NULL;
307         /* Refer to /etc/mtab */
308         const char      *mtab = MOUNTED;
309         char    file_path[PATH_MAX + 1];
310         struct mntent   *mnt = NULL;
311         struct statfs64 fsbuf;
312
313         /* Get full path */
314         if (realpath(file, file_path) == NULL) {
315                 perror("Couldn't get full path");
316                 PRINT_FILE_NAME(file);
317                 return -1;
318         }
319
320         if (statfs64(file_path, &fsbuf) < 0) {
321                 perror("Failed to get filesystem information");
322                 PRINT_FILE_NAME(file);
323                 return -1;
324         }
325
326         if (fsbuf.f_type != EXT4_SUPER_MAGIC) {
327                 PRINT_ERR_MSG(NGMSG_EXT4);
328                 return -1;
329         }
330
331         fp = setmntent(mtab, "r");
332         if (fp == NULL) {
333                 perror("Couldn't access /etc/mtab");
334                 return -1;
335         }
336
337         while ((mnt = getmntent(fp)) != NULL) {
338                 if (mnt->mnt_fsname[0] != '/')
339                         continue;
340                 len = strlen(mnt->mnt_dir);
341                 ret = memcmp(file_path, mnt->mnt_dir, len);
342                 if (ret != 0)
343                         continue;
344
345                 if (maxlen >= len)
346                         continue;
347
348                 maxlen = len;
349
350                 mnt_type = realloc(mnt_type, strlen(mnt->mnt_type) + 1);
351                 if (mnt_type == NULL) {
352                         endmntent(fp);
353                         return -1;
354                 }
355                 memset(mnt_type, 0, strlen(mnt->mnt_type) + 1);
356                 strncpy(mnt_type, mnt->mnt_type, strlen(mnt->mnt_type));
357                 strncpy(lost_found_dir, mnt->mnt_dir, PATH_MAX);
358                 strncpy(devname, mnt->mnt_fsname, strlen(mnt->mnt_fsname) + 1);
359         }
360
361         endmntent(fp);
362         if (strcmp(mnt_type, FS_EXT4) == 0) {
363                 FREE(mnt_type);
364                 return 0;
365         } else {
366                 FREE(mnt_type);
367                 PRINT_ERR_MSG(NGMSG_EXT4);
368                 return -1;
369         }
370 }
371
372 /*
373  * calc_entry_counts() -        Calculate file counts.
374  *
375  * @file:               file name.
376  * @buf:                file info.
377  * @flag:               file type.
378  * @ftwbuf:             the pointer of a struct FTW.
379  */
380 static int calc_entry_counts(const char *file EXT2FS_ATTR((unused)),
381                 const struct stat64 *buf, int flag EXT2FS_ATTR((unused)),
382                 struct FTW *ftwbuf EXT2FS_ATTR((unused)))
383 {
384         if (S_ISREG(buf->st_mode))
385                 regular_count++;
386
387         total_count++;
388
389         return 0;
390 }
391
392 /*
393  * page_in_core() -     Get information on whether pages are in core.
394  *
395  * @fd:                 defrag target file's descriptor.
396  * @defrag_data:        data used for defrag.
397  * @vec:                page state array.
398  * @page_num:           page number.
399  */
400 static int page_in_core(int fd, struct move_extent defrag_data,
401                         unsigned char **vec, unsigned int *page_num)
402 {
403         long    pagesize;
404         void    *page = NULL;
405         loff_t  offset, end_offset, length;
406
407         if (vec == NULL || *vec != NULL)
408                 return -1;
409
410         pagesize = sysconf(_SC_PAGESIZE);
411         if (pagesize < 0)
412                 return -1;
413         /* In mmap, offset should be a multiple of the page size */
414         offset = (loff_t)defrag_data.orig_start * block_size;
415         length = (loff_t)defrag_data.len * block_size;
416         end_offset = offset + length;
417         /* Round the offset down to the nearest multiple of pagesize */
418         offset = (offset / pagesize) * pagesize;
419         length = end_offset - offset;
420
421         page = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, offset);
422         if (page == MAP_FAILED)
423                 return -1;
424
425         *page_num = 0;
426         *page_num = (length + pagesize - 1) / pagesize;
427         *vec = (unsigned char *)calloc(*page_num, 1);
428         if (*vec == NULL)
429                 return -1;
430
431         /* Get information on whether pages are in core */
432         if (mincore(page, (size_t)length, *vec) == -1 ||
433                 munmap(page, length) == -1) {
434                 FREE(*vec);
435                 return -1;
436         }
437
438         return 0;
439 }
440
441 /*
442  * defrag_fadvise() -   Predeclare an access pattern for file data.
443  *
444  * @fd:                 defrag target file's descriptor.
445  * @defrag_data:        data used for defrag.
446  * @vec:                page state array.
447  * @page_num:           page number.
448  */
449 static int defrag_fadvise(int fd, struct move_extent defrag_data,
450                    unsigned char *vec, unsigned int page_num)
451 {
452         int     flag = 1;
453         long    pagesize = sysconf(_SC_PAGESIZE);
454         int     fadvise_flag = POSIX_FADV_DONTNEED;
455         int     sync_flag = SYNC_FILE_RANGE_WAIT_BEFORE |
456                             SYNC_FILE_RANGE_WRITE |
457                             SYNC_FILE_RANGE_WAIT_AFTER;
458         unsigned int    i;
459         loff_t  offset;
460
461         offset = (loff_t)defrag_data.orig_start * block_size;
462         offset = (offset / pagesize) * pagesize;
463
464         /* Sync file for fadvise process */
465         if (sync_file_range(fd, offset,
466                 (loff_t)pagesize * page_num, sync_flag) < 0)
467                 return -1;
468
469         /* Try to release buffer cache which this process used,
470          * then other process can use the released buffer
471          */
472         for (i = 0; i < page_num; i++) {
473                 if ((vec[i] & 0x1) == 0) {
474                         offset += pagesize;
475                         continue;
476                 }
477                 if (posix_fadvise(fd, offset, pagesize, fadvise_flag) < 0) {
478                         if ((mode_flag & DETAIL) && flag) {
479                                 perror("\tFailed to fadvise");
480                                 flag = 0;
481                         }
482                 }
483                 offset += pagesize;
484         }
485
486         return 0;
487 }
488
489 /*
490  * check_free_size() -  Check if there's enough disk space.
491  *
492  * @fd:                 defrag target file's descriptor.
493  * @file:               file name.
494  * @blk_count:          file blocks.
495  */
496 static int check_free_size(int fd, const char *file, ext4_fsblk_t blk_count)
497 {
498         ext4_fsblk_t    free_blk_count;
499         struct statfs64 fsbuf;
500
501         if (fstatfs64(fd, &fsbuf) < 0) {
502                 if (mode_flag & DETAIL) {
503                         PRINT_FILE_NAME(file);
504                         PRINT_ERR_MSG_WITH_ERRNO(
505                                 "Failed to get filesystem information");
506                 }
507                 return -1;
508         }
509
510         /* Compute free space for root and normal user separately */
511         if (current_uid == ROOT_UID)
512                 free_blk_count = fsbuf.f_bfree;
513         else
514                 free_blk_count = fsbuf.f_bavail;
515
516         if (free_blk_count >= blk_count)
517                 return 0;
518
519         return -ENOSPC;
520 }
521
522 /*
523  * file_frag_count() -  Get file fragment count.
524  *
525  * @fd:                 defrag target file's descriptor.
526  */
527 static int file_frag_count(int fd)
528 {
529         int     ret;
530         struct fiemap   fiemap_buf;
531
532         /* When fm_extent_count is 0,
533          * ioctl just get file fragment count.
534          */
535         memset(&fiemap_buf, 0, sizeof(struct fiemap));
536         fiemap_buf.fm_start = 0;
537         fiemap_buf.fm_length = FIEMAP_MAX_OFFSET;
538         fiemap_buf.fm_flags |= FIEMAP_FLAG_SYNC;
539
540         ret = ioctl(fd, FS_IOC_FIEMAP, &fiemap_buf);
541         if (ret < 0)
542                 return ret;
543
544         return fiemap_buf.fm_mapped_extents;
545 }
546
547 /*
548  * file_check() -       Check file's attributes.
549  *
550  * @fd:                 defrag target file's descriptor.
551  * @buf:                a pointer of the struct stat64.
552  * @file:               file name.
553  * @extents:            file extents.
554  * @blk_count:          file blocks.
555  */
556 static int file_check(int fd, const struct stat64 *buf, const char *file,
557                 int extents, ext4_fsblk_t blk_count)
558 {
559         int     ret;
560         struct flock    lock;
561
562         /* Write-lock check is more reliable */
563         lock.l_type = F_WRLCK;
564         lock.l_start = 0;
565         lock.l_whence = SEEK_SET;
566         lock.l_len = 0;
567
568         /* Free space */
569         ret = check_free_size(fd, file, blk_count);
570         if (ret < 0) {
571                 if ((mode_flag & DETAIL) && ret == -ENOSPC) {
572                         printf("\033[79;0H\033[K[%u/%u] \"%s\"\t\t"
573                                 "  extents: %d -> %d\n", defraged_file_count,
574                                 total_count, file, extents, extents);
575                         IN_FTW_PRINT_ERR_MSG(
576                         "Defrag size is larger than filesystem's free space");
577                 }
578                 return -1;
579         }
580
581         /* Access authority */
582         if (current_uid != ROOT_UID &&
583                 buf->st_uid != current_uid) {
584                 if (mode_flag & DETAIL) {
585                         printf("\033[79;0H\033[K[%u/%u] \"%s\"\t\t"
586                                 "  extents: %d -> %d\n", defraged_file_count,
587                                 total_count, file, extents, extents);
588                         IN_FTW_PRINT_ERR_MSG(
589                                 "File is not current user's file"
590                                 " or current user is not root");
591                 }
592                 return -1;
593         }
594
595         /* Lock status */
596         if (fcntl(fd, F_GETLK, &lock) < 0) {
597                 if (mode_flag & DETAIL) {
598                         PRINT_FILE_NAME(file);
599                         PRINT_ERR_MSG_WITH_ERRNO(
600                                 "Failed to get lock information");
601                 }
602                 return -1;
603         } else if (lock.l_type != F_UNLCK) {
604                 if (mode_flag & DETAIL) {
605                         PRINT_FILE_NAME(file);
606                         IN_FTW_PRINT_ERR_MSG("File has been locked");
607                 }
608                 return -1;
609         }
610
611         return 0;
612 }
613
614 /*
615  * insert_extent_by_logical() - Sequentially insert extent by logical.
616  *
617  * @ext_list_head:      the head of logical extent list.
618  * @ext:                the extent element which will be inserted.
619  */
620 static int insert_extent_by_logical(struct fiemap_extent_list **ext_list_head,
621                         struct fiemap_extent_list *ext)
622 {
623         struct fiemap_extent_list       *ext_list_tmp = *ext_list_head;
624
625         if (ext == NULL)
626                 goto out;
627
628         /* First element */
629         if (*ext_list_head == NULL) {
630                 (*ext_list_head) = ext;
631                 (*ext_list_head)->prev = *ext_list_head;
632                 (*ext_list_head)->next = *ext_list_head;
633                 return 0;
634         }
635
636         if (ext->data.logical <= ext_list_tmp->data.logical) {
637                 /* Insert before head */
638                 if (ext_list_tmp->data.logical <
639                         ext->data.logical + ext->data.len)
640                         /* Overlap */
641                         goto out;
642                 /* Adjust head */
643                 *ext_list_head = ext;
644         } else {
645                 /* Insert into the middle or last of the list */
646                 do {
647                         if (ext->data.logical < ext_list_tmp->data.logical)
648                                 break;
649                         ext_list_tmp = ext_list_tmp->next;
650                 } while (ext_list_tmp != (*ext_list_head));
651                 if (ext->data.logical <
652                     ext_list_tmp->prev->data.logical +
653                         ext_list_tmp->prev->data.len)
654                         /* Overlap */
655                         goto out;
656
657                 if (ext_list_tmp != *ext_list_head &&
658                     ext_list_tmp->data.logical <
659                     ext->data.logical + ext->data.len)
660                         /* Overlap */
661                         goto out;
662         }
663         ext_list_tmp = ext_list_tmp->prev;
664         /* Insert "ext" after "ext_list_tmp" */
665         insert(ext_list_tmp, ext);
666         return 0;
667 out:
668         errno = EINVAL;
669         return -1;
670 }
671
672 /*
673  * insert_extent_by_physical() -        Sequentially insert extent by physical.
674  *
675  * @ext_list_head:      the head of physical extent list.
676  * @ext:                the extent element which will be inserted.
677  */
678 static int insert_extent_by_physical(struct fiemap_extent_list **ext_list_head,
679                         struct fiemap_extent_list *ext)
680 {
681         struct fiemap_extent_list       *ext_list_tmp = *ext_list_head;
682
683         if (ext == NULL)
684                 goto out;
685
686         /* First element */
687         if (*ext_list_head == NULL) {
688                 (*ext_list_head) = ext;
689                 (*ext_list_head)->prev = *ext_list_head;
690                 (*ext_list_head)->next = *ext_list_head;
691                 return 0;
692         }
693
694         if (ext->data.physical <= ext_list_tmp->data.physical) {
695                 /* Insert before head */
696                 if (ext_list_tmp->data.physical <
697                                         ext->data.physical + ext->data.len)
698                         /* Overlap */
699                         goto out;
700                 /* Adjust head */
701                 *ext_list_head = ext;
702         } else {
703                 /* Insert into the middle or last of the list */
704                 do {
705                         if (ext->data.physical < ext_list_tmp->data.physical)
706                                 break;
707                         ext_list_tmp = ext_list_tmp->next;
708                 } while (ext_list_tmp != (*ext_list_head));
709                 if (ext->data.physical <
710                     ext_list_tmp->prev->data.physical +
711                                 ext_list_tmp->prev->data.len)
712                         /* Overlap */
713                         goto out;
714
715                 if (ext_list_tmp != *ext_list_head &&
716                     ext_list_tmp->data.physical <
717                                 ext->data.physical + ext->data.len)
718                         /* Overlap */
719                         goto out;
720         }
721         ext_list_tmp = ext_list_tmp->prev;
722         /* Insert "ext" after "ext_list_tmp" */
723         insert(ext_list_tmp, ext);
724         return 0;
725 out:
726         errno = EINVAL;
727         return -1;
728 }
729
730 /*
731  * insert_exts_group() -        Insert a exts_group.
732  *
733  * @ext_group_head:             the head of a exts_group list.
734  * @exts_group:                 the exts_group element which will be inserted.
735  */
736 static int insert_exts_group(struct fiemap_extent_group **ext_group_head,
737                                 struct fiemap_extent_group *exts_group)
738 {
739         struct fiemap_extent_group      *ext_group_tmp = NULL;
740
741         if (exts_group == NULL) {
742                 errno = EINVAL;
743                 return -1;
744         }
745
746         /* Initialize list */
747         if (*ext_group_head == NULL) {
748                 (*ext_group_head) = exts_group;
749                 (*ext_group_head)->prev = *ext_group_head;
750                 (*ext_group_head)->next = *ext_group_head;
751                 return 0;
752         }
753
754         ext_group_tmp = (*ext_group_head)->prev;
755         insert(ext_group_tmp, exts_group);
756
757         return 0;
758 }
759
760 /*
761  * join_extents() -             Find continuous region(exts_group).
762  *
763  * @ext_list_head:              the head of the extent list.
764  * @ext_group_head:             the head of the target exts_group list.
765  */
766 static int join_extents(struct fiemap_extent_list *ext_list_head,
767                 struct fiemap_extent_group **ext_group_head)
768 {
769         __u64   len = ext_list_head->data.len;
770         struct fiemap_extent_list *ext_list_start = ext_list_head;
771         struct fiemap_extent_list *ext_list_tmp = ext_list_head->next;
772
773         do {
774                 struct fiemap_extent_group      *ext_group_tmp = NULL;
775
776                 /* This extent and previous extent are not continuous,
777                  * so, all previous extents are treated as an extent group.
778                  */
779                 if ((ext_list_tmp->prev->data.logical +
780                         ext_list_tmp->prev->data.len)
781                                 != ext_list_tmp->data.logical) {
782                         ext_group_tmp =
783                                 malloc(sizeof(struct fiemap_extent_group));
784                         if (ext_group_tmp == NULL)
785                                 return -1;
786
787                         memset(ext_group_tmp, 0,
788                                 sizeof(struct fiemap_extent_group));
789                         ext_group_tmp->len = len;
790                         ext_group_tmp->start = ext_list_start;
791                         ext_group_tmp->end = ext_list_tmp->prev;
792
793                         if (insert_exts_group(ext_group_head,
794                                 ext_group_tmp) < 0) {
795                                 FREE(ext_group_tmp);
796                                 return -1;
797                         }
798                         ext_list_start = ext_list_tmp;
799                         len = ext_list_tmp->data.len;
800                         ext_list_tmp = ext_list_tmp->next;
801                         continue;
802                 }
803
804                 /* This extent and previous extent are continuous,
805                  * so, they belong to the same extent group, and we check
806                  * if the next extent belongs to the same extent group.
807                  */
808                 len += ext_list_tmp->data.len;
809                 ext_list_tmp = ext_list_tmp->next;
810         } while (ext_list_tmp != ext_list_head->next);
811
812         return 0;
813 }
814
815 /*
816  * get_file_extents() - Get file's extent list.
817  *
818  * @fd:                 defrag target file's descriptor.
819  * @ext_list_head:      the head of the extent list.
820  */
821 static int get_file_extents(int fd, struct fiemap_extent_list **ext_list_head)
822 {
823         __u32   i;
824         int     ret;
825         int     ext_buf_size, fie_buf_size;
826         __u64   pos = 0;
827         struct fiemap   *fiemap_buf = NULL;
828         struct fiemap_extent    *ext_buf = NULL;
829         struct fiemap_extent_list       *ext_list = NULL;
830
831         /* Convert units, in bytes.
832          * Be careful : now, physical block number in extent is 48bit,
833          * and the maximum blocksize for ext4 is 4K(12bit),
834          * so there is no overflow, but in future it may be changed.
835          */
836
837         /* Alloc space for fiemap */
838         ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
839         fie_buf_size = sizeof(struct fiemap) + ext_buf_size;
840
841         fiemap_buf = malloc(fie_buf_size);
842         if (fiemap_buf == NULL)
843                 return -1;
844
845         ext_buf = fiemap_buf->fm_extents;
846         memset(fiemap_buf, 0, fie_buf_size);
847         fiemap_buf->fm_length = FIEMAP_MAX_OFFSET;
848         fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC;
849         fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT;
850
851         do {
852                 fiemap_buf->fm_start = pos;
853                 memset(ext_buf, 0, ext_buf_size);
854                 ret = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
855                 if (ret < 0 || fiemap_buf->fm_mapped_extents == 0)
856                         goto out;
857                 for (i = 0; i < fiemap_buf->fm_mapped_extents; i++) {
858                         ext_list = NULL;
859                         ext_list = malloc(sizeof(struct fiemap_extent_list));
860                         if (ext_list == NULL)
861                                 goto out;
862
863                         ext_list->data.physical = ext_buf[i].fe_physical
864                                                 / block_size;
865                         ext_list->data.logical = ext_buf[i].fe_logical
866                                                 / block_size;
867                         ext_list->data.len = ext_buf[i].fe_length
868                                                 / block_size;
869
870                         ret = insert_extent_by_physical(
871                                         ext_list_head, ext_list);
872                         if (ret < 0) {
873                                 FREE(ext_list);
874                                 goto out;
875                         }
876                 }
877                 /* Record file's logical offset this time */
878                 pos = ext_buf[EXTENT_MAX_COUNT-1].fe_logical +
879                         ext_buf[EXTENT_MAX_COUNT-1].fe_length;
880                 /*
881                  * If fm_extents array has been filled and
882                  * there are extents left, continue to cycle.
883                  */
884         } while (fiemap_buf->fm_mapped_extents
885                                         == EXTENT_MAX_COUNT &&
886                 !(ext_buf[EXTENT_MAX_COUNT-1].fe_flags
887                                         & FIEMAP_EXTENT_LAST));
888
889         FREE(fiemap_buf);
890         return 0;
891 out:
892         FREE(fiemap_buf);
893         return -1;
894 }
895
896 /*
897  * get_logical_count() -        Get the file logical extents count.
898  *
899  * @logical_list_head:  the head of the logical extent list.
900  */
901 static int get_logical_count(struct fiemap_extent_list *logical_list_head)
902 {
903         int ret = 0;
904         struct fiemap_extent_list *ext_list_tmp  = logical_list_head;
905
906         do {
907                 ret++;
908                 ext_list_tmp = ext_list_tmp->next;
909         } while (ext_list_tmp != logical_list_head);
910
911         return ret;
912 }
913
914 /*
915  * get_physical_count() -       Get the file physical extents count.
916  *
917  * @physical_list_head: the head of the physical extent list.
918  */
919 static int get_physical_count(struct fiemap_extent_list *physical_list_head)
920 {
921         int ret = 0;
922         struct fiemap_extent_list *ext_list_tmp = physical_list_head;
923
924         do {
925                 if ((ext_list_tmp->data.physical + ext_list_tmp->data.len)
926                                 != ext_list_tmp->next->data.physical) {
927                         /* This extent and next extent are not continuous. */
928                         ret++;
929                 }
930
931                 ext_list_tmp = ext_list_tmp->next;
932         } while (ext_list_tmp != physical_list_head);
933
934         return ret;
935 }
936
937 /*
938  * change_physical_to_logical() -       Change list from physical to logical.
939  *
940  * @physical_list_head: the head of physical extent list.
941  * @logical_list_head:  the head of logical extent list.
942  */
943 static int change_physical_to_logical(
944                         struct fiemap_extent_list **physical_list_head,
945                         struct fiemap_extent_list **logical_list_head)
946 {
947         int ret;
948         struct fiemap_extent_list *ext_list_tmp = *physical_list_head;
949         struct fiemap_extent_list *ext_list_next = ext_list_tmp->next;
950
951         while (1) {
952                 if (ext_list_tmp == ext_list_next) {
953                         ret = insert_extent_by_logical(
954                                 logical_list_head, ext_list_tmp);
955                         if (ret < 0)
956                                 return -1;
957
958                         *physical_list_head = NULL;
959                         break;
960                 }
961
962                 ext_list_tmp->prev->next = ext_list_tmp->next;
963                 ext_list_tmp->next->prev = ext_list_tmp->prev;
964                 *physical_list_head = ext_list_next;
965
966                 ret = insert_extent_by_logical(
967                         logical_list_head, ext_list_tmp);
968                 if (ret < 0) {
969                         FREE(ext_list_tmp);
970                         return -1;
971                 }
972                 ext_list_tmp = ext_list_next;
973                 ext_list_next = ext_list_next->next;
974         }
975
976         return 0;
977 }
978
979 /* get_file_blocks() -  Get total file blocks.
980  *
981  * @ext_list_head:      the extent list head of the target file
982  */
983 static ext4_fsblk_t get_file_blocks(struct fiemap_extent_list *ext_list_head)
984 {
985         ext4_fsblk_t blk_count = 0;
986         struct fiemap_extent_list *ext_list_tmp = ext_list_head;
987
988         do {
989                 blk_count += ext_list_tmp->data.len;
990                 ext_list_tmp = ext_list_tmp->next;
991         } while (ext_list_tmp != ext_list_head);
992
993         return blk_count;
994 }
995
996 /*
997  * free_ext() -         Free the extent list.
998  *
999  * @ext_list_head:      the extent list head of which will be free.
1000  */
1001 static void free_ext(struct fiemap_extent_list *ext_list_head)
1002 {
1003         struct fiemap_extent_list       *ext_list_tmp = NULL;
1004
1005         if (ext_list_head == NULL)
1006                 return;
1007
1008         while (ext_list_head->next != ext_list_head) {
1009                 ext_list_tmp = ext_list_head;
1010                 ext_list_head->prev->next = ext_list_head->next;
1011                 ext_list_head->next->prev = ext_list_head->prev;
1012                 ext_list_head = ext_list_head->next;
1013                 free(ext_list_tmp);
1014         }
1015         free(ext_list_head);
1016 }
1017
1018 /*
1019  * free_exts_group() -          Free the exts_group.
1020  *
1021  * @*ext_group_head:    the exts_group list head which will be free.
1022  */
1023 static void free_exts_group(struct fiemap_extent_group *ext_group_head)
1024 {
1025         struct fiemap_extent_group      *ext_group_tmp = NULL;
1026
1027         if (ext_group_head == NULL)
1028                 return;
1029
1030         while (ext_group_head->next != ext_group_head) {
1031                 ext_group_tmp = ext_group_head;
1032                 ext_group_head->prev->next = ext_group_head->next;
1033                 ext_group_head->next->prev = ext_group_head->prev;
1034                 ext_group_head = ext_group_head->next;
1035                 free(ext_group_tmp);
1036         }
1037         free(ext_group_head);
1038 }
1039
1040 /*
1041  * get_best_count() -   Get the file best extents count.
1042  *
1043  * @block_count:                the file's physical block count.
1044  */
1045 static int get_best_count(ext4_fsblk_t block_count)
1046 {
1047         int ret;
1048         unsigned int flex_bg_num;
1049
1050         /* Calcuate best extents count */
1051         if (feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
1052                 flex_bg_num = 1 << log_groups_per_flex;
1053                 ret = ((block_count - 1) /
1054                         ((ext4_fsblk_t)blocks_per_group *
1055                                 flex_bg_num)) + 1;
1056         } else
1057                 ret = ((block_count - 1) / blocks_per_group) + 1;
1058
1059         return ret;
1060 }
1061
1062
1063 /*
1064  * file_statistic() -   Get statistic info of the file's fragments.
1065  *
1066  * @file:               the file's name.
1067  * @buf:                the pointer of the struct stat64.
1068  * @flag:               file type.
1069  * @ftwbuf:             the pointer of a struct FTW.
1070  */
1071 static int file_statistic(const char *file, const struct stat64 *buf,
1072                         int flag EXT2FS_ATTR((unused)),
1073                         struct FTW *ftwbuf EXT2FS_ATTR((unused)))
1074 {
1075         int     fd;
1076         int     ret;
1077         int     now_ext_count, best_ext_count = 0, physical_ext_count;
1078         int     i, j;
1079         __u64   size_per_ext = 0;
1080         float   ratio = 0.0;
1081         ext4_fsblk_t    blk_count = 0;
1082         char    msg_buffer[PATH_MAX + 24];
1083         struct fiemap_extent_list *physical_list_head = NULL;
1084         struct fiemap_extent_list *logical_list_head = NULL;
1085
1086         defraged_file_count++;
1087
1088         if (mode_flag & DETAIL) {
1089                 if (total_count == 1 && regular_count == 1)
1090                         printf("<File>\n");
1091                 else {
1092                         printf("[%u/%u]", defraged_file_count, total_count);
1093                         fflush(stdout);
1094                 }
1095         }
1096         if (lost_found_dir[0] != '\0' &&
1097             !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
1098                 if (mode_flag & DETAIL) {
1099                         PRINT_FILE_NAME(file);
1100                         STATISTIC_ERR_MSG(NGMSG_LOST_FOUND);
1101                 }
1102                         return 0;
1103         }
1104
1105         if (!S_ISREG(buf->st_mode)) {
1106                 if (mode_flag & DETAIL) {
1107                         PRINT_FILE_NAME(file);
1108                         STATISTIC_ERR_MSG(NGMSG_FILE_UNREG);
1109                 }
1110                 return 0;
1111         }
1112
1113         /* Access authority */
1114         if (current_uid != ROOT_UID &&
1115                 buf->st_uid != current_uid) {
1116                 if (mode_flag & DETAIL) {
1117                         PRINT_FILE_NAME(file);
1118                         STATISTIC_ERR_MSG(
1119                                 "File is not current user's file"
1120                                 " or current user is not root");
1121                 }
1122                 return 0;
1123         }
1124
1125         /* Empty file */
1126         if (buf->st_size == 0) {
1127                 if (mode_flag & DETAIL) {
1128                         PRINT_FILE_NAME(file);
1129                         STATISTIC_ERR_MSG("File size is 0");
1130                 }
1131                 return 0;
1132         }
1133
1134         /* Has no blocks */
1135         if (buf->st_blocks == 0) {
1136                 if (mode_flag & DETAIL) {
1137                         PRINT_FILE_NAME(file);
1138                         STATISTIC_ERR_MSG("File has no blocks");
1139                 }
1140                 return 0;
1141         }
1142
1143         fd = open64(file, O_RDONLY);
1144         if (fd < 0) {
1145                 if (mode_flag & DETAIL) {
1146                         PRINT_FILE_NAME(file);
1147                         STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
1148                 }
1149                 return 0;
1150         }
1151
1152         /* Get file's physical extents  */
1153         ret = get_file_extents(fd, &physical_list_head);
1154         if (ret < 0) {
1155                 if (mode_flag & DETAIL) {
1156                         PRINT_FILE_NAME(file);
1157                         STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1158                 }
1159                 goto out;
1160         }
1161
1162         /* Get the count of file's continuous physical region */
1163         physical_ext_count = get_physical_count(physical_list_head);
1164
1165         /* Change list from physical to logical */
1166         ret = change_physical_to_logical(&physical_list_head,
1167                                                         &logical_list_head);
1168         if (ret < 0) {
1169                 if (mode_flag & DETAIL) {
1170                         PRINT_FILE_NAME(file);
1171                         STATISTIC_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1172                 }
1173                 goto out;
1174         }
1175
1176         /* Count file fragments before defrag */
1177         now_ext_count = get_logical_count(logical_list_head);
1178
1179         if (current_uid == ROOT_UID) {
1180                 /* Calculate the size per extent */
1181                 blk_count = get_file_blocks(logical_list_head);
1182
1183                 best_ext_count = get_best_count(blk_count);
1184
1185                 /* e4defrag rounds size_per_ext up to a block size boundary */
1186                 size_per_ext = blk_count * (buf->st_blksize / 1024) /
1187                                                         now_ext_count;
1188
1189                 ratio = (float)(physical_ext_count - best_ext_count) * 100 /
1190                                                         blk_count;
1191
1192                 extents_before_defrag += now_ext_count;
1193                 extents_after_defrag += best_ext_count;
1194                 files_block_count += blk_count;
1195         }
1196
1197         if (total_count == 1 && regular_count == 1) {
1198                 /* File only */
1199                 if (mode_flag & DETAIL) {
1200                         int count = 0;
1201                         struct fiemap_extent_list *ext_list_tmp =
1202                                                 logical_list_head;
1203
1204                         /* Print extents info */
1205                         do {
1206                                 count++;
1207                                 printf("[ext %d]:\tstart %llu:\tlogical "
1208                                                 "%llu:\tlen %llu\n", count,
1209                                                 ext_list_tmp->data.physical,
1210                                                 ext_list_tmp->data.logical,
1211                                                 ext_list_tmp->data.len);
1212                                 ext_list_tmp = ext_list_tmp->next;
1213                         } while (ext_list_tmp != logical_list_head);
1214
1215                 } else {
1216                         printf("%-40s%10s/%-10s%9s\n",
1217                                         "<File>", "now", "best", "size/ext");
1218                         if (current_uid == ROOT_UID) {
1219                                 if (strlen(file) > 40)
1220                                         printf("%s\n%50d/%-10d%6llu KB\n",
1221                                                 file, now_ext_count,
1222                                                 best_ext_count, size_per_ext);
1223                                 else
1224                                         printf("%-40s%10d/%-10d%6llu KB\n",
1225                                                 file, now_ext_count,
1226                                                 best_ext_count, size_per_ext);
1227                         } else {
1228                                 if (strlen(file) > 40)
1229                                         printf("%s\n%50d/%-10s%7s\n",
1230                                                         file, now_ext_count,
1231                                                         "-", "-");
1232                                 else
1233                                         printf("%-40s%10d/%-10s%7s\n",
1234                                                         file, now_ext_count,
1235                                                         "-", "-");
1236                         }
1237                 }
1238                 succeed_cnt++;
1239                 goto out;
1240         }
1241
1242         if (mode_flag & DETAIL) {
1243                 /* Print statistic info */
1244                 sprintf(msg_buffer, "[%u/%u]%s",
1245                                 defraged_file_count, total_count, file);
1246                 if (current_uid == ROOT_UID) {
1247                         if (strlen(msg_buffer) > 40)
1248                                 printf("\033[79;0H\033[K%s\n"
1249                                                 "%50d/%-10d%6llu KB\n",
1250                                                 msg_buffer, now_ext_count,
1251                                                 best_ext_count, size_per_ext);
1252                         else
1253                                 printf("\033[79;0H\033[K%-40s"
1254                                                 "%10d/%-10d%6llu KB\n",
1255                                                 msg_buffer, now_ext_count,
1256                                                 best_ext_count, size_per_ext);
1257                 } else {
1258                         if (strlen(msg_buffer) > 40)
1259                                 printf("\033[79;0H\033[K%s\n%50d/%-10s%7s\n",
1260                                                 msg_buffer, now_ext_count,
1261                                                         "-", "-");
1262                         else
1263                                 printf("\033[79;0H\033[K%-40s%10d/%-10s%7s\n",
1264                                                 msg_buffer, now_ext_count,
1265                                                         "-", "-");
1266                 }
1267         }
1268
1269         for (i = 0; i < SHOW_FRAG_FILES; i++) {
1270                 if (ratio >= frag_rank[i].ratio) {
1271                         for (j = SHOW_FRAG_FILES - 1; j > i; j--) {
1272                                 memset(&frag_rank[j], 0,
1273                                         sizeof(struct frag_statistic_ino));
1274                                 strncpy(frag_rank[j].msg_buffer,
1275                                         frag_rank[j - 1].msg_buffer,
1276                                         strnlen(frag_rank[j - 1].msg_buffer,
1277                                         PATH_MAX));
1278                                 frag_rank[j].now_count =
1279                                         frag_rank[j - 1].now_count;
1280                                 frag_rank[j].best_count =
1281                                         frag_rank[j - 1].best_count;
1282                                 frag_rank[j].size_per_ext =
1283                                         frag_rank[j - 1].size_per_ext;
1284                                 frag_rank[j].ratio =
1285                                         frag_rank[j - 1].ratio;
1286                         }
1287                         memset(&frag_rank[i], 0,
1288                                         sizeof(struct frag_statistic_ino));
1289                         strncpy(frag_rank[i].msg_buffer, file,
1290                                                 strnlen(file, PATH_MAX));
1291                         frag_rank[i].now_count = now_ext_count;
1292                         frag_rank[i].best_count = best_ext_count;
1293                         frag_rank[i].size_per_ext = size_per_ext;
1294                         frag_rank[i].ratio = ratio;
1295                         break;
1296                 }
1297         }
1298
1299         succeed_cnt++;
1300
1301 out:
1302         close(fd);
1303         free_ext(physical_list_head);
1304         free_ext(logical_list_head);
1305         return 0;
1306 }
1307
1308 /*
1309  * print_progress -     Print defrag progress
1310  *
1311  * @file:               file name.
1312  * @start:              logical offset for defrag target file
1313  * @file_size:          defrag target filesize
1314  */
1315 static void print_progress(const char *file, loff_t start, loff_t file_size)
1316 {
1317         int percent = (start * 100) / file_size;
1318         printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
1319                 defraged_file_count, total_count, file, min(percent, 100));
1320         fflush(stdout);
1321
1322         return;
1323 }
1324
1325 /*
1326  * call_defrag() -      Execute the defrag program.
1327  *
1328  * @fd:                 target file descriptor.
1329  * @donor_fd:           donor file descriptor.
1330  * @file:                       target file name.
1331  * @buf:                        pointer of the struct stat64.
1332  * @ext_list_head:      head of the extent list.
1333  */
1334 static int call_defrag(int fd, int donor_fd, const char *file,
1335         const struct stat64 *buf, struct fiemap_extent_list *ext_list_head)
1336 {
1337         loff_t  start = 0;
1338         unsigned int    page_num;
1339         unsigned char   *vec = NULL;
1340         int     defraged_ret = 0;
1341         int     ret;
1342         struct move_extent      move_data;
1343         struct fiemap_extent_list       *ext_list_tmp = NULL;
1344
1345         memset(&move_data, 0, sizeof(struct move_extent));
1346         move_data.donor_fd = donor_fd;
1347
1348         /* Print defrag progress */
1349         print_progress(file, start, buf->st_size);
1350
1351         ext_list_tmp = ext_list_head;
1352         do {
1353                 move_data.orig_start = ext_list_tmp->data.logical;
1354                 /* Logical offset of orig and donor should be same */
1355                 move_data.donor_start = move_data.orig_start;
1356                 move_data.len = ext_list_tmp->data.len;
1357                 move_data.moved_len = 0;
1358
1359                 ret = page_in_core(fd, move_data, &vec, &page_num);
1360                 if (ret < 0) {
1361                         if (mode_flag & DETAIL) {
1362                                 printf("\n");
1363                                 PRINT_ERR_MSG_WITH_ERRNO(
1364                                                 "Failed to get file map");
1365                         } else {
1366                                 printf("\t[ NG ]\n");
1367                         }
1368                         return -1;
1369                 }
1370
1371                 /* EXT4_IOC_MOVE_EXT */
1372                 defraged_ret =
1373                         ioctl(fd, EXT4_IOC_MOVE_EXT, &move_data);
1374
1375                 /* Free pages */
1376                 ret = defrag_fadvise(fd, move_data, vec, page_num);
1377                 if (vec) {
1378                         free(vec);
1379                         vec = NULL;
1380                 }
1381                 if (ret < 0) {
1382                         if (mode_flag & DETAIL) {
1383                                 printf("\n");
1384                                 PRINT_ERR_MSG_WITH_ERRNO(
1385                                         "Failed to free page");
1386                         } else {
1387                                 printf("\t[ NG ]\n");
1388                         }
1389                         return -1;
1390                 }
1391
1392                 if (defraged_ret < 0) {
1393                         if (mode_flag & DETAIL) {
1394                                 printf("\n");
1395                                 PRINT_ERR_MSG_WITH_ERRNO(
1396                                         "Failed to defrag with "
1397                                         "EXT4_IOC_MOVE_EXT ioctl");
1398                                 if (errno == ENOTTY)
1399                                         printf("\tAt least 2.6.31-rc1 of "
1400                                                 "vanilla kernel is required\n");
1401                         } else {
1402                                 printf("\t[ NG ]\n");
1403                         }
1404                         return -1;
1405                 }
1406                 /* Adjust logical offset for next ioctl */
1407                 move_data.orig_start += move_data.moved_len;
1408                 move_data.donor_start = move_data.orig_start;
1409
1410                 start = move_data.orig_start * buf->st_blksize;
1411
1412                 /* Print defrag progress */
1413                 print_progress(file, start, buf->st_size);
1414
1415                 /* End of file */
1416                 if (start >= buf->st_size)
1417                         break;
1418
1419                 ext_list_tmp = ext_list_tmp->next;
1420         } while (ext_list_tmp != ext_list_head);
1421
1422         return 0;
1423 }
1424
1425 /*
1426  * file_defrag() -              Check file attributes and call ioctl to defrag.
1427  *
1428  * @file:               the file's name.
1429  * @buf:                the pointer of the struct stat64.
1430  * @flag:               file type.
1431  * @ftwbuf:             the pointer of a struct FTW.
1432  */
1433 static int file_defrag(const char *file, const struct stat64 *buf,
1434                         int flag EXT2FS_ATTR((unused)),
1435                         struct FTW *ftwbuf EXT2FS_ATTR((unused)))
1436 {
1437         int     fd;
1438         int     donor_fd = -1;
1439         int     ret;
1440         int     best;
1441         int     file_frags_start, file_frags_end;
1442         int     orig_physical_cnt, donor_physical_cnt = 0;
1443         char    tmp_inode_name[PATH_MAX + 8];
1444         ext4_fsblk_t                    blk_count = 0;
1445         struct fiemap_extent_list       *orig_list_physical = NULL;
1446         struct fiemap_extent_list       *orig_list_logical = NULL;
1447         struct fiemap_extent_list       *donor_list_physical = NULL;
1448         struct fiemap_extent_list       *donor_list_logical = NULL;
1449         struct fiemap_extent_group      *orig_group_head = NULL;
1450         struct fiemap_extent_group      *orig_group_tmp = NULL;
1451
1452         defraged_file_count++;
1453
1454         if (mode_flag & DETAIL) {
1455                 printf("[%u/%u]", defraged_file_count, total_count);
1456                 fflush(stdout);
1457         }
1458
1459         if (lost_found_dir[0] != '\0' &&
1460             !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
1461                 if (mode_flag & DETAIL) {
1462                         PRINT_FILE_NAME(file);
1463                         IN_FTW_PRINT_ERR_MSG(NGMSG_LOST_FOUND);
1464                 }
1465                 return 0;
1466         }
1467
1468         if (!S_ISREG(buf->st_mode)) {
1469                 if (mode_flag & DETAIL) {
1470                         PRINT_FILE_NAME(file);
1471                         IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_UNREG);
1472                 }
1473                 return 0;
1474         }
1475
1476         /* Empty file */
1477         if (buf->st_size == 0) {
1478                 if (mode_flag & DETAIL) {
1479                         PRINT_FILE_NAME(file);
1480                         IN_FTW_PRINT_ERR_MSG("File size is 0");
1481                 }
1482                 return 0;
1483         }
1484
1485         /* Has no blocks */
1486         if (buf->st_blocks == 0) {
1487                 if (mode_flag & DETAIL) {
1488                         PRINT_FILE_NAME(file);
1489                         STATISTIC_ERR_MSG("File has no blocks");
1490                 }
1491                 return 0;
1492         }
1493
1494         fd = open64(file, O_RDWR);
1495         if (fd < 0) {
1496                 if (mode_flag & DETAIL) {
1497                         PRINT_FILE_NAME(file);
1498                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
1499                 }
1500                 return 0;
1501         }
1502
1503         /* Get file's extents */
1504         ret = get_file_extents(fd, &orig_list_physical);
1505         if (ret < 0) {
1506                 if (mode_flag & DETAIL) {
1507                         PRINT_FILE_NAME(file);
1508                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1509                 }
1510                 goto out;
1511         }
1512
1513         /* Get the count of file's continuous physical region */
1514         orig_physical_cnt = get_physical_count(orig_list_physical);
1515
1516         /* Change list from physical to logical */
1517         ret = change_physical_to_logical(&orig_list_physical,
1518                                                         &orig_list_logical);
1519         if (ret < 0) {
1520                 if (mode_flag & DETAIL) {
1521                         PRINT_FILE_NAME(file);
1522                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1523                 }
1524                 goto out;
1525         }
1526
1527         /* Count file fragments before defrag */
1528         file_frags_start = get_logical_count(orig_list_logical);
1529
1530         blk_count = get_file_blocks(orig_list_logical);
1531         if (file_check(fd, buf, file, file_frags_start, blk_count) < 0)
1532                 goto out;
1533
1534         if (fsync(fd) < 0) {
1535                 if (mode_flag & DETAIL) {
1536                         PRINT_FILE_NAME(file);
1537                         PRINT_ERR_MSG_WITH_ERRNO("Failed to sync(fsync)");
1538                 }
1539                 goto out;
1540         }
1541
1542         if (current_uid == ROOT_UID)
1543                 best = get_best_count(blk_count);
1544         else
1545                 best = 1;
1546
1547         if (file_frags_start <= best)
1548                 goto check_improvement;
1549
1550         /* Combine extents to group */
1551         ret = join_extents(orig_list_logical, &orig_group_head);
1552         if (ret < 0) {
1553                 if (mode_flag & DETAIL) {
1554                         PRINT_FILE_NAME(file);
1555                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1556                 }
1557                 goto out;
1558         }
1559
1560         /* Create donor inode */
1561         memset(tmp_inode_name, 0, PATH_MAX + 8);
1562         sprintf(tmp_inode_name, "%.*s.defrag",
1563                                 (int)strnlen(file, PATH_MAX), file);
1564         donor_fd = open64(tmp_inode_name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
1565         if (donor_fd < 0) {
1566                 if (mode_flag & DETAIL) {
1567                         PRINT_FILE_NAME(file);
1568                         if (errno == EEXIST)
1569                                 PRINT_ERR_MSG_WITH_ERRNO(
1570                                 "File is being defraged by other program");
1571                         else
1572                                 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
1573                 }
1574                 goto out;
1575         }
1576
1577         /* Unlink donor inode */
1578         ret = unlink(tmp_inode_name);
1579         if (ret < 0) {
1580                 if (mode_flag & DETAIL) {
1581                         PRINT_FILE_NAME(file);
1582                         PRINT_ERR_MSG_WITH_ERRNO("Failed to unlink");
1583                 }
1584                 goto out;
1585         }
1586
1587         /* Allocate space for donor inode */
1588         orig_group_tmp = orig_group_head;
1589         do {
1590                 ret = fallocate64(donor_fd, 0,
1591                   (loff_t)orig_group_tmp->start->data.logical * block_size,
1592                   (loff_t)orig_group_tmp->len * block_size);
1593                 if (ret < 0) {
1594                         if (mode_flag & DETAIL) {
1595                                 PRINT_FILE_NAME(file);
1596                                 PRINT_ERR_MSG_WITH_ERRNO("Failed to fallocate");
1597                         }
1598                         goto out;
1599                 }
1600
1601                 orig_group_tmp = orig_group_tmp->next;
1602         } while (orig_group_tmp != orig_group_head);
1603
1604         /* Get donor inode's extents */
1605         ret = get_file_extents(donor_fd, &donor_list_physical);
1606         if (ret < 0) {
1607                 if (mode_flag & DETAIL) {
1608                         PRINT_FILE_NAME(file);
1609                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1610                 }
1611                 goto out;
1612         }
1613
1614         /* Calcuate donor inode's continuous physical region */
1615         donor_physical_cnt = get_physical_count(donor_list_physical);
1616
1617         /* Change donor extent list from physical to logical */
1618         ret = change_physical_to_logical(&donor_list_physical,
1619                                                         &donor_list_logical);
1620         if (ret < 0) {
1621                 if (mode_flag & DETAIL) {
1622                         PRINT_FILE_NAME(file);
1623                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_EXTENT);
1624                 }
1625                 goto out;
1626         }
1627
1628 check_improvement:
1629         if (mode_flag & DETAIL) {
1630                 if (file_frags_start != 1)
1631                         frag_files_before_defrag++;
1632
1633                 extents_before_defrag += file_frags_start;
1634         }
1635
1636         if (file_frags_start <= best ||
1637                         orig_physical_cnt <= donor_physical_cnt) {
1638                 printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
1639                         defraged_file_count, total_count, file, 100);
1640                 if (mode_flag & DETAIL)
1641                         printf("  extents: %d -> %d",
1642                                 file_frags_start, file_frags_start);
1643
1644                 printf("\t[ OK ]\n");
1645                 succeed_cnt++;
1646
1647                 if (file_frags_start != 1)
1648                         frag_files_after_defrag++;
1649
1650                 extents_after_defrag += file_frags_start;
1651                 goto out;
1652         }
1653
1654         /* Defrag the file */
1655         ret = call_defrag(fd, donor_fd, file, buf, donor_list_logical);
1656
1657         /* Count file fragments after defrag and print extents info */
1658         if (mode_flag & DETAIL) {
1659                 file_frags_end = file_frag_count(fd);
1660                 if (file_frags_end < 0) {
1661                         printf("\n");
1662                         PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_INFO);
1663                         goto out;
1664                 }
1665
1666                 if (file_frags_end != 1)
1667                         frag_files_after_defrag++;
1668
1669                 extents_after_defrag += file_frags_end;
1670
1671                 if (ret < 0)
1672                         goto out;
1673
1674                 printf("  extents: %d -> %d",
1675                         file_frags_start, file_frags_end);
1676                 fflush(stdout);
1677         }
1678
1679         if (ret < 0)
1680                 goto out;
1681
1682         printf("\t[ OK ]\n");
1683         fflush(stdout);
1684         succeed_cnt++;
1685
1686 out:
1687         close(fd);
1688         if (donor_fd != -1)
1689                 close(donor_fd);
1690         free_ext(orig_list_physical);
1691         free_ext(orig_list_logical);
1692         free_ext(donor_list_physical);
1693         free_exts_group(orig_group_head);
1694         return 0;
1695 }
1696
1697 /*
1698  * main() -             Ext4 online defrag.
1699  *
1700  * @argc:               the number of parameter.
1701  * @argv[]:             the pointer array of parameter.
1702  */
1703 int main(int argc, char *argv[])
1704 {
1705         int     opt;
1706         int     i, j, ret = 0;
1707         int     flags = FTW_PHYS | FTW_MOUNT;
1708         int     arg_type = -1;
1709         int     success_flag = 0;
1710         char    dir_name[PATH_MAX + 1];
1711         char    dev_name[PATH_MAX + 1];
1712         struct stat64   buf;
1713         ext2_filsys fs = NULL;
1714
1715         /* Parse arguments */
1716         if (argc == 1)
1717                 goto out;
1718
1719         while ((opt = getopt(argc, argv, "vc")) != EOF) {
1720                 switch (opt) {
1721                 case 'v':
1722                         mode_flag |= DETAIL;
1723                         break;
1724                 case 'c':
1725                         mode_flag |= STATISTIC;
1726                         break;
1727                 default:
1728                         goto out;
1729                 }
1730         }
1731
1732         if (argc == optind)
1733                 goto out;
1734
1735         current_uid = getuid();
1736
1737         /* Main process */
1738         for (i = optind; i < argc; i++) {
1739                 succeed_cnt = 0;
1740                 regular_count = 0;
1741                 total_count = 0;
1742                 frag_files_before_defrag = 0;
1743                 frag_files_after_defrag = 0;
1744                 extents_before_defrag = 0;
1745                 extents_after_defrag = 0;
1746                 defraged_file_count = 0;
1747                 files_block_count = 0;
1748                 blocks_per_group = 0;
1749                 feature_incompat = 0;
1750                 log_groups_per_flex = 0;
1751
1752                 memset(dir_name, 0, PATH_MAX + 1);
1753                 memset(dev_name, 0, PATH_MAX + 1);
1754                 memset(lost_found_dir, 0, PATH_MAX + 1);
1755                 memset(frag_rank, 0,
1756                         sizeof(struct frag_statistic_ino) * SHOW_FRAG_FILES);
1757
1758                 if ((mode_flag & STATISTIC) && i > optind)
1759                         printf("\n");
1760
1761 #if BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN
1762                 PRINT_ERR_MSG("Endian's type is not big/little endian");
1763                 PRINT_FILE_NAME(argv[i]);
1764                 continue;
1765 #endif
1766
1767                 if (lstat64(argv[i], &buf) < 0) {
1768                         perror(NGMSG_FILE_INFO);
1769                         PRINT_FILE_NAME(argv[i]);
1770                         continue;
1771                 }
1772
1773                 if (S_ISBLK(buf.st_mode)) {
1774                         /* Block device */
1775                         strncpy(dev_name, argv[i], strnlen(argv[i], PATH_MAX));
1776                         if (get_mount_point(argv[i], dir_name, PATH_MAX) < 0)
1777                                 continue;
1778                         if (lstat64(dir_name, &buf) < 0) {
1779                                 perror(NGMSG_FILE_INFO);
1780                                 PRINT_FILE_NAME(argv[i]);
1781                                 continue;
1782                         }
1783                         arg_type = DEVNAME;
1784                         if (!(mode_flag & STATISTIC))
1785                                 printf("ext4 defragmentation for device(%s)\n",
1786                                         argv[i]);
1787                 } else if (S_ISDIR(buf.st_mode)) {
1788                         /* Directory */
1789                         if (access(argv[i], R_OK) < 0) {
1790                                 perror(argv[i]);
1791                                 continue;
1792                         }
1793                         arg_type = DIRNAME;
1794                         strncpy(dir_name, argv[i], strnlen(argv[i], PATH_MAX));
1795                 } else if (S_ISREG(buf.st_mode)) {
1796                         /* Regular file */
1797                         arg_type = FILENAME;
1798                 } else {
1799                         /* Irregular file */
1800                         PRINT_ERR_MSG(NGMSG_FILE_UNREG);
1801                         PRINT_FILE_NAME(argv[i]);
1802                         continue;
1803                 }
1804
1805                 /* Set blocksize */
1806                 block_size = buf.st_blksize;
1807
1808                 /* For device case,
1809                  * filesystem type checked in get_mount_point()
1810                  */
1811                 if (arg_type == FILENAME || arg_type == DIRNAME) {
1812                         if (is_ext4(argv[i], dev_name) < 0)
1813                                 continue;
1814                         if (realpath(argv[i], dir_name) == NULL) {
1815                                 perror("Couldn't get full path");
1816                                 PRINT_FILE_NAME(argv[i]);
1817                                 continue;
1818                         }
1819                 }
1820
1821                 if (current_uid == ROOT_UID) {
1822                         /* Get super block info */
1823                         ret = ext2fs_open(dev_name, 0, 0, block_size,
1824                                         unix_io_manager, &fs);
1825                         if (ret) {
1826                                 if (mode_flag & DETAIL) {
1827                                         perror("Can't get super block info");
1828                                         PRINT_FILE_NAME(argv[i]);
1829                                 }
1830                                 continue;
1831                         }
1832
1833                         blocks_per_group = fs->super->s_blocks_per_group;
1834                         feature_incompat = fs->super->s_feature_incompat;
1835                         log_groups_per_flex = fs->super->s_log_groups_per_flex;
1836
1837                         ext2fs_close(fs);
1838                 }
1839
1840                 switch (arg_type) {
1841                 case DIRNAME:
1842                         if (!(mode_flag & STATISTIC))
1843                                 printf("ext4 defragmentation "
1844                                         "for directory(%s)\n", argv[i]);
1845
1846                         int mount_dir_len = 0;
1847                         mount_dir_len = strnlen(lost_found_dir, PATH_MAX);
1848
1849                         strncat(lost_found_dir, "/lost+found",
1850                                 PATH_MAX - strnlen(lost_found_dir, PATH_MAX));
1851
1852                         /* Not the case("e4defrag  mount_piont_dir") */
1853                         if (dir_name[mount_dir_len] != '\0') {
1854                                 /*
1855                                  * "e4defrag mount_piont_dir/lost+found"
1856                                  * or "e4defrag mount_piont_dir/lost+found/"
1857                                  */
1858                                 if (strncmp(lost_found_dir, dir_name,
1859                                             strnlen(lost_found_dir,
1860                                                     PATH_MAX)) == 0 &&
1861                                     (dir_name[strnlen(lost_found_dir,
1862                                                       PATH_MAX)] == '\0' ||
1863                                      dir_name[strnlen(lost_found_dir,
1864                                                       PATH_MAX)] == '/')) {
1865                                         PRINT_ERR_MSG(NGMSG_LOST_FOUND);
1866                                         PRINT_FILE_NAME(argv[i]);
1867                                         continue;
1868                                 }
1869
1870                                 /* "e4defrag mount_piont_dir/else_dir" */
1871                                 memset(lost_found_dir, 0, PATH_MAX + 1);
1872                         }
1873                 case DEVNAME:
1874                         if (arg_type == DEVNAME) {
1875                                 strncpy(lost_found_dir, dir_name,
1876                                         strnlen(dir_name, PATH_MAX));
1877                                 strncat(lost_found_dir, "/lost+found/",
1878                                         PATH_MAX - strnlen(lost_found_dir,
1879                                                            PATH_MAX));
1880                         }
1881
1882                         nftw64(dir_name, calc_entry_counts, FTW_OPEN_FD, flags);
1883
1884                         if (mode_flag & STATISTIC) {
1885                                 if (mode_flag & DETAIL)
1886                                         printf("%-40s%10s/%-10s%9s\n",
1887                                         "<File>", "now", "best", "size/ext");
1888
1889                                 if (!(mode_flag & DETAIL) &&
1890                                                 current_uid != ROOT_UID) {
1891                                         printf(" Done.\n");
1892                                         success_flag = 1;
1893                                         continue;
1894                                 }
1895
1896                                 nftw64(dir_name, file_statistic,
1897                                                         FTW_OPEN_FD, flags);
1898
1899                                 if (succeed_cnt != 0 &&
1900                                         current_uid == ROOT_UID) {
1901                                         if (mode_flag & DETAIL)
1902                                                 printf("\n");
1903                                         printf("%-40s%10s/%-10s%9s\n",
1904                                                 "<Fragmented files>", "now",
1905                                                 "best", "size/ext");
1906                                         for (j = 0; j < SHOW_FRAG_FILES; j++) {
1907                                                 if (strlen(frag_rank[j].
1908                                                         msg_buffer) > 37) {
1909                                                         printf("%d. %s\n%50d/"
1910                                                         "%-10d%6llu KB\n",
1911                                                         j + 1,
1912                                                         frag_rank[j].msg_buffer,
1913                                                         frag_rank[j].now_count,
1914                                                         frag_rank[j].best_count,
1915                                                         frag_rank[j].
1916                                                                 size_per_ext);
1917                                                 } else if (strlen(frag_rank[j].
1918                                                         msg_buffer) > 0) {
1919                                                         printf("%d. %-37s%10d/"
1920                                                         "%-10d%6llu KB\n",
1921                                                         j + 1,
1922                                                         frag_rank[j].msg_buffer,
1923                                                         frag_rank[j].now_count,
1924                                                         frag_rank[j].best_count,
1925                                                         frag_rank[j].
1926                                                                 size_per_ext);
1927                                                 } else
1928                                                         break;
1929                                         }
1930                                 }
1931                                 break;
1932                         }
1933                         /* File tree walk */
1934                         nftw64(dir_name, file_defrag, FTW_OPEN_FD, flags);
1935                         printf("\n\tSuccess:\t\t\t[ %u/%u ]\n", succeed_cnt,
1936                                 total_count);
1937                         printf("\tFailure:\t\t\t[ %u/%u ]\n",
1938                                 total_count - succeed_cnt, total_count);
1939                         if (mode_flag & DETAIL) {
1940                                 printf("\tTotal extents:\t\t\t%4d->%d\n",
1941                                         extents_before_defrag,
1942                                         extents_after_defrag);
1943                                 printf("\tFragmented percentage:\t\t"
1944                                         "%3llu%%->%llu%%\n",
1945                                         !regular_count ? 0 :
1946                                         ((unsigned long long)
1947                                         frag_files_before_defrag * 100) /
1948                                         regular_count,
1949                                         !regular_count ? 0 :
1950                                         ((unsigned long long)
1951                                         frag_files_after_defrag * 100) /
1952                                         regular_count);
1953                         }
1954                         break;
1955                 case FILENAME:
1956                         total_count = 1;
1957                         regular_count = 1;
1958                         strncat(lost_found_dir, "/lost+found/",
1959                                 PATH_MAX - strnlen(lost_found_dir,
1960                                                    PATH_MAX));
1961                         if (strncmp(lost_found_dir, dir_name,
1962                                     strnlen(lost_found_dir,
1963                                             PATH_MAX)) == 0) {
1964                                 PRINT_ERR_MSG(NGMSG_LOST_FOUND);
1965                                 PRINT_FILE_NAME(argv[i]);
1966                                 continue;
1967                         }
1968
1969                         if (mode_flag & STATISTIC) {
1970                                 file_statistic(argv[i], &buf, FTW_F, NULL);
1971                                 break;
1972                         } else
1973                                 printf("ext4 defragmentation for %s\n",
1974                                                                  argv[i]);
1975                         /* Defrag single file process */
1976                         file_defrag(argv[i], &buf, FTW_F, NULL);
1977                         if (succeed_cnt != 0)
1978                                 printf(" Success:\t\t\t[1/1]\n");
1979                         else
1980                                 printf(" Success:\t\t\t[0/1]\n");
1981
1982                         break;
1983                 }
1984
1985                 if (succeed_cnt != 0)
1986                         success_flag = 1;
1987                 if (mode_flag & STATISTIC) {
1988                         if (current_uid != ROOT_UID) {
1989                                 printf(" Done.\n");
1990                                 continue;
1991                         }
1992
1993                         if (!succeed_cnt) {
1994                                 if (mode_flag & DETAIL)
1995                                         printf("\n");
1996
1997                                 if (arg_type == DEVNAME)
1998                                         printf(" In this device(%s), "
1999                                         "none can be defragmented.\n", argv[i]);
2000                                 else if (arg_type == DIRNAME)
2001                                         printf(" In this directory(%s), "
2002                                         "none can be defragmented.\n", argv[i]);
2003                                 else
2004                                         printf(" This file(%s) "
2005                                         "can't be defragmented.\n", argv[i]);
2006                         } else {
2007                                 float files_ratio = 0.0;
2008                                 float score = 0.0;
2009                                 __u64 size_per_ext = files_block_count *
2010                                                 (buf.st_blksize / 1024) /
2011                                                 extents_before_defrag;
2012                                 files_ratio = (float)(extents_before_defrag -
2013                                                 extents_after_defrag) *
2014                                                 100 / files_block_count;
2015                                 score = CALC_SCORE(files_ratio);
2016                                 printf("\n Total/best extents\t\t\t\t%d/%d\n"
2017                                         " Average size per extent"
2018                                         "\t\t\t%llu KB\n"
2019                                         " Fragmentation score\t\t\t\t%.0f\n",
2020                                                 extents_before_defrag,
2021                                                 extents_after_defrag,
2022                                                 size_per_ext, score);
2023                                 printf(" [0-30 no problem:"
2024                                         " 31-55 a little bit fragmented:"
2025                                         " 56- needs defrag]\n");
2026
2027                                 if (arg_type == DEVNAME)
2028                                         printf(" This device (%s) ", argv[i]);
2029                                 else if (arg_type == DIRNAME)
2030                                         printf(" This directory (%s) ",
2031                                                                 argv[i]);
2032                                 else
2033                                         printf(" This file (%s) ", argv[i]);
2034
2035                                 if (score > BOUND_SCORE)
2036                                         printf("needs defragmentation.\n");
2037                                 else
2038                                         printf("does not need "
2039                                                         "defragmentation.\n");
2040                         }
2041                         printf(" Done.\n");
2042                 }
2043
2044         }
2045
2046         if (success_flag)
2047                 return 0;
2048
2049         exit(1);
2050
2051 out:
2052         printf(MSG_USAGE);
2053         exit(1);
2054 }
2055