~vorlon/ubuntu/natty/e2fsprogs/multiarch

« back to all changes in this revision

Viewing changes to misc/e2freefrag.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2009-08-25 18:34:46 UTC
  • mfrom: (8.2.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090825183446-p2iuz63g8g4ytlf4
Tags: 1.41.9-1ubuntu1
* Merge from Debian, remaining changes:
  - Do not build-depend on dietlibc-dev, which is universe.
  - Do now allow pkg-create-dbgsym to operate on this package.
  - Use external libblkid and libuuid from util-linux, rather than
    building our own.
  - Do not include /etc/e2fsck.conf and remove on upgrade.

* Included a couple of extra revisions from GIT maint:
  - (ffd8078) e2freefrag: Update manpage to include e2fsprogs version
    and release date
  - (31b5a2b) mke2fs.conf: Use the feature name "extent" instead of
    "extents"
  - (8bafedb) tune2fs: Fix "tune2fs -j <dev>" for extent-enabled
     filesystems.  LP: #416648.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * e2freefrag - report filesystem free-space fragmentation
 
3
 *
 
4
 * Copyright (C) 2009 Sun Microsystems, Inc.
 
5
 *
 
6
 * Author: Rupesh Thakare <rupesh@sun.com>
 
7
 *         Andreas Dilger <adilger@sun.com>
 
8
 *
 
9
 * %Begin-Header%
 
10
 * This file may be redistributed under the terms of the GNU Public
 
11
 * License version 2.
 
12
 * %End-Header%
 
13
 */
 
14
#include <stdio.h>
 
15
#ifdef HAVE_UNISTD_H
 
16
#include <unistd.h>
 
17
#endif
 
18
#ifdef HAVE_STDLIB_H
 
19
#include <stdlib.h>
 
20
#endif
 
21
#ifdef HAVE_GETOPT_H
 
22
#include <getopt.h>
 
23
#else
 
24
extern char *optarg;
 
25
extern int optind;
 
26
#endif
 
27
 
 
28
#include "ext2fs/ext2_fs.h"
 
29
#include "ext2fs/ext2fs.h"
 
30
#include "e2freefrag.h"
 
31
 
 
32
void usage(const char *prog)
 
33
{
 
34
        fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
 
35
                "device_name\n", prog);
 
36
        exit(1);
 
37
}
 
38
 
 
39
static int ul_log2(unsigned long arg)
 
40
{
 
41
        int     l = 0;
 
42
 
 
43
        arg >>= 1;
 
44
        while (arg) {
 
45
                l++;
 
46
                arg >>= 1;
 
47
        }
 
48
        return l;
 
49
}
 
50
 
 
51
void init_chunk_info(ext2_filsys fs, struct chunk_info *info)
 
52
{
 
53
        int i;
 
54
 
 
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;
 
59
        } else {
 
60
                info->chunkbits = ul_log2(DEFAULT_CHUNKSIZE);
 
61
                info->blks_in_chunk = DEFAULT_CHUNKSIZE >> info->blocksize_bits;
 
62
        }
 
63
 
 
64
        info->min = ~0UL;
 
65
        info->max = info->avg = 0;
 
66
        info->real_free_chunks = 0;
 
67
 
 
68
        for (i = 0; i < MAX_HIST; i++) {
 
69
                info->histogram.fc_chunks[i] = 0;
 
70
                info->histogram.fc_blocks[i] = 0;
 
71
        }
 
72
}
 
73
 
 
74
void update_chunk_stats(struct chunk_info *info, unsigned long chunk_size)
 
75
{
 
76
        unsigned long index;
 
77
 
 
78
        index = ul_log2(chunk_size) + 1;
 
79
        if (index >= MAX_HIST)
 
80
                index = MAX_HIST-1;
 
81
        info->histogram.fc_chunks[index]++;
 
82
        info->histogram.fc_blocks[index] += chunk_size;
 
83
 
 
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++;
 
90
}
 
91
 
 
92
void scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
 
93
{
 
94
        unsigned long long blocks_count = fs->super->s_blocks_count;
 
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;
 
100
        int used;
 
101
 
 
102
        for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
 
103
                unsigned long long blk, num_blks;
 
104
                int chunk_free;
 
105
 
 
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;
 
109
                else
 
110
                        num_blks = info->blks_in_chunk;
 
111
 
 
112
                chunk_free = 0;
 
113
 
 
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;
 
121
                        }
 
122
                        used = ext2fs_fast_test_block_bitmap(fs->block_map,
 
123
                                                             chunk_start_blk);
 
124
                        if (!used) {
 
125
                                last_chunk_size++;
 
126
                                chunk_free++;
 
127
                        }
 
128
 
 
129
                        if (used && last_chunk_size != 0) {
 
130
                                update_chunk_stats(info, last_chunk_size);
 
131
                                last_chunk_size = 0;
 
132
                        }
 
133
                }
 
134
 
 
135
                if (chunk_free == info->blks_in_chunk)
 
136
                        info->free_chunks++;
 
137
        }
 
138
        if (last_chunk_size != 0)
 
139
                update_chunk_stats(info, last_chunk_size);
 
140
}
 
141
 
 
142
errcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info)
 
143
{
 
144
        unsigned long total_chunks;
 
145
        char *unitp = "KMGTPEZY";
 
146
        int units = 10;
 
147
        unsigned long start = 0, end, cum;
 
148
        int i, retval = 0;
 
149
 
 
150
        scan_block_bitmap(fs, info);
 
151
 
 
152
        printf("Total blocks: %u\nFree blocks: %u (%0.1f%%)\n",
 
153
               fs->super->s_blocks_count, fs->super->s_free_blocks_count,
 
154
               (double)fs->super->s_free_blocks_count * 100 /
 
155
                                                fs->super->s_blocks_count);
 
156
 
 
157
        if (info->chunkbytes) {
 
158
                printf("\nChunksize: %lu bytes (%u blocks)\n",
 
159
                       info->chunkbytes, info->blks_in_chunk);
 
160
                total_chunks = (fs->super->s_blocks_count +
 
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);
 
166
        }
 
167
 
 
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;
 
174
        } else {
 
175
                info->min = 0;
 
176
        }
 
177
 
 
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);
 
180
 
 
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) {
 
187
                        char end_str[32];
 
188
 
 
189
                        sprintf(end_str, "%5lu%c-", end, *unitp);
 
190
                        if (i == MAX_HIST-1)
 
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);
 
198
                }
 
199
                start = end;
 
200
                if (start == 1<<10) {
 
201
                        start = 1;
 
202
                        units += 10;
 
203
                        unitp++;
 
204
                }
 
205
        }
 
206
 
 
207
        return retval;
 
208
}
 
209
 
 
210
void close_device(char *device_name, ext2_filsys fs)
 
211
{
 
212
        int retval = ext2fs_close(fs);
 
213
 
 
214
        if (retval)
 
215
                com_err(device_name, retval, "while closing the filesystem.\n");
 
216
}
 
217
 
 
218
void collect_info(ext2_filsys fs, struct chunk_info *chunk_info)
 
219
{
 
220
        unsigned int retval = 0, i, free_blks;
 
221
 
 
222
        printf("Device: %s\n", fs->device_name);
 
223
        printf("Blocksize: %u bytes\n", fs->blocksize);
 
224
 
 
225
        retval = ext2fs_read_block_bitmap(fs);
 
226
        if (retval) {
 
227
                com_err(fs->device_name, retval, "while reading block bitmap");
 
228
                close_device(fs->device_name, fs);
 
229
                exit(1);
 
230
        }
 
231
 
 
232
        init_chunk_info(fs, chunk_info);
 
233
 
 
234
        retval = get_chunk_info(fs, chunk_info);
 
235
        if (retval) {
 
236
                com_err(fs->device_name, retval, "while collecting chunk info");
 
237
                close_device(fs->device_name, fs);
 
238
                exit(1);
 
239
        }
 
240
}
 
241
 
 
242
void open_device(char *device_name, ext2_filsys *fs)
 
243
{
 
244
        int retval;
 
245
        int flag = EXT2_FLAG_FORCE;
 
246
 
 
247
        retval = ext2fs_open(device_name, flag, 0, 0, unix_io_manager, fs);
 
248
        if (retval) {
 
249
                com_err(device_name, retval, "while opening filesystem");
 
250
                exit(1);
 
251
        }
 
252
}
 
253
 
 
254
int main(int argc, char *argv[])
 
255
{
 
256
        struct chunk_info chunk_info = { };
 
257
        errcode_t retval = 0;
 
258
        ext2_filsys fs = NULL;
 
259
        char *device_name;
 
260
        char *progname;
 
261
        char c, *end;
 
262
 
 
263
        add_error_table(&et_ext2_error_table);
 
264
        progname = argv[0];
 
265
 
 
266
        while ((c = getopt(argc, argv, "c:h")) != EOF) {
 
267
                switch (c) {
 
268
                case 'c':
 
269
                        chunk_info.chunkbytes = strtoull(optarg, &end, 0);
 
270
                        if (*end != '\0') {
 
271
                                fprintf(stderr, "%s: bad chunk size '%s'\n",
 
272
                                        progname, optarg);
 
273
                                usage(progname);
 
274
                        }
 
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]);
 
279
                                usage(progname);
 
280
                        }
 
281
                        chunk_info.chunkbytes *= 1024;
 
282
                        break;
 
283
                default:
 
284
                        fprintf(stderr, "%s: bad option '%c'\n",
 
285
                                progname, c);
 
286
                case 'h':
 
287
                        usage(progname);
 
288
                        break;
 
289
                }
 
290
        }
 
291
 
 
292
        if (optind == argc) {
 
293
                fprintf(stderr, "%s: missing device name.\n", progname);
 
294
                usage(progname);
 
295
        }
 
296
 
 
297
        device_name = argv[optind];
 
298
 
 
299
        open_device(device_name, &fs);
 
300
 
 
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);
 
304
                exit(1);
 
305
        }
 
306
        collect_info(fs, &chunk_info);
 
307
        close_device(device_name, fs);
 
308
 
 
309
        return retval;
 
310
}