]>
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
29 #include "ext2fs/ext2_fs.h"
30 #include "ext2fs/ext2fs.h"
31 #include "e2freefrag.h"
33 static void usage(const char *prog
)
35 fprintf(stderr
, "usage: %s [-c chunksize in kb] [-h] "
36 "device_name\n", prog
);
42 static int ul_log2(unsigned long arg
)
54 static void init_chunk_info(ext2_filsys fs
, struct chunk_info
*info
)
58 info
->blocksize_bits
= ul_log2((unsigned long)fs
->blocksize
);
59 if (info
->chunkbytes
) {
60 info
->chunkbits
= ul_log2(info
->chunkbytes
);
61 info
->blks_in_chunk
= info
->chunkbytes
>> info
->blocksize_bits
;
63 info
->chunkbits
= ul_log2(DEFAULT_CHUNKSIZE
);
64 info
->blks_in_chunk
= DEFAULT_CHUNKSIZE
>> info
->blocksize_bits
;
68 info
->max
= info
->avg
= 0;
69 info
->real_free_chunks
= 0;
71 for (i
= 0; i
< MAX_HIST
; i
++) {
72 info
->histogram
.fc_chunks
[i
] = 0;
73 info
->histogram
.fc_blocks
[i
] = 0;
77 static void update_chunk_stats(struct chunk_info
*info
,
78 unsigned long chunk_size
)
82 idx
= ul_log2(chunk_size
) + 1;
85 info
->histogram
.fc_chunks
[idx
]++;
86 info
->histogram
.fc_blocks
[idx
] += chunk_size
;
88 if (chunk_size
> info
->max
)
89 info
->max
= chunk_size
;
90 if (chunk_size
< info
->min
)
91 info
->min
= chunk_size
;
92 info
->avg
+= chunk_size
;
93 info
->real_free_chunks
++;
96 static void scan_block_bitmap(ext2_filsys fs
, struct chunk_info
*info
)
98 unsigned long long blocks_count
= ext2fs_blocks_count(fs
->super
);
99 unsigned long long chunks
= (blocks_count
+ info
->blks_in_chunk
) >>
100 (info
->chunkbits
- info
->blocksize_bits
);
101 unsigned long long chunk_num
;
102 unsigned long last_chunk_size
= 0;
103 unsigned long long chunk_start_blk
= 0;
106 for (chunk_num
= 0; chunk_num
< chunks
; chunk_num
++) {
107 unsigned long long blk
, num_blks
;
110 /* Last chunk may be smaller */
111 if (chunk_start_blk
+ info
->blks_in_chunk
> blocks_count
)
112 num_blks
= blocks_count
- chunk_start_blk
;
114 num_blks
= info
->blks_in_chunk
;
118 /* Initialize starting block for first chunk correctly else
119 * there is a segfault when blocksize = 1024 in which case
120 * block_map->start = 1 */
121 for (blk
= 0; blk
< num_blks
; blk
++, chunk_start_blk
++) {
122 if (chunk_num
== 0 && blk
== 0) {
123 blk
= fs
->super
->s_first_data_block
;
124 chunk_start_blk
= blk
;
126 used
= ext2fs_fast_test_block_bitmap2(fs
->block_map
,
127 chunk_start_blk
>> fs
->cluster_ratio_bits
);
133 if (used
&& last_chunk_size
!= 0) {
134 update_chunk_stats(info
, last_chunk_size
);
139 if (chunk_free
== info
->blks_in_chunk
)
142 if (last_chunk_size
!= 0)
143 update_chunk_stats(info
, last_chunk_size
);
146 static errcode_t
get_chunk_info(ext2_filsys fs
, struct chunk_info
*info
,
149 unsigned long total_chunks
;
150 const char *unitp
= "KMGTPEZY";
152 unsigned long start
= 0, end
;
155 scan_block_bitmap(fs
, info
);
157 fprintf(f
, "Total blocks: %llu\nFree blocks: %llu (%0.1f%%)\n",
158 ext2fs_blocks_count(fs
->super
),
159 ext2fs_free_blocks_count(fs
->super
),
160 (double)ext2fs_free_blocks_count(fs
->super
) * 100 /
161 ext2fs_blocks_count(fs
->super
));
163 if (info
->chunkbytes
) {
164 fprintf(f
, "\nChunksize: %lu bytes (%u blocks)\n",
165 info
->chunkbytes
, info
->blks_in_chunk
);
166 total_chunks
= (ext2fs_blocks_count(fs
->super
) +
167 info
->blks_in_chunk
) >>
168 (info
->chunkbits
- info
->blocksize_bits
);
169 fprintf(f
, "Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
170 total_chunks
, info
->free_chunks
,
171 (double)info
->free_chunks
* 100 / total_chunks
);
174 /* Display chunk information in KB */
175 if (info
->real_free_chunks
) {
176 unsigned int scale
= fs
->blocksize
>> 10;
177 info
->min
= info
->min
* scale
;
178 info
->max
= info
->max
* scale
;
179 info
->avg
= info
->avg
/ info
->real_free_chunks
* scale
;
184 fprintf(f
, "\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
185 "Avg. free extent: %lu KB\n", info
->min
, info
->max
, info
->avg
);
186 fprintf(f
, "Num. free extent: %lu\n", info
->real_free_chunks
);
188 fprintf(f
, "\nHISTOGRAM OF FREE EXTENT SIZES:\n");
189 fprintf(f
, "%s : %12s %12s %7s\n", "Extent Size Range",
190 "Free extents", "Free Blocks", "Percent");
191 for (i
= 0; i
< MAX_HIST
; i
++) {
192 end
= 1 << (i
+ info
->blocksize_bits
- units
);
193 if (info
->histogram
.fc_chunks
[i
] != 0) {
196 sprintf(end_str
, "%5lu%c-", end
, *unitp
);
198 strcpy(end_str
, "max ");
199 fprintf(f
, "%5lu%c...%7s : %12lu %12lu %6.2f%%\n",
200 start
, *unitp
, end_str
,
201 info
->histogram
.fc_chunks
[i
],
202 info
->histogram
.fc_blocks
[i
],
203 (double)info
->histogram
.fc_blocks
[i
] * 100 /
204 ext2fs_free_blocks_count(fs
->super
));
207 if (start
== 1<<10) {
217 static void close_device(char *device_name
, ext2_filsys fs
)
219 int retval
= ext2fs_close_free(&fs
);
222 com_err(device_name
, retval
, "while closing the filesystem.\n");
225 static void collect_info(ext2_filsys fs
, struct chunk_info
*chunk_info
, FILE *f
)
227 unsigned int retval
= 0;
229 fprintf(f
, "Device: %s\n", fs
->device_name
);
230 fprintf(f
, "Blocksize: %u bytes\n", fs
->blocksize
);
232 retval
= ext2fs_read_block_bitmap(fs
);
234 com_err(fs
->device_name
, retval
, "while reading block bitmap");
235 close_device(fs
->device_name
, fs
);
239 init_chunk_info(fs
, chunk_info
);
241 retval
= get_chunk_info(fs
, chunk_info
, f
);
243 com_err(fs
->device_name
, retval
, "while collecting chunk info");
244 close_device(fs
->device_name
, fs
);
250 static void open_device(char *device_name
, ext2_filsys
*fs
)
253 int flag
= EXT2_FLAG_FORCE
| EXT2_FLAG_64BITS
;
255 retval
= ext2fs_open(device_name
, flag
, 0, 0, unix_io_manager
, fs
);
257 com_err(device_name
, retval
, "while opening filesystem");
260 (*fs
)->default_bitmap_type
= EXT2FS_BMAP64_RBTREE
;
267 void do_freefrag(int argc
, char **argv
)
269 int main(int argc
, char *argv
[])
272 struct chunk_info chunk_info
;
273 ext2_filsys fs
= NULL
;
279 if (check_fs_open(argv
[0]))
285 add_error_table(&et_ext2_error_table
);
288 memset(&chunk_info
, 0, sizeof(chunk_info
));
290 while ((c
= getopt(argc
, argv
, "c:h")) != EOF
) {
293 chunk_info
.chunkbytes
= strtoull(optarg
, &end
, 0);
295 fprintf(stderr
, "%s: bad chunk size '%s'\n",
299 if (chunk_info
.chunkbytes
&
300 (chunk_info
.chunkbytes
- 1)) {
301 fprintf(stderr
, "%s: chunk size must be a "
302 "power of 2.\n", argv
[0]);
305 chunk_info
.chunkbytes
*= 1024;
315 if (optind
== argc
) {
316 fprintf(stderr
, "%s: missing device name.\n", progname
);
320 device_name
= argv
[optind
];
322 open_device(device_name
, &fs
);
327 if (chunk_info
.chunkbytes
&& (chunk_info
.chunkbytes
< fs
->blocksize
)) {
328 fprintf(stderr
, "%s: chunksize must be greater than or equal "
329 "to filesystem blocksize.\n", progname
);
332 collect_info(fs
, &chunk_info
, stdout
);
334 close_device(device_name
, fs
);