mirror of https://github.com/vitalif/e2fsprogs
Initial checkin of the filefrag program, which reports on how
badly fragmented a file might be.bitmap-optimize
parent
2e5fcce05e
commit
9642413014
|
@ -35,11 +35,13 @@ BADBLOCKS_OBJS= badblocks.o
|
|||
E2IMAGE_OBJS= e2image.o
|
||||
FSCK_OBJS= fsck.o base_device.o
|
||||
BLKID_OBJS= blkid.o
|
||||
FILEFRAG_OBJS= filefrag.o
|
||||
|
||||
SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \
|
||||
$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
|
||||
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
|
||||
$(srcdir)/uuidgen.c $(srcdir)/blkid.c
|
||||
$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
|
||||
$(srcdir)/filefrag.c $(srcdir)/base_device.c
|
||||
|
||||
LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
|
||||
DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
|
||||
|
@ -56,7 +58,7 @@ DEPLIBS_E2P= $(LIBE2P) $(LIBCOM_ERR)
|
|||
.c.o:
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
all:: $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES)
|
||||
all:: $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) filefrag
|
||||
|
||||
findsuper: findsuper.o
|
||||
$(CC) $(ALL_LDFLAGS) -o findsuper findsuper.o
|
||||
|
@ -115,6 +117,9 @@ badblocks: $(BADBLOCKS_OBJS) $(DEPLIBS)
|
|||
logsave: logsave.o
|
||||
$(CC) $(ALL_LDFLAGS) -o logsave logsave.o
|
||||
|
||||
filefrag: $(FILEFRAG_OBJS)
|
||||
$(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS)
|
||||
|
||||
tune2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/tune2fs.8.in
|
||||
$(SUBSTITUTE) $(srcdir)/tune2fs.8.in tune2fs.8
|
||||
|
||||
|
@ -160,6 +165,9 @@ uuidgen.1: $(DEP_SUBSTITUTE) $(srcdir)/uuidgen.1.in
|
|||
blkid.1: $(DEP_SUBSTITUTE) $(srcdir)/blkid.1.in
|
||||
$(SUBSTITUTE) $(srcdir)/blkid.1.in blkid.1
|
||||
|
||||
filefrag.8: $(DEP_SUBSTITUTE) $(srcdir)/filefrag.8.in
|
||||
$(SUBSTITUTE) $(srcdir)/filefrag.8.in filefrag.8
|
||||
|
||||
installdirs:
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(sbindir) \
|
||||
$(DESTDIR)$(root_sbindir) $(DESTDIR)$(bindir) \
|
||||
|
@ -224,7 +232,7 @@ uninstall:
|
|||
|
||||
clean:
|
||||
$(RM) -f $(SPROGS) $(USPROGS) $(UPROGS) $(UMANPAGES) $(SMANPAGES) \
|
||||
base_device base_device.out mke2fs.static \
|
||||
base_device base_device.out mke2fs.static filefrag \
|
||||
\#* *.s *.o *.a *~ core
|
||||
|
||||
mostlyclean: clean
|
||||
|
@ -288,3 +296,6 @@ uuidgen.o: $(srcdir)/uuidgen.c $(top_srcdir)/lib/uuid/uuid.h \
|
|||
$(srcdir)/nls-enable.h
|
||||
blkid.o: $(srcdir)/blkid.c $(top_srcdir)/lib/blkid/blkid.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
logsave.o: $(srcdir)/logsave.c
|
||||
filefrag.o: $(srcdir)/filefrag.c
|
||||
base_device.o: $(srcdir)/base_device.c $(srcdir)/fsck.h
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
.\" -*- nroff -*-
|
||||
.TH FILEFRAG 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
|
||||
.SH NAME
|
||||
filefrag \- report on file fragmentation
|
||||
.SH SYNOPSIS
|
||||
.B filefrag
|
||||
[
|
||||
.B \-v
|
||||
]
|
||||
[
|
||||
.I files...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B filefrag
|
||||
reports on how badly fragmented a particular file might be. It makes
|
||||
allowances for indirect blocks for ext2 and ext3 filesystems, but can be
|
||||
used on files for any filesystem.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-v
|
||||
Be verbose when checking for file fragmentation.
|
||||
.SH AUTHOR
|
||||
.B filefrag
|
||||
was written by Theodore Ts'o <tytso@mit.edu>.
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* filefrag.c -- report if a particular file is fragmented
|
||||
*
|
||||
* Copyright 2003 by Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <linux/fd.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#define FIBMAP _IO(0x00,1) /* bmap access */
|
||||
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
|
||||
|
||||
static unsigned long get_bmap(int fd, unsigned long block)
|
||||
{
|
||||
int ret;
|
||||
unsigned long b;
|
||||
|
||||
b = block;
|
||||
ret = ioctl(fd, FIBMAP, &b);
|
||||
if (ret < 0) {
|
||||
if (errno == EPERM) {
|
||||
fprintf(stderr, "No permission to use FIBMAP ioctl; must have root privileges\n");
|
||||
exit(1);
|
||||
}
|
||||
perror("FIBMAP");
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
#define EXT2_DIRECT 12
|
||||
|
||||
void frag_report(const char *filename)
|
||||
{
|
||||
struct statfs fsinfo;
|
||||
struct stat64 fileinfo;
|
||||
long i, fd, bs, block, last_block, numblocks;
|
||||
long bpib; /* Blocks per indirect block */
|
||||
long cylgroups;
|
||||
int discont = 0, expected;
|
||||
int is_ext2 = 0;
|
||||
|
||||
if (statfs(filename, &fsinfo) < 0) {
|
||||
perror("statfs");
|
||||
return;
|
||||
}
|
||||
if (stat64(filename, &fileinfo) < 0) {
|
||||
perror("stat");
|
||||
return;
|
||||
}
|
||||
if (!S_ISREG(fileinfo.st_mode)) {
|
||||
printf("%s: Not a regular file\n", filename);
|
||||
return;
|
||||
}
|
||||
if ((fsinfo.f_type == 0xef51) || (fsinfo.f_type == 0xef52) ||
|
||||
(fsinfo.f_type == 0xef53))
|
||||
is_ext2++;
|
||||
if (verbose) {
|
||||
printf("Filesystem type is: %lx\n", fsinfo.f_type);
|
||||
}
|
||||
cylgroups = (fsinfo.f_blocks + fsinfo.f_bsize*8-1) / fsinfo.f_bsize*8;
|
||||
if (verbose) {
|
||||
printf("Filesystem cylinder groups is approximately %ld\n",
|
||||
cylgroups);
|
||||
}
|
||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, FIGETBSZ, &bs) < 0) {
|
||||
perror("FIGETBSZ");
|
||||
return;
|
||||
}
|
||||
if (verbose)
|
||||
printf("Blocksize of file %s is %d\n", filename, bs);
|
||||
bpib = bs / 4;
|
||||
numblocks = (fileinfo.st_size + (bs-1)) / bs;
|
||||
if (verbose)
|
||||
printf("File size of %s is %lld (%d blocks)\n", filename,
|
||||
(long long) fileinfo.st_size, numblocks);
|
||||
for (i=0; i < numblocks; i++) {
|
||||
if (is_ext2) {
|
||||
if (((i-EXT2_DIRECT) % bpib) == 0)
|
||||
last_block++;
|
||||
if (((i-EXT2_DIRECT-bpib) % (bpib*bpib)) == 0)
|
||||
last_block++;
|
||||
if (((i-EXT2_DIRECT-bpib-bpib*bpib) % (bpib*bpib*bpib)) == 0)
|
||||
last_block++;
|
||||
}
|
||||
block = get_bmap(fd, i);
|
||||
if (i && (block != last_block +1) ) {
|
||||
if (verbose)
|
||||
printf("Discontinuity: Block %ld is at %ld (was %ld)\n",
|
||||
i, block, last_block);
|
||||
discont++;
|
||||
}
|
||||
if (block)
|
||||
last_block = block;
|
||||
}
|
||||
if (discont==0)
|
||||
printf("%s: 1 extent found", filename);
|
||||
else
|
||||
printf("%s: %d extents found", filename, discont+1);
|
||||
expected = (numblocks/((bs*8)-(fsinfo.f_files/8/cylgroups)-3))+1;
|
||||
if (is_ext2 && expected != discont+1)
|
||||
printf(", perfection would be %d extent%s\n", expected,
|
||||
(expected>1) ? "s" : "");
|
||||
else
|
||||
fputc('\n', stdout);
|
||||
|
||||
}
|
||||
|
||||
void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-v] file ...\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
char **cpp;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "v")) != EOF)
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
if (optind == argc)
|
||||
usage(argv[0]);
|
||||
for (cpp=argv+optind; *cpp; cpp++) {
|
||||
if (verbose)
|
||||
printf("Checking %s\n", *cpp);
|
||||
frag_report(*cpp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue