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