]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e4defrag: Use libext2fs to get the correct superblock information
authorKazuya Mio <k-mio@sx.jp.nec.com>
Sun, 19 Dec 2010 22:01:24 +0000 (22:01 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 24 Dec 2010 21:56:24 +0000 (16:56 -0500)
Currently, e4defrag always does byte-swapping when it gets superblock
information, so the calculation of the best extents count is not
correct on little endian machine. This doesn't cause data corruption,
but it may confuse users by showing the wrong extent count.  To solve
this problem, we use ext2fs_open() instead of get_superblock_info()
that is the original function.

Signed-off-by: Kazuya Mio <k-mio@sx.jp.nec.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
misc/e4defrag.c

index 9008bc27f4dc4ff324b3b6351a2d746b03e68084..eea30571ee3767277b7069dace0e8fc95c1d9e5b 100644 (file)
@@ -163,101 +163,6 @@ struct frag_statistic_ino {
        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 */
-};
-
 char   lost_found_dir[PATH_MAX + 1];
 int    block_size;
 int    extents_before_defrag;
@@ -271,8 +176,8 @@ unsigned int        regular_count;
 unsigned int   succeed_cnt;
 unsigned int   total_count;
 __u8 log_groups_per_flex;
-__le32 blocks_per_group;
-__le32 feature_incompat;
+__u32 blocks_per_group;
+__u32 feature_incompat;
 ext4_fsblk_t   files_block_count;
 struct frag_statistic_ino      frag_rank[SHOW_FRAG_FILES];
 
@@ -392,7 +297,7 @@ static int get_mount_point(const char *devname, char *mount_point,
  *
  * @file:              the file's name.
  */
-static int is_ext4(const char *file)
+static int is_ext4(const char *file, char *devname)
 {
        int     maxlen = 0;
        int     len, ret;
@@ -449,6 +354,7 @@ static 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);
@@ -1127,67 +1033,6 @@ static void free_exts_group(struct fiemap_extent_group *ext_group_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.
- */
-static int get_superblock_info(const char *file, struct ext4_super_block *sb)
-{
-       /* Refer to /etc/mtab */
-       const 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.
  *
@@ -1854,13 +1699,14 @@ 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     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;
 
        /* Parse arguments */
        if (argc == 1)
@@ -1900,6 +1746,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);
@@ -1921,6 +1768,7 @@ int main(int argc, char *argv[])
 
                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) {
@@ -1957,7 +1805,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");
@@ -1968,8 +1816,9 @@ 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) {
+                       ret = ext2fs_open(dev_name, 0, 0, block_size,
+                                       unix_io_manager, &fs);
+                       if (ret) {
                                if (mode_flag & DETAIL) {
                                        perror("Can't get super block info");
                                        PRINT_FILE_NAME(argv[i]);
@@ -1977,9 +1826,11 @@ int main(int argc, char *argv[])
                                continue;
                        }
 
-                       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;
+                       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(fs);
                }
 
                switch (arg_type) {