]>
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: %u (%0.1f%%)\n",
158 ext2fs_blocks_count(fs
->super
), fs
->super
->s_free_blocks_count
,
159 (double)fs
->super
->s_free_blocks_count
* 100 /
160 ext2fs_blocks_count(fs
->super
));
162 if (info
->chunkbytes
) {
163 fprintf(f
, "\nChunksize: %lu bytes (%u blocks)\n",
164 info
->chunkbytes
, info
->blks_in_chunk
);
165 total_chunks
= (ext2fs_blocks_count(fs
->super
) +
166 info
->blks_in_chunk
) >>
167 (info
->chunkbits
- info
->blocksize_bits
);
168 fprintf(f
, "Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
169 total_chunks
, info
->free_chunks
,
170 (double)info
->free_chunks
* 100 / total_chunks
);
173 /* Display chunk information in KB */
174 if (info
->real_free_chunks
) {
175 unsigned int scale
= fs
->blocksize
>> 10;
176 info
->min
= info
->min
* scale
;
177 info
->max
= info
->max
* scale
;
178 info
->avg
= info
->avg
/ info
->real_free_chunks
* scale
;
183 fprintf(f
, "\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
184 "Avg. free extent: %lu KB\n", info
->min
, info
->max
, info
->avg
);
185 fprintf(f
, "Num. free extent: %lu\n", info
->real_free_chunks
);
187 fprintf(f
, "\nHISTOGRAM OF FREE EXTENT SIZES:\n");
188 fprintf(f
, "%s : %12s %12s %7s\n", "Extent Size Range",
189 "Free extents", "Free Blocks", "Percent");
190 for (i
= 0; i
< MAX_HIST
; i
++) {
191 end
= 1 << (i
+ info
->blocksize_bits
- units
);
192 if (info
->histogram
.fc_chunks
[i
] != 0) {
195 sprintf(end_str
, "%5lu%c-", end
, *unitp
);
197 strcpy(end_str
, "max ");
198 fprintf(f
, "%5lu%c...%7s : %12lu %12lu %6.2f%%\n",
199 start
, *unitp
, end_str
,
200 info
->histogram
.fc_chunks
[i
],
201 info
->histogram
.fc_blocks
[i
],
202 (double)info
->histogram
.fc_blocks
[i
] * 100 /
203 fs
->super
->s_free_blocks_count
);
206 if (start
== 1<<10) {
216 static void close_device(char *device_name
, ext2_filsys fs
)
218 int retval
= ext2fs_close_free(&fs
);
221 com_err(device_name
, retval
, "while closing the filesystem.\n");
224 static void collect_info(ext2_filsys fs
, struct chunk_info
*chunk_info
, FILE *f
)
226 unsigned int retval
= 0;
228 fprintf(f
, "Device: %s\n", fs
->device_name
);
229 fprintf(f
, "Blocksize: %u bytes\n", fs
->blocksize
);
231 retval
= ext2fs_read_block_bitmap(fs
);
233 com_err(fs
->device_name
, retval
, "while reading block bitmap");
234 close_device(fs
->device_name
, fs
);
238 init_chunk_info(fs
, chunk_info
);
240 retval
= get_chunk_info(fs
, chunk_info
, f
);
242 com_err(fs
->device_name
, retval
, "while collecting chunk info");
243 close_device(fs
->device_name
, fs
);
249 static void open_device(char *device_name
, ext2_filsys
*fs
)
252 int flag
= EXT2_FLAG_FORCE
| EXT2_FLAG_64BITS
;
254 retval
= ext2fs_open(device_name
, flag
, 0, 0, unix_io_manager
, fs
);
256 com_err(device_name
, retval
, "while opening filesystem");
259 (*fs
)->default_bitmap_type
= EXT2FS_BMAP64_RBTREE
;
266 void do_freefrag(int argc
, char **argv
)
268 int main(int argc
, char *argv
[])
271 struct chunk_info chunk_info
;
272 ext2_filsys fs
= NULL
;
278 if (check_fs_open(argv
[0]))
284 add_error_table(&et_ext2_error_table
);
287 memset(&chunk_info
, 0, sizeof(chunk_info
));
289 while ((c
= getopt(argc
, argv
, "c:h")) != EOF
) {
292 chunk_info
.chunkbytes
= strtoull(optarg
, &end
, 0);
294 fprintf(stderr
, "%s: bad chunk size '%s'\n",
298 if (chunk_info
.chunkbytes
&
299 (chunk_info
.chunkbytes
- 1)) {
300 fprintf(stderr
, "%s: chunk size must be a "
301 "power of 2.\n", argv
[0]);
304 chunk_info
.chunkbytes
*= 1024;
314 if (optind
== argc
) {
315 fprintf(stderr
, "%s: missing device name.\n", progname
);
319 device_name
= argv
[optind
];
321 open_device(device_name
, &fs
);
326 if (chunk_info
.chunkbytes
&& (chunk_info
.chunkbytes
< fs
->blocksize
)) {
327 fprintf(stderr
, "%s: chunksize must be greater than or equal "
328 "to filesystem blocksize.\n", progname
);
331 collect_info(fs
, &chunk_info
, stdout
);
333 close_device(device_name
, fs
);