]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blobdiff - misc/e4defrag.c
Revert "e4defrag: use 64-bit counters to track # files defragged"
[thirdparty/e2fsprogs.git] / misc / e4defrag.c
index 1c7c012fff6f7a45c8b938107af8bb800a9a55bf..9d237da24ba2d5f1c610ea589e7bf3f4d8bce1b1 100644 (file)
 #define _LARGEFILE64_SOURCE
 #endif
 
-#define _XOPEN_SOURCE  500
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
+
+#include "config.h"
 #include <ctype.h>
 #include <dirent.h>
 #include <endian.h>
 #include <unistd.h>
 #include <ext2fs/ext2_types.h>
 #include <ext2fs/ext2fs.h>
-#include <linux/fs.h>
 #include <sys/ioctl.h>
+#include <ext2fs/fiemap.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/statfs.h>
-#include <sys/syscall.h>
 #include <sys/vfs.h>
 
-/* Ioctl command */
-#define FS_IOC_FIEMAP          _IOWR('f', 11, struct fiemap)
-#define EXT4_IOC_MOVE_EXT      _IOWR('f', 15, struct move_extent)
+#include "../version.h"
+
+/* A relatively new ioctl interface ... */
+#ifndef EXT4_IOC_MOVE_EXT
+#define EXT4_IOC_MOVE_EXT      _IOWR('f', 15, struct move_extent)
+#endif
 
 /* Macro functions */
 #define PRINT_ERR_MSG(msg)     fprintf(stderr, "%s\n", (msg))
@@ -55,8 +60,6 @@
 #define STATISTIC_ERR_MSG_WITH_ERRNO(msg)      \
        fprintf(stderr, "\t%s:%s\n", (msg), strerror(errno))
 #define min(x, y) (((x) > (y)) ? (y) : (x))
-#define SECTOR_TO_BLOCK(sectors, blocksize) \
-       ((sectors) / ((blocksize) >> 9))
 #define CALC_SCORE(ratio) \
        ((ratio) > 10 ? (80 + 20 * (ratio) / 100) : (8 * (ratio)))
 /* Wrap up the free function */
 #define EXT2FS_ATTR(x)
 #endif
 
-#ifndef __NR_fadvise64
-#define __NR_fadvise64         250
-#endif
-
-#ifndef __NR_sync_file_range
-#define __NR_sync_file_range   314
-#endif
-
-#ifndef __NR_fallocate
-#define __NR_fallocate         324
-#endif
-
-#ifndef POSIX_FADV_DONTNEED
-#if defined(__s390x__)
-#define POSIX_FADV_DONTNEED    6 /* Don't need these pages */
-#else
-#define POSIX_FADV_DONTNEED    4 /* Don't need these pages */
-#endif
-#endif
-
-#ifndef SYNC_FILE_RANGE_WAIT_BEFORE
-#define SYNC_FILE_RANGE_WAIT_BEFORE    1
-#endif
-#ifndef SYNC_FILE_RANGE_WRITE
-#define SYNC_FILE_RANGE_WRITE          2
-#endif
-#ifndef SYNC_FILE_RANGE_WAIT_AFTER
-#define SYNC_FILE_RANGE_WAIT_AFTER     4
-#endif
-
 /* The mode of defrag */
 #define DETAIL                 0x01
 #define STATISTIC              0x02
 /* Definition of flex_bg */
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG          0x0200
 
-/* The following four macros are used for ioctl FS_IOC_FIEMAP
- * FIEMAP_FLAG_SYNC:   sync file data before map.
- * FIEMAP_EXTENT_LAST: last extent in file.
- * FIEMAP_MAX_OFFSET:  max file offset.
+/* The following macro is used for ioctl FS_IOC_FIEMAP
  * EXTENT_MAX_COUNT:   the maximum number of extents for exchanging between
  *                     kernel-space and user-space per ioctl
  */
-#define FIEMAP_FLAG_SYNC       0x00000001
-#define FIEMAP_EXTENT_LAST     0x00000001
-#define FIEMAP_EXTENT_UNWRITTEN        0x00000800
-#define FIEMAP_MAX_OFFSET      (~0ULL)
 #define EXTENT_MAX_COUNT       512
 
 /* The following macros are error message */
@@ -190,203 +156,48 @@ struct move_extent {
        __u64 moved_len;        /* moved block length */
 };
 
-struct fiemap_extent {
-       __u64 fe_logical;       /* logical offset in bytes for the start of
-                               * the extent from the beginning of the file */
-       __u64 fe_physical;      /* physical offset in bytes for the start
-                               * of the extent from the beginning
-                               * of the disk */
-       __u64 fe_length;        /* length in bytes for this extent */
-       __u64 fe_reserved64[2];
-       __u32 fe_flags;         /* FIEMAP_EXTENT_* flags for this extent */
-       __u32 fe_reserved[3];
-};
-
-struct fiemap {
-       __u64 fm_start;         /* logical offset (inclusive) at
-                               * which to start mapping (in) */
-       __u64 fm_length;        /* logical length of mapping which
-                               * userspace wants (in) */
-       __u32 fm_flags;         /* FIEMAP_FLAG_* flags for request (in/out) */
-       __u32 fm_mapped_extents;/* number of extents that were mapped (out) */
-       __u32 fm_extent_count;  /* size of fm_extents array (in) */
-       __u32 fm_reserved;
-       struct fiemap_extent fm_extents[0];/* array of mapped extents (out) */
-};
-
 struct frag_statistic_ino {
        int now_count;  /* the file's extents count of before defrag */
        int best_count; /* the best file's extents count */
+       __u64 size_per_ext;     /* size(KB) per extent */
        float ratio;    /* the ratio of fragmentation */
        char msg_buffer[PATH_MAX + 1];  /* pathname of the file */
 };
 
-typedef __u16 __le16;
-typedef __u32 __le32;
-typedef __u64 __le64;
-
-/*
- * Structure of the super block
- */
-struct ext4_super_block {
-/*00*/ __le32  s_inodes_count;         /* Inodes count */
-       __le32  s_blocks_count_lo;      /* Blocks count */
-       __le32  s_r_blocks_count_lo;    /* Reserved blocks count */
-       __le32  s_free_blocks_count_lo; /* Free blocks count */
-/*10*/ __le32  s_free_inodes_count;    /* Free inodes count */
-       __le32  s_first_data_block;     /* First Data Block */
-       __le32  s_log_block_size;       /* Block size */
-       __le32  s_obso_log_frag_size;   /* Obsoleted fragment size */
-/*20*/ __le32  s_blocks_per_group;     /* # Blocks per group */
-       __le32  s_obso_frags_per_group; /* Obsoleted fragments per group */
-       __le32  s_inodes_per_group;     /* # Inodes per group */
-       __le32  s_mtime;                /* Mount time */
-/*30*/ __le32  s_wtime;                /* Write time */
-       __le16  s_mnt_count;            /* Mount count */
-       __le16  s_max_mnt_count;        /* Maximal mount count */
-       __le16  s_magic;                /* Magic signature */
-       __le16  s_state;                /* File system state */
-       __le16  s_errors;               /* Behaviour when detecting errors */
-       __le16  s_minor_rev_level;      /* minor revision level */
-/*40*/ __le32  s_lastcheck;            /* time of last check */
-       __le32  s_checkinterval;        /* max. time between checks */
-       __le32  s_creator_os;           /* OS */
-       __le32  s_rev_level;            /* Revision level */
-/*50*/ __le16  s_def_resuid;           /* Default uid for reserved blocks */
-       __le16  s_def_resgid;           /* Default gid for reserved blocks */
-       /*
-        * These fields are for EXT4_DYNAMIC_REV superblocks only.
-        *
-        * Note: the difference between the compatible feature set and
-        * the incompatible feature set is that if there is a bit set
-        * in the incompatible feature set that the kernel doesn't
-        * know about, it should refuse to mount the filesystem.
-        *
-        * e2fsck's requirements are more strict; if it doesn't know
-        * about a feature in either the compatible or incompatible
-        * feature set, it must abort and not try to meddle with
-        * things it doesn't understand...
-        */
-       __le32  s_first_ino;            /* First non-reserved inode */
-       __le16  s_inode_size;           /* size of inode structure */
-       __le16  s_block_group_nr;       /* block group # of this superblock */
-       __le32  s_feature_compat;       /* compatible feature set */
-/*60*/ __le32  s_feature_incompat;     /* incompatible feature set */
-       __le32  s_feature_ro_compat;    /* readonly-compatible feature set */
-/*68*/ __u8    s_uuid[16];             /* 128-bit uuid for volume */
-/*78*/ char    s_volume_name[16];      /* volume name */
-/*88*/ char    s_last_mounted[64];     /* directory where last mounted */
-/*C8*/ __le32  s_algorithm_usage_bitmap; /* For compression */
-       /*
-        * Performance hints.  Directory preallocation should only
-        * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
-        */
-       __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/
-       __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
-       __le16  s_reserved_gdt_blocks;  /* Per group desc for online growth */
-       /*
-        * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
-        */
-/*D0*/ __u8    s_journal_uuid[16];     /* uuid of journal superblock */
-/*E0*/ __le32  s_journal_inum;         /* inode number of journal file */
-       __le32  s_journal_dev;          /* device number of journal file */
-       __le32  s_last_orphan;          /* start of list of inodes to delete */
-       __le32  s_hash_seed[4];         /* HTREE hash seed */
-       __u8    s_def_hash_version;     /* Default hash version to use */
-       __u8    s_reserved_char_pad;
-       __le16  s_desc_size;            /* size of group descriptor */
-/*100*/        __le32  s_default_mount_opts;
-       __le32  s_first_meta_bg;        /* First metablock block group */
-       __le32  s_mkfs_time;            /* When the filesystem was created */
-       __le32  s_jnl_blocks[17];       /* Backup of the journal inode */
-       /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
-/*150*/        __le32  s_blocks_count_hi;      /* Blocks count */
-       __le32  s_r_blocks_count_hi;    /* Reserved blocks count */
-       __le32  s_free_blocks_count_hi; /* Free blocks count */
-       __le16  s_min_extra_isize;      /* All inodes have at least # bytes */
-       __le16  s_want_extra_isize;     /* New inodes should reserve # bytes */
-       __le32  s_flags;                /* Miscellaneous flags */
-       __le16  s_raid_stride;          /* RAID stride */
-       __le16  s_mmp_interval;         /* # seconds to wait in MMP checking */
-       __le64  s_mmp_block;            /* Block for multi-mount protection */
-       __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
-       __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
-       __u8    s_reserved_char_pad2;
-       __le16  s_reserved_pad;
-       __u32   s_reserved[162];        /* Padding to the end of the block */
-};
+static char    lost_found_dir[PATH_MAX + 1];
+static int     block_size;
+static int     extents_before_defrag;
+static int     extents_after_defrag;
+static int     mode_flag;
+static unsigned int    current_uid;
+static unsigned int    defraged_file_count;
+static unsigned int    frag_files_before_defrag;
+static unsigned int    frag_files_after_defrag;
+static unsigned int    regular_count;
+static unsigned int    succeed_cnt;
+static unsigned int    total_count;
+static __u8 log_groups_per_flex;
+static __u32 blocks_per_group;
+static __u32 feature_incompat;
+static ext4_fsblk_t    files_block_count;
+static struct frag_statistic_ino       frag_rank[SHOW_FRAG_FILES];
 
-char   lost_found_dir[PATH_MAX + 1];
-int    block_size;
-int    extents_before_defrag;
-int    extents_after_defrag;
-int    mode_flag;
-unsigned int   current_uid;
-unsigned int   defraged_file_count;
-unsigned int   frag_files_before_defrag;
-unsigned int   frag_files_after_defrag;
-unsigned int   regular_count;
-unsigned int   succeed_cnt;
-unsigned int   total_count;
-__u8 log_groups_per_flex;
-__le32 blocks_per_group;
-__le32 feature_incompat;
-ext4_fsblk_t   files_block_count;
-struct frag_statistic_ino      frag_rank[SHOW_FRAG_FILES];
 
 /*
- * ext2fs_swab32() -   Change endian.
- *
- * @val:               the entry used for change.
+ * We prefer posix_fadvise64 when available, as it allows 64bit offset on
+ * 32bit systems
  */
-__u32 ext2fs_swab32(__u32 val)
-{
-#if BYTE_ORDER == BIG_ENDIAN
-       return (val >> 24) | ((val >> 8) & 0xFF00) |
-               ((val << 8) & 0xFF0000) | (val << 24);
-#else
-       return val;
+#if defined(HAVE_POSIX_FADVISE64)
+#define posix_fadvise  posix_fadvise64
+#elif defined(HAVE_FADVISE64)
+#define posix_fadvise  fadvise64
+#elif !defined(HAVE_POSIX_FADVISE)
+#error posix_fadvise not available!
 #endif
-}
-
-/*
- * fadvise() -         Give advice about file access.
- *
- * @fd:                        defrag target file's descriptor.
- * @offset:            file offset.
- * @len:               area length.
- * @advise:            process flag.
- */
-int fadvise(int fd, loff_t offset, size_t len, int advise)
-{
-       return syscall(__NR_fadvise64, fd, offset, len, advise);
-}
-
-/*
- * sync_file_range() - Sync file region.
- *
- * @fd:                        defrag target file's descriptor.
- * @offset:            file offset.
- * @length:            area length.
- * @flag:              process flag.
- */
-int sync_file_range(int fd, loff_t offset, loff_t length, unsigned int flag)
-{
-       return syscall(__NR_sync_file_range, fd, offset, length, flag);
-}
 
-/*
- * fallocate() -       Manipulate file space.
- *
- * @fd:                        defrag target file's descriptor.
- * @mode:              process flag.
- * @offset:            file offset.
- * @len:               file size.
- */
-int fallocate(int fd, int mode, loff_t offset, loff_t len)
-{
-       return syscall(__NR_fallocate, fd, mode, offset, len);
-}
+#ifndef HAVE_FALLOCATE64
+#error fallocate64 not available!
+#endif /* ! HAVE_FALLOCATE64 */
 
 /*
  * get_mount_point() - Get device's mount point.
@@ -395,12 +206,20 @@ int fallocate(int fd, int mode, loff_t offset, loff_t len)
  * @mount_point:       the mount point.
  * @dir_path_len:      the length of directory.
  */
-int get_mount_point(const char *devname, char *mount_point, int dir_path_len)
+static int get_mount_point(const char *devname, char *mount_point,
+                                                       int dir_path_len)
 {
        /* Refer to /etc/mtab */
-       char    *mtab = MOUNTED;
-       FILE    *fp = NULL;
+       const char      *mtab = MOUNTED;
+       FILE            *fp = NULL;
        struct mntent   *mnt = NULL;
+       struct stat64   sb;
+
+       if (stat64(devname, &sb) < 0) {
+               perror(NGMSG_FILE_INFO);
+               PRINT_FILE_NAME(devname);
+               return -1;
+       }
 
        fp = setmntent(mtab, "r");
        if (fp == NULL) {
@@ -409,7 +228,15 @@ int get_mount_point(const char *devname, char *mount_point, int dir_path_len)
        }
 
        while ((mnt = getmntent(fp)) != NULL) {
-               if (strcmp(devname, mnt->mnt_fsname) != 0)
+               struct stat64 ms;
+
+               /*
+                * To handle device symlinks, we see if the
+                * device number matches, not the name
+                */
+               if (stat64(mnt->mnt_fsname, &ms) < 0)
+                       continue;
+               if (sb.st_rdev != ms.st_rdev)
                        continue;
 
                endmntent(fp);
@@ -431,14 +258,14 @@ int get_mount_point(const char *devname, char *mount_point, int dir_path_len)
  *
  * @file:              the file's name.
  */
-int is_ext4(const char *file)
+static int is_ext4(const char *file, char *devname)
 {
        int     maxlen = 0;
        int     len, ret;
        FILE    *fp = NULL;
        char    *mnt_type = NULL;
        /* Refer to /etc/mtab */
-       char    *mtab = MOUNTED;
+       const char      *mtab = MOUNTED;
        char    file_path[PATH_MAX + 1];
        struct mntent   *mnt = NULL;
        struct statfs64 fsbuf;
@@ -468,6 +295,8 @@ int is_ext4(const char *file)
        }
 
        while ((mnt = getmntent(fp)) != NULL) {
+               if (mnt->mnt_fsname[0] != '/')
+                       continue;
                len = strlen(mnt->mnt_dir);
                ret = memcmp(file_path, mnt->mnt_dir, len);
                if (ret != 0)
@@ -486,10 +315,11 @@ int is_ext4(const char *file)
                memset(mnt_type, 0, strlen(mnt->mnt_type) + 1);
                strncpy(mnt_type, mnt->mnt_type, strlen(mnt->mnt_type));
                strncpy(lost_found_dir, mnt->mnt_dir, PATH_MAX);
+               strncpy(devname, mnt->mnt_fsname, strlen(mnt->mnt_fsname) + 1);
        }
 
        endmntent(fp);
-       if (strcmp(mnt_type, FS_EXT4) == 0) {
+       if (mnt_type && strcmp(mnt_type, FS_EXT4) == 0) {
                FREE(mnt_type);
                return 0;
        } else {
@@ -507,7 +337,7 @@ int is_ext4(const char *file)
  * @flag:              file type.
  * @ftwbuf:            the pointer of a struct FTW.
  */
-int calc_entry_counts(const char *file EXT2FS_ATTR((unused)),
+static int calc_entry_counts(const char *file EXT2FS_ATTR((unused)),
                const struct stat64 *buf, int flag EXT2FS_ATTR((unused)),
                struct FTW *ftwbuf EXT2FS_ATTR((unused)))
 {
@@ -527,16 +357,19 @@ int calc_entry_counts(const char *file EXT2FS_ATTR((unused)),
  * @vec:               page state array.
  * @page_num:          page number.
  */
-int page_in_core(int fd, struct move_extent defrag_data,
+static int page_in_core(int fd, struct move_extent defrag_data,
                        unsigned char **vec, unsigned int *page_num)
 {
-       long    pagesize = sysconf(_SC_PAGESIZE);
+       long    pagesize;
        void    *page = NULL;
        loff_t  offset, end_offset, length;
 
        if (vec == NULL || *vec != NULL)
                return -1;
 
+       pagesize = sysconf(_SC_PAGESIZE);
+       if (pagesize < 0)
+               return -1;
        /* In mmap, offset should be a multiple of the page size */
        offset = (loff_t)defrag_data.orig_start * block_size;
        length = (loff_t)defrag_data.len * block_size;
@@ -552,8 +385,10 @@ int page_in_core(int fd, struct move_extent defrag_data,
        *page_num = 0;
        *page_num = (length + pagesize - 1) / pagesize;
        *vec = (unsigned char *)calloc(*page_num, 1);
-       if (*vec == NULL)
+       if (*vec == NULL) {
+               munmap(page, length);
                return -1;
+       }
 
        /* Get information on whether pages are in core */
        if (mincore(page, (size_t)length, *vec) == -1 ||
@@ -573,7 +408,7 @@ int page_in_core(int fd, struct move_extent defrag_data,
  * @vec:               page state array.
  * @page_num:          page number.
  */
-int defrag_fadvise(int fd, struct move_extent defrag_data,
+static int defrag_fadvise(int fd, struct move_extent defrag_data,
                   unsigned char *vec, unsigned int page_num)
 {
        int     flag = 1;
@@ -585,13 +420,18 @@ int defrag_fadvise(int fd, struct move_extent defrag_data,
        unsigned int    i;
        loff_t  offset;
 
+       if (pagesize < 1)
+               return -1;
+
        offset = (loff_t)defrag_data.orig_start * block_size;
        offset = (offset / pagesize) * pagesize;
 
+#ifdef HAVE_SYNC_FILE_RANGE
        /* Sync file for fadvise process */
        if (sync_file_range(fd, offset,
                (loff_t)pagesize * page_num, sync_flag) < 0)
                return -1;
+#endif
 
        /* Try to release buffer cache which this process used,
         * then other process can use the released buffer
@@ -601,7 +441,7 @@ int defrag_fadvise(int fd, struct move_extent defrag_data,
                        offset += pagesize;
                        continue;
                }
-               if (fadvise(fd, offset, pagesize, fadvise_flag) < 0) {
+               if (posix_fadvise(fd, offset, pagesize, fadvise_flag) < 0) {
                        if ((mode_flag & DETAIL) && flag) {
                                perror("\tFailed to fadvise");
                                flag = 0;
@@ -618,11 +458,10 @@ int defrag_fadvise(int fd, struct move_extent defrag_data,
  *
  * @fd:                        defrag target file's descriptor.
  * @file:              file name.
- * @buf:               the pointer of the struct stat64.
+ * @blk_count:         file blocks.
  */
-int check_free_size(int fd, const char *file, const struct stat64 *buf)
+static int check_free_size(int fd, const char *file, ext4_fsblk_t blk_count)
 {
-       ext4_fsblk_t    blk_count;
        ext4_fsblk_t    free_blk_count;
        struct statfs64 fsbuf;
 
@@ -635,9 +474,6 @@ int check_free_size(int fd, const char *file, const struct stat64 *buf)
                return -1;
        }
 
-       /* Target file size measured by filesystem IO blocksize */
-       blk_count = SECTOR_TO_BLOCK(buf->st_blocks, fsbuf.f_bsize);
-
        /* Compute free space for root and normal user separately */
        if (current_uid == ROOT_UID)
                free_blk_count = fsbuf.f_bfree;
@@ -655,7 +491,7 @@ int check_free_size(int fd, const char *file, const struct stat64 *buf)
  *
  * @fd:                        defrag target file's descriptor.
  */
-int file_frag_count(int fd)
+static int file_frag_count(int fd)
 {
        int     ret;
        struct fiemap   fiemap_buf;
@@ -680,11 +516,12 @@ int file_frag_count(int fd)
  *
  * @fd:                        defrag target file's descriptor.
  * @buf:               a pointer of the struct stat64.
- * @file:              the file's name.
- * @extents:           the file's extents.
+ * @file:              file name.
+ * @extents:           file extents.
+ * @blk_count:         file blocks.
  */
-int file_check(int fd, const struct stat64 *buf, const char *file,
-               int extents)
+static int file_check(int fd, const struct stat64 *buf, const char *file,
+               int extents, ext4_fsblk_t blk_count)
 {
        int     ret;
        struct flock    lock;
@@ -696,7 +533,7 @@ int file_check(int fd, const struct stat64 *buf, const char *file,
        lock.l_len = 0;
 
        /* Free space */
-       ret = check_free_size(fd, file, buf);
+       ret = check_free_size(fd, file, blk_count);
        if (ret < 0) {
                if ((mode_flag & DETAIL) && ret == -ENOSPC) {
                        printf("\033[79;0H\033[K[%u/%u] \"%s\"\t\t"
@@ -747,7 +584,7 @@ int file_check(int fd, const struct stat64 *buf, const char *file,
  * @ext_list_head:     the head of logical extent list.
  * @ext:               the extent element which will be inserted.
  */
-int insert_extent_by_logical(struct fiemap_extent_list **ext_list_head,
+static int insert_extent_by_logical(struct fiemap_extent_list **ext_list_head,
                        struct fiemap_extent_list *ext)
 {
        struct fiemap_extent_list       *ext_list_tmp = *ext_list_head;
@@ -805,7 +642,7 @@ out:
  * @ext_list_head:     the head of physical extent list.
  * @ext:               the extent element which will be inserted.
  */
-int insert_extent_by_physical(struct fiemap_extent_list **ext_list_head,
+static int insert_extent_by_physical(struct fiemap_extent_list **ext_list_head,
                        struct fiemap_extent_list *ext)
 {
        struct fiemap_extent_list       *ext_list_tmp = *ext_list_head;
@@ -863,7 +700,7 @@ out:
  * @ext_group_head:            the head of a exts_group list.
  * @exts_group:                        the exts_group element which will be inserted.
  */
-int insert_exts_group(struct fiemap_extent_group **ext_group_head,
+static int insert_exts_group(struct fiemap_extent_group **ext_group_head,
                                struct fiemap_extent_group *exts_group)
 {
        struct fiemap_extent_group      *ext_group_tmp = NULL;
@@ -893,7 +730,7 @@ int insert_exts_group(struct fiemap_extent_group **ext_group_head,
  * @ext_list_head:             the head of the extent list.
  * @ext_group_head:            the head of the target exts_group list.
  */
-int join_extents(struct fiemap_extent_list *ext_list_head,
+static int join_extents(struct fiemap_extent_list *ext_list_head,
                struct fiemap_extent_group **ext_group_head)
 {
        __u64   len = ext_list_head->data.len;
@@ -948,7 +785,7 @@ int join_extents(struct fiemap_extent_list *ext_list_head,
  * @fd:                        defrag target file's descriptor.
  * @ext_list_head:     the head of the extent list.
  */
-int get_file_extents(int fd, struct fiemap_extent_list **ext_list_head)
+static int get_file_extents(int fd, struct fiemap_extent_list **ext_list_head)
 {
        __u32   i;
        int     ret;
@@ -982,7 +819,7 @@ int get_file_extents(int fd, struct fiemap_extent_list **ext_list_head)
                fiemap_buf->fm_start = pos;
                memset(ext_buf, 0, ext_buf_size);
                ret = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf);
-               if (ret < 0)
+               if (ret < 0 || fiemap_buf->fm_mapped_extents == 0)
                        goto out;
                for (i = 0; i < fiemap_buf->fm_mapped_extents; i++) {
                        ext_list = NULL;
@@ -1028,7 +865,7 @@ out:
  *
  * @logical_list_head: the head of the logical extent list.
  */
-int get_logical_count(struct fiemap_extent_list *logical_list_head)
+static int get_logical_count(struct fiemap_extent_list *logical_list_head)
 {
        int ret = 0;
        struct fiemap_extent_list *ext_list_tmp  = logical_list_head;
@@ -1046,14 +883,16 @@ int get_logical_count(struct fiemap_extent_list *logical_list_head)
  *
  * @physical_list_head:        the head of the physical extent list.
  */
-int get_physical_count(struct fiemap_extent_list *physical_list_head)
+static int get_physical_count(struct fiemap_extent_list *physical_list_head)
 {
        int ret = 0;
        struct fiemap_extent_list *ext_list_tmp = physical_list_head;
 
        do {
                if ((ext_list_tmp->data.physical + ext_list_tmp->data.len)
-                               != ext_list_tmp->next->data.physical) {
+                               != ext_list_tmp->next->data.physical ||
+                   (ext_list_tmp->data.logical + ext_list_tmp->data.len)
+                               != ext_list_tmp->next->data.logical) {
                        /* This extent and next extent are not continuous. */
                        ret++;
                }
@@ -1070,8 +909,9 @@ int get_physical_count(struct fiemap_extent_list *physical_list_head)
  * @physical_list_head:        the head of physical extent list.
  * @logical_list_head: the head of logical extent list.
  */
-int change_physical_to_logical(struct fiemap_extent_list **physical_list_head,
-                               struct fiemap_extent_list **logical_list_head)
+static int change_physical_to_logical(
+                       struct fiemap_extent_list **physical_list_head,
+                       struct fiemap_extent_list **logical_list_head)
 {
        int ret;
        struct fiemap_extent_list *ext_list_tmp = *physical_list_head;
@@ -1105,12 +945,29 @@ int change_physical_to_logical(struct fiemap_extent_list **physical_list_head,
        return 0;
 }
 
+/* get_file_blocks() -  Get total file blocks.
+ *
+ * @ext_list_head:     the extent list head of the target file
+ */
+static ext4_fsblk_t get_file_blocks(struct fiemap_extent_list *ext_list_head)
+{
+       ext4_fsblk_t blk_count = 0;
+       struct fiemap_extent_list *ext_list_tmp = ext_list_head;
+
+       do {
+               blk_count += ext_list_tmp->data.len;
+               ext_list_tmp = ext_list_tmp->next;
+       } while (ext_list_tmp != ext_list_head);
+
+       return blk_count;
+}
+
 /*
  * free_ext() -                Free the extent list.
  *
  * @ext_list_head:     the extent list head of which will be free.
  */
-void free_ext(struct fiemap_extent_list *ext_list_head)
+static void free_ext(struct fiemap_extent_list *ext_list_head)
 {
        struct fiemap_extent_list       *ext_list_tmp = NULL;
 
@@ -1132,7 +989,7 @@ void free_ext(struct fiemap_extent_list *ext_list_head)
  *
  * @*ext_group_head:   the exts_group list head which will be free.
  */
- void free_exts_group(struct fiemap_extent_group *ext_group_head)
+static void free_exts_group(struct fiemap_extent_group *ext_group_head)
 {
        struct fiemap_extent_group      *ext_group_tmp = NULL;
 
@@ -1149,78 +1006,19 @@ void free_ext(struct fiemap_extent_list *ext_list_head)
        free(ext_group_head);
 }
 
-/*
- * get_superblock_info() -     Get superblock info by the file name.
- *
- * @file:              the file's name.
- * @sb:                the pointer of the struct ext4_super_block.
- */
-int get_superblock_info(const char *file, struct ext4_super_block *sb)
-{
-       /* Refer to /etc/mtab */
-       char    *mtab = MOUNTED;
-       FILE    *fp = NULL;
-
-       int     fd = -1;
-       int     ret;
-       size_t maxlen = 0;
-       size_t len;
-       char    dev_name[PATH_MAX + 1];
-       struct mntent   *mnt = NULL;
-
-       fp = setmntent(mtab, "r");
-       if (fp == NULL)
-               return -1;
-
-       while ((mnt = getmntent(fp)) != NULL) {
-               len = strlen(mnt->mnt_dir);
-               ret = memcmp(file, mnt->mnt_dir, len);
-               if (ret != 0)
-                       continue;
-
-               if (len < maxlen)
-                       continue;
-
-               maxlen = len;
-
-               memset(dev_name, 0, PATH_MAX + 1);
-               strncpy(dev_name, mnt->mnt_fsname,
-                               strnlen(mnt->mnt_fsname, PATH_MAX));
-       }
-
-       fd = open64(dev_name, O_RDONLY);
-       if (fd < 0) {
-               ret = -1;
-               goto out;
-       }
-
-       /* Set offset to read superblock */
-       ret = lseek64(fd, SUPERBLOCK_OFFSET, SEEK_SET);
-       if (ret < 0)
-               goto out;
-
-       ret = read(fd, sb, sizeof(struct ext4_super_block));
-       if (ret < 0)
-               goto out;
-
-out:
-       if (fd != -1)
-               close(fd);
-       endmntent(fp);
-       return ret;
-}
-
 /*
  * get_best_count() -  Get the file best extents count.
  *
  * @block_count:               the file's physical block count.
  */
-int get_best_count(ext4_fsblk_t block_count)
+static int get_best_count(ext4_fsblk_t block_count)
 {
        int ret;
        unsigned int flex_bg_num;
 
-       /* Calcuate best extents count */
+       if (blocks_per_group == 0)
+               return 1;
+
        if (feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
                flex_bg_num = 1 << log_groups_per_flex;
                ret = ((block_count - 1) /
@@ -1241,14 +1039,15 @@ int get_best_count(ext4_fsblk_t block_count)
  * @flag:              file type.
  * @ftwbuf:            the pointer of a struct FTW.
  */
-int file_statistic(const char *file, const struct stat64 *buf,
+static int file_statistic(const char *file, const struct stat64 *buf,
                        int flag EXT2FS_ATTR((unused)),
                        struct FTW *ftwbuf EXT2FS_ATTR((unused)))
 {
        int     fd;
        int     ret;
-       int     now_ext_count, best_ext_count, physical_ext_count;
+       int     now_ext_count, best_ext_count = 0, physical_ext_count;
        int     i, j;
+       __u64   size_per_ext = 0;
        float   ratio = 0.0;
        ext4_fsblk_t    blk_count = 0;
        char    msg_buffer[PATH_MAX + 24];
@@ -1349,12 +1148,15 @@ int file_statistic(const char *file, const struct stat64 *buf,
        now_ext_count = get_logical_count(logical_list_head);
 
        if (current_uid == ROOT_UID) {
-               /* Calculate fragment ratio  */
-               blk_count =
-                               SECTOR_TO_BLOCK(buf->st_blocks, block_size);
+               /* Calculate the size per extent */
+               blk_count = get_file_blocks(logical_list_head);
 
                best_ext_count = get_best_count(blk_count);
 
+               /* e4defrag rounds size_per_ext up to a block size boundary */
+               size_per_ext = blk_count * (buf->st_blksize / 1024) /
+                                                       now_ext_count;
+
                ratio = (float)(physical_ext_count - best_ext_count) * 100 /
                                                        blk_count;
 
@@ -1383,16 +1185,16 @@ int file_statistic(const char *file, const struct stat64 *buf,
 
                } else {
                        printf("%-40s%10s/%-10s%9s\n",
-                                       "<File>", "now", "best", "ratio");
+                                       "<File>", "now", "best", "size/ext");
                        if (current_uid == ROOT_UID) {
                                if (strlen(file) > 40)
-                                       printf("%s\n%50d/%-10d%8.2f%%\n",
+                                       printf("%s\n%50d/%-10d%6llu KB\n",
                                                file, now_ext_count,
-                                               best_ext_count, ratio);
+                                               best_ext_count, size_per_ext);
                                else
-                                       printf("%-40s%10d/%-10d%8.2f%%\n",
+                                       printf("%-40s%10d/%-10d%6llu KB\n",
                                                file, now_ext_count,
-                                               best_ext_count, ratio);
+                                               best_ext_count, size_per_ext);
                        } else {
                                if (strlen(file) > 40)
                                        printf("%s\n%50d/%-10s%7s\n",
@@ -1415,14 +1217,14 @@ int file_statistic(const char *file, const struct stat64 *buf,
                if (current_uid == ROOT_UID) {
                        if (strlen(msg_buffer) > 40)
                                printf("\033[79;0H\033[K%s\n"
-                                               "%50d/%-10d%8.2f%%\n",
+                                               "%50d/%-10d%6llu KB\n",
                                                msg_buffer, now_ext_count,
-                                               best_ext_count, ratio);
+                                               best_ext_count, size_per_ext);
                        else
                                printf("\033[79;0H\033[K%-40s"
-                                               "%10d/%-10d%8.2f%%\n",
+                                               "%10d/%-10d%6llu KB\n",
                                                msg_buffer, now_ext_count,
-                                               best_ext_count, ratio);
+                                               best_ext_count, size_per_ext);
                } else {
                        if (strlen(msg_buffer) > 40)
                                printf("\033[79;0H\033[K%s\n%50d/%-10s%7s\n",
@@ -1438,8 +1240,20 @@ int file_statistic(const char *file, const struct stat64 *buf,
        for (i = 0; i < SHOW_FRAG_FILES; i++) {
                if (ratio >= frag_rank[i].ratio) {
                        for (j = SHOW_FRAG_FILES - 1; j > i; j--) {
-                               memcpy(&frag_rank[j], &frag_rank[j - 1],
+                               memset(&frag_rank[j], 0,
                                        sizeof(struct frag_statistic_ino));
+                               strncpy(frag_rank[j].msg_buffer,
+                                       frag_rank[j - 1].msg_buffer,
+                                       strnlen(frag_rank[j - 1].msg_buffer,
+                                       PATH_MAX));
+                               frag_rank[j].now_count =
+                                       frag_rank[j - 1].now_count;
+                               frag_rank[j].best_count =
+                                       frag_rank[j - 1].best_count;
+                               frag_rank[j].size_per_ext =
+                                       frag_rank[j - 1].size_per_ext;
+                               frag_rank[j].ratio =
+                                       frag_rank[j - 1].ratio;
                        }
                        memset(&frag_rank[i], 0,
                                        sizeof(struct frag_statistic_ino));
@@ -1447,6 +1261,7 @@ int file_statistic(const char *file, const struct stat64 *buf,
                                                strnlen(file, PATH_MAX));
                        frag_rank[i].now_count = now_ext_count;
                        frag_rank[i].best_count = best_ext_count;
+                       frag_rank[i].size_per_ext = size_per_ext;
                        frag_rank[i].ratio = ratio;
                        break;
                }
@@ -1468,7 +1283,7 @@ out:
  * @start:             logical offset for defrag target file
  * @file_size:         defrag target filesize
  */
-void print_progress(const char *file, loff_t start, loff_t file_size)
+static void print_progress(const char *file, loff_t start, loff_t file_size)
 {
        int percent = (start * 100) / file_size;
        printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
@@ -1487,7 +1302,7 @@ void print_progress(const char *file, loff_t start, loff_t file_size)
  * @buf:                       pointer of the struct stat64.
  * @ext_list_head:     head of the extent list.
  */
-int call_defrag(int fd, int donor_fd, const char *file,
+static int call_defrag(int fd, int donor_fd, const char *file,
        const struct stat64 *buf, struct fiemap_extent_list *ext_list_head)
 {
        loff_t  start = 0;
@@ -1549,7 +1364,11 @@ int call_defrag(int fd, int donor_fd, const char *file,
                        if (mode_flag & DETAIL) {
                                printf("\n");
                                PRINT_ERR_MSG_WITH_ERRNO(
-                                               "Failed to defrag");
+                                       "Failed to defrag with "
+                                       "EXT4_IOC_MOVE_EXT ioctl");
+                               if (errno == ENOTTY)
+                                       printf("\tAt least 2.6.31-rc1 of "
+                                               "vanilla kernel is required\n");
                        } else {
                                printf("\t[ NG ]\n");
                        }
@@ -1582,7 +1401,7 @@ int call_defrag(int fd, int donor_fd, const char *file,
  * @flag:              file type.
  * @ftwbuf:            the pointer of a struct FTW.
  */
-int file_defrag(const char *file, const struct stat64 *buf,
+static int file_defrag(const char *file, const struct stat64 *buf,
                        int flag EXT2FS_ATTR((unused)),
                        struct FTW *ftwbuf EXT2FS_ATTR((unused)))
 {
@@ -1591,8 +1410,9 @@ int file_defrag(const char *file, const struct stat64 *buf,
        int     ret;
        int     best;
        int     file_frags_start, file_frags_end;
-       int     orig_physical_cnt, donor_physical_cnt;
+       int     orig_physical_cnt, donor_physical_cnt = 0;
        char    tmp_inode_name[PATH_MAX + 8];
+       ext4_fsblk_t                    blk_count = 0;
        struct fiemap_extent_list       *orig_list_physical = NULL;
        struct fiemap_extent_list       *orig_list_logical = NULL;
        struct fiemap_extent_list       *donor_list_physical = NULL;
@@ -1642,7 +1462,7 @@ int file_defrag(const char *file, const struct stat64 *buf,
                return 0;
        }
 
-       fd = open64(file, O_RDONLY);
+       fd = open64(file, O_RDWR);
        if (fd < 0) {
                if (mode_flag & DETAIL) {
                        PRINT_FILE_NAME(file);
@@ -1678,7 +1498,8 @@ int file_defrag(const char *file, const struct stat64 *buf,
        /* Count file fragments before defrag */
        file_frags_start = get_logical_count(orig_list_logical);
 
-       if (file_check(fd, buf, file, file_frags_start) < 0)
+       blk_count = get_file_blocks(orig_list_logical);
+       if (file_check(fd, buf, file, file_frags_start, blk_count) < 0)
                goto out;
 
        if (fsync(fd) < 0) {
@@ -1689,11 +1510,7 @@ int file_defrag(const char *file, const struct stat64 *buf,
                goto out;
        }
 
-       if (current_uid == ROOT_UID)
-               best =
-               get_best_count(SECTOR_TO_BLOCK(buf->st_blocks, block_size));
-       else
-               best = 1;
+       best = get_best_count(blk_count);
 
        if (file_frags_start <= best)
                goto check_improvement;
@@ -1710,7 +1527,8 @@ int file_defrag(const char *file, const struct stat64 *buf,
 
        /* Create donor inode */
        memset(tmp_inode_name, 0, PATH_MAX + 8);
-       sprintf(tmp_inode_name, "%.*s.defrag",  strnlen(file, PATH_MAX), file);
+       sprintf(tmp_inode_name, "%.*s.defrag",
+                               (int)strnlen(file, PATH_MAX), file);
        donor_fd = open64(tmp_inode_name, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
        if (donor_fd < 0) {
                if (mode_flag & DETAIL) {
@@ -1737,7 +1555,7 @@ int file_defrag(const char *file, const struct stat64 *buf,
        /* Allocate space for donor inode */
        orig_group_tmp = orig_group_head;
        do {
-               ret = fallocate(donor_fd, 0,
+               ret = fallocate64(donor_fd, 0,
                  (loff_t)orig_group_tmp->start->data.logical * block_size,
                  (loff_t)orig_group_tmp->len * block_size);
                if (ret < 0) {
@@ -1761,7 +1579,7 @@ int file_defrag(const char *file, const struct stat64 *buf,
                goto out;
        }
 
-       /* Calcuate donor inode's continuous physical region */
+       /* Calculate donor inode's continuous physical region */
        donor_physical_cnt = get_physical_count(donor_list_physical);
 
        /* Change donor extent list from physical to logical */
@@ -1853,13 +1671,17 @@ out:
 int main(int argc, char *argv[])
 {
        int     opt;
-       int     i, j;
+       int     i, j, ret = 0;
        int     flags = FTW_PHYS | FTW_MOUNT;
        int     arg_type = -1;
+       int     mount_dir_len = 0;
        int     success_flag = 0;
        char    dir_name[PATH_MAX + 1];
+       char    dev_name[PATH_MAX + 1];
        struct stat64   buf;
-       struct ext4_super_block sb;
+       ext2_filsys fs = NULL;
+
+       printf("e4defrag %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
 
        /* Parse arguments */
        if (argc == 1)
@@ -1899,6 +1721,7 @@ int main(int argc, char *argv[])
                log_groups_per_flex = 0;
 
                memset(dir_name, 0, PATH_MAX + 1);
+               memset(dev_name, 0, PATH_MAX + 1);
                memset(lost_found_dir, 0, PATH_MAX + 1);
                memset(frag_rank, 0,
                        sizeof(struct frag_statistic_ino) * SHOW_FRAG_FILES);
@@ -1918,8 +1741,18 @@ int main(int argc, char *argv[])
                        continue;
                }
 
+               /* Handle i.e. lvm device symlinks */
+               if (S_ISLNK(buf.st_mode)) {
+                       struct stat64   buf2;
+
+                       if (stat64(argv[i], &buf2) == 0 &&
+                           S_ISBLK(buf2.st_mode))
+                               buf = buf2;
+               }
+
                if (S_ISBLK(buf.st_mode)) {
                        /* Block device */
+                       strncpy(dev_name, argv[i], strnlen(argv[i], PATH_MAX));
                        if (get_mount_point(argv[i], dir_name, PATH_MAX) < 0)
                                continue;
                        if (lstat64(dir_name, &buf) < 0) {
@@ -1956,7 +1789,7 @@ int main(int argc, char *argv[])
                 * filesystem type checked in get_mount_point()
                 */
                if (arg_type == FILENAME || arg_type == DIRNAME) {
-                       if (is_ext4(argv[i]) < 0)
+                       if (is_ext4(argv[i], dev_name) < 0)
                                continue;
                        if (realpath(argv[i], dir_name) == NULL) {
                                perror("Couldn't get full path");
@@ -1967,37 +1800,39 @@ int main(int argc, char *argv[])
 
                if (current_uid == ROOT_UID) {
                        /* Get super block info */
-                       memset(&sb, 0, sizeof(struct ext4_super_block));
-                       if (get_superblock_info(dir_name, &sb) < 0) {
-                               if (mode_flag & DETAIL) {
-                                       perror("Can't get super block info");
-                                       PRINT_FILE_NAME(argv[i]);
-                               }
-                               continue;
+                       ret = ext2fs_open(dev_name, EXT2_FLAG_64BITS, 0,
+                                         block_size, unix_io_manager, &fs);
+                       if (ret) {
+                               if (mode_flag & DETAIL)
+                                       fprintf(stderr,
+                                               "Warning: couldn't get file "
+                                               "system details for %s: %s\n",
+                                               dev_name, error_message(ret));
+                       } else {
+                               blocks_per_group = fs->super->s_blocks_per_group;
+                               feature_incompat = fs->super->s_feature_incompat;
+                               log_groups_per_flex = fs->super->s_log_groups_per_flex;
+                               ext2fs_close_free(&fs);
                        }
-
-                       blocks_per_group = ext2fs_swab32(sb.s_blocks_per_group);
-                       feature_incompat = ext2fs_swab32(sb.s_feature_incompat);
-                       log_groups_per_flex = sb.s_log_groups_per_flex;
                }
 
                switch (arg_type) {
+
                case DIRNAME:
                        if (!(mode_flag & STATISTIC))
                                printf("ext4 defragmentation "
                                        "for directory(%s)\n", argv[i]);
 
-                       int mount_dir_len = 0;
                        mount_dir_len = strnlen(lost_found_dir, PATH_MAX);
 
                        strncat(lost_found_dir, "/lost+found",
                                PATH_MAX - strnlen(lost_found_dir, PATH_MAX));
 
-                       /* Not the case("e4defrag  mount_piont_dir") */
+                       /* Not the case("e4defrag  mount_point_dir") */
                        if (dir_name[mount_dir_len] != '\0') {
                                /*
-                                * "e4defrag mount_piont_dir/lost+found"
-                                * or "e4defrag mount_piont_dir/lost+found/"
+                                * "e4defrag mount_point_dir/lost+found"
+                                * or "e4defrag mount_point_dir/lost+found/"
                                 */
                                if (strncmp(lost_found_dir, dir_name,
                                            strnlen(lost_found_dir,
@@ -2011,9 +1846,10 @@ int main(int argc, char *argv[])
                                        continue;
                                }
 
-                               /* "e4defrag mount_piont_dir/else_dir" */
+                               /* "e4defrag mount_point_dir/else_dir" */
                                memset(lost_found_dir, 0, PATH_MAX + 1);
                        }
+                       /* fall through */
                case DEVNAME:
                        if (arg_type == DEVNAME) {
                                strncpy(lost_found_dir, dir_name,
@@ -2028,11 +1864,12 @@ int main(int argc, char *argv[])
                        if (mode_flag & STATISTIC) {
                                if (mode_flag & DETAIL)
                                        printf("%-40s%10s/%-10s%9s\n",
-                                       "<File>", "now", "best", "ratio");
+                                       "<File>", "now", "best", "size/ext");
 
                                if (!(mode_flag & DETAIL) &&
                                                current_uid != ROOT_UID) {
                                        printf(" Done.\n");
+                                       success_flag = 1;
                                        continue;
                                }
 
@@ -2045,24 +1882,28 @@ int main(int argc, char *argv[])
                                                printf("\n");
                                        printf("%-40s%10s/%-10s%9s\n",
                                                "<Fragmented files>", "now",
-                                               "best", "ratio");
+                                               "best", "size/ext");
                                        for (j = 0; j < SHOW_FRAG_FILES; j++) {
                                                if (strlen(frag_rank[j].
                                                        msg_buffer) > 37) {
                                                        printf("%d. %s\n%50d/"
-                                                       "%-10d%8.2f%%\n", j + 1,
+                                                       "%-10d%6llu KB\n",
+                                                       j + 1,
                                                        frag_rank[j].msg_buffer,
                                                        frag_rank[j].now_count,
                                                        frag_rank[j].best_count,
-                                                       frag_rank[j].ratio);
+                                                       frag_rank[j].
+                                                               size_per_ext);
                                                } else if (strlen(frag_rank[j].
                                                        msg_buffer) > 0) {
                                                        printf("%d. %-37s%10d/"
-                                                       "%-10d%8.2f%%\n", j + 1,
+                                                       "%-10d%6llu KB\n",
+                                                       j + 1,
                                                        frag_rank[j].msg_buffer,
                                                        frag_rank[j].now_count,
                                                        frag_rank[j].best_count,
-                                                       frag_rank[j].ratio);
+                                                       frag_rank[j].
+                                                               size_per_ext);
                                                } else
                                                        break;
                                        }
@@ -2145,26 +1986,31 @@ int main(int argc, char *argv[])
                        } else {
                                float files_ratio = 0.0;
                                float score = 0.0;
+                               __u64 size_per_ext = files_block_count *
+                                               (buf.st_blksize / 1024) /
+                                               extents_before_defrag;
                                files_ratio = (float)(extents_before_defrag -
                                                extents_after_defrag) *
                                                100 / files_block_count;
                                score = CALC_SCORE(files_ratio);
                                printf("\n Total/best extents\t\t\t\t%d/%d\n"
-                                       " Fragmentation ratio\t\t\t\t%.2f%%\n"
-                                       " Fragmentation score\t\t\t\t%.2f\n",
+                                       " Average size per extent"
+                                       "\t\t\t%llu KB\n"
+                                       " Fragmentation score\t\t\t\t%.0f\n",
                                                extents_before_defrag,
                                                extents_after_defrag,
-                                               files_ratio, score);
+                                               size_per_ext, score);
                                printf(" [0-30 no problem:"
                                        " 31-55 a little bit fragmented:"
-                                       " 55- needs defrag]\n");
+                                       " 56- needs defrag]\n");
 
                                if (arg_type == DEVNAME)
-                                       printf(" This device(%s) ", argv[i]);
+                                       printf(" This device (%s) ", argv[i]);
                                else if (arg_type == DIRNAME)
-                                       printf(" This directory(%s) ", argv[i]);
+                                       printf(" This directory (%s) ",
+                                                               argv[i]);
                                else
-                                       printf(" This file(%s) ", argv[i]);
+                                       printf(" This file (%s) ", argv[i]);
 
                                if (score > BOUND_SCORE)
                                        printf("needs defragmentation.\n");