diff options
author | Theodore Ts'o <tytso@mit.edu> | 2009-08-22 13:18:29 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-08-22 13:18:29 -0400 |
commit | 1d72214658d339bd4725fe74aa42397df419e914 (patch) | |
tree | c678e0f56eccab2ebede9d314abb58aa232147bb /misc | |
parent | 88fca201aca752cbb7a981e1fe1b2a875cc29833 (diff) | |
parent | 154a5d7537c35959aa646ef8f18daed8c9f1a2be (diff) | |
download | e2fsprogs-1d72214658d339bd4725fe74aa42397df419e914.tar.gz |
Merge branch 'maint' into next
Diffstat (limited to 'misc')
-rw-r--r-- | misc/Makefile.in | 4 | ||||
-rw-r--r-- | misc/e2freefrag.8.in | 23 | ||||
-rw-r--r-- | misc/e2freefrag.c | 100 | ||||
-rw-r--r-- | misc/filefrag.8.in | 6 | ||||
-rw-r--r-- | misc/filefrag.c | 26 | ||||
-rw-r--r-- | misc/tune2fs.c | 149 |
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); } |