1 ext4: online defrag -- Online defrag command
3 From: Akira Fujita <a-fujita@rs.jp.nec.com>
5 - The defrag command. Usage is as follows:
6 - Put the multiple files closer together.
7 # e4defrag -r directory-name
8 - Defrag for free space fragmentation.
9 # e4defrag -f file-name
10 - Defrag for a single file.
12 - Defrag for all files on ext4.
13 # e4defrag device-name
15 Signed-off-by: Akira Fujita <a-fujita@rs.jp.nec.com>
16 Signed-off-by: Takashi Sato <t-sato@yk.jp.nec.com>
19 * e4defrag.c - ext4 filesystem defragmenter
21 * Copyright (C) 2008 NEC Software Tohoku, Ltd.
23 * Author: Akira Fujita <a-fujita@rs.jp.nec.com>
24 * Takashi Sato <t-sato@yk.jp.nec.com>
27 #ifndef _LARGEFILE_SOURCE
28 #define _LARGEFILE_SOURCE
31 #ifndef _LARGEFILE64_SOURCE
32 #define _LARGEFILE64_SOURCE
35 #define _XOPEN_SOURCE 500
47 #include <sys/statfs.h>
49 #include <sys/ioctl.h>
53 #include <sys/syscall.h>
55 #include <ext2fs/ext2_types.h>
59 #define EXT4_IOC_DEFRAG _IOW('f', 15, struct ext4_ext_defrag_data)
60 #define EXT4_IOC_SUPER_INFO _IOR('f', 16, struct ext4_super_block)
61 #define EXT4_IOC_FREE_BLOCKS_INFO _IOWR('f', 17, struct ext4_extents_info)
62 #define EXT4_IOC_FIEMAP_INO _IOWR('f', 18, struct fiemap_ino)
63 #define EXT4_IOC_MOVE_VICTIM _IOW('f', 19, struct ext4_extents_info)
64 #define FS_IOC_FIEMAP _IOWR('f', 11, struct fiemap)
67 #define PRINT_ERR_MSG(msg) fprintf(stderr, "%s\n", (msg));
68 #define IN_FTW_PRINT_ERR_MSG(msg) \
69 fprintf(stderr, "\t%s\t\t[ NG ]\n", (msg));
70 #define PRINT_FILE_NAME(file) fprintf(stderr, " \"%s\"\n", (file));
71 #define PRINT_ERR_MSG_WITH_ERRNO(msg) \
72 fprintf(stderr, "\t%s:%s\t[ NG ]\n", (msg), strerror(errno));
73 #define min(x, y) (((x) > (y)) ? (y) : (x))
74 /* Wrap up the free function */
80 /* Insert list2 after list1 */
81 #define insert(list1, list2) \
83 list2->next = list1->next; \
84 list1->next->prev = list2; \
85 list2->prev = list1; \
86 list1->next = list2; \
89 #ifndef __NR_fadvise64
90 #define __NR_fadvise64 250
93 #ifndef __NR_sync_file_range
94 #define __NR_sync_file_range 314
97 #ifndef POSIX_FADV_DONTNEED
98 #if defined(__s390x__)
99 #define POSIX_FADV_DONTNEED 6 /* Don't need these pages */
101 #define POSIX_FADV_DONTNEED 4 /* Don't need these pages */
105 #ifndef SYNC_FILE_RANGE_WAIT_BEFORE
106 #define SYNC_FILE_RANGE_WAIT_BEFORE 1
108 #ifndef SYNC_FILE_RANGE_WRITE
109 #define SYNC_FILE_RANGE_WRITE 2
111 #ifndef SYNC_FILE_RANGE_WAIT_AFTER
112 #define SYNC_FILE_RANGE_WAIT_AFTER 4
122 #define FTW_OPEN_FD 2000
124 #define FS_EXT4 "ext4"
126 #define CHECK_FRAG_COUNT 1
128 /* Extent status which are used in extent_t */
129 #define EXT4_EXT_USE 0
130 #define EXT4_EXT_FREE 1
132 /* The maximum number of extents for exchanging between
133 * kernel-space and user-space per ioctl
135 #define DEFRAG_MAX_ENT 32
137 /* The phase of force defrag mode */
138 #define DEFRAG_FORCE_TRY 1
139 #define DEFRAG_FORCE_GATHER 3
141 /* Magic number for ext4 */
142 #define EXT4_SUPER_MAGIC 0xEF53
144 /* Defrag size(64MB) per ioctl(not including force mode) */
145 #define DEFRAG_SIZE ((unsigned long)1 << 26)
147 /* Force defrag mode: Max file size in bytes (128MB) */
148 #define MAX_FILE_SIZE ((unsigned long)1 << 27)
151 /* The following four macros are used for ioctl FS_IOC_FIEMAP
152 * FIEMAP_FLAG_SYNC: sync file data before map.
153 * FIEMAP_EXTENT_LAST: last extent in file.
154 * FIEMAP_MAX_OFFSET: max file offset.
155 * EXTENT_MAX_COUNT: the maximum number of extents for exchanging between
156 kernel-space and user-space per ioctl
158 #define FIEMAP_FLAG_SYNC 0x00000001
159 #define FIEMAP_EXTENT_LAST 0x00000001
160 #define FIEMAP_MAX_OFFSET (~0ULL)
161 #define EXTENT_MAX_COUNT 512
163 /* The following macros are error message */
165 "Usage : e4defrag [-v] file...| directory...| device...\n\
166 : e4defrag -f file [blocknr] \n\
167 : e4defrag -r directory... | device... \n"
169 #define MSG_R_OPTION " with regional block allocation mode.\n"
170 #define NGMSG_MTAB "Can not access /etc/mtab"
171 #define NGMSG_UNMOUNT "FS is not mounted"
172 #define NGMSG_EXT4 "FS is not ext4 File System"
173 #define NGMSG_FS_INFO "Get FSInfo fail"
174 #define NGMSG_FILE_INFO "Get FileInfo fail"
175 #define NGMSG_FILE_OPEN "Open fail"
176 #define NGMSG_FILE_SYNC "Sync(fsync) fail"
177 #define NGMSG_FILE_DEFRAG "Defrag fail"
178 #define NGMSG_FILE_BLOCKSIZE "Can't get blocksize"
179 #define NGMSG_FILE_SUPER "Can't get super block info"
180 #define NGMSG_FILE_UNREG "File is not regular file"
181 #define NGMSG_VICTIM_UID "Victim file is not current user's file"
183 #define NGMSG_FILE_LARGE \
184 "Defrag size is larger than FileSystem's free space"
186 #define NGMSG_FILE_PRIORITY \
187 "File is not current user's file or current user is not root"
189 #define NGMSG_FILE_LOCK "File is locked"
190 #define NGMSG_FILE_BLANK "File size is 0"
191 #define NGMSG_GET_LCKINFO "Get LockInfo fail"
193 "Can not process %s in regional mode.\n"
194 #define NGMSG_LOST_FOUND "Can not process \"lost+found\""
195 #define NGMSG_REALPATH "Can not get full path"
196 #define NGMSG_FILE_MAP "Get file map fail"
197 #define NGMSG_FILE_DROP_BUFFER "Free page fail"
198 #define NGMSG_FADVISE_SYSCALL "\tFadvise fail"
199 #define NGMSG_FORCE_DEFRAG_SIZE \
200 "Cannot specify a file larger than %luMB in force defrag mode"
201 #define NGMSG_ENDIAN "Endian type is not big/little endian"
203 /* Data type for filesystem-wide blocks number */
204 typedef unsigned long long ext4_fsblk_t;
206 /* Data type for file logical block number */
207 typedef unsigned int ext4_lblk_t;
209 /* Data type for block offset of block group */
210 typedef int ext4_grpblk_t;
212 struct ext4_extent_data {
213 ext4_lblk_t block; /* start logical block number */
214 ext4_fsblk_t start; /* start physical block number */
215 int len; /* blocks count */
218 /* Used for defrag */
219 struct ext4_ext_defrag_data {
220 ext4_lblk_t start_offset; /* start offset to defrag in blocks */
221 ext4_lblk_t defrag_size; /* size of defrag in blocks */
222 ext4_fsblk_t goal; /* block offset for allocation */
223 int flag; /* free space mode flag */
224 struct ext4_extent_data ext;
227 typedef __u16 __le16;
228 typedef __u32 __le32;
229 typedef __u64 __le64;
232 * Structure of the super block
234 struct ext4_super_block {
235 /*00*/ __le32 s_inodes_count; /* Inodes count */
236 __le32 s_blocks_count_lo; /* Blocks count */
237 __le32 s_r_blocks_count_lo; /* Reserved blocks count */
238 __le32 s_free_blocks_count_lo; /* Free blocks count */
239 /*10*/ __le32 s_free_inodes_count; /* Free inodes count */
240 __le32 s_first_data_block; /* First Data Block */
241 __le32 s_log_block_size; /* Block size */
242 __le32 s_obso_log_frag_size; /* Obsoleted fragment size */
243 /*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
244 __le32 s_obso_frags_per_group; /* Obsoleted fragments per group */
245 __le32 s_inodes_per_group; /* # Inodes per group */
246 __le32 s_mtime; /* Mount time */
247 /*30*/ __le32 s_wtime; /* Write time */
248 __le16 s_mnt_count; /* Mount count */
249 __le16 s_max_mnt_count; /* Maximal mount count */
250 __le16 s_magic; /* Magic signature */
251 __le16 s_state; /* File system state */
252 __le16 s_errors; /* Behaviour when detecting errors */
253 __le16 s_minor_rev_level; /* minor revision level */
254 /*40*/ __le32 s_lastcheck; /* time of last check */
255 __le32 s_checkinterval; /* max. time between checks */
256 __le32 s_creator_os; /* OS */
257 __le32 s_rev_level; /* Revision level */
258 /*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */
259 __le16 s_def_resgid; /* Default gid for reserved blocks */
261 * These fields are for EXT4_DYNAMIC_REV superblocks only.
263 * Note: the difference between the compatible feature set and
264 * the incompatible feature set is that if there is a bit set
265 * in the incompatible feature set that the kernel doesn't
266 * know about, it should refuse to mount the filesystem.
268 * e2fsck's requirements are more strict; if it doesn't know
269 * about a feature in either the compatible or incompatible
270 * feature set, it must abort and not try to meddle with
271 * things it doesn't understand...
273 __le32 s_first_ino; /* First non-reserved inode */
274 __le16 s_inode_size; /* size of inode structure */
275 __le16 s_block_group_nr; /* block group # of this superblock */
276 __le32 s_feature_compat; /* compatible feature set */
277 /*60*/ __le32 s_feature_incompat; /* incompatible feature set */
278 __le32 s_feature_ro_compat; /* readonly-compatible feature set */
279 /*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
280 /*78*/ char s_volume_name[16]; /* volume name */
281 /*88*/ char s_last_mounted[64]; /* directory where last mounted */
282 /*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
284 * Performance hints. Directory preallocation should only
285 * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
287 __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
288 __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
289 __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
291 * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
293 /*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
294 /*E0*/ __le32 s_journal_inum; /* inode number of journal file */
295 __le32 s_journal_dev; /* device number of journal file */
296 __le32 s_last_orphan; /* start of list of inodes to delete */
297 __le32 s_hash_seed[4]; /* HTREE hash seed */
298 __u8 s_def_hash_version; /* Default hash version to use */
299 __u8 s_reserved_char_pad;
300 __le16 s_desc_size; /* size of group descriptor */
301 /*100*/ __le32 s_default_mount_opts;
302 __le32 s_first_meta_bg; /* First metablock block group */
303 __le32 s_mkfs_time; /* When the filesystem was created */
304 __le32 s_jnl_blocks[17]; /* Backup of the journal inode */
305 /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
306 /*150*/ __le32 s_blocks_count_hi; /* Blocks count */
307 __le32 s_r_blocks_count_hi; /* Reserved blocks count */
308 __le32 s_free_blocks_count_hi; /* Free blocks count */
309 __le16 s_min_extra_isize; /* All inodes have at least # bytes */
310 __le16 s_want_extra_isize; /* New inodes should reserve # bytes */
311 __le32 s_flags; /* Miscellaneous flags */
312 __le16 s_raid_stride; /* RAID stride */
313 __le16 s_mmp_interval; /* # seconds to wait in MMP checking */
314 __le64 s_mmp_block; /* Block for multi-mount protection */
315 __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
316 __u8 s_log_groups_per_flex; /* FLEX_BG group size */
317 __u8 s_reserved_char_pad2;
318 __le16 s_reserved_pad;
319 __u32 s_reserved[162]; /* Padding to the end of the block */
322 struct ext4_extents_info {
323 unsigned long long ino; /* inode number */
324 int max_entries; /* maximum extents count */
325 int entries; /* extent number/count */
326 ext4_lblk_t f_offset; /* file offset */
327 ext4_grpblk_t g_offset; /* group offset */
329 struct ext4_extent_data ext[DEFRAG_MAX_ENT];
332 typedef struct extent {
334 unsigned long tag; /* extent status */
335 unsigned long ino; /* file's inode number */
336 struct ext4_extent_data data; /* extent belong to file */
340 typedef struct exts_group {
341 struct exts_group *prev;
342 extent_t *start; /* start ext */
343 extent_t *end; /* end ext */
344 int len; /* length of this continuous region */
345 struct exts_group *next;
348 struct fiemap_extent {
349 __u64 fe_logical; /* logical offset in bytes for the start of
350 * the extent from the beginning of the file */
351 __u64 fe_physical; /* physical offset in bytes for the start
352 * of the extent from the beginning
354 __u64 fe_length; /* length in bytes for this extent */
355 __u64 fe_reserved64[2];
356 __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */
357 __u32 fe_reserved[3];
361 __u64 fm_start; /* logical offset (inclusive) at
362 * which to start mapping (in) */
363 __u64 fm_length; /* logical length of mapping which
364 * userspace wants (in) */
365 __u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */
366 __u32 fm_mapped_extents;/* number of extents that were mapped (out) */
367 __u32 fm_extent_count; /* size of fm_extents array (in) */
369 struct fiemap_extent fm_extents[0];/* array of mapped extents (out) */
374 struct fiemap fiemap;
380 int extents_before_defrag;
381 int extents_after_defrag;
382 unsigned long succeed_cnt;
383 unsigned long regular_count;
384 unsigned long total_count;
385 unsigned long frag_files_before_defrag;
386 unsigned long frag_files_after_defrag;
387 unsigned long defraged_file_count;
388 char lost_found_dir[PATH_MAX + 1];
390 ext4_fsblk_t fgoal = -1;
393 * ext2fs_swab32() - Change endian.
395 * @val: the entry used for change.
397 __u32 ext2fs_swab32(__u32 val)
399 #if BYTE_ORDER == BIG_ENDIAN
400 return (val>>24) | ((val>>8)&0xFF00) |
401 ((val<<8)&0xFF0000) | (val<<24);
408 * fadvise() - Give advice about file access.
410 * @fd: the file's descriptor.
411 * @offset: file offset.
413 * @advise: process flag.
415 int fadvise(int fd, loff_t offset, size_t len, int advise)
417 return syscall(__NR_fadvise64, fd, offset, len, advise);
421 * sync_file_range() - Sync file region.
423 * @fd: the file's descriptor.
424 * @offset: file offset.
425 * @length: area length.
426 * @flag: process flag.
428 int sync_file_range(int fd, loff_t offset, loff_t length, unsigned int flag)
430 return syscall(__NR_sync_file_range, fd, offset, length, flag);
434 * page_in_core() - Get information on whether pages are in core.
436 * @fd: the file's descriptor.
437 * @defrag_data: data used for defrag.
438 * @vec: page state array.
439 * @page_num: page number.
441 int page_in_core(int fd, struct ext4_ext_defrag_data defrag_data,
442 unsigned char **vec, unsigned long *page_num)
445 int pagesize = getpagesize();
447 loff_t offset, end_offset, length;
449 if (vec == NULL || *vec != NULL)
452 if (ioctl(fd, FIGETBSZ, &blocksize) < 0)
455 /* In mmap, offset should be a multiple of the page size */
456 offset = defrag_data.start_offset * blocksize;
457 length = defrag_data.defrag_size * blocksize;
458 end_offset = offset + length;
459 /* Round the offset down to the nearest multiple of pagesize */
460 offset = (offset / pagesize) * pagesize;
461 length = end_offset - offset;
463 page = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, offset);
464 if (page == MAP_FAILED)
468 *page_num = (length + pagesize - 1) / pagesize;
469 *vec = (unsigned char *)calloc(*page_num, 1);
473 /* Get information on whether pages are in core */
474 if (mincore(page, (size_t)length, *vec) == -1 ||
475 munmap(page, length) == -1) {
484 * defrag_fadvise() - Predeclare an access pattern for file data.
486 * @fd: the file's descriptor.
487 * @defrag_data: data used for defrag.
488 * @vec: page state array.
489 * @page_num: page number.
491 int defrag_fadvise(int fd, struct ext4_ext_defrag_data defrag_data,
492 unsigned char *vec, unsigned long page_num)
496 int pagesize = getpagesize();
497 int fadvise_flag = POSIX_FADV_DONTNEED;
498 int sync_flag = SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE|
499 SYNC_FILE_RANGE_WAIT_AFTER;
503 if (ioctl(fd, FIGETBSZ, &blocksize) < 0)
506 offset = (loff_t)defrag_data.start_offset * blocksize;
507 offset = (offset / pagesize) * pagesize;
509 /* Sync file for fadvise process */
510 if (sync_file_range(fd, offset,
511 (loff_t)pagesize*page_num, sync_flag) != 0)
514 /* Try to release buffer cache which this process used,
515 * then other process can use the released buffer
517 for (i = 0; i < page_num; i++) {
518 if ((vec[i] & 0x1) == 0) {
522 if (fadvise(fd, offset, pagesize, fadvise_flag) != 0) {
523 if (detail_flag && flag) {
524 perror(NGMSG_FADVISE_SYSCALL);
535 * check_free_size() - Check if there's enough disk space.
537 * @fd: the file's descriptor.
538 * @file_name file name.
539 * @buf: the pointer of the struct stat64.
541 int check_free_size(int fd, const char *file_name, const struct stat64 *buf)
544 off64_t free_size = 0;
547 /* Target file size */
550 if (fstatfs(fd, &fsbuf) < 0) {
552 PRINT_FILE_NAME(file_name);
553 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FS_INFO);
558 /* Compute free space for root and normal user separately */
559 if (getuid() == ROOT_UID)
560 free_size = (off64_t)fsbuf.f_bsize * fsbuf.f_bfree;
562 free_size = (off64_t)fsbuf.f_bsize * fsbuf.f_bavail;
564 if (free_size >= size)
568 PRINT_FILE_NAME(file_name);
569 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_LARGE);
574 int file_check(int fd, const struct stat64 *buf, const char *file_name);
575 int force_defrag(int fd, const char *file_name,
576 const struct stat64 *buf, int blocksize);
579 * file_frag_count() - Get file fragment count.
581 * @fd: the file's descriptor.
583 long long file_frag_count(int fd)
586 struct fiemap file_extent_map;
588 /* When fm_extent_count is 0,
589 * ioctl just get file fragment count.
591 memset(&file_extent_map, 0, sizeof(struct fiemap));
592 file_extent_map.fm_start = 0;
593 file_extent_map.fm_length = FIEMAP_MAX_OFFSET;
594 file_extent_map.fm_flags |= FIEMAP_FLAG_SYNC;
596 ret = ioctl(fd, FS_IOC_FIEMAP, &file_extent_map);
600 return file_extent_map.fm_mapped_extents;
604 * ftw_fn() - Check file attributes and ioctl call to avoid.
605 * illegal operations.
607 * @file: the file's name.
608 * @buf: the pointer of the struct stat64.
610 * @ftwbuf: the pointer of a struct FTW.
612 int ftw_fn(const char *file, const struct stat64 *buf, int flag,
619 int defraged_size = 0;
621 long long file_frags_start, file_frags_end;
622 unsigned long page_num;
623 unsigned char *vec = NULL;
625 struct ext4_ext_defrag_data df_data;
627 defraged_file_count++;
630 printf("[%lu/%lu]", defraged_file_count, total_count);
634 if (lost_found_dir[0] != '\0' &&
635 !memcmp(file, lost_found_dir, strnlen(lost_found_dir, PATH_MAX))) {
637 PRINT_FILE_NAME(file);
638 IN_FTW_PRINT_ERR_MSG(NGMSG_LOST_FOUND);
645 PRINT_FILE_NAME(file);
646 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_UNREG);
651 fd = open64(file, O_RDONLY);
654 PRINT_FILE_NAME(file);
655 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_OPEN);
660 if (file_check(fd, buf, file) == RETURN_NG)
665 PRINT_FILE_NAME(file);
666 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_SYNC);
671 if (ioctl(fd, FIGETBSZ, &blocksize) < 0) {
673 PRINT_FILE_NAME(file);
674 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_BLOCKSIZE);
678 /* Ioctl call does the actual defragment job */
679 df_data.start_offset = 0;
682 df_data.flag = force_flag;
684 /* Count file fragments before defrag */
686 file_frags_start = file_frag_count(fd);
687 if (file_frags_start == RETURN_NG) {
688 PRINT_FILE_NAME(file);
689 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_INFO);
693 if (file_frags_start != 1)
694 frag_files_before_defrag++;
696 extents_before_defrag += file_frags_start;
699 /* Print process progress */
700 percent = (start * 100) / buf->st_size;
701 printf("\033[79;0H\033[K[%lu/%lu]%s:\t%3d%%",
702 defraged_file_count, total_count, file, min(percent, 100));
706 df_data.defrag_size = (min((buf->st_size - start),
707 DEFRAG_SIZE) + blocksize - 1) / blocksize;
708 ret = page_in_core(fd, df_data, &vec, &page_num);
709 if (ret == RETURN_NG) {
712 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_MAP);
714 printf("\t[ NG ]\n");
720 /* EXT4_IOC_DEFRAG */
721 defraged_size = ioctl(fd, EXT4_IOC_DEFRAG, &df_data);
724 ret = defrag_fadvise(fd, df_data, vec, page_num);
729 if (ret == RETURN_NG) {
732 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_DROP_BUFFER
735 printf("\t[ NG ]\n");
741 /* Go into force defrag mode */
742 if (defraged_size < 0 && force_flag == DEFRAG_FORCE_TRY
743 && errno == ENOSPC) {
744 /* File size is larger than max size of
747 if (buf->st_size > MAX_FILE_SIZE) {
749 fprintf(stderr, "\n\t");
750 fprintf(stderr, NGMSG_FORCE_DEFRAG_SIZE,
751 (MAX_FILE_SIZE) / (1024 * 1024)
753 fprintf(stderr, "\t[ NG ]\n");
755 printf("\t[ NG ]\n");
761 printf("\033[79;0H\033[K");
762 defraged_size = force_defrag(fd, file, buf, blocksize);
763 if (defraged_size * blocksize >= buf->st_size)
764 /* Whole file is enforcedly defraged */
768 printf("\033[79;0H\033[K[%lu/%lu]%s\t"
777 if (defraged_size < 0) {
780 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_DEFRAG);
782 printf("\t[ NG ]\n");
787 df_data.start_offset += defraged_size;
788 start = (long long)df_data.start_offset * blocksize;
790 /* Print process progress */
791 percent = (start * 100) / buf->st_size;
793 /* Disk space file used is bigger than logical size */
794 printf("\033[79;0H\033[K[%lu/%lu]%s:\t%3d%%",
795 defraged_file_count, total_count, file,
800 if (start >= buf->st_size)
804 /* Count file fragments after defrag and print extents info */
806 file_frags_end = file_frag_count(fd);
807 if (file_frags_end == RETURN_NG) {
809 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_INFO);
813 if (file_frags_end != 1)
814 frag_files_after_defrag++;
816 extents_after_defrag += file_frags_end;
821 printf(" extents: %lld -> %lld",
822 file_frags_start, file_frags_end);
829 printf("\t[ OK ]\n");
839 * file_check() - Check file's attributes.
841 * @fd: the file's descriptor.
842 * @buf: a pointer of the struct stat64.
843 * @file_name: the file's name.
845 int file_check(int fd, const struct stat64 *buf, const char *file_name)
849 /* Write-lock check is more reliable */
850 lock.l_type = F_WRLCK;
852 lock.l_whence = SEEK_SET;
856 if (S_ISREG(buf->st_mode) == 0) {
858 PRINT_FILE_NAME(file_name);
859 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_UNREG);
865 if (check_free_size(fd, file_name, buf) == RETURN_NG)
869 if (getuid() != ROOT_UID &&
870 buf->st_uid != getuid()) {
872 PRINT_FILE_NAME(file_name);
873 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_PRIORITY);
879 if (fcntl(fd, F_GETLK, &lock) < 0) {
881 PRINT_FILE_NAME(file_name);
882 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_GET_LCKINFO);
885 } else if (lock.l_type != F_UNLCK) {
887 PRINT_FILE_NAME(file_name);
888 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_LOCK);
894 if (buf->st_size == 0) {
896 PRINT_FILE_NAME(file_name);
897 IN_FTW_PRINT_ERR_MSG(NGMSG_FILE_BLANK);
906 * is_ext4() - Whether on an ext4 filesystem.
908 * @filename: the file's name.
910 int is_ext4(const char *filename)
912 int maxlen, len, ret;
914 char *mnt_type = NULL;
915 /* Refer to /etc/mtab */
916 char *mtab = MOUNTED;
917 char file_path[PATH_MAX + 1];
918 struct mntent *mnt = NULL;
922 if (realpath(filename, file_path) == NULL) {
923 perror(NGMSG_REALPATH);
924 PRINT_FILE_NAME(filename);
928 if (statfs(file_path, &buffs) < 0) {
929 perror(NGMSG_FS_INFO);
930 PRINT_FILE_NAME(filename);
934 if (buffs.f_type != EXT4_SUPER_MAGIC) {
935 PRINT_ERR_MSG(NGMSG_EXT4);
939 fp = setmntent(mtab, "r");
946 while ((mnt = getmntent(fp)) != NULL) {
947 len = strlen(mnt->mnt_dir);
948 ret = memcmp(file_path, mnt->mnt_dir, len);
957 mnt_type = realloc(mnt_type, strlen(mnt->mnt_type) + 1);
962 strcpy(mnt_type, mnt->mnt_type);
963 strncpy(lost_found_dir, mnt->mnt_dir, PATH_MAX);
967 if (strcmp(mnt_type, FS_EXT4) == 0) {
972 PRINT_ERR_MSG(NGMSG_EXT4);
978 * calc_entry_counts - calculate file counts
983 * @ftwbuf: the pointer of a struct FTW.
985 int calc_entry_counts(const char *file, const struct stat64 *buf, int flag,
998 * get_mount_point() - Get device's mount point.
1000 * @devname: the device's name.
1001 * @mount_point: the mount point.
1002 * @dir_path_len: the length of directory.
1004 int get_mount_point(const char *devname, char *mount_point,
1007 /* Refer to /etc/mtab */
1008 char *mtab = MOUNTED;
1010 struct mntent *mnt = NULL;
1012 fp = setmntent(mtab, "r");
1018 while ((mnt = getmntent(fp)) != NULL) {
1019 if (strcmp(devname, mnt->mnt_fsname) != 0)
1023 if (strcmp(mnt->mnt_type, FS_EXT4) == 0) {
1024 strncpy(mount_point, mnt->mnt_dir,
1028 PRINT_ERR_MSG(NGMSG_EXT4);
1032 PRINT_ERR_MSG(NGMSG_UNMOUNT);
1037 * main() - ext4 online defrag.
1039 * @argc: the number of parameter.
1040 * @argv[]: the pointer array of parameter.
1042 int main(int argc, char *argv[])
1050 char dir_name[PATH_MAX + 1];
1058 /* Do not follow symlink */
1060 /* Stay within the same filesystem */
1063 /* Parse arguments */
1064 if (argc == 1 || (argc == 2 && argv[1][0] == '-'))
1067 while ((opt = getopt(argc, argv, "rvf")) != EOF) {
1078 force_flag = DEFRAG_FORCE_TRY;
1085 printf("Illegal argument\n");
1089 /* Now the agrc must be 4(e4defrag -f file blocknr) */
1091 res_strlen = strlen(argv[3]);
1092 for (res_strlen -= 1; res_strlen >= 0; res_strlen--) {
1093 if (!isdigit(argv[3][res_strlen])) {
1094 printf("Illegal argument\n");
1099 fgoal = strtoul(argv[3], NULL, 0);
1101 printf("block num shold be < 4294967295"
1102 "(max num of unsigned long 32bit)\n");
1114 for (; i < argc; i++) {
1118 frag_files_before_defrag = 0;
1119 frag_files_after_defrag = 0;
1120 extents_before_defrag = 0;
1121 extents_after_defrag = 0;
1122 defraged_file_count = 0;
1124 memset(dir_name, 0, PATH_MAX + 1);
1125 memset(lost_found_dir, 0, PATH_MAX + 1);
1127 if (force_flag && i == 3)
1130 #if BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN
1131 PRINT_ERR_MSG(NGMSG_ENDIAN);
1132 PRINT_FILE_NAME(argv[i]);
1136 if (lstat64(argv[i], &buf) < 0) {
1137 perror(NGMSG_FILE_INFO);
1138 PRINT_FILE_NAME(argv[i]);
1142 /* Only regular file is acceptalbe with force defrag mode */
1143 if (force_flag && !S_ISREG(buf.st_mode)) {
1144 printf("Inappropriate file type\n");
1148 if (S_ISBLK(buf.st_mode)) {
1150 if (get_mount_point(argv[i], dir_name, PATH_MAX)
1154 printf("ext4 defragmentation for device(%s)\n",
1156 } else if (S_ISDIR(buf.st_mode)) {
1158 if (access(argv[i], R_OK) < 0) {
1163 strcpy(dir_name, argv[i]);
1164 } else if (S_ISREG(buf.st_mode)) {
1166 arg_type = FILENAME;
1168 /* Irregular file */
1169 PRINT_ERR_MSG(NGMSG_FILE_UNREG);
1170 PRINT_FILE_NAME(argv[i]);
1175 * filesystem type checked in get_mount_point()
1177 if (arg_type == FILENAME || arg_type == DIRNAME) {
1178 if (is_ext4(argv[i]) == RETURN_NG)
1180 if (realpath(argv[i], dir_name) == NULL) {
1181 perror(NGMSG_REALPATH);
1182 PRINT_FILE_NAME(argv[i]);
1189 printf("ext4 defragmentation for directory(%s)\n",
1192 int mount_dir_len = 0;
1193 mount_dir_len = strnlen(lost_found_dir, PATH_MAX);
1195 strncat(lost_found_dir, "/lost+found",
1196 PATH_MAX - strnlen(lost_found_dir, PATH_MAX));
1198 /* Not the case("e4defrag mount_piont_dir") */
1199 if (dir_name[mount_dir_len] != '\0') {
1200 /* "e4defrag mount_piont_dir/lost+found"
1201 * or "e4defrag mount_piont_dir/lost+found/"
1203 if (strncmp(lost_found_dir, dir_name,
1204 strnlen(lost_found_dir,
1206 (dir_name[strnlen(lost_found_dir,
1207 PATH_MAX)] == '\0' ||
1208 dir_name[strnlen(lost_found_dir,
1209 PATH_MAX)] == '/')) {
1210 PRINT_ERR_MSG(NGMSG_LOST_FOUND);
1211 PRINT_FILE_NAME(argv[i]);
1215 /* "e4defrag mount_piont_dir/else_dir" */
1216 memset(lost_found_dir, 0, PATH_MAX + 1);
1219 if (arg_type == DEVNAME) {
1220 strncpy(lost_found_dir, dir_name,
1221 strnlen(dir_name, PATH_MAX));
1222 strncat(lost_found_dir, "/lost+found/",
1223 PATH_MAX - strnlen(lost_found_dir,
1227 /* Regional block allocation */
1228 if (regional_flag) {
1229 unsigned int bg_num = 0;
1231 struct ext4_super_block sb;
1233 printf(MSG_R_OPTION);
1235 fd = open64(dir_name, O_RDONLY);
1238 perror(NGMSG_FILE_OPEN);
1239 PRINT_FILE_NAME(dir_name);
1244 memset(&sb, 0, sizeof(struct ext4_super_block));
1246 ret = ioctl(fd, EXT4_IOC_SUPER_INFO, &sb);
1248 perror(NGMSG_FILE_SUPER);
1249 PRINT_FILE_NAME(dir_name);
1255 sb.s_blocks_per_group =
1256 ext2fs_swab32(sb.s_blocks_per_group);
1257 sb.s_inodes_per_group =
1258 ext2fs_swab32(sb.s_inodes_per_group);
1259 sb.s_first_data_block =
1260 ext2fs_swab32(sb.s_first_data_block);
1262 bg_num = (buf.st_ino - 1) /
1263 sb.s_inodes_per_group;
1264 goal = bg_num * sb.s_blocks_per_group +
1265 sb.s_first_data_block;
1267 nftw64(dir_name, calc_entry_counts, FTW_OPEN_FD, flags);
1269 /* File tree walk */
1270 nftw64(dir_name, ftw_fn, FTW_OPEN_FD, flags);
1271 printf("\n\tSuccess:\t\t\t[ %lu/%lu ]\n", succeed_cnt,
1273 printf("\tFailure:\t\t\t[ %lu/%lu ]\n",
1274 total_count - succeed_cnt, total_count);
1276 printf("\tTotal extents:\t\t\t%4d->%d\n",
1277 extents_before_defrag,
1278 extents_after_defrag);
1279 printf("\tFragmented percentage:\t\t"
1280 "%3llu%%->%llu%%\n",
1281 !regular_count ? 0 :
1282 ((unsigned long long)
1283 frag_files_before_defrag * 100) /
1285 !regular_count ? 0 :
1286 ((unsigned long long)
1287 frag_files_after_defrag * 100) /
1293 strncat(lost_found_dir, "/lost+found/",
1294 PATH_MAX - strnlen(lost_found_dir,
1296 if (strncmp(lost_found_dir, dir_name,
1297 strnlen(lost_found_dir,
1299 PRINT_ERR_MSG(NGMSG_LOST_FOUND);
1300 PRINT_FILE_NAME(argv[i]);
1304 if (regional_flag) {
1305 fprintf(stderr, NGMSG_TYPE, argv[i]);
1308 printf("ext4 defragmentation for %s\n", argv[i]);
1309 /* Defrag single file process */
1310 ftw_fn(argv[i], &buf, FTW_F, NULL);
1311 if (succeed_cnt != 0)
1312 printf(" Success:\t\t\t[1/1]\n");
1314 printf(" Success:\t\t\t[0/1]\n");
1319 if (succeed_cnt != 0)
1334 * insert_extent() - Sequentially insert extent by physical block number.
1336 * @extlist_head: the head of an extent list.
1337 * @ext: the extent element which will be inserted.
1339 int insert_extent(extent_t **extlist_head, extent_t *ext)
1341 extent_t *ext_tmp = *extlist_head;
1347 if (*extlist_head == NULL) {
1348 (*extlist_head) = ext;
1349 (*extlist_head)->prev = *extlist_head;
1350 (*extlist_head)->next = *extlist_head;
1354 if (ext->data.start <= ext_tmp->data.start) {
1355 /* Insert before head */
1356 if (ext_tmp->data.start < ext->data.start + ext->data.len)
1360 *extlist_head = ext;
1362 /* Insert into the middle or last of the list */
1364 if (ext->data.start < ext_tmp->data.start)
1366 ext_tmp = ext_tmp->next;
1367 } while (ext_tmp != (*extlist_head));
1368 if (ext->data.start <
1369 ext_tmp->prev->data.start + ext_tmp->prev->data.len)
1373 if (ext_tmp != *extlist_head &&
1374 ext_tmp->data.start < ext->data.start + ext->data.len)
1378 ext_tmp = ext_tmp->prev;
1379 /* Insert "ext" after "ext_tmp" */
1380 insert(ext_tmp, ext);
1385 * insert_exts_group() - Insert a exts_group in decreasing order
1388 * @exts_group_list_head: the head of a exts_group list.
1389 * @exts_group: the exts_group element which will be inserted.
1391 int insert_exts_group(exts_group_t **exts_group_list_head,
1392 exts_group_t *exts_group)
1394 exts_group_t *exts_group_tmp = NULL;
1396 if (exts_group == NULL)
1399 /* Initialize list */
1400 if (*exts_group_list_head == NULL) {
1401 (*exts_group_list_head) = exts_group;
1402 (*exts_group_list_head)->prev = *exts_group_list_head;
1403 (*exts_group_list_head)->next = *exts_group_list_head;
1407 if (exts_group->len >= (*exts_group_list_head)->len) {
1408 /* Insert before exts_group_list_head */
1409 exts_group_tmp = (*exts_group_list_head)->prev;
1410 insert(exts_group_tmp, exts_group);
1411 *exts_group_list_head = exts_group;
1415 /* Find insertion positon */
1416 for (exts_group_tmp = (*exts_group_list_head)->next;
1417 exts_group_tmp != *exts_group_list_head;
1418 exts_group_tmp = exts_group_tmp->next) {
1419 if (exts_group_tmp->len < exts_group->len)
1422 exts_group_tmp = exts_group_tmp->prev;
1423 insert(exts_group_tmp, exts_group);
1429 * get_exts_group() - Get element from the exts_group list.
1431 * @exts_group_list_head: the head of a exts_group list.
1432 * @exts_group: the exts_group element which will be got.
1434 exts_group_t *get_exts_group(exts_group_t **exts_group_list_head,
1435 exts_group_t *exts_group)
1437 if (exts_group == NULL || *exts_group_list_head == NULL)
1440 /* Keep "exts_group_list_head" point to the largest extent group */
1441 if (exts_group == *exts_group_list_head)
1442 *exts_group_list_head = exts_group->next;
1444 if (*exts_group_list_head == (*exts_group_list_head)->next &&
1445 exts_group == *exts_group_list_head)
1446 /* Delete the last element in the list */
1447 *exts_group_list_head = NULL;
1449 exts_group->prev->next = exts_group->next;
1450 exts_group->next->prev = exts_group->prev;
1455 * free_exts_group() - Free the exts_group.
1457 * @*exts_group_list_head: the exts_group list head which will be free.
1459 void free_exts_group(exts_group_t *exts_group_list_head)
1461 exts_group_t *exts_group_tmp = NULL;
1463 if (exts_group_list_head == NULL)
1466 while (exts_group_list_head->next != exts_group_list_head) {
1467 exts_group_tmp = exts_group_list_head;
1468 exts_group_list_head->prev->next = exts_group_list_head->next;
1469 exts_group_list_head->next->prev = exts_group_list_head->prev;
1470 exts_group_list_head = exts_group_list_head->next;
1471 free(exts_group_tmp);
1473 free(exts_group_list_head);
1477 * free_ext() - Free the extent list.
1479 * @extent_list_head: the extent list head of which will be free.
1481 void free_ext(extent_t *extent_list_head)
1483 extent_t *extent_tmp = NULL;
1485 if (extent_list_head == NULL)
1488 while (extent_list_head->next != extent_list_head) {
1489 extent_tmp = extent_list_head;
1490 extent_list_head->prev->next = extent_list_head->next;
1491 extent_list_head->next->prev = extent_list_head->prev;
1492 extent_list_head = extent_list_head->next;
1495 free(extent_list_head);
1499 * do_defrag() - Execute the defrag program in force mode.
1501 * @fd: the file's descriptor.
1502 * @exts_group: the exts_group which will be defraged.
1503 * @defrag_data: the data which will be defraged.
1505 int do_defrag(int fd, exts_group_t *exts_group,
1506 struct ext4_ext_defrag_data defrag_data)
1508 int defraged_size = 0;
1509 int fadvise_ret = 0;
1510 unsigned long page_num;
1511 unsigned char *vec = NULL;
1513 /* Init defrag_data for defrag */
1514 defrag_data.ext.start = exts_group->start->data.start;
1515 defrag_data.ext.len = exts_group->len;
1516 defrag_data.ext.block = 0;
1517 defrag_data.defrag_size = exts_group->len;
1518 /* Move victim extents to make sufficient space */
1519 defrag_data.flag = DEFRAG_FORCE_GATHER;
1520 defrag_data.goal = exts_group->start->data.start;
1522 if (page_in_core(fd, defrag_data, &vec, &page_num) == RETURN_NG)
1525 defraged_size = ioctl(fd, EXT4_IOC_DEFRAG, &defrag_data);
1528 fadvise_ret = defrag_fadvise(fd, defrag_data, vec, page_num);
1531 if (fadvise_ret == RETURN_NG || defraged_size < 0)
1534 return defraged_size;
1538 * get_used_extent() - Get used extent in the block group.
1540 * @fd: the file's descriptor.
1541 * @ext_list_head: the head of the extent list.
1542 * @istart: start inode in the block group.
1543 * @iend: end inode in the block group.
1544 * @bstart: start block in the block group.
1545 * @bend: end block in the block group.
1547 int get_used_extent(int fd, extent_t **ext_list_head,
1548 unsigned long long istart, unsigned long long iend,
1549 ext4_fsblk_t bstart, ext4_fsblk_t bend)
1553 int extents_buffer_size, fiemap_ino_size;
1555 __u64 group_start, group_end;
1556 unsigned long long ino;
1557 struct fiemap_extent *extents_buf = NULL;
1558 struct fiemap_ino *fiemap_ino_buf = NULL;
1560 ret = ioctl(fd, FIGETBSZ, &blocksize);
1563 perror(NGMSG_FILE_BLOCKSIZE);
1568 /* Convert units, in bytes.
1569 * Be careful : now, physical block number in extent is 48bit,
1570 * and the maximum blocksize for ext4 is 4K(12bit),
1571 * so there is no overflow, but in future it may be changed.
1573 group_start = bstart * blocksize;
1574 group_end = bend * blocksize;
1576 /* Alloc space for fiemap_ino */
1577 fiemap_ino_size = sizeof(struct fiemap_ino);
1578 extents_buffer_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent);
1580 fiemap_ino_buf = malloc(fiemap_ino_size + extents_buffer_size);
1581 if (!fiemap_ino_buf)
1584 extents_buf = fiemap_ino_buf->fiemap.fm_extents;
1585 memset(fiemap_ino_buf, 0, fiemap_ino_size);
1586 fiemap_ino_buf->fiemap.fm_length = FIEMAP_MAX_OFFSET;
1587 fiemap_ino_buf->fiemap.fm_flags |= FIEMAP_FLAG_SYNC;
1588 fiemap_ino_buf->fiemap.fm_extent_count = EXTENT_MAX_COUNT;
1590 for (ino = istart; ino <= iend; ino++) {
1591 fiemap_ino_buf->ino = ino;
1595 fiemap_ino_buf->fiemap.fm_start = pos;
1596 memset(extents_buf, 0, extents_buffer_size);
1598 ret = ioctl(fd, EXT4_IOC_FIEMAP_INO, fiemap_ino_buf);
1600 /* Skip non-regular file and unused inode */
1601 if (errno == EOPNOTSUPP || errno == ESTALE
1602 || errno == ENOENT || errno == EACCES)
1607 for (i = 0; i < fiemap_ino_buf->
1608 fiemap.fm_mapped_extents; i++) {
1609 extent_t *extent = NULL;
1611 /* Is this extent in current block group ? */
1612 if (extents_buf[i].fe_physical < group_start ||
1613 extents_buf[i].fe_physical > group_end)
1616 extent = malloc(sizeof(extent_t));
1620 extent->data.start = extents_buf[i].fe_physical
1622 extent->data.block = extents_buf[i].fe_logical
1624 extent->data.len = extents_buf[i].fe_length
1627 extent->tag = EXT4_EXT_USE;
1629 if (insert_extent(ext_list_head, extent) < 0) {
1635 /* Record file's logical offset this time */
1636 pos = extents_buf[EXTENT_MAX_COUNT-1].fe_logical +
1637 extents_buf[EXTENT_MAX_COUNT-1].fe_length;
1638 /* If fm_extents array has been filled and
1639 * there are extents left, continue to cycle.
1641 } while (fiemap_ino_buf->fiemap.fm_mapped_extents
1642 == EXTENT_MAX_COUNT &&
1643 !(extents_buf[EXTENT_MAX_COUNT-1].fe_flags
1644 & FIEMAP_EXTENT_LAST));
1647 FREE(fiemap_ino_buf);
1650 FREE(fiemap_ino_buf);
1655 * get_free_extent() - Get used extent in the block group.
1657 * @fd: the file's descriptor.
1658 * @ino: inode number from struct stat64.
1659 * @blocks_per_group: the block number of each block group.
1660 * @ext_list_head: the head of the extent list.
1662 int get_free_extent(int fd, unsigned long long ino,
1663 int blocks_per_group, extent_t **ext_list_head)
1665 ext4_grpblk_t pos = 0;
1666 struct ext4_extents_info extents_info;
1668 memset(&extents_info, 0, sizeof(struct ext4_extents_info));
1669 extents_info.ino = ino;
1670 extents_info.max_entries = DEFRAG_MAX_ENT;
1671 while (pos < blocks_per_group) {
1673 if (ioctl(fd, EXT4_IOC_FREE_BLOCKS_INFO, &extents_info) < 0)
1677 extents_info.ext[i].len != 0 && i < DEFRAG_MAX_ENT; i++) {
1678 /* Alloc space for extent */
1679 extent_t *extent = NULL;
1681 extent = malloc(sizeof(extent_t));
1684 memset(extent, 0, sizeof(extent_t));
1685 memcpy(&(extent->data), &(extents_info.ext[i]),
1686 sizeof(struct ext4_extent_data));
1688 extent->tag = EXT4_EXT_FREE;
1689 if (insert_extent(ext_list_head, extent) < 0) {
1695 /* No free extent after the logical block number "pos".
1696 * In other word, offset this time equals to prev recursion.
1698 if (pos == extents_info.g_offset)
1700 if (i < DEFRAG_MAX_ENT)
1702 /* Record the offset of logical block number this time */
1703 pos = extents_info.g_offset;
1704 memset(extents_info.ext, 0,
1705 sizeof(struct ext4_extent_data) * DEFRAG_MAX_ENT);
1712 * join_extents() - Find continuous region(exts_group).
1714 * @ext_list_head: the head of the extent list.
1715 * @target_exts_group_list_head:the head of the target exts_group list.
1716 * @exts_group_list_head: the head of the original exts_group list.
1717 * @filesize: the file's descriptor.
1718 * @max: the max size of free space.
1720 int join_extents(extent_t *ext_list_head,
1721 exts_group_t **target_exts_group_list_head,
1722 exts_group_t **exts_group_list_head,
1723 unsigned long filesize, int *max)
1726 extent_t *ext_start, *extent_tmp;
1728 ext_start = ext_list_head;
1729 extent_tmp = ext_list_head;
1731 len = ext_list_head->data.len;
1732 extent_tmp = extent_tmp->next;
1734 exts_group_t *exts_group_tmp = NULL;
1736 if (len >= filesize) {
1738 * one extent group is enough for defrag, so return.
1740 exts_group_tmp = malloc(sizeof(exts_group_t));
1741 if (!exts_group_tmp)
1744 exts_group_tmp->prev = NULL;
1745 exts_group_tmp->next = NULL;
1746 exts_group_tmp->start = ext_start;
1747 exts_group_tmp->end = extent_tmp->prev;
1748 exts_group_tmp->len = len;
1749 if (insert_exts_group(target_exts_group_list_head,
1750 exts_group_tmp) < 0) {
1751 FREE(exts_group_tmp);
1754 return CHECK_FRAG_COUNT;
1757 /* This extent and previous extent are not continuous,
1758 * so, all previous extents are treated as an extent group.
1760 if ((extent_tmp->prev->data.start + extent_tmp->prev->data.len)
1761 != extent_tmp->data.start) {
1762 exts_group_tmp = malloc(sizeof(exts_group_t));
1763 if (exts_group_tmp == NULL)
1766 memset(exts_group_tmp, 0, sizeof(exts_group_t));
1767 exts_group_tmp->len = len;
1768 exts_group_tmp->start = ext_start;
1769 exts_group_tmp->end = extent_tmp->prev;
1771 if (insert_exts_group(exts_group_list_head,
1772 exts_group_tmp) < 0) {
1773 FREE(exts_group_tmp);
1777 ext_start = extent_tmp;
1778 len = extent_tmp->data.len;
1779 extent_tmp = extent_tmp->next;
1783 /* This extent and previous extent are continuous,
1784 * so, they belong to the same extent group, and we check
1785 * if the next extent belongs to the same extent group.
1787 len += extent_tmp->data.len;
1788 extent_tmp = extent_tmp->next;
1789 } while (extent_tmp != ext_list_head->next);
1795 * find_exts_group() - Find target exts_group.
1797 * @ext_count: the number of extents.
1798 * @filesize: the file's size.
1799 * @exts_group_list_head: the head of the original exts_group list
1800 * @target_exts_group_list_head: the head of the target exts_group list.
1802 int find_exts_group(int *ext_count, unsigned long filesize,
1803 exts_group_t **exts_group_list_head,
1804 exts_group_t **target_exts_group_list_head)
1806 /* Blocks we found for target file */
1809 if (!(*exts_group_list_head))
1812 while (*exts_group_list_head) {
1813 exts_group_t *exts_group_tmp = NULL;
1815 /* Even add the current largest extent group,
1816 * the sapce we found is still not enough for the file,
1817 * so just add the current largest extent group,
1818 * and do the next loop.
1820 if ((*exts_group_list_head)->len + len < filesize) {
1821 len += (*exts_group_list_head)->len;
1822 exts_group_tmp = get_exts_group(exts_group_list_head,
1823 *exts_group_list_head);
1824 if (insert_exts_group(target_exts_group_list_head,
1825 exts_group_tmp) < 0) {
1826 FREE(exts_group_tmp);
1833 /* Now, if add the current largest extent group,
1834 * the space we found is enough,
1835 * So, search from the smallest extent group
1836 * to avoid waste of space
1838 exts_group_tmp = (*exts_group_list_head)->prev;
1840 if (exts_group_tmp->len + len >= filesize) {
1841 len += exts_group_tmp->len;
1843 get_exts_group(exts_group_list_head,
1845 if (insert_exts_group
1846 (target_exts_group_list_head,
1847 exts_group_tmp) < 0) {
1848 FREE(exts_group_tmp);
1852 /* The only entry go out normally */
1855 exts_group_tmp = exts_group_tmp->prev;
1856 } while (exts_group_tmp !=
1857 (*exts_group_list_head)->prev);
1859 /* If we come here, there must be something wrong */
1863 /* If we come here, there must be something wrong(space not enough) */
1868 * check_frag_count() - Check file frag.
1870 * @fd: the file's discriptor.
1871 * @extent_count: the number of extents.
1873 int check_frag_count(int fd, int extent_count)
1875 long long file_extent_count = RETURN_NG;
1877 file_extent_count = file_frag_count(fd);
1878 if (file_extent_count == RETURN_NG)
1881 if (extent_count >= file_extent_count) {
1891 * defrag_proc() - Reserve extent group and execute
1892 * the defrag program.
1894 * @fd: the file's discriptor.
1895 * @file_name file name.
1896 * @target_exts_group_head: the head of the original exts_group list.
1897 * @ino: inode number from struct stat64.
1899 int defrag_proc(int fd, const char *file_name,
1900 exts_group_t *target_exts_group_head, unsigned long long ino)
1908 exts_group_t *exts_group = NULL;
1909 extent_t *extent = NULL;
1910 struct ext4_extents_info extents_info;
1911 struct ext4_ext_defrag_data defrag_data;
1913 if (!target_exts_group_head)
1917 memset(&buf, 0, sizeof(struct stat64));
1918 ret = fstat64(fd, &buf);
1921 printf("\033[79;0H\033[K[%lu/%lu]%s\n",
1922 defraged_file_count,
1923 total_count, file_name);
1924 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_INFO);
1929 /* Get block size */
1930 ret = ioctl(fd, FIGETBSZ, &blocksize);
1933 printf("\033[79;0H\033[K[%lu/%lu]%s\n",
1934 defraged_file_count,
1935 total_count, file_name);
1936 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_BLOCKSIZE);
1941 memset(&extents_info, 0, sizeof(extents_info));
1942 memset(&defrag_data, 0, sizeof(struct ext4_ext_defrag_data));
1943 extents_info.ino = 0;
1944 exts_group = target_exts_group_head;
1945 extents_info.max_entries = DEFRAG_MAX_ENT;
1946 extents_info.ino = ino;
1947 defrag_data.start_offset = 0;
1950 /* Move victim extents to make sufficient space */
1951 extent = exts_group->start;
1952 int flush_count = 0;
1954 if (extent->tag != EXT4_EXT_USE) {
1955 extent = extent->next;
1958 extents_info.ino = extent->ino;
1959 extents_info.goal = fgoal;
1960 memcpy(extents_info.ext, &extent->data,
1961 sizeof(struct ext4_extent_data));
1963 extent = extent->next;
1964 extents_info.entries = 1;
1965 ret = ioctl(fd, EXT4_IOC_MOVE_VICTIM, &extents_info);
1967 if (errno == EACCES && detail_flag) {
1968 printf("\033[79;0H\033[K[%lu/%lu]%s\n",
1969 defraged_file_count,
1970 total_count, file_name);
1971 PRINT_ERR_MSG_WITH_ERRNO
1979 printf(" Move victim extents to");
1980 printf(" the other block group\n");
1983 /* moved extent info */
1985 /* flush the defrag process info */
1986 printf("\033[79;0H\033[K ext%-3d",
1988 printf(" phys:\t%8llu logical:\t%8u "
1990 (extents_info.ext[0]).start,
1991 (extents_info.ext[0]).block,
1992 (extents_info.ext[0]).len);
1995 printf(" ext%-3d phys:\t%8llu logical:"
1996 "\t%8u length:\t%8d\n", count,
1997 (extents_info.ext[0]).start,
1998 (extents_info.ext[0]).block,
1999 (extents_info.ext[0]).len);
2002 } while (extent != exts_group->end->next);
2004 if (fsync(fd) < 0) {
2006 printf("\033[79;0H\033[K[%lu/%lu]%s\n",
2007 defraged_file_count,
2008 total_count, file_name);
2009 PRINT_ERR_MSG_WITH_ERRNO(NGMSG_FILE_SYNC);
2014 /* Init extents_info for ioctl (RESERVE) */
2015 extents_info.entries = 1;
2016 extents_info.ext[0].block = exts_group->start->data.block;
2017 extents_info.ext[0].start = exts_group->start->data.start;
2018 extents_info.ext[0].len = exts_group->len;
2021 ret = do_defrag(fd, exts_group, defrag_data);
2024 printf("\033[79;0H\033[K[%lu/%lu]%s\n",
2025 defraged_file_count,
2026 total_count, file_name);
2027 printf("\tDEFRAG_ERROR ret = %d\t[ NG ]\n",
2032 /* Defrag success, so update offset */
2033 defrag_data.start_offset += ret;
2034 ret = defrag_data.start_offset;
2036 /* Print process progress */
2038 percent = ((long long)ret * blocksize * 100) /
2040 printf("\033[79;0H\033[K[%lu/%lu]%s:\t%d%%",
2041 defraged_file_count, total_count,
2042 file_name, min(percent, 100));
2046 exts_group = exts_group->next;
2047 } while (exts_group != target_exts_group_head);
2052 * force_defrag() - Execute the defrag program in force defrag mode.
2054 * @fd: the file's descriptor.
2055 * @file_name file name.
2056 * @buf: a pointer of the struct stat64.
2057 * @blocksize: block size in byte.
2059 int force_defrag(int fd, const char *file_name,
2060 const struct stat64 *buf, int blocksize)
2065 unsigned int gnumber;
2066 unsigned long filesize;
2067 unsigned long long istart, iend;
2068 ext4_fsblk_t bstart, bend;
2069 extent_t *extlist_head = NULL;
2070 exts_group_t *exts_group_list_head, *exts_group_list_target_head;
2071 struct ext4_super_block sb;
2073 exts_group_list_head = NULL;
2074 exts_group_list_target_head = NULL;
2076 /* Get super block info */
2077 memset(&sb, 0, sizeof(struct ext4_super_block));
2079 if (ioctl(fd, EXT4_IOC_SUPER_INFO, &sb) < 0)
2082 sb.s_blocks_per_group = ext2fs_swab32(sb.s_blocks_per_group);
2083 sb.s_inodes_per_group = ext2fs_swab32(sb.s_inodes_per_group);
2085 gnumber = (buf->st_ino - 1) / sb.s_inodes_per_group;
2086 istart = gnumber * sb.s_inodes_per_group;
2087 iend = istart + sb.s_inodes_per_group - 1;
2088 bstart = gnumber * sb.s_blocks_per_group;
2089 bend = bstart + sb.s_blocks_per_group - 1;
2091 /* Compute filesize in block */
2092 filesize = (buf->st_size + blocksize - 1) / blocksize;
2094 /* Get used extents in the block group */
2095 ret = get_used_extent(fd, &extlist_head, istart, iend, bstart, bend);
2096 if (ret == RETURN_NG)
2099 /* Get free extents in the group */
2100 ret = get_free_extent(fd, buf->st_ino,
2101 sb.s_blocks_per_group, &extlist_head);
2102 if (ret == RETURN_NG)
2105 /* All space in this group is used by other groups' inodes */
2106 if (extlist_head == NULL) {
2111 /* Get continuous region(extents group) */
2112 ret = join_extents(extlist_head, &exts_group_list_target_head,
2113 &exts_group_list_head, filesize, &maxlen);
2114 if (ret == RETURN_NG)
2116 if (ret == CHECK_FRAG_COUNT) {
2121 if (maxlen < filesize) {
2122 /* No enough space */
2128 if (!exts_group_list_head) {
2133 /* Find target extents group */
2134 ret = find_exts_group(&exts, filesize, &exts_group_list_head,
2135 &exts_group_list_target_head);
2136 if (ret == RETURN_NG)
2140 /* Check file extent count */
2141 ret = check_frag_count(fd, exts);
2142 if (ret == RETURN_NG)
2145 /* Reserve extent group and execute the defrag program */
2146 ret = defrag_proc(fd, file_name,
2147 exts_group_list_target_head, buf->st_ino);
2150 free_exts_group(exts_group_list_target_head);
2151 free_exts_group(exts_group_list_head);
2152 free_ext(extlist_head);