10b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o/*
20b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * e2freefrag - report filesystem free-space fragmentation
30b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
40b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * Copyright (C) 2009 Sun Microsystems, Inc.
50b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
60b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * Author: Rupesh Thakare <rupesh@sun.com>
70b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *         Andreas Dilger <adilger@sun.com>
80b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
90b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * %Begin-Header%
100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * This file may be redistributed under the terms of the GNU Public
110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * License version 2.
120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * %End-Header%
130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o */
14d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <stdio.h>
160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_UNISTD_H
170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <unistd.h>
180b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_STDLIB_H
200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <stdlib.h>
210b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
220b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_GETOPT_H
230b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <getopt.h>
240b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#else
250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oextern char *optarg;
260b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oextern int optind;
270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "ext2fs/ext2_fs.h"
300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "ext2fs/ext2fs.h"
310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "e2freefrag.h"
320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
333cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void usage(const char *prog)
340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		"device_name\n", prog);
375e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#ifndef DEBUGFS
380b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	exit(1);
395e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#endif
400b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
420b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ostatic int ul_log2(unsigned long arg)
430b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        int     l = 0;
450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
460b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        arg >>= 1;
470b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        while (arg) {
480b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                l++;
490b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                arg >>= 1;
500b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        }
510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        return l;
520b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
530b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
543cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
550b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
560b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int i;
570b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
580b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->blocksize_bits = ul_log2((unsigned long)fs->blocksize);
59cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (info->chunkbytes) {
60cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->chunkbits = ul_log2(info->chunkbytes);
61cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->blks_in_chunk = info->chunkbytes >> info->blocksize_bits;
62cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	} else {
63cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->chunkbits = ul_log2(DEFAULT_CHUNKSIZE);
64cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->blks_in_chunk = DEFAULT_CHUNKSIZE >> info->blocksize_bits;
65cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	}
660b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
670b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->min = ~0UL;
680b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->max = info->avg = 0;
690b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->real_free_chunks = 0;
700b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
71ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger	for (i = 0; i < MAX_HIST; i++) {
72ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger		info->histogram.fc_chunks[i] = 0;
73ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger		info->histogram.fc_blocks[i] = 0;
74ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger	}
750b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
760b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
773cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void update_chunk_stats(struct chunk_info *info,
783cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o			       unsigned long chunk_size)
791e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o{
803cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	unsigned long idx;
811e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
823cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	idx = ul_log2(chunk_size) + 1;
833cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	if (idx >= MAX_HIST)
843cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o		idx = MAX_HIST-1;
853cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	info->histogram.fc_chunks[idx]++;
863cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	info->histogram.fc_blocks[idx] += chunk_size;
871e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
881e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (chunk_size > info->max)
891e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		info->max = chunk_size;
901e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (chunk_size < info->min)
911e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		info->min = chunk_size;
921e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->avg += chunk_size;
931e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->real_free_chunks++;
941e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o}
951e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
963cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
970b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
984efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	unsigned long long blocks_count = ext2fs_blocks_count(fs->super);
990b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunks = (blocks_count + info->blks_in_chunk) >>
1000b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				(info->chunkbits - info->blocksize_bits);
1010b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunk_num;
1020b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long last_chunk_size = 0;
1030b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunk_start_blk = 0;
1043e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o	int used;
1050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
1070b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		unsigned long long blk, num_blks;
1080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		int chunk_free;
1090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		/* Last chunk may be smaller */
1110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (chunk_start_blk + info->blks_in_chunk > blocks_count)
1120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			num_blks = blocks_count - chunk_start_blk;
1130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		else
1140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			num_blks = info->blks_in_chunk;
1150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		chunk_free = 0;
1170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1180b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		/* Initialize starting block for first chunk correctly else
1190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		 * there is a segfault when blocksize = 1024 in which case
1200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		 * block_map->start = 1 */
1213e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o		for (blk = 0; blk < num_blks; blk++, chunk_start_blk++) {
1223e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o			if (chunk_num == 0 && blk == 0) {
1233e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o				blk = fs->super->s_first_data_block;
1243e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o				chunk_start_blk = blk;
1253e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o			}
1263c041a514cf65c65e102ff22e0dee2a3fa724873Valerie Aurora Henson			used = ext2fs_fast_test_block_bitmap2(fs->block_map,
127554bc091b7e8a24acc737ab68bc00d2e04354653Robin Dong				chunk_start_blk >> fs->cluster_ratio_bits);
1280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (!used) {
1290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				last_chunk_size++;
1300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				chunk_free++;
1310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
1320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (used && last_chunk_size != 0) {
1341e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o				update_chunk_stats(info, last_chunk_size);
1350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				last_chunk_size = 0;
1360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
1370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
1380b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1390b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (chunk_free == info->blks_in_chunk)
1400b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			info->free_chunks++;
1410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
1421e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (last_chunk_size != 0)
1431e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		update_chunk_stats(info, last_chunk_size);
1440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
1450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1463cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info,
1473cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o				FILE *f)
1480b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
1490b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long total_chunks;
1503cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	const char *unitp = "KMGTPEZY";
1510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int units = 10;
152cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger	unsigned long start = 0, end;
1530b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int i, retval = 0;
1540b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1550b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	scan_block_bitmap(fs, info);
1560b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1575e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
1585e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		ext2fs_blocks_count(fs->super), fs->super->s_free_blocks_count,
1595e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		(double)fs->super->s_free_blocks_count * 100 /
1605e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		ext2fs_blocks_count(fs->super));
1610b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
162cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (info->chunkbytes) {
1635e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		fprintf(f, "\nChunksize: %lu bytes (%u blocks)\n",
1645e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o			info->chunkbytes, info->blks_in_chunk);
1654efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson		total_chunks = (ext2fs_blocks_count(fs->super) +
166cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o				info->blks_in_chunk) >>
167cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o			(info->chunkbits - info->blocksize_bits);
1685e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		fprintf(f, "Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
1695e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o			total_chunks, info->free_chunks,
1705e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o			(double)info->free_chunks * 100 / total_chunks);
171cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	}
1720b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1730b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	/* Display chunk information in KB */
1740b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (info->real_free_chunks) {
175d05508956734d55f7ee286085a1f6570d11848b7Theodore Ts'o		unsigned int scale = fs->blocksize >> 10;
176d05508956734d55f7ee286085a1f6570d11848b7Theodore Ts'o		info->min = info->min * scale;
177d05508956734d55f7ee286085a1f6570d11848b7Theodore Ts'o		info->max = info->max * scale;
178d05508956734d55f7ee286085a1f6570d11848b7Theodore Ts'o		info->avg = info->avg / info->real_free_chunks * scale;
1790b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	} else {
1800b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		info->min = 0;
1810b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
1820b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1835e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
1845e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		"Avg. free extent: %lu KB\n", info->min, info->max, info->avg);
1855e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "Num. free extent: %lu\n", info->real_free_chunks);
1860b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1875e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "\nHISTOGRAM OF FREE EXTENT SIZES:\n");
1885e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "%s :  %12s  %12s  %7s\n", "Extent Size Range",
1895e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		"Free extents", "Free Blocks", "Percent");
1900b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	for (i = 0; i < MAX_HIST; i++) {
1910b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		end = 1 << (i + info->blocksize_bits - units);
1921e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		if (info->histogram.fc_chunks[i] != 0) {
1931e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			char end_str[32];
1941e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
1951e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			sprintf(end_str, "%5lu%c-", end, *unitp);
1961e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			if (i == MAX_HIST-1)
1971e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o				strcpy(end_str, "max ");
1985e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o			fprintf(f, "%5lu%c...%7s  :  %12lu  %12lu  %6.2f%%\n",
1995e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o				start, *unitp, end_str,
2005e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o				info->histogram.fc_chunks[i],
2015e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o				info->histogram.fc_blocks[i],
2025e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o				(double)info->histogram.fc_blocks[i] * 100 /
2035e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o				fs->super->s_free_blocks_count);
2041e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		}
2050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		start = end;
2060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (start == 1<<10) {
2070b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			start = 1;
2080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			units += 10;
2090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			unitp++;
2100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
2110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	return retval;
2140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2163cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void close_device(char *device_name, ext2_filsys fs)
2170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
21847fee2ef6a23ae06f680336ffde57caa64604a4cLukas Czerner	int retval = ext2fs_close_free(&fs);
2190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval)
2210b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(device_name, retval, "while closing the filesystem.\n");
2220b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2230b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2243cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void collect_info(ext2_filsys fs, struct chunk_info *chunk_info, FILE *f)
2250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
226cf5301d7f2c3bbed3d26600335102414cbf0c4baAndreas Dilger	unsigned int retval = 0;
2270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2285e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "Device: %s\n", fs->device_name);
2295e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fprintf(f, "Blocksize: %u bytes\n", fs->blocksize);
2300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	retval = ext2fs_read_block_bitmap(fs);
2320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(fs->device_name, retval, "while reading block bitmap");
2340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		close_device(fs->device_name, fs);
2350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2380b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	init_chunk_info(fs, chunk_info);
2390b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2405e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	retval = get_chunk_info(fs, chunk_info, f);
2410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2420b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(fs->device_name, retval, "while collecting chunk info");
2430b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                close_device(fs->device_name, fs);
2440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2460b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2470b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2483cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o#ifndef DEBUGFS
2493cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'ostatic void open_device(char *device_name, ext2_filsys *fs)
2500b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
2510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int retval;
252ea2d3788621cec5ed067280c7d228ec8897d2208Theodore Ts'o	int flag = EXT2_FLAG_FORCE | EXT2_FLAG_64BITS;
2530b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2540b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	retval = ext2fs_open(device_name, flag, 0, 0, unix_io_manager, fs);
2550b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2560b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(device_name, retval, "while opening filesystem");
2570b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2580b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
259ea2d3788621cec5ed067280c7d228ec8897d2208Theodore Ts'o	(*fs)->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
2600b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2613cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o#endif
2620b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2635e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#ifdef DEBUGFS
2645e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#include "debugfs.h"
2655e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o
2665e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'ovoid do_freefrag(int argc, char **argv)
2675e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#else
2680b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oint main(int argc, char *argv[])
2695e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#endif
2700b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
2713cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	struct chunk_info chunk_info;
2720b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	ext2_filsys fs = NULL;
2730b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	char *progname;
274b887f08f959fa3ef4ead9b6e2fd71becf4877a40Mike Frysinger	char *end;
275b887f08f959fa3ef4ead9b6e2fd71becf4877a40Mike Frysinger	int c;
2760b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2775e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#ifdef DEBUGFS
2785e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	if (check_fs_open(argv[0]))
2795e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o		return;
280bf140bf29866991a3711688a5182fc5b1ae7c7cdArtemiy Volkov	reset_getopt();
2815e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#else
2823cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	char *device_name;
2833cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o
284137a7dc05c80cd4e0a4e7aeb21ec79f800a9eecdTheodore Ts'o	add_error_table(&et_ext2_error_table);
2855e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#endif
2860b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	progname = argv[0];
2873cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	memset(&chunk_info, 0, sizeof(chunk_info));
2880b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2890b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	while ((c = getopt(argc, argv, "c:h")) != EOF) {
2900b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		switch (c) {
2910b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		case 'c':
2920b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			chunk_info.chunkbytes = strtoull(optarg, &end, 0);
2930b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (*end != '\0') {
2940b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				fprintf(stderr, "%s: bad chunk size '%s'\n",
2950b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o					progname, optarg);
2960b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				usage(progname);
2970b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
2980b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (chunk_info.chunkbytes &
2990b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			    (chunk_info.chunkbytes - 1)) {
3000b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				fprintf(stderr, "%s: chunk size must be a "
301aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o					"power of 2.\n", argv[0]);
3020b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				usage(progname);
3030b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
3040b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			chunk_info.chunkbytes *= 1024;
3050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			break;
3060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		case 'h':
3074ebbc0a310b8c2dc239a6b4a99e65331872dcf9aEric Sandeen		default:
3080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			usage(progname);
3090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			break;
3100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
3110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
3120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
3135e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#ifndef DEBUGFS
3140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (optind == argc) {
3150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		fprintf(stderr, "%s: missing device name.\n", progname);
3160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		usage(progname);
3170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
3180b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
3190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	device_name = argv[optind];
3200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
3210b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	open_device(device_name, &fs);
3225e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#else
3235e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	fs = current_fs;
3245e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#endif
3250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
326cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (chunk_info.chunkbytes && (chunk_info.chunkbytes < fs->blocksize)) {
3270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		fprintf(stderr, "%s: chunksize must be greater than or equal "
3280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			"to filesystem blocksize.\n", progname);
3290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
3300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
3315e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o	collect_info(fs, &chunk_info, stdout);
3325e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#ifndef DEBUGFS
3330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	close_device(device_name, fs);
3340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
3353cebf9c1029ca983ebbbae79f7905a02d087ff98Theodore Ts'o	return 0;
3365e96c5721d58acfbf9d76b62214f6ae421fe4e6bTheodore Ts'o#endif
3370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
338