1
/* -*- mode: c; c-basic-offset: 8; -*-
2
* vim: noexpandtab sw=8 ts=8 sts=0:
6
* Shared routines for the ocfs2 o2info utility
8
* Copyright (C) 2010 Oracle. All rights reserved.
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public
12
* License version 2 as published by the Free Software Foundation.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* General Public License for more details.
20
#define _XOPEN_SOURCE 600
21
#define _LARGEFILE64_SOURCE
26
#include <sys/ioctl.h>
29
#include "ocfs2/ocfs2.h"
30
#include "ocfs2/bitops.h"
31
#include "ocfs2-kernel/fiemap.h"
32
#include "tools-internal/verbose.h"
33
#include "libo2info.h"
35
int o2info_get_fs_features(ocfs2_filesys *fs, struct o2info_fs_features *ofs)
38
struct ocfs2_super_block *sb = NULL;
40
memset(ofs, 0, sizeof(*ofs));
42
sb = OCFS2_RAW_SB(fs->fs_super);
43
ofs->compat = sb->s_feature_compat;
44
ofs->incompat = sb->s_feature_incompat;
45
ofs->rocompat = sb->s_feature_ro_compat;
50
int o2info_get_volinfo(ocfs2_filesys *fs, struct o2info_volinfo *vf)
53
struct ocfs2_super_block *sb = NULL;
55
memset(vf, 0, sizeof(*vf));
57
sb = OCFS2_RAW_SB(fs->fs_super);
58
vf->blocksize = fs->fs_blocksize;
59
vf->clustersize = fs->fs_clustersize;
60
vf->maxslots = sb->s_max_slots;
61
memcpy(vf->label, sb->s_label, OCFS2_MAX_VOL_LABEL_LEN);
62
memcpy(vf->uuid_str, fs->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
63
rc = o2info_get_fs_features(fs, &(vf->ofs));
68
int o2info_get_mkfs(ocfs2_filesys *fs, struct o2info_mkfs *oms)
73
struct ocfs2_dinode *di = NULL;
75
memset(oms, 0, sizeof(*oms));
77
err = ocfs2_malloc_block(fs->fs_io, &buf);
79
tcom_err(err, "while allocating buffer");
83
err = ocfs2_lookup_system_inode(fs, JOURNAL_SYSTEM_INODE, 0, &blkno);
85
tcom_err(err, "while looking up journal system inode");
89
err = ocfs2_read_inode(fs, blkno, buf);
91
tcom_err(err, "while reading journal system inode");
95
di = (struct ocfs2_dinode *)buf;
96
oms->journal_size = di->i_size;
97
err = o2info_get_volinfo(fs, &(oms->ovf));
106
int o2info_get_freeinode(ocfs2_filesys *fs, struct o2info_freeinode *ofi)
111
uint64_t inode_alloc;
113
struct ocfs2_dinode *dinode_alloc = NULL;
114
struct ocfs2_chain_list *cl = NULL;
115
struct ocfs2_chain_rec *rec = NULL;
116
struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super);
118
ofi->slotnum = sb->s_max_slots;
120
ret = ocfs2_malloc_block(fs->fs_io, &block);
122
tcom_err(ret, "while allocating block buffer");
126
dinode_alloc = (struct ocfs2_dinode *)block;
128
for (i = 0; i < ofi->slotnum; i++) {
130
ofi->fi[i].total = ofi->fi[i].free = 0;
132
ret = ocfs2_lookup_system_inode(fs, INODE_ALLOC_SYSTEM_INODE,
135
tcom_err(ret, "while looking up the global"
140
ret = ocfs2_read_inode(fs, inode_alloc, (char *)dinode_alloc);
142
tcom_err(ret, "reading global_bitmap inode "
143
"%"PRIu64" for stats", inode_alloc);
147
cl = &(dinode_alloc->id2.i_chain);
149
for (j = 0; j < cl->cl_next_free_rec; j++) {
150
rec = &(cl->cl_recs[j]);
151
ofi->fi[i].total += rec->c_total;
152
ofi->fi[i].free += rec->c_free;
162
static int ul_log2(unsigned long arg)
175
static void o2info_update_freefrag_stats(struct o2info_freefrag *off,
176
unsigned int chunksize)
180
index = ul_log2(chunksize);
181
if (index >= OCFS2_INFO_MAX_HIST)
182
index = OCFS2_INFO_MAX_HIST - 1;
184
off->histogram.fc_chunks[index]++;
185
off->histogram.fc_clusters[index] += chunksize;
187
if (chunksize > off->max)
188
off->max = chunksize;
190
if (chunksize < off->min)
191
off->min = chunksize;
193
off->avg += chunksize;
194
off->free_chunks_real++;
197
static int o2info_scan_global_bitmap_chain(ocfs2_filesys *fs,
198
struct ocfs2_chain_rec *rec,
199
struct o2info_freefrag *off)
205
struct ocfs2_group_desc *bg = NULL;
207
unsigned int max_bits, num_clusters;
208
unsigned int offset = 0, cluster, chunk;
209
unsigned int chunk_free, last_chunksize = 0;
214
ret = ocfs2_malloc_block(fs->fs_io, &block);
216
tcom_err(ret, "while allocating block buffer");
222
blkno = rec->c_blkno;
224
blkno = bg->bg_next_group;
226
ret = ocfs2_read_blocks(fs, blkno, 1, block);
228
tcom_err(ret, "while reading group descriptor "
229
"%"PRIu64" for stats", blkno);
233
bg = (struct ocfs2_group_desc *)block;
235
if (!bg->bg_free_bits_count)
238
max_bits = bg->bg_bits;
241
for (chunk = 0; chunk < off->chunks_in_group; chunk++) {
244
* last chunk may be not an entire one.
246
if ((offset + off->clusters_in_chunk) > max_bits)
247
num_clusters = max_bits - offset;
249
num_clusters = off->clusters_in_chunk;
253
for (cluster = 0; cluster < num_clusters; cluster++) {
254
used = ocfs2_test_bit(offset,
255
(unsigned long *)bg->bg_bitmap);
261
if (used && (last_chunksize)) {
262
o2info_update_freefrag_stats(off,
270
if (chunk_free == off->clusters_in_chunk)
275
* need to update the info of last free chunk.
278
o2info_update_freefrag_stats(off, last_chunksize);
280
} while (bg->bg_next_group);
289
static int o2info_scan_global_bitmap(ocfs2_filesys *fs,
290
struct ocfs2_chain_list *cl,
291
struct o2info_freefrag *off)
294
struct ocfs2_chain_rec *rec = NULL;
296
off->chunks_in_group = (cl->cl_cpg / off->clusters_in_chunk) + 1;
298
for (i = 0; i < cl->cl_next_free_rec; i++) {
299
rec = &(cl->cl_recs[i]);
300
ret = o2info_scan_global_bitmap_chain(fs, rec, off);
308
int o2info_get_freefrag(ocfs2_filesys *fs, struct o2info_freefrag *off)
314
struct ocfs2_dinode *gb_di = NULL;
315
struct ocfs2_chain_list *cl = NULL;
317
ret = ocfs2_malloc_block(fs->fs_io, &block);
319
tcom_err(ret, "while allocating block buffer");
323
gb_di = (struct ocfs2_dinode *)block;
325
ret = ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE,
328
tcom_err(ret, "while looking up the global bitmap inode");
332
ret = ocfs2_read_inode(fs, gb_inode, (char *)gb_di);
334
tcom_err(ret, "reading global_bitmap inode "
335
"%"PRIu64" for stats", gb_inode);
339
off->clusters = gb_di->id1.bitmap1.i_total;
340
off->free_clusters = gb_di->id1.bitmap1.i_total -
341
gb_di->id1.bitmap1.i_used;
343
off->total_chunks = (off->clusters + off->clusters_in_chunk) >>
344
(off->chunkbits - off->clustersize_bits);
345
cl = &(gb_di->id2.i_chain);
347
ret = o2info_scan_global_bitmap(fs, cl, off);
351
if (off->free_chunks_real) {
352
off->min <<= (off->clustersize_bits - 10);
353
off->max <<= (off->clustersize_bits - 10);
354
off->avg /= off->free_chunks_real;
355
off->avg <<= (off->clustersize_bits - 10);
365
static int figure_extents(int fd, uint32_t *num, int flags)
368
static struct fiemap fiemap;
370
fiemap.fm_start = 0ULL;
371
fiemap.fm_length = FIEMAP_MAX_OFFSET;
373
if (flags & FIEMAP_FLAG_XATTR)
374
fiemap.fm_flags = FIEMAP_FLAG_XATTR;
376
fiemap.fm_extent_count = 0;
377
ret = ioctl(fd, FS_IOC_FIEMAP, &fiemap);
380
tcom_err(ret, "fiemap get count error");
384
*num = fiemap.fm_mapped_extents;
389
static uint32_t clusters_in_bytes(uint32_t clustersize, uint32_t bytes)
391
uint64_t ret = bytes + clustersize - 1;
396
ret = ret >> ul_log2(clustersize);
397
if (ret > UINT32_MAX)
400
return (uint32_t)ret;
403
static int do_fiemap(int fd, int flags, struct o2info_fiemap *ofp)
407
int ret = 0, last = 0;
408
int cluster_shift = 0, blk_shift = 0;
409
int count = (sizeof(buf) - sizeof(struct fiemap)) /
410
sizeof(struct fiemap_extent);
412
struct fiemap *fiemap = (struct fiemap *)buf;
413
struct fiemap_extent *fm_ext = &fiemap->fm_extents[0];
414
uint32_t num_extents = 0, extents_got = 0, i;
416
uint32_t prev_start = 0, prev_len = 0;
417
uint32_t start = 0, len = 0, phy_pos = 0;
419
if (ofp->clustersize)
420
cluster_shift = ul_log2(ofp->clustersize);
423
blk_shift = ul_log2(ofp->blocksize);
425
memset(fiemap, 0, sizeof(*fiemap));
427
ret = figure_extents(fd, &num_extents, 0);
431
if (flags & FIEMAP_FLAG_XATTR)
432
fiemap->fm_flags = FIEMAP_FLAG_XATTR;
434
fiemap->fm_flags = flags;
437
fiemap->fm_length = ~0ULL;
438
fiemap->fm_extent_count = count;
440
ret = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
443
if (errno == EBADR) {
444
fprintf(stderr, "fiemap failed with unsupported"
445
" flags %x\n", fiemap->fm_flags);
447
fprintf(stderr, "fiemap error: %d, %s\n",
452
if (!fiemap->fm_mapped_extents)
455
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
457
start = fm_ext[i].fe_logical >> cluster_shift;
458
len = fm_ext[i].fe_length >> cluster_shift;
459
phy_pos = fm_ext[i].fe_physical >> blk_shift;
461
if (fiemap->fm_flags & FIEMAP_FLAG_XATTR) {
464
if (fm_ext[i].fe_flags &
465
FIEMAP_EXTENT_UNWRITTEN)
466
ofp->unwrittens += len;
468
if (fm_ext[i].fe_flags & FIEMAP_EXTENT_SHARED)
471
if ((prev_start + prev_len) < start)
472
ofp->holes += start - prev_start -
476
if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
483
ofp->clusters += len;
486
fiemap->fm_start = (fm_ext[i-1].fe_logical +
487
fm_ext[i-1].fe_length);
490
if (extents_got != num_extents) {
491
fprintf(stderr, "Got wrong extents number, expected:%lu, "
492
"got:%lu\n", num_extents, extents_got);
496
if (flags & FIEMAP_FLAG_XATTR)
497
ofp->num_extents_xattr = num_extents;
499
ofp->num_extents = num_extents;
504
int o2info_get_fiemap(int fd, int flags, struct o2info_fiemap *ofp)
508
ret = do_fiemap(fd, flags, ofp);
512
if ((ofp->clusters > 1) && ofp->num_extents) {
513
float e = ofp->num_extents, c = ofp->clusters;
514
int clusters_per_mb = clusters_in_bytes(ofp->clustersize,
515
OCFS2_MAX_CLUSTERSIZE);
516
ofp->frag = 100 * (e / c);
517
ofp->score = ofp->frag * clusters_per_mb;