#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>
+#include "../version.h"
+
/* A relatively new ioctl interface ... */
#ifndef EXT4_IOC_MOVE_EXT
#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
char msg_buffer[PATH_MAX + 1]; /* pathname of the file */
};
-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;
-__u32 blocks_per_group;
-__u32 feature_incompat;
-ext4_fsblk_t files_block_count;
-struct frag_statistic_ino frag_rank[SHOW_FRAG_FILES];
-
-
-/* Local definitions of some syscalls glibc may not yet have */
-
-#ifndef HAVE_POSIX_FADVISE
-#warning Using locally defined posix_fadvise interface.
-
-#ifndef __NR_fadvise64_64
-#error Your kernel headers dont define __NR_fadvise64_64
-#endif
-
-/*
- * fadvise() - Give advice about file access.
- *
- * @fd: defrag target file's descriptor.
- * @offset: file offset.
- * @len: area length.
- * @advise: process flag.
- */
-static int posix_fadvise(int fd, loff_t offset, size_t len, int advise)
-{
- return syscall(__NR_fadvise64_64, fd, offset, len, advise);
-}
-#endif /* ! HAVE_FADVISE64_64 */
-
-#ifndef HAVE_SYNC_FILE_RANGE
-#warning Using locally defined sync_file_range interface.
+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];
-#ifndef __NR_sync_file_range
-#ifndef __NR_sync_file_range2 /* ppc */
-#error Your kernel headers dont define __NR_sync_file_range
-#endif
-#endif
/*
- * sync_file_range() - Sync file region.
- *
- * @fd: defrag target file's descriptor.
- * @offset: file offset.
- * @length: area length.
- * @flag: process flag.
+ * We prefer posix_fadvise64 when available, as it allows 64bit offset on
+ * 32bit systems
*/
-int sync_file_range(int fd, loff_t offset, loff_t length, unsigned int flag)
-{
-#ifdef __NR_sync_file_range
- return syscall(__NR_sync_file_range, fd, offset, length, flag);
-#else
- return syscall(__NR_sync_file_range2, fd, flag, offset, length);
+#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
-}
-#endif /* ! HAVE_SYNC_FILE_RANGE */
#ifndef HAVE_FALLOCATE64
-#warning Using locally defined fallocate syscall interface.
-
-#ifndef __NR_fallocate
-#error Your kernel headers dont define __NR_fallocate
-#endif
-
-/*
- * fallocate64() - Manipulate file space.
- *
- * @fd: defrag target file's descriptor.
- * @mode: process flag.
- * @offset: file offset.
- * @len: file size.
- */
-static int fallocate64(int fd, int mode, loff_t offset, loff_t len)
-{
- return syscall(__NR_fallocate, fd, mode, offset, len);
-}
-#endif /* ! HAVE_FALLOCATE */
+#error fallocate64 not available!
+#endif /* ! HAVE_FALLOCATE64 */
/*
* get_mount_point() - Get device's mount point.
{
/* Refer to /etc/mtab */
const char *mtab = MOUNTED;
- FILE *fp = NULL;
+ 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) {
}
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);
}
endmntent(fp);
- if (strcmp(mnt_type, FS_EXT4) == 0) {
+ if (mnt_type && strcmp(mnt_type, FS_EXT4) == 0) {
FREE(mnt_type);
return 0;
} else {
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;
*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 ||
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
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++;
}
int ret;
unsigned int flex_bg_num;
- /* Calcuate best extents count */
+ /* Calculate best extents count */
if (feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG) {
flex_bg_num = 1 << log_groups_per_flex;
ret = ((block_count - 1) /
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 */
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;
ext2_filsys fs = NULL;
+ printf("e4defrag %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
+
/* Parse arguments */
if (argc == 1)
goto out;
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 (current_uid == ROOT_UID) {
/* Get super block info */
- ret = ext2fs_open(dev_name, 0, 0, block_size,
- unix_io_manager, &fs);
+ ret = ext2fs_open(dev_name, EXT2_FLAG_64BITS, 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]);
- }
+ if (mode_flag & DETAIL)
+ com_err(argv[1], ret,
+ "while trying to open file system: %s",
+ dev_name);
continue;
}
feature_incompat = fs->super->s_feature_incompat;
log_groups_per_flex = fs->super->s_log_groups_per_flex;
- ext2fs_close(fs);
+ ext2fs_close_free(&fs);
}
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,
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,