summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-08-22 13:18:29 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-08-22 13:18:29 -0400
commit1d72214658d339bd4725fe74aa42397df419e914 (patch)
treec678e0f56eccab2ebede9d314abb58aa232147bb /misc
parent88fca201aca752cbb7a981e1fe1b2a875cc29833 (diff)
parent154a5d7537c35959aa646ef8f18daed8c9f1a2be (diff)
downloade2fsprogs-1d72214658d339bd4725fe74aa42397df419e914.tar.gz
Merge branch 'maint' into next
Diffstat (limited to 'misc')
-rw-r--r--misc/Makefile.in4
-rw-r--r--misc/e2freefrag.8.in23
-rw-r--r--misc/e2freefrag.c100
-rw-r--r--misc/filefrag.8.in6
-rw-r--r--misc/filefrag.c26
-rw-r--r--misc/tune2fs.c149
6 files changed, 191 insertions, 117 deletions
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 5d9af4d4..e5369209 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -299,8 +299,8 @@ logsave.profiled: profiled/logsave.o
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o logsave.profiled profiled/logsave.o
e2freefrag: $(E2FREEFRAG_OBJS)
- @echo " LD $@"
- @$(CC) $(ALL_LDFLAGS) -o e2freefrag $(E2FREEFRAG_OBJS) $(LIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2freefrag $(E2FREEFRAG_OBJS) $(LIBS)
filefrag: $(FILEFRAG_OBJS)
$(E) " LD $@"
diff --git a/misc/e2freefrag.8.in b/misc/e2freefrag.8.in
index 9c47e97f..56fdbff7 100644
--- a/misc/e2freefrag.8.in
+++ b/misc/e2freefrag.8.in
@@ -30,9 +30,12 @@ can be used to gauge the level of free space fragmentation in the filesystem.
.SH OPTIONS
.TP
.BI \-c " chunk_kb"
-Desired size of chunk. It is specified in units of kilobytes (KB). If no
+If a chunk size is specified, then
+.B e2freefrag
+will print how many free chunks of size
.I chunk_kb
-is specified on the command line, then the default value is 1024KB.
+are available in units of kilobytes (Kb). The chunk size must be a
+power of two and be larger than filesystem block size.
.TP
.BI \-h
Print the usage of the program.
@@ -47,23 +50,17 @@ Total blocks: 1504085
.br
Free blocks: 292995 (19.5%)
.br
-Chunk size: 1048576 bytes (256 blocks)
-.br
-Total chunks: 5876
-.br
-Free chunks: 463 (7.9%)
-.br
-Min free chunk: 4 KB
+Min. free extent: 4 KB
.br
-Max free chunk: 24008 KB
+Max. free extent: 24008 KB
.br
-Avg free chunk: 252 KB
+Avg. free extent: 252 KB
.br
-HISTOGRAM OF FREE CHUNK SIZES:
+HISTOGRAM OF FREE EXTENT SIZES:
.br
-Chunk Size Range : Free chunks Free Blocks Percent
+Extent Size Range : Free extents Free Blocks Percent
.br
4K... 8K- : 704 704 0.2%
.br
diff --git a/misc/e2freefrag.c b/misc/e2freefrag.c
index 4936a053..a4ab9948 100644
--- a/misc/e2freefrag.c
+++ b/misc/e2freefrag.c
@@ -52,9 +52,14 @@ void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
{
int i;
- info->chunkbits = ul_log2(info->chunkbytes);
info->blocksize_bits = ul_log2((unsigned long)fs->blocksize);
- info->blks_in_chunk = info->chunkbytes >> info->blocksize_bits;
+ if (info->chunkbytes) {
+ info->chunkbits = ul_log2(info->chunkbytes);
+ info->blks_in_chunk = info->chunkbytes >> info->blocksize_bits;
+ } else {
+ info->chunkbits = ul_log2(DEFAULT_CHUNKSIZE);
+ info->blks_in_chunk = DEFAULT_CHUNKSIZE >> info->blocksize_bits;
+ }
info->min = ~0UL;
info->max = info->avg = 0;
@@ -66,6 +71,24 @@ void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
}
}
+void update_chunk_stats(struct chunk_info *info, unsigned long chunk_size)
+{
+ unsigned long index;
+
+ 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;
+
+ if (chunk_size > info->max)
+ info->max = chunk_size;
+ if (chunk_size < info->min)
+ info->min = chunk_size;
+ info->avg += chunk_size;
+ info->real_free_chunks++;
+}
+
void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
{
unsigned long long blocks_count = fs->super->s_blocks_count;
@@ -74,6 +97,7 @@ void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
unsigned long long chunk_num;
unsigned long last_chunk_size = 0;
unsigned long long chunk_start_blk = 0;
+ int used;
for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
unsigned long long blk, num_blks;
@@ -90,30 +114,20 @@ void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
/* Initialize starting block for first chunk correctly else
* there is a segfault when blocksize = 1024 in which case
* block_map->start = 1 */
- for (blk = (chunk_num == 0 ? fs->super->s_first_data_block : 0);
- blk < num_blks; blk++, chunk_start_blk++) {
- int used = ext2fs_fast_test_block_bitmap(fs->block_map,
- chunk_start_blk);
+ for (blk = 0; blk < num_blks; blk++, chunk_start_blk++) {
+ if (chunk_num == 0 && blk == 0) {
+ blk = fs->super->s_first_data_block;
+ chunk_start_blk = blk;
+ }
+ used = ext2fs_fast_test_block_bitmap(fs->block_map,
+ chunk_start_blk);
if (!used) {
last_chunk_size++;
chunk_free++;
}
if (used && last_chunk_size != 0) {
- unsigned long index;
-
- index = ul_log2(last_chunk_size) + 1;
- info->histogram.fc_chunks[index]++;
- info->histogram.fc_blocks[index] +=
- last_chunk_size;
-
- if (last_chunk_size > info->max)
- info->max = last_chunk_size;
- if (last_chunk_size < info->min)
- info->min = last_chunk_size;
- info->avg += last_chunk_size;
-
- info->real_free_chunks++;
+ update_chunk_stats(info, last_chunk_size);
last_chunk_size = 0;
}
}
@@ -121,6 +135,8 @@ void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
if (chunk_free == info->blks_in_chunk)
info->free_chunks++;
}
+ if (last_chunk_size != 0)
+ update_chunk_stats(info, last_chunk_size);
}
errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info)
@@ -138,13 +154,16 @@ errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info)
(double)fs->super->s_free_blocks_count * 100 /
fs->super->s_blocks_count);
- printf("\nChunksize: %lu bytes (%u blocks)\n",
- info->chunkbytes, info->blks_in_chunk);
- total_chunks = (fs->super->s_blocks_count + info->blks_in_chunk) >>
- (info->chunkbits - info->blocksize_bits);
- printf("Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
- total_chunks, info->free_chunks,
- (double)info->free_chunks * 100 / total_chunks);
+ if (info->chunkbytes) {
+ printf("\nChunksize: %lu bytes (%u blocks)\n",
+ info->chunkbytes, info->blks_in_chunk);
+ total_chunks = (fs->super->s_blocks_count +
+ info->blks_in_chunk) >>
+ (info->chunkbits - info->blocksize_bits);
+ printf("Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
+ total_chunks, info->free_chunks,
+ (double)info->free_chunks * 100 / total_chunks);
+ }
/* Display chunk information in KB */
if (info->real_free_chunks) {
@@ -156,21 +175,27 @@ errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info)
info->min = 0;
}
- printf("\nMin free chunk: %lu KB \nMax free chunk: %lu KB\n"
- "Avg free chunk: %lu KB\n", info->min, info->max, info->avg);
+ printf("\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
+ "Avg. free extent: %lu KB\n", info->min, info->max, info->avg);
- printf("\nHISTOGRAM OF FREE CHUNK SIZES:\n");
- printf("%s : %12s %12s %7s\n", "Chunk Size Range", "Free chunks",
+ printf("\nHISTOGRAM OF FREE EXTENT SIZES:\n");
+ printf("%s : %12s %12s %7s\n", "Extent Size Range", "Free extents",
"Free Blocks", "Percent");
for (i = 0; i < MAX_HIST; i++) {
end = 1 << (i + info->blocksize_bits - units);
- if (info->histogram.fc_chunks[i] != 0)
- printf("%5lu%c...%5lu%c- : %12lu %12lu %6.2f%%\n",
- start, *unitp, end, *unitp,
+ if (info->histogram.fc_chunks[i] != 0) {
+ char end_str[32];
+
+ sprintf(end_str, "%5lu%c-", end, *unitp);
+ if (i == MAX_HIST-1)
+ strcpy(end_str, "max ");
+ printf("%5lu%c...%7s : %12lu %12lu %6.2f%%\n",
+ start, *unitp, end_str,
info->histogram.fc_chunks[i],
info->histogram.fc_blocks[i],
(double)info->histogram.fc_blocks[i] * 100 /
fs->super->s_free_blocks_count);
+ }
start = end;
if (start == 1<<10) {
start = 1;
@@ -228,13 +253,14 @@ void open_device(char *device_name, ext2_filsys *fs)
int main(int argc, char *argv[])
{
- struct chunk_info chunk_info = { .chunkbytes = DEFAULT_CHUNKSIZE };
+ struct chunk_info chunk_info = { };
errcode_t retval = 0;
ext2_filsys fs = NULL;
char *device_name;
char *progname;
char c, *end;
+ add_error_table(&et_ext2_error_table);
progname = argv[0];
while ((c = getopt(argc, argv, "c:h")) != EOF) {
@@ -249,7 +275,7 @@ int main(int argc, char *argv[])
if (chunk_info.chunkbytes &
(chunk_info.chunkbytes - 1)) {
fprintf(stderr, "%s: chunk size must be a "
- "power of 2.", argv[0]);
+ "power of 2.\n", argv[0]);
usage(progname);
}
chunk_info.chunkbytes *= 1024;
@@ -272,7 +298,7 @@ int main(int argc, char *argv[])
open_device(device_name, &fs);
- if (chunk_info.chunkbytes < fs->blocksize) {
+ if (chunk_info.chunkbytes && (chunk_info.chunkbytes < fs->blocksize)) {
fprintf(stderr, "%s: chunksize must be greater than or equal "
"to filesystem blocksize.\n", progname);
exit(1);
diff --git a/misc/filefrag.8.in b/misc/filefrag.8.in
index 681fe9a8..463f7315 100644
--- a/misc/filefrag.8.in
+++ b/misc/filefrag.8.in
@@ -5,7 +5,7 @@ filefrag \- report on file fragmentation
.SH SYNOPSIS
.B filefrag
[
-.B \-bsvx
+.B \-Bbsvx
]
[
.I files...
@@ -23,6 +23,10 @@ extent information using FIEMAP ioctl which is more efficient and faster.
If FIEMAP is not supported then filefrag will fall back to using FIBMAP.
.SH OPTIONS
.TP
+.B \-B
+Force the use of the older FIBMAP ioctl instead of the FIEMAP ioctl for
+testing purposes.
+.TP
.B \-b
Use 1024 byte blocksize for the output.
.TP
diff --git a/misc/filefrag.c b/misc/filefrag.c
index 66a09e7e..10bb0ebb 100644
--- a/misc/filefrag.c
+++ b/misc/filefrag.c
@@ -46,6 +46,7 @@ int verbose = 0;
int no_bs = 0; /* Don't use the files blocksize, use 1K blocksize */
int sync_file = 0; /* fsync file before getting the mapping */
int xattr_map = 0; /* get xattr mapping */
+int force_bmap = 0;
int logical_width = 12;
int physical_width = 14;
unsigned long long filesize;
@@ -172,6 +173,7 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents)
unsigned long flags = 0;
unsigned int i;
static int fiemap_incompat_printed;
+ int fiemap_header_printed = 0;
int tot_extents = 1, n = 0;
int last = 0;
int rc;
@@ -189,11 +191,6 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents)
if (xattr_map)
flags |= FIEMAP_FLAG_XATTR;
- if (verbose)
- printf(" ext %*s %*s %*s length flags\n", logical_width,
- "logical", physical_width, "physical",
- physical_width, "expected");
-
do {
fiemap->fm_length = ~0ULL;
fiemap->fm_flags = flags;
@@ -208,6 +205,13 @@ static int filefrag_fiemap(int fd, int blk_shift, int *num_extents)
return rc;
}
+ if (verbose && !fiemap_header_printed) {
+ printf(" ext %*s %*s %*s length flags\n", logical_width,
+ "logical", physical_width, "physical",
+ physical_width, "expected");
+ fiemap_header_printed = 1;
+ }
+
if (!verbose) {
*num_extents = fiemap->fm_mapped_extents;
goto out;
@@ -327,7 +331,8 @@ static void frag_report(const char *filename)
printf("File size of %s is %lld (%ld block%s, blocksize %d)\n",
filename, (long long) fileinfo.st_size, numblocks,
numblocks == 1 ? "" : "s", bs);
- if (filefrag_fiemap(fd, int_log2(bs), &num_extents) != 0) {
+ if (force_bmap ||
+ filefrag_fiemap(fd, int_log2(bs), &num_extents) != 0) {
for (i = 0, count = 0; i < numblocks; i++) {
if (is_ext2 && last_block) {
if (((i-EXT2_DIRECT) % bpib) == 0)
@@ -341,6 +346,8 @@ static void frag_report(const char *filename)
rc = get_bmap(fd, i, &block);
if (block == 0)
continue;
+ if (!num_extents)
+ num_extents++;
count++;
if (last_block && (block != last_block+1) ) {
if (verbose)
@@ -368,7 +375,7 @@ static void frag_report(const char *filename)
static void usage(const char *progname)
{
- fprintf(stderr, "Usage: %s [-bvsx] file ...\n", progname);
+ fprintf(stderr, "Usage: %s [-Bbvsx] file ...\n", progname);
exit(1);
}
@@ -377,8 +384,11 @@ int main(int argc, char**argv)
char **cpp;
int c;
- while ((c = getopt(argc, argv, "bsvx")) != EOF)
+ while ((c = getopt(argc, argv, "Bbsvx")) != EOF)
switch (c) {
+ case 'B':
+ force_bmap++;
+ break;
case 'b':
no_bs++;
break;
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 60b50fd8..41a06382 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -962,42 +962,40 @@ static void parse_extended_opts(ext2_filsys fs, const char *opts)
}
/*
- * Fill in two bitmaps that we need to to control the inode resizing
- * process. The first is the set of blocks that must be moved, and
- * the second is the set of blocks which are allocation bitmap blocks
- * and must be treated specially.
+ * Fill in the block bitmap bmap with the information regarding the
+ * blocks to be moved
*/
static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
- ext2fs_block_bitmap bmap,
- ext2fs_block_bitmap metadata_bmap)
+ ext2fs_block_bitmap bmap)
{
dgrp_t i;
+ int retval;
+ ext2_badblocks_list bb_list = 0;
blk_t j, needed_blocks = 0;
- blk_t i_bmap, b_bmap;
blk_t start_blk, end_blk;
- int num;
- for (i = 0; i < fs->group_desc_count; i++) {
- b_bmap = fs->group_desc[i].bg_block_bitmap;
- ext2fs_mark_block_bitmap(metadata_bmap, b_bmap);
- i_bmap = fs->group_desc[i].bg_inode_bitmap;
- ext2fs_mark_block_bitmap(metadata_bmap, i_bmap);
+ retval = ext2fs_read_bb_inode(fs, &bb_list);
+ if (retval)
+ return retval;
+ for (i = 0; i < fs->group_desc_count; i++) {
start_blk = fs->group_desc[i].bg_inode_table +
fs->inode_blocks_per_group;
end_blk = fs->group_desc[i].bg_inode_table +
new_ino_blks_per_grp;
- num=0;
for (j = start_blk; j < end_blk; j++) {
if (ext2fs_test_block_bitmap(fs->block_map, j)) {
- /* FIXME!!
- * What happens if the block is marked
- * as a bad block
+ /*
+ * IF the block is a bad block we fail
*/
+ if (ext2fs_badblocks_list_test(bb_list, j)) {
+ ext2fs_badblocks_list_free(bb_list);
+ return ENOSPC;
+ }
+
ext2fs_mark_block_bitmap(bmap, j);
- needed_blocks++;
} else {
/*
* We are going to use this block for
@@ -1005,27 +1003,52 @@ static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
*/
ext2fs_mark_block_bitmap(fs->block_map, j);
}
- if ((j == i_bmap) || (j == b_bmap))
- num++;
}
- if (num <= fs->group_desc[i].bg_free_blocks_count)
- continue;
+ needed_blocks += end_blk - start_blk;
}
+ ext2fs_badblocks_list_free(bb_list);
if (needed_blocks > fs->super->s_free_blocks_count)
return ENOSPC;
return 0;
}
-static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap,
- ext2fs_block_bitmap metadata_bmap)
+static int ext2fs_is_meta_block(ext2_filsys fs, blk_t blk)
+{
+ dgrp_t group;
+ group = ext2fs_group_of_blk(fs, blk);
+ if (fs->group_desc[group].bg_block_bitmap == blk)
+ return 1;
+ if (fs->group_desc[group].bg_inode_bitmap == blk)
+ return 1;
+ return 0;
+}
+
+static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk_t blk)
+{
+ blk_t start_blk, end_blk;
+ start_blk = fs->super->s_first_data_block +
+ EXT2_BLOCKS_PER_GROUP(fs->super) * group;
+ /*
+ * We cannot get new block beyond end_blk for for the last block group
+ * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
+ */
+ end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
+ if (blk >= start_blk && blk <= end_blk)
+ return 1;
+ return 0;
+}
+
+static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
{
+
char *buf;
+ dgrp_t group;
errcode_t retval;
+ int meta_data = 0;
blk_t blk, new_blk, goal;
struct blk_move *bmv;
- dgrp_t group;
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
@@ -1036,20 +1059,31 @@ static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap,
if (!ext2fs_test_block_bitmap(bmap, blk))
continue;
- /*
- * If the block is a bitmap block, find a new block in
- * the same block group.
- */
- if (ext2fs_test_block_bitmap(metadata_bmap, blk)) {
+ if (ext2fs_is_meta_block(fs, blk)) {
+ /*
+ * If the block is mapping a fs meta data block
+ * like group desc/block bitmap/inode bitmap. We
+ * should find a block in the same group and fix
+ * the respective fs metadata pointers. Otherwise
+ * fail
+ */
group = ext2fs_group_of_blk(fs, blk);
goal = ext2fs_group_first_block(fs, group);
- } else
- goal = new_blk;
+ meta_data = 1;
+ } else {
+ goal = new_blk;
+ }
retval = ext2fs_new_block(fs, goal, NULL, &new_blk);
if (retval)
goto err_out;
+ /* new fs meta data block should be in the same group */
+ if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
+ retval = ENOSPC;
+ goto err_out;
+ }
+
/* Mark this block as allocated */
ext2fs_mark_block_bitmap(fs->block_map, new_blk);
@@ -1214,7 +1248,6 @@ static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
return 0;
}
-
static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
{
dgrp_t i;
@@ -1367,7 +1400,7 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
{
errcode_t retval;
int new_ino_blks_per_grp;
- ext2fs_block_bitmap bmap, metadata_bmap;
+ ext2fs_block_bitmap bmap;
ext2fs_read_inode_bitmap(fs);
ext2fs_read_block_bitmap(fs);
@@ -1387,34 +1420,33 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
&bmap);
- if (retval)
- return retval;
-
- retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
- &metadata_bmap);
- if (retval)
+ if (retval) {
+ fputs(_("Failed to allocate block bitmap when "
+ "increasing inode size\n"), stderr);
return retval;
-
- retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap,
- metadata_bmap);
- if (retval)
+ }
+ retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
+ if (retval) {
+ fputs(_("Not enough space to increase inode size \n"), stderr);
goto err_out;
-
- retval = move_block(fs, bmap, metadata_bmap);
- if (retval)
+ }
+ retval = move_block(fs, bmap);
+ if (retval) {
+ fputs(_("Failed to relocate blocks during inode resize \n"),
+ stderr);
goto err_out;
-
+ }
retval = inode_scan_and_fix(fs, bmap);
if (retval)
- goto err_out;
+ goto err_out_undo;
retval = group_desc_scan_and_fix(fs, bmap);
if (retval)
- goto err_out;
+ goto err_out_undo;
retval = expand_inode_table(fs, new_size);
if (retval)
- goto err_out;
+ goto err_out_undo;
ext2fs_calculate_summary_stats(fs);
@@ -1428,6 +1460,15 @@ err_out:
ext2fs_free_block_bitmap(bmap);
return retval;
+
+err_out_undo:
+ free_blk_move_list();
+ ext2fs_free_block_bitmap(bmap);
+ fputs(_("Error in resizing the inode size.\n"
+ "Run e2undo to undo the "
+ "file system changes. \n"), stderr);
+
+ return retval;
}
static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
@@ -1744,11 +1785,7 @@ retry_open:
* with the new free inode count
*/
fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
- if (resize_inode(fs, new_inode_size)) {
- fputs(_("Error in resizing the inode size.\n"
- "Run e2undo to undo the "
- "file system changes. \n"), stderr);
- } else {
+ if (resize_inode(fs, new_inode_size) == 0) {
printf(_("Setting inode size %lu\n"),
new_inode_size);
}