]>
git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - misc/e2freefrag.c
2 * e2freefrag - report filesystem free-space fragmentation
4 * Copyright (C) 2009 Sun Microsystems, Inc.
6 * Author: Rupesh Thakare <rupesh@sun.com>
7 * Andreas Dilger <adilger@sun.com>
10 * This file may be redistributed under the terms of the GNU Public
28 #include "ext2fs/ext2_fs.h"
29 #include "ext2fs/ext2fs.h"
30 #include "e2freefrag.h"
32 void usage(const char *prog
)
34 fprintf(stderr
, "usage: %s [-c chunksize in kb] [-h] "
35 "device_name\n", prog
);
39 static int ul_log2(unsigned long arg
)
51 void init_chunk_info(ext2_filsys fs
, struct chunk_info
*info
)
55 info
->blocksize_bits
= ul_log2((unsigned long)fs
->blocksize
);
56 if (info
->chunkbytes
) {
57 info
->chunkbits
= ul_log2(info
->chunkbytes
);
58 info
->blks_in_chunk
= info
->chunkbytes
>> info
->blocksize_bits
;
60 info
->chunkbits
= ul_log2(DEFAULT_CHUNKSIZE
);
61 info
->blks_in_chunk
= DEFAULT_CHUNKSIZE
>> info
->blocksize_bits
;
65 info
->max
= info
->avg
= 0;
66 info
->real_free_chunks
= 0;
68 for (i
= 0; i
< MAX_HIST
; i
++) {
69 info
->histogram
.fc_chunks
[i
] = 0;
70 info
->histogram
.fc_blocks
[i
] = 0;
74 void update_chunk_stats(struct chunk_info
*info
, unsigned long chunk_size
)
78 index
= ul_log2(chunk_size
) + 1;
79 if (index
>= MAX_HIST
)
81 info
->histogram
.fc_chunks
[index
]++;
82 info
->histogram
.fc_blocks
[index
] += chunk_size
;
84 if (chunk_size
> info
->max
)
85 info
->max
= chunk_size
;
86 if (chunk_size
< info
->min
)
87 info
->min
= chunk_size
;
88 info
->avg
+= chunk_size
;
89 info
->real_free_chunks
++;
92 void scan_block_bitmap(ext2_filsys fs
, struct chunk_info
*info
)
94 unsigned long long blocks_count
= ext2fs_blocks_count(fs
->super
);
95 unsigned long long chunks
= (blocks_count
+ info
->blks_in_chunk
) >>
96 (info
->chunkbits
- info
->blocksize_bits
);
97 unsigned long long chunk_num
;
98 unsigned long last_chunk_size
= 0;
99 unsigned long long chunk_start_blk
= 0;
102 for (chunk_num
= 0; chunk_num
< chunks
; chunk_num
++) {
103 unsigned long long blk
, num_blks
;
106 /* Last chunk may be smaller */
107 if (chunk_start_blk
+ info
->blks_in_chunk
> blocks_count
)
108 num_blks
= blocks_count
- chunk_start_blk
;
110 num_blks
= info
->blks_in_chunk
;
114 /* Initialize starting block for first chunk correctly else
115 * there is a segfault when blocksize = 1024 in which case
116 * block_map->start = 1 */
117 for (blk
= 0; blk
< num_blks
; blk
++, chunk_start_blk
++) {
118 if (chunk_num
== 0 && blk
== 0) {
119 blk
= fs
->super
->s_first_data_block
;
120 chunk_start_blk
= blk
;
122 used
= ext2fs_fast_test_block_bitmap2(fs
->block_map
,
129 if (used
&& last_chunk_size
!= 0) {
130 update_chunk_stats(info
, last_chunk_size
);
135 if (chunk_free
== info
->blks_in_chunk
)
138 if (last_chunk_size
!= 0)
139 update_chunk_stats(info
, last_chunk_size
);
142 errcode_t
get_chunk_info(ext2_filsys fs
, struct chunk_info
*info
)
144 unsigned long total_chunks
;
145 char *unitp
= "KMGTPEZY";
147 unsigned long start
= 0, end
, cum
;
150 scan_block_bitmap(fs
, info
);
152 printf("Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
153 ext2fs_blocks_count(fs
->super
), fs
->super
->s_free_blocks_count
,
154 (double)fs
->super
->s_free_blocks_count
* 100 /
155 ext2fs_blocks_count(fs
->super
));
157 if (info
->chunkbytes
) {
158 printf("\nChunksize: %lu bytes (%u blocks)\n",
159 info
->chunkbytes
, info
->blks_in_chunk
);
160 total_chunks
= (ext2fs_blocks_count(fs
->super
) +
161 info
->blks_in_chunk
) >>
162 (info
->chunkbits
- info
->blocksize_bits
);
163 printf("Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
164 total_chunks
, info
->free_chunks
,
165 (double)info
->free_chunks
* 100 / total_chunks
);
168 /* Display chunk information in KB */
169 if (info
->real_free_chunks
) {
170 info
->min
= (info
->min
* fs
->blocksize
) >> 10;
171 info
->max
= (info
->max
* fs
->blocksize
) >> 10;
172 info
->avg
= (info
->avg
/ info
->real_free_chunks
*
173 fs
->blocksize
) >> 10;
178 printf("\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
179 "Avg. free extent: %lu KB\n", info
->min
, info
->max
, info
->avg
);
181 printf("\nHISTOGRAM OF FREE EXTENT SIZES:\n");
182 printf("%s : %12s %12s %7s\n", "Extent Size Range", "Free extents",
183 "Free Blocks", "Percent");
184 for (i
= 0; i
< MAX_HIST
; i
++) {
185 end
= 1 << (i
+ info
->blocksize_bits
- units
);
186 if (info
->histogram
.fc_chunks
[i
] != 0) {
189 sprintf(end_str
, "%5lu%c-", end
, *unitp
);
191 strcpy(end_str
, "max ");
192 printf("%5lu%c...%7s : %12lu %12lu %6.2f%%\n",
193 start
, *unitp
, end_str
,
194 info
->histogram
.fc_chunks
[i
],
195 info
->histogram
.fc_blocks
[i
],
196 (double)info
->histogram
.fc_blocks
[i
] * 100 /
197 fs
->super
->s_free_blocks_count
);
200 if (start
== 1<<10) {
210 void close_device(char *device_name
, ext2_filsys fs
)
212 int retval
= ext2fs_close(fs
);
215 com_err(device_name
, retval
, "while closing the filesystem.\n");
218 void collect_info(ext2_filsys fs
, struct chunk_info
*chunk_info
)
220 unsigned int retval
= 0, i
, free_blks
;
222 printf("Device: %s\n", fs
->device_name
);
223 printf("Blocksize: %u bytes\n", fs
->blocksize
);
225 retval
= ext2fs_read_block_bitmap(fs
);
227 com_err(fs
->device_name
, retval
, "while reading block bitmap");
228 close_device(fs
->device_name
, fs
);
232 init_chunk_info(fs
, chunk_info
);
234 retval
= get_chunk_info(fs
, chunk_info
);
236 com_err(fs
->device_name
, retval
, "while collecting chunk info");
237 close_device(fs
->device_name
, fs
);
242 void open_device(char *device_name
, ext2_filsys
*fs
)
245 int flag
= EXT2_FLAG_FORCE
;
247 retval
= ext2fs_open(device_name
, flag
, 0, 0, unix_io_manager
, fs
);
249 com_err(device_name
, retval
, "while opening filesystem");
254 int main(int argc
, char *argv
[])
256 struct chunk_info chunk_info
= { };
257 errcode_t retval
= 0;
258 ext2_filsys fs
= NULL
;
263 add_error_table(&et_ext2_error_table
);
266 while ((c
= getopt(argc
, argv
, "c:h")) != EOF
) {
269 chunk_info
.chunkbytes
= strtoull(optarg
, &end
, 0);
271 fprintf(stderr
, "%s: bad chunk size '%s'\n",
275 if (chunk_info
.chunkbytes
&
276 (chunk_info
.chunkbytes
- 1)) {
277 fprintf(stderr
, "%s: chunk size must be a "
278 "power of 2.\n", argv
[0]);
281 chunk_info
.chunkbytes
*= 1024;
284 fprintf(stderr
, "%s: bad option '%c'\n",
292 if (optind
== argc
) {
293 fprintf(stderr
, "%s: missing device name.\n", progname
);
297 device_name
= argv
[optind
];
299 open_device(device_name
, &fs
);
301 if (chunk_info
.chunkbytes
&& (chunk_info
.chunkbytes
< fs
->blocksize
)) {
302 fprintf(stderr
, "%s: chunksize must be greater than or equal "
303 "to filesystem blocksize.\n", progname
);
306 collect_info(fs
, &chunk_info
);
307 close_device(device_name
, fs
);