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