]>
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 scan_block_bitmap(ext2_filsys fs
, struct chunk_info
*info
)
76 unsigned long long blocks_count
= fs
->super
->s_blocks_count
;
77 unsigned long long chunks
= (blocks_count
+ info
->blks_in_chunk
) >>
78 (info
->chunkbits
- info
->blocksize_bits
);
79 unsigned long long chunk_num
;
80 unsigned long last_chunk_size
= 0;
81 unsigned long long chunk_start_blk
= 0;
83 for (chunk_num
= 0; chunk_num
< chunks
; chunk_num
++) {
84 unsigned long long blk
, num_blks
;
87 /* Last chunk may be smaller */
88 if (chunk_start_blk
+ info
->blks_in_chunk
> blocks_count
)
89 num_blks
= blocks_count
- chunk_start_blk
;
91 num_blks
= info
->blks_in_chunk
;
95 /* Initialize starting block for first chunk correctly else
96 * there is a segfault when blocksize = 1024 in which case
97 * block_map->start = 1 */
98 for (blk
= (chunk_num
== 0 ? fs
->super
->s_first_data_block
: 0);
99 blk
< num_blks
; blk
++, chunk_start_blk
++) {
100 int used
= ext2fs_fast_test_block_bitmap(fs
->block_map
,
107 if (used
&& last_chunk_size
!= 0) {
110 index
= ul_log2(last_chunk_size
) + 1;
111 info
->histogram
.fc_chunks
[index
]++;
112 info
->histogram
.fc_blocks
[index
] +=
115 if (last_chunk_size
> info
->max
)
116 info
->max
= last_chunk_size
;
117 if (last_chunk_size
< info
->min
)
118 info
->min
= last_chunk_size
;
119 info
->avg
+= last_chunk_size
;
121 info
->real_free_chunks
++;
126 if (chunk_free
== info
->blks_in_chunk
)
131 errcode_t
get_chunk_info(ext2_filsys fs
, struct chunk_info
*info
)
133 unsigned long total_chunks
;
134 char *unitp
= "KMGTPEZY";
136 unsigned long start
= 0, end
, cum
;
139 scan_block_bitmap(fs
, info
);
141 printf("Total blocks: %u\nFree blocks: %u (%0.1f%%)\n",
142 fs
->super
->s_blocks_count
, fs
->super
->s_free_blocks_count
,
143 (double)fs
->super
->s_free_blocks_count
* 100 /
144 fs
->super
->s_blocks_count
);
146 if (info
->chunkbytes
) {
147 printf("\nChunksize: %lu bytes (%u blocks)\n",
148 info
->chunkbytes
, info
->blks_in_chunk
);
149 total_chunks
= (fs
->super
->s_blocks_count
+
150 info
->blks_in_chunk
) >>
151 (info
->chunkbits
- info
->blocksize_bits
);
152 printf("Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
153 total_chunks
, info
->free_chunks
,
154 (double)info
->free_chunks
* 100 / total_chunks
);
157 /* Display chunk information in KB */
158 if (info
->real_free_chunks
) {
159 info
->min
= (info
->min
* fs
->blocksize
) >> 10;
160 info
->max
= (info
->max
* fs
->blocksize
) >> 10;
161 info
->avg
= (info
->avg
/ info
->real_free_chunks
*
162 fs
->blocksize
) >> 10;
167 printf("\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
168 "Avg. free extent: %lu KB\n", info
->min
, info
->max
, info
->avg
);
170 printf("\nHISTOGRAM OF FREE EXTENT SIZES:\n");
171 printf("%s : %12s %12s %7s\n", "Extent Size Range", "Free extents",
172 "Free Blocks", "Percent");
173 for (i
= 0; i
< MAX_HIST
; i
++) {
174 end
= 1 << (i
+ info
->blocksize_bits
- units
);
175 if (info
->histogram
.fc_chunks
[i
] != 0)
176 printf("%5lu%c...%5lu%c- : %12lu %12lu %6.2f%%\n",
177 start
, *unitp
, end
, *unitp
,
178 info
->histogram
.fc_chunks
[i
],
179 info
->histogram
.fc_blocks
[i
],
180 (double)info
->histogram
.fc_blocks
[i
] * 100 /
181 fs
->super
->s_free_blocks_count
);
183 if (start
== 1<<10) {
193 void close_device(char *device_name
, ext2_filsys fs
)
195 int retval
= ext2fs_close(fs
);
198 com_err(device_name
, retval
, "while closing the filesystem.\n");
201 void collect_info(ext2_filsys fs
, struct chunk_info
*chunk_info
)
203 unsigned int retval
= 0, i
, free_blks
;
205 printf("Device: %s\n", fs
->device_name
);
206 printf("Blocksize: %u bytes\n", fs
->blocksize
);
208 retval
= ext2fs_read_block_bitmap(fs
);
210 com_err(fs
->device_name
, retval
, "while reading block bitmap");
211 close_device(fs
->device_name
, fs
);
215 init_chunk_info(fs
, chunk_info
);
217 retval
= get_chunk_info(fs
, chunk_info
);
219 com_err(fs
->device_name
, retval
, "while collecting chunk info");
220 close_device(fs
->device_name
, fs
);
225 void open_device(char *device_name
, ext2_filsys
*fs
)
228 int flag
= EXT2_FLAG_FORCE
;
230 retval
= ext2fs_open(device_name
, flag
, 0, 0, unix_io_manager
, fs
);
232 com_err(device_name
, retval
, "while opening filesystem");
237 int main(int argc
, char *argv
[])
239 struct chunk_info chunk_info
= { };
240 errcode_t retval
= 0;
241 ext2_filsys fs
= NULL
;
246 add_error_table(&et_ext2_error_table
);
249 while ((c
= getopt(argc
, argv
, "c:h")) != EOF
) {
252 chunk_info
.chunkbytes
= strtoull(optarg
, &end
, 0);
254 fprintf(stderr
, "%s: bad chunk size '%s'\n",
258 if (chunk_info
.chunkbytes
&
259 (chunk_info
.chunkbytes
- 1)) {
260 fprintf(stderr
, "%s: chunk size must be a "
261 "power of 2.\n", argv
[0]);
264 chunk_info
.chunkbytes
*= 1024;
267 fprintf(stderr
, "%s: bad option '%c'\n",
275 if (optind
== argc
) {
276 fprintf(stderr
, "%s: missing device name.\n", progname
);
280 device_name
= argv
[optind
];
282 open_device(device_name
, &fs
);
284 if (chunk_info
.chunkbytes
&& (chunk_info
.chunkbytes
< fs
->blocksize
)) {
285 fprintf(stderr
, "%s: chunksize must be greater than or equal "
286 "to filesystem blocksize.\n", progname
);
289 collect_info(fs
, &chunk_info
);
290 close_device(device_name
, fs
);