* [PATCH 1/2] debugfs: add filefrag command
@ 2011-11-17 21:12 Theodore Ts'o
2011-11-17 21:12 ` [PATCH 2/2] debugfs: fix gcc -Wall complaints Theodore Ts'o
2011-11-17 21:19 ` [PATCH 1/2] debugfs: add filefrag command Eric Sandeen
0 siblings, 2 replies; 4+ messages in thread
From: Theodore Ts'o @ 2011-11-17 21:12 UTC (permalink / raw)
To: Ext4 Developers List; +Cc: Theodore Ts'o
Add the ability to report on the fragmentation of a file on a file
system opened using debugfs.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
debugfs/Makefile.in | 8 +-
debugfs/debug_cmds.ct | 3 +
debugfs/debugfs.8.in | 21 +++
debugfs/debugfs.h | 1 +
debugfs/filefrag.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++
debugfs/ro_debug_cmds.ct | 3 +
6 files changed, 357 insertions(+), 3 deletions(-)
create mode 100644 debugfs/filefrag.c
diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
index e03a3c6..c6aaa3a 100644
--- a/debugfs/Makefile.in
+++ b/debugfs/Makefile.in
@@ -17,15 +17,17 @@ MANPAGES= debugfs.8
MK_CMDS= _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
- lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o
+ lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
+ filefrag.o
RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
- lsdel.o logdump.o htree.o e2freefrag.o
+ lsdel.o logdump.o htree.o e2freefrag.o filefrag.o
SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
$(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
$(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
- $(srcdir)/htree.c $(srcdir)/unused.c
+ $(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
+ $(srcdir)/filefrag.c
LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
$(LIBUUID)
diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
index 47de672..af969b1 100644
--- a/debugfs/debug_cmds.ct
+++ b/debugfs/debug_cmds.ct
@@ -52,6 +52,9 @@ request do_dump_extents, "Dump extents information ",
request do_blocks, "Dump blocks used by an inode ",
blocks;
+request do_filefrag, "Report fragmentation information for an inode",
+ filefrag;
+
request do_link, "Create directory link",
link, ln;
diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
index 69490ff..70c8326 100644
--- a/debugfs/debugfs.8.in
+++ b/debugfs/debugfs.8.in
@@ -251,6 +251,27 @@ Set or clear various filesystem features in the superblock. After setting
or clearing any filesystem features that were requested, print the current
state of the filesystem feature set.
.TP
+.I filefrag [-dvr] filespec
+Print the number of contiguous extents in
+.IR filespec .
+If
+.I filespec
+is a directory and the
+.I -d
+option is not specified,
+.I filefrag
+will print the number of contiguous extents for each file in
+the directory. The
+.I -v
+option will cause
+.I filefrag
+print a tabular listing of the contiguous extents in the
+file. The
+.I -r
+option will cause
+.I filefrag
+to do a recursive listing of the directory.
+.TP
.I find_free_block [count [goal]]
Find the first
.I count
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 6d7dfcd..0afa1df 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -134,3 +134,4 @@ extern void do_supported_features(int argc, char **argv);
extern void do_punch(int argc, char **argv);
extern void do_freefrag(int argc, char **argv);
+extern void do_filefrag(int argc, char *argv[]);
diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
new file mode 100644
index 0000000..30933b6
--- /dev/null
+++ b/debugfs/filefrag.c
@@ -0,0 +1,324 @@
+/*
+ * filefrag.c --- display the fragmentation information for a file
+ *
+ * Copyright (C) 2011 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utime.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+
+#include "debugfs.h"
+
+#define VERBOSE_OPT 0x0001
+#define DIR_OPT 0x0002
+#define RECURSIVE_OPT 0x0004
+
+struct dir_list {
+ char *name;
+ ext2_ino_t ino;
+ struct dir_list *next;
+};
+
+struct filefrag_struct {
+ FILE *f;
+ const char *name;
+ const char *dir_name;
+ int options;
+ int logical_width;
+ int physical_width;
+ int ext;
+ int cont_ext;
+ e2_blkcnt_t num;
+ e2_blkcnt_t logical_start;
+ blk64_t physical_start;
+ blk64_t expected;
+ struct dir_list *dir_list, *dir_last;
+};
+
+static int int_log10(unsigned long long arg)
+{
+ int l = 0;
+
+ arg = arg / 10;
+ while (arg) {
+ l++;
+ arg = arg / 10;
+ }
+ return l;
+}
+
+static void print_header(struct filefrag_struct *fs)
+{
+ if (fs->options & VERBOSE_OPT) {
+ fprintf(fs->f, "%4s %*s %*s %*s %*s\n", "ext",
+ fs->logical_width, "logical", fs->physical_width,
+ "physical", fs->physical_width, "expected",
+ fs->logical_width, "length");
+ }
+}
+
+static void report_filefrag(struct filefrag_struct *fs)
+{
+ if (fs->num == 0)
+ return;
+ if (fs->options & VERBOSE_OPT) {
+ if (fs->expected)
+ fprintf(fs->f, "%4d %*lu %*llu %*llu %*lu\n", fs->ext,
+ fs->logical_width,
+ (unsigned long) fs->logical_start,
+ fs->physical_width, fs->physical_start,
+ fs->physical_width, fs->expected,
+ fs->logical_width, (unsigned long) fs->num);
+ else
+ fprintf(fs->f, "%4d %*lu %*llu %*s %*lu\n", fs->ext,
+ fs->logical_width,
+ (unsigned long) fs->logical_start,
+ fs->physical_width, fs->physical_start,
+ fs->physical_width, "",
+ fs->logical_width, (unsigned long) fs->num);
+ }
+ fs->ext++;
+}
+
+static int filefrag_blocks_proc(ext2_filsys ext4_fs EXT2FS_ATTR((unused)),
+ blk64_t *blocknr, e2_blkcnt_t blockcnt,
+ blk64_t ref_block EXT2FS_ATTR((unused)),
+ int ref_offset EXT2FS_ATTR((unused)),
+ void *private)
+{
+ struct filefrag_struct *fs = private;
+
+ if (blockcnt < 0 || *blocknr == 0)
+ return 0;
+
+ if ((fs->num == 0) || (blockcnt != fs->logical_start + fs->num) ||
+ (*blocknr != fs->physical_start + fs->num)) {
+ report_filefrag(fs);
+ if (blockcnt == fs->logical_start + fs->num)
+ fs->expected = fs->physical_start + fs->num;
+ else
+ fs->expected = 0;
+ fs->logical_start = blockcnt;
+ fs->physical_start = *blocknr;
+ fs->num = 1;
+ fs->cont_ext++;
+ } else
+ fs->num++;
+ return 0;
+}
+
+static void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
+ struct filefrag_struct *fs)
+{
+ errcode_t retval;
+ int blocksize = current_fs->blocksize;
+
+ fs->logical_width = int_log10((EXT2_I_SIZE(inode) + blocksize - 1) /
+ blocksize) + 1;
+ if (fs->logical_width < 7)
+ fs->logical_width = 7;
+ fs->ext = 0;
+ fs->cont_ext = 0;
+ fs->logical_start = 0;
+ fs->physical_start = 0;
+ fs->num = 0;
+
+ if (fs->options & VERBOSE_OPT) {
+ blk64_t num_blocks = ext2fs_inode_i_blocks(current_fs, inode);
+
+ if (!(current_fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
+ !(inode->i_flags & EXT4_HUGE_FILE_FL))
+ num_blocks /= current_fs->blocksize / 512;
+
+ fprintf(fs->f, "\n%s has %llu block(s), i_size is %llu\n",
+ fs->name, num_blocks, EXT2_I_SIZE(inode));
+ }
+ print_header(fs);
+ retval = ext2fs_block_iterate3(current_fs, ino,
+ BLOCK_FLAG_READ_ONLY, NULL,
+ filefrag_blocks_proc, fs);
+ if (retval)
+ com_err("ext2fs_block_iterate3", retval, 0);
+
+ report_filefrag(fs);
+ fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
+ LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
+}
+
+static int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset EXT2FS_ATTR((unused)),
+ int blocksize EXT2FS_ATTR((unused)),
+ char *buf EXT2FS_ATTR((unused)),
+ void *private)
+{
+ struct filefrag_struct *fs = private;
+ struct ext2_inode inode;
+ ext2_ino_t ino;
+ char name[EXT2_NAME_LEN + 1];
+ char *cp;
+ int thislen;
+
+ if (entry == DIRENT_DELETED_FILE)
+ return 0;
+
+ thislen = dirent->name_len & 0xFF;
+ strncpy(name, dirent->name, thislen);
+ name[thislen] = '\0';
+ ino = dirent->inode;
+
+ if (!strcmp(name, ".") || !strcmp(name, ".."))
+ return 0;
+
+ cp = malloc(strlen(fs->dir_name) + strlen(name) + 2);
+ if (!cp) {
+ fprintf(stderr, "Couldn't allocate memory for %s/%s\n",
+ fs->dir_name, name);
+ return 0;
+ }
+
+ sprintf(cp, "%s/%s", fs->dir_name, name);
+ fs->name = cp;
+
+ if (debugfs_read_inode(ino, &inode, fs->name))
+ goto errout;
+
+ filefrag(ino, &inode, fs);
+
+ if ((fs->options & RECURSIVE_OPT) && LINUX_S_ISDIR(inode.i_mode)) {
+ struct dir_list *p;
+
+ p = malloc(sizeof(struct dir_list));
+ if (!p) {
+ fprintf(stderr, "Couldn't allocate dir_list for %s\n",
+ fs->name);
+ goto errout;
+ }
+ memset(p, 0, sizeof(struct dir_list));
+ p->name = cp;
+ p->ino = ino;
+ if (fs->dir_last)
+ fs->dir_last->next = p;
+ else
+ fs->dir_list = p;
+ fs->dir_last = p;
+ return 0;
+ }
+errout:
+ free(cp);
+ fs->name = 0;
+ return 0;
+}
+
+
+static void dir_iterate(ext2_ino_t ino, struct filefrag_struct *fs)
+{
+ errcode_t retval;
+ struct dir_list *p = NULL;
+
+ fs->dir_name = fs->name;
+
+ while (1) {
+ retval = ext2fs_dir_iterate2(current_fs, ino, 0,
+ 0, filefrag_dir_proc, fs);
+ if (retval)
+ com_err("ext2fs_dir_iterate2", retval, 0);
+ if (p) {
+ free(p->name);
+ fs->dir_list = p->next;
+ if (!fs->dir_list)
+ fs->dir_last = 0;
+ free(p);
+ }
+ p = fs->dir_list;
+ if (!p)
+ break;
+ ino = p->ino;
+ fs->dir_name = p->name;
+ }
+}
+
+void do_filefrag(int argc, char *argv[])
+{
+ struct filefrag_struct fs;
+ struct ext2_inode inode;
+ ext2_ino_t ino;
+ int c;
+
+ memset(&fs, 0, sizeof(fs));
+ if (check_fs_open(argv[0]))
+ return;
+
+ reset_getopt();
+ while ((c = getopt (argc, argv, "dvr")) != EOF) {
+ switch (c) {
+ case 'd':
+ fs.options |= DIR_OPT;
+ break;
+ case 'v':
+ fs.options |= VERBOSE_OPT;
+ break;
+ case 'r':
+ fs.options |= RECURSIVE_OPT;
+ break;
+ default:
+ goto print_usage;
+ }
+ }
+
+ if (argc > optind+1) {
+ print_usage:
+ com_err(0, 0, "Usage: filefrag [-dv] file");
+ return;
+ }
+
+ if (argc == optind) {
+ ino = cwd;
+ fs.name = ".";
+ } else {
+ ino = string_to_inode(argv[optind]);
+ fs.name = argv[optind];
+ }
+ if (!ino)
+ return;
+
+ if (debugfs_read_inode(ino, &inode, argv[0]))
+ return;
+
+ fs.f = open_pager();
+ fs.physical_width = int_log10(ext2fs_blocks_count(current_fs->super));
+ fs.physical_width++;
+ if (fs.physical_width < 8)
+ fs.physical_width = 8;
+
+ if (!LINUX_S_ISDIR(inode.i_mode) || (fs.options & DIR_OPT))
+ filefrag(ino, &inode, &fs);
+ else
+ dir_iterate(ino, &fs);
+
+ fprintf(fs.f, "\n");
+ close_pager(fs.f);
+
+ return;
+}
diff --git a/debugfs/ro_debug_cmds.ct b/debugfs/ro_debug_cmds.ct
index 7eb552d..4feb621 100644
--- a/debugfs/ro_debug_cmds.ct
+++ b/debugfs/ro_debug_cmds.ct
@@ -45,6 +45,9 @@ request do_dump_extents, "Dump extents information ",
request do_blocks, "Dump blocks used by an inode ",
blocks;
+request do_filefrag, "Report fragmentation information for an inode",
+ filefrag;
+
request do_testi, "Test an inode's in-use flag",
testi;
--
1.7.4.1.22.gec8e1.dirty
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] debugfs: fix gcc -Wall complaints
2011-11-17 21:12 [PATCH 1/2] debugfs: add filefrag command Theodore Ts'o
@ 2011-11-17 21:12 ` Theodore Ts'o
2011-11-17 21:19 ` [PATCH 1/2] debugfs: add filefrag command Eric Sandeen
1 sibling, 0 replies; 4+ messages in thread
From: Theodore Ts'o @ 2011-11-17 21:12 UTC (permalink / raw)
To: Ext4 Developers List; +Cc: Theodore Ts'o
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
debugfs/debugfs.c | 8 +++---
debugfs/debugfs.h | 3 ++
debugfs/filefrag.c | 2 +-
debugfs/set_fields.c | 55 ++++++++++++++++++++++++++-----------------------
misc/e2freefrag.c | 44 +++++++++++++++++++++------------------
5 files changed, 61 insertions(+), 51 deletions(-)
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index fda8d92..5751004 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -284,7 +284,6 @@ void do_init_filesys(int argc, char **argv)
root = cwd = EXT2_ROOT_INO;
return;
}
-#endif /* READ_ONLY */
static void print_features(struct ext2_super_block * s, FILE *f)
{
@@ -304,6 +303,7 @@ static void print_features(struct ext2_super_block * s, FILE *f)
fputs("(none)", f);
fputs("\n", f);
}
+#endif /* READ_ONLY */
static void print_bg_opts(ext2_filsys fs, dgrp_t group, int mask,
const char *str, int *first, FILE *f)
@@ -933,7 +933,7 @@ void do_dump_extents(int argc, char **argv)
static int print_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)),
blk64_t *blocknr,
- e2_blkcnt_t blockcnt,
+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
blk64_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *private EXT2FS_ATTR((unused)))
@@ -1286,6 +1286,7 @@ void do_print_working_directory(int argc, char *argv[])
return;
}
+#ifndef READ_ONLY
/*
* Given a mode, return the ext2 file type
*/
@@ -1315,7 +1316,6 @@ static int ext2_file_type(unsigned int mode)
return 0;
}
-#ifndef READ_ONLY
static void make_link(char *sourcename, char *destname)
{
ext2_ino_t ino;
@@ -2190,7 +2190,7 @@ void do_punch(int argc, char *argv[])
}
#endif /* READ_ONLY */
-void do_dump_mmp(int argc, char *argv[])
+void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
{
struct ext2_super_block *sb;
struct mmp_struct *mmp_s;
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 0afa1df..eb044b1 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -133,5 +133,8 @@ extern void do_set_current_time(int argc, char **argv);
extern void do_supported_features(int argc, char **argv);
extern void do_punch(int argc, char **argv);
+extern void do_dump_mmp(int argc, char **argv);
+extern void do_set_mmp_value(int argc, char **argv);
+
extern void do_freefrag(int argc, char **argv);
extern void do_filefrag(int argc, char *argv[]);
diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
index 30933b6..7f28bc0 100644
--- a/debugfs/filefrag.c
+++ b/debugfs/filefrag.c
@@ -271,7 +271,7 @@ void do_filefrag(int argc, char *argv[])
return;
reset_getopt();
- while ((c = getopt (argc, argv, "dvr")) != EOF) {
+ while ((c = getopt(argc, argv, "dvr")) != EOF) {
switch (c) {
case 'd':
fs.options |= DIR_OPT;
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index 0041160..08bfd8d 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -44,6 +44,7 @@ static struct ext2_super_block set_sb;
static struct ext2_inode_large set_inode;
static struct ext2_group_desc set_gd;
static struct ext4_group_desc set_gd4;
+static struct mmp_struct set_mmp;
static dgrp_t set_bg;
static ext2_ino_t set_ino;
static int array_idx;
@@ -68,6 +69,8 @@ static errcode_t parse_hashalg(struct field_set_info *info, char *field, char *a
static errcode_t parse_time(struct field_set_info *info, char *field, char *arg);
static errcode_t parse_bmap(struct field_set_info *info, char *field, char *arg);
static errcode_t parse_gd_csum(struct field_set_info *info, char *field, char *arg);
+static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
+ char *arg);
static struct field_set_info super_fields[] = {
{ "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint },
@@ -242,8 +245,17 @@ static struct field_set_info ext4_bg_fields[] = {
{ 0, 0, 0, 0 }
};
-/* forward declaration */
-static struct field_set_info mmp_fields[];
+static struct field_set_info mmp_fields[] = {
+ { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), parse_mmp_clear },
+ { "magic", &set_mmp.mmp_magic, NULL, 4, parse_uint },
+ { "seq", &set_mmp.mmp_seq, NULL, 4, parse_uint },
+ { "time", &set_mmp.mmp_time, NULL, 8, parse_uint },
+ { "nodename", &set_mmp.mmp_nodename, NULL, sizeof(set_mmp.mmp_nodename),
+ parse_string },
+ { "bdevname", &set_mmp.mmp_bdevname, NULL, sizeof(set_mmp.mmp_bdevname),
+ parse_string },
+ { "check_interval", &set_mmp.mmp_check_interval, NULL, 2, parse_uint },
+};
static int check_suffix(const char *field)
{
@@ -412,7 +424,8 @@ static errcode_t parse_uint(struct field_set_info *info, char *field,
return 0;
}
-static errcode_t parse_int(struct field_set_info *info, char *field, char *arg)
+static errcode_t parse_int(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
long num;
char *tmp;
@@ -443,8 +456,8 @@ static errcode_t parse_int(struct field_set_info *info, char *field, char *arg)
return 0;
}
-static errcode_t parse_string(struct field_set_info *info, char *field,
- char *arg)
+static errcode_t parse_string(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
char *cp = (char *) info->ptr;
@@ -457,7 +470,8 @@ static errcode_t parse_string(struct field_set_info *info, char *field,
return 0;
}
-static errcode_t parse_time(struct field_set_info *info, char *field, char *arg)
+static errcode_t parse_time(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
time_t t;
__u32 *ptr32;
@@ -475,7 +489,8 @@ static errcode_t parse_time(struct field_set_info *info, char *field, char *arg)
return 0;
}
-static errcode_t parse_uuid(struct field_set_info *info, char *field, char *arg)
+static errcode_t parse_uuid(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
unsigned char * p = (unsigned char *) info->ptr;
@@ -493,8 +508,8 @@ static errcode_t parse_uuid(struct field_set_info *info, char *field, char *arg)
return 0;
}
-static errcode_t parse_hashalg(struct field_set_info *info, char *field,
- char *arg)
+static errcode_t parse_hashalg(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
int hashv;
unsigned char *p = (unsigned char *) info->ptr;
@@ -508,8 +523,8 @@ static errcode_t parse_hashalg(struct field_set_info *info, char *field,
return 0;
}
-static errcode_t parse_bmap(struct field_set_info *info, char *field,
- char *arg)
+static errcode_t parse_bmap(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)), char *arg)
{
unsigned long num;
blk_t blk;
@@ -733,8 +748,9 @@ void do_set_block_group_descriptor(int argc, char *argv[])
}
}
-static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
- char *arg)
+static errcode_t parse_mmp_clear(struct field_set_info *info,
+ char *field EXT2FS_ATTR((unused)),
+ char *arg EXT2FS_ATTR((unused)))
{
errcode_t retval;
@@ -747,19 +763,6 @@ static errcode_t parse_mmp_clear(struct field_set_info *info, char *field,
return 1; /* we don't need the MMP block written again */
}
-struct mmp_struct set_mmp;
-static struct field_set_info mmp_fields[] = {
- { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), parse_mmp_clear },
- { "magic", &set_mmp.mmp_magic, NULL, 4, parse_uint },
- { "seq", &set_mmp.mmp_seq, NULL, 4, parse_uint },
- { "time", &set_mmp.mmp_time, NULL, 8, parse_uint },
- { "nodename", &set_mmp.mmp_nodename, NULL, sizeof(set_mmp.mmp_nodename),
- parse_string },
- { "bdevname", &set_mmp.mmp_bdevname, NULL, sizeof(set_mmp.mmp_bdevname),
- parse_string },
- { "check_interval", &set_mmp.mmp_check_interval, NULL, 2, parse_uint },
-};
-
void do_set_mmp_value(int argc, char *argv[])
{
const char *usage = "<field> <value>\n"
diff --git a/misc/e2freefrag.c b/misc/e2freefrag.c
index 0964e66..30af43e 100644
--- a/misc/e2freefrag.c
+++ b/misc/e2freefrag.c
@@ -30,7 +30,7 @@ extern int optind;
#include "ext2fs/ext2fs.h"
#include "e2freefrag.h"
-void usage(const char *prog)
+static void usage(const char *prog)
{
fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
"device_name\n", prog);
@@ -51,7 +51,7 @@ static int ul_log2(unsigned long arg)
return l;
}
-void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
+static void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
{
int i;
@@ -74,15 +74,16 @@ void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
}
}
-void update_chunk_stats(struct chunk_info *info, unsigned long chunk_size)
+static void update_chunk_stats(struct chunk_info *info,
+ unsigned long chunk_size)
{
- unsigned long index;
+ unsigned long idx;
- index = ul_log2(chunk_size) + 1;
- if (index >= MAX_HIST)
- index = MAX_HIST-1;
- info->histogram.fc_chunks[index]++;
- info->histogram.fc_blocks[index] += chunk_size;
+ idx = ul_log2(chunk_size) + 1;
+ if (idx >= MAX_HIST)
+ idx = MAX_HIST-1;
+ info->histogram.fc_chunks[idx]++;
+ info->histogram.fc_blocks[idx] += chunk_size;
if (chunk_size > info->max)
info->max = chunk_size;
@@ -92,7 +93,7 @@ void update_chunk_stats(struct chunk_info *info, unsigned long chunk_size)
info->real_free_chunks++;
}
-void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
+static void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
{
unsigned long long blocks_count = ext2fs_blocks_count(fs->super);
unsigned long long chunks = (blocks_count + info->blks_in_chunk) >>
@@ -142,10 +143,11 @@ void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
update_chunk_stats(info, last_chunk_size);
}
-errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info, FILE *f)
+static errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
+ FILE *f)
{
unsigned long total_chunks;
- char *unitp = "KMGTPEZY";
+ const char *unitp = "KMGTPEZY";
int units = 10;
unsigned long start = 0, end;
int i, retval = 0;
@@ -211,7 +213,7 @@ errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info, FILE *f)
return retval;
}
-void close_device(char *device_name, ext2_filsys fs)
+static void close_device(char *device_name, ext2_filsys fs)
{
int retval = ext2fs_close(fs);
@@ -219,7 +221,7 @@ void close_device(char *device_name, ext2_filsys fs)
com_err(device_name, retval, "while closing the filesystem.\n");
}
-void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
+static void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
{
unsigned int retval = 0;
@@ -243,7 +245,8 @@ void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
}
}
-void open_device(char *device_name, ext2_filsys *fs)
+#ifndef DEBUGFS
+static void open_device(char *device_name, ext2_filsys *fs)
{
int retval;
int flag = EXT2_FLAG_FORCE;
@@ -254,9 +257,9 @@ void open_device(char *device_name, ext2_filsys *fs)
exit(1);
}
}
+#endif
#ifdef DEBUGFS
-
#include "debugfs.h"
void do_freefrag(int argc, char **argv)
@@ -264,10 +267,8 @@ void do_freefrag(int argc, char **argv)
int main(int argc, char *argv[])
#endif
{
- struct chunk_info chunk_info = { };
- errcode_t retval = 0;
+ struct chunk_info chunk_info;
ext2_filsys fs = NULL;
- char *device_name;
char *progname;
char *end;
int c;
@@ -276,9 +277,12 @@ int main(int argc, char *argv[])
if (check_fs_open(argv[0]))
return;
#else
+ char *device_name;
+
add_error_table(&et_ext2_error_table);
#endif
progname = argv[0];
+ memset(&chunk_info, 0, sizeof(chunk_info));
while ((c = getopt(argc, argv, "c:h")) != EOF) {
switch (c) {
@@ -326,6 +330,6 @@ int main(int argc, char *argv[])
#ifndef DEBUGFS
close_device(device_name, fs);
- return retval;
+ return 0;
#endif
}
--
1.7.4.1.22.gec8e1.dirty
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] debugfs: add filefrag command
2011-11-17 21:12 [PATCH 1/2] debugfs: add filefrag command Theodore Ts'o
2011-11-17 21:12 ` [PATCH 2/2] debugfs: fix gcc -Wall complaints Theodore Ts'o
@ 2011-11-17 21:19 ` Eric Sandeen
2011-11-17 21:27 ` Theodore Tso
1 sibling, 1 reply; 4+ messages in thread
From: Eric Sandeen @ 2011-11-17 21:19 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: Ext4 Developers List
On 11/17/11 3:12 PM, Theodore Ts'o wrote:
> Add the ability to report on the fragmentation of a file on a file
> system opened using debugfs.
>
> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
> ---
> debugfs/Makefile.in | 8 +-
> debugfs/debug_cmds.ct | 3 +
> debugfs/debugfs.8.in | 21 +++
> debugfs/debugfs.h | 1 +
> debugfs/filefrag.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++
Is it possible to share any of ^^^ that code ^^^ with misc/filefrag.c somehow?
-Eric
> debugfs/ro_debug_cmds.ct | 3 +
> 6 files changed, 357 insertions(+), 3 deletions(-)
> create mode 100644 debugfs/filefrag.c
>
> diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
> index e03a3c6..c6aaa3a 100644
> --- a/debugfs/Makefile.in
> +++ b/debugfs/Makefile.in
> @@ -17,15 +17,17 @@ MANPAGES= debugfs.8
> MK_CMDS= _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
>
> DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
> - lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o
> + lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
> + filefrag.o
>
> RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
> - lsdel.o logdump.o htree.o e2freefrag.o
> + lsdel.o logdump.o htree.o e2freefrag.o filefrag.o
>
> SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
> $(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
> $(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
> - $(srcdir)/htree.c $(srcdir)/unused.c
> + $(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
> + $(srcdir)/filefrag.c
>
> LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
> $(LIBUUID)
> diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
> index 47de672..af969b1 100644
> --- a/debugfs/debug_cmds.ct
> +++ b/debugfs/debug_cmds.ct
> @@ -52,6 +52,9 @@ request do_dump_extents, "Dump extents information ",
> request do_blocks, "Dump blocks used by an inode ",
> blocks;
>
> +request do_filefrag, "Report fragmentation information for an inode",
> + filefrag;
> +
> request do_link, "Create directory link",
> link, ln;
>
> diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
> index 69490ff..70c8326 100644
> --- a/debugfs/debugfs.8.in
> +++ b/debugfs/debugfs.8.in
> @@ -251,6 +251,27 @@ Set or clear various filesystem features in the superblock. After setting
> or clearing any filesystem features that were requested, print the current
> state of the filesystem feature set.
> .TP
> +.I filefrag [-dvr] filespec
> +Print the number of contiguous extents in
> +.IR filespec .
> +If
> +.I filespec
> +is a directory and the
> +.I -d
> +option is not specified,
> +.I filefrag
> +will print the number of contiguous extents for each file in
> +the directory. The
> +.I -v
> +option will cause
> +.I filefrag
> +print a tabular listing of the contiguous extents in the
> +file. The
> +.I -r
> +option will cause
> +.I filefrag
> +to do a recursive listing of the directory.
> +.TP
> .I find_free_block [count [goal]]
> Find the first
> .I count
> diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
> index 6d7dfcd..0afa1df 100644
> --- a/debugfs/debugfs.h
> +++ b/debugfs/debugfs.h
> @@ -134,3 +134,4 @@ extern void do_supported_features(int argc, char **argv);
> extern void do_punch(int argc, char **argv);
>
> extern void do_freefrag(int argc, char **argv);
> +extern void do_filefrag(int argc, char *argv[]);
> diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
> new file mode 100644
> index 0000000..30933b6
> --- /dev/null
> +++ b/debugfs/filefrag.c
> @@ -0,0 +1,324 @@
> +/*
> + * filefrag.c --- display the fragmentation information for a file
> + *
> + * Copyright (C) 2011 Theodore Ts'o. This file may be redistributed
> + * under the terms of the GNU Public License.
> + */
> +
> +#include "config.h"
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <ctype.h>
> +#include <string.h>
> +#include <time.h>
> +#ifdef HAVE_ERRNO_H
> +#include <errno.h>
> +#endif
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <utime.h>
> +#ifdef HAVE_GETOPT_H
> +#include <getopt.h>
> +#else
> +extern int optind;
> +extern char *optarg;
> +#endif
> +
> +#include "debugfs.h"
> +
> +#define VERBOSE_OPT 0x0001
> +#define DIR_OPT 0x0002
> +#define RECURSIVE_OPT 0x0004
> +
> +struct dir_list {
> + char *name;
> + ext2_ino_t ino;
> + struct dir_list *next;
> +};
> +
> +struct filefrag_struct {
> + FILE *f;
> + const char *name;
> + const char *dir_name;
> + int options;
> + int logical_width;
> + int physical_width;
> + int ext;
> + int cont_ext;
> + e2_blkcnt_t num;
> + e2_blkcnt_t logical_start;
> + blk64_t physical_start;
> + blk64_t expected;
> + struct dir_list *dir_list, *dir_last;
> +};
> +
> +static int int_log10(unsigned long long arg)
> +{
> + int l = 0;
> +
> + arg = arg / 10;
> + while (arg) {
> + l++;
> + arg = arg / 10;
> + }
> + return l;
> +}
> +
> +static void print_header(struct filefrag_struct *fs)
> +{
> + if (fs->options & VERBOSE_OPT) {
> + fprintf(fs->f, "%4s %*s %*s %*s %*s\n", "ext",
> + fs->logical_width, "logical", fs->physical_width,
> + "physical", fs->physical_width, "expected",
> + fs->logical_width, "length");
> + }
> +}
> +
> +static void report_filefrag(struct filefrag_struct *fs)
> +{
> + if (fs->num == 0)
> + return;
> + if (fs->options & VERBOSE_OPT) {
> + if (fs->expected)
> + fprintf(fs->f, "%4d %*lu %*llu %*llu %*lu\n", fs->ext,
> + fs->logical_width,
> + (unsigned long) fs->logical_start,
> + fs->physical_width, fs->physical_start,
> + fs->physical_width, fs->expected,
> + fs->logical_width, (unsigned long) fs->num);
> + else
> + fprintf(fs->f, "%4d %*lu %*llu %*s %*lu\n", fs->ext,
> + fs->logical_width,
> + (unsigned long) fs->logical_start,
> + fs->physical_width, fs->physical_start,
> + fs->physical_width, "",
> + fs->logical_width, (unsigned long) fs->num);
> + }
> + fs->ext++;
> +}
> +
> +static int filefrag_blocks_proc(ext2_filsys ext4_fs EXT2FS_ATTR((unused)),
> + blk64_t *blocknr, e2_blkcnt_t blockcnt,
> + blk64_t ref_block EXT2FS_ATTR((unused)),
> + int ref_offset EXT2FS_ATTR((unused)),
> + void *private)
> +{
> + struct filefrag_struct *fs = private;
> +
> + if (blockcnt < 0 || *blocknr == 0)
> + return 0;
> +
> + if ((fs->num == 0) || (blockcnt != fs->logical_start + fs->num) ||
> + (*blocknr != fs->physical_start + fs->num)) {
> + report_filefrag(fs);
> + if (blockcnt == fs->logical_start + fs->num)
> + fs->expected = fs->physical_start + fs->num;
> + else
> + fs->expected = 0;
> + fs->logical_start = blockcnt;
> + fs->physical_start = *blocknr;
> + fs->num = 1;
> + fs->cont_ext++;
> + } else
> + fs->num++;
> + return 0;
> +}
> +
> +static void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
> + struct filefrag_struct *fs)
> +{
> + errcode_t retval;
> + int blocksize = current_fs->blocksize;
> +
> + fs->logical_width = int_log10((EXT2_I_SIZE(inode) + blocksize - 1) /
> + blocksize) + 1;
> + if (fs->logical_width < 7)
> + fs->logical_width = 7;
> + fs->ext = 0;
> + fs->cont_ext = 0;
> + fs->logical_start = 0;
> + fs->physical_start = 0;
> + fs->num = 0;
> +
> + if (fs->options & VERBOSE_OPT) {
> + blk64_t num_blocks = ext2fs_inode_i_blocks(current_fs, inode);
> +
> + if (!(current_fs->super->s_feature_ro_compat &
> + EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
> + !(inode->i_flags & EXT4_HUGE_FILE_FL))
> + num_blocks /= current_fs->blocksize / 512;
> +
> + fprintf(fs->f, "\n%s has %llu block(s), i_size is %llu\n",
> + fs->name, num_blocks, EXT2_I_SIZE(inode));
> + }
> + print_header(fs);
> + retval = ext2fs_block_iterate3(current_fs, ino,
> + BLOCK_FLAG_READ_ONLY, NULL,
> + filefrag_blocks_proc, fs);
> + if (retval)
> + com_err("ext2fs_block_iterate3", retval, 0);
> +
> + report_filefrag(fs);
> + fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
> + LINUX_S_ISDIR(inode->i_mode) ? " (dir)" : "");
> +}
> +
> +static int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
> + int entry,
> + struct ext2_dir_entry *dirent,
> + int offset EXT2FS_ATTR((unused)),
> + int blocksize EXT2FS_ATTR((unused)),
> + char *buf EXT2FS_ATTR((unused)),
> + void *private)
> +{
> + struct filefrag_struct *fs = private;
> + struct ext2_inode inode;
> + ext2_ino_t ino;
> + char name[EXT2_NAME_LEN + 1];
> + char *cp;
> + int thislen;
> +
> + if (entry == DIRENT_DELETED_FILE)
> + return 0;
> +
> + thislen = dirent->name_len & 0xFF;
> + strncpy(name, dirent->name, thislen);
> + name[thislen] = '\0';
> + ino = dirent->inode;
> +
> + if (!strcmp(name, ".") || !strcmp(name, ".."))
> + return 0;
> +
> + cp = malloc(strlen(fs->dir_name) + strlen(name) + 2);
> + if (!cp) {
> + fprintf(stderr, "Couldn't allocate memory for %s/%s\n",
> + fs->dir_name, name);
> + return 0;
> + }
> +
> + sprintf(cp, "%s/%s", fs->dir_name, name);
> + fs->name = cp;
> +
> + if (debugfs_read_inode(ino, &inode, fs->name))
> + goto errout;
> +
> + filefrag(ino, &inode, fs);
> +
> + if ((fs->options & RECURSIVE_OPT) && LINUX_S_ISDIR(inode.i_mode)) {
> + struct dir_list *p;
> +
> + p = malloc(sizeof(struct dir_list));
> + if (!p) {
> + fprintf(stderr, "Couldn't allocate dir_list for %s\n",
> + fs->name);
> + goto errout;
> + }
> + memset(p, 0, sizeof(struct dir_list));
> + p->name = cp;
> + p->ino = ino;
> + if (fs->dir_last)
> + fs->dir_last->next = p;
> + else
> + fs->dir_list = p;
> + fs->dir_last = p;
> + return 0;
> + }
> +errout:
> + free(cp);
> + fs->name = 0;
> + return 0;
> +}
> +
> +
> +static void dir_iterate(ext2_ino_t ino, struct filefrag_struct *fs)
> +{
> + errcode_t retval;
> + struct dir_list *p = NULL;
> +
> + fs->dir_name = fs->name;
> +
> + while (1) {
> + retval = ext2fs_dir_iterate2(current_fs, ino, 0,
> + 0, filefrag_dir_proc, fs);
> + if (retval)
> + com_err("ext2fs_dir_iterate2", retval, 0);
> + if (p) {
> + free(p->name);
> + fs->dir_list = p->next;
> + if (!fs->dir_list)
> + fs->dir_last = 0;
> + free(p);
> + }
> + p = fs->dir_list;
> + if (!p)
> + break;
> + ino = p->ino;
> + fs->dir_name = p->name;
> + }
> +}
> +
> +void do_filefrag(int argc, char *argv[])
> +{
> + struct filefrag_struct fs;
> + struct ext2_inode inode;
> + ext2_ino_t ino;
> + int c;
> +
> + memset(&fs, 0, sizeof(fs));
> + if (check_fs_open(argv[0]))
> + return;
> +
> + reset_getopt();
> + while ((c = getopt (argc, argv, "dvr")) != EOF) {
> + switch (c) {
> + case 'd':
> + fs.options |= DIR_OPT;
> + break;
> + case 'v':
> + fs.options |= VERBOSE_OPT;
> + break;
> + case 'r':
> + fs.options |= RECURSIVE_OPT;
> + break;
> + default:
> + goto print_usage;
> + }
> + }
> +
> + if (argc > optind+1) {
> + print_usage:
> + com_err(0, 0, "Usage: filefrag [-dv] file");
> + return;
> + }
> +
> + if (argc == optind) {
> + ino = cwd;
> + fs.name = ".";
> + } else {
> + ino = string_to_inode(argv[optind]);
> + fs.name = argv[optind];
> + }
> + if (!ino)
> + return;
> +
> + if (debugfs_read_inode(ino, &inode, argv[0]))
> + return;
> +
> + fs.f = open_pager();
> + fs.physical_width = int_log10(ext2fs_blocks_count(current_fs->super));
> + fs.physical_width++;
> + if (fs.physical_width < 8)
> + fs.physical_width = 8;
> +
> + if (!LINUX_S_ISDIR(inode.i_mode) || (fs.options & DIR_OPT))
> + filefrag(ino, &inode, &fs);
> + else
> + dir_iterate(ino, &fs);
> +
> + fprintf(fs.f, "\n");
> + close_pager(fs.f);
> +
> + return;
> +}
> diff --git a/debugfs/ro_debug_cmds.ct b/debugfs/ro_debug_cmds.ct
> index 7eb552d..4feb621 100644
> --- a/debugfs/ro_debug_cmds.ct
> +++ b/debugfs/ro_debug_cmds.ct
> @@ -45,6 +45,9 @@ request do_dump_extents, "Dump extents information ",
> request do_blocks, "Dump blocks used by an inode ",
> blocks;
>
> +request do_filefrag, "Report fragmentation information for an inode",
> + filefrag;
> +
> request do_testi, "Test an inode's in-use flag",
> testi;
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] debugfs: add filefrag command
2011-11-17 21:19 ` [PATCH 1/2] debugfs: add filefrag command Eric Sandeen
@ 2011-11-17 21:27 ` Theodore Tso
0 siblings, 0 replies; 4+ messages in thread
From: Theodore Tso @ 2011-11-17 21:27 UTC (permalink / raw)
To: Eric Sandeen; +Cc: Theodore Tso, Ext4 Developers List
On Nov 17, 2011, at 4:19 PM, Eric Sandeen wrote:
> On 11/17/11 3:12 PM, Theodore Ts'o wrote:
>> Add the ability to report on the fragmentation of a file on a file
>> system opened using debugfs.
>>
>> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
>> ---
>> debugfs/Makefile.in | 8 +-
>> debugfs/debug_cmds.ct | 3 +
>> debugfs/debugfs.8.in | 21 +++
>> debugfs/debugfs.h | 1 +
>> debugfs/filefrag.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++
>
> Is it possible to share any of ^^^ that code ^^^ with misc/filefrag.c somehow?
Well, the debugs code accesses the file system directly; I thought about creating glue code that created an interface similar to FIEMAP ioctl, but the glue code ends up being more than the code to do just do the fragmentation calculation.
-- Ted
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-11-17 21:27 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-17 21:12 [PATCH 1/2] debugfs: add filefrag command Theodore Ts'o
2011-11-17 21:12 ` [PATCH 2/2] debugfs: fix gcc -Wall complaints Theodore Ts'o
2011-11-17 21:19 ` [PATCH 1/2] debugfs: add filefrag command Eric Sandeen
2011-11-17 21:27 ` Theodore Tso
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.