From: Rakesh Pandit Date: Mon, 28 Jul 2014 00:04:48 +0000 (-0400) Subject: filefrag: fix block size value X-Git-Tag: v1.42.12~53 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01824c9bbcd2c1037085213f6cd7d591f78db9c5;p=thirdparty%2Fe2fsprogs.git filefrag: fix block size value ioctl(FIGETBSZ) was used to get block size earlier but 2508eaa7 (filefrag: improvements to filefrag FIEMAP handling) moved to fstatfs f_bsize which doesn't work well for many files systems. Block size returned using fstatfs isn't block size but "optimal transfer block size" as per man page. Even stat st_blksize is "preferred I/O block size" and in may file systems it may even vary from file to file (POSIX). This patch changes filefrag to use FIGETBSZ preferentially over f_bsize. [ Modified by tytso to add the fallback to f_bsize if FIGETBSZ fails for some reason ] Signed-off-by: Rakesh Pandit Signed-off-by: Theodore Ts'o --- diff --git a/misc/filefrag.c b/misc/filefrag.c index bb060b6d3..2ce1b9b52 100644 --- a/misc/filefrag.c +++ b/misc/filefrag.c @@ -351,6 +351,7 @@ static int filefrag_fibmap(int fd, int blk_shift, int *num_extents, static int frag_report(const char *filename) { static struct statfs fsinfo; + static unsigned int blksize; ext2fs_struct_stat st; int blk_shift; long fd; @@ -381,22 +382,22 @@ static int frag_report(const char *filename) #endif rc = -errno; perror("stat"); - close(fd); - return rc; + goto out_close; } if (last_device != st.st_dev) { if (fstatfs(fd, &fsinfo) < 0) { rc = -errno; perror("fstatfs"); - close(fd); - return rc; + goto out_close; } + if (ioctl(fd, FIGETBSZ, &blksize) < 0) + blksize = fsinfo.f_bsize; if (verbose) printf("Filesystem type is: %lx\n", (unsigned long)fsinfo.f_type); } - st.st_blksize = fsinfo.f_bsize; + st.st_blksize = blksize; if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0) flags = 0; if (!(flags & EXT4_EXTENTS_FL) && @@ -405,13 +406,13 @@ static int frag_report(const char *filename) is_ext2++; if (is_ext2) { - long cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize * 8); + long cylgroups = div_ceil(fsinfo.f_blocks, blksize * 8); if (verbose && last_device != st.st_dev) printf("Filesystem cylinder groups approximately %ld\n", cylgroups); - data_blocks_per_cyl = fsinfo.f_bsize * 8 - + data_blocks_per_cyl = blksize * 8 - (fsinfo.f_files / 8 / cylgroups) - 3; } last_device = st.st_dev; @@ -420,11 +421,11 @@ static int frag_report(const char *filename) if (width > physical_width) physical_width = width; - numblocks = (st.st_size + fsinfo.f_bsize - 1) / fsinfo.f_bsize; + numblocks = (st.st_size + blksize - 1) / blksize; if (blocksize != 0) blk_shift = int_log2(blocksize); else - blk_shift = int_log2(fsinfo.f_bsize); + blk_shift = int_log2(blksize); width = int_log10(numblocks); if (width > logical_width) @@ -432,7 +433,7 @@ static int frag_report(const char *filename) if (verbose) printf("File size of %s is %llu (%llu block%s of %d bytes)\n", filename, (unsigned long long)st.st_size, - numblocks * fsinfo.f_bsize >> blk_shift, + numblocks * blksize >> blk_shift, numblocks == 1 ? "" : "s", 1 << blk_shift); if (!force_bmap) {