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