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