minix/minix/fs/mfs/stats.c
David van Moolenbroek 1311233cfb libminixfs: keep track of block usage
This patch changes the libminixfs API and implementation such that the
library is at all times aware of how many total and used blocks there
are in the file system.  This removes the last upcall of libminixfs
into file systems (fs_blockstats).  In the process, make this part of
the libminixfs API a little prettier and more robust.  Change file
systems accordingly.  Since this change only adds to MFS being unable
to deal with zones and blocks having different sizes, fail to mount
such file systems immediately rather than triggering an assert later.

Change-Id: I078e589c7e1be1fa691cf391bf5dfddd1baf2c86
2015-08-14 18:39:21 +00:00

90 lines
2.7 KiB
C

#include "fs.h"
#include <string.h>
#include <minix/com.h>
#include <assert.h>
#include <minix/u64.h>
#include "buf.h"
#include "inode.h"
#include "super.h"
#include "const.h"
/*===========================================================================*
* count_free_bits *
*===========================================================================*/
bit_t count_free_bits(sp, map)
struct super_block *sp; /* the filesystem to allocate from */
int map; /* IMAP (inode map) or ZMAP (zone map) */
{
/* Allocate a bit from a bit map and return its bit number. */
block_t start_block; /* first bit block */
block_t block;
bit_t map_bits; /* how many bits are there in the bit map? */
short bit_blocks; /* how many blocks are there in the bit map? */
bit_t origin; /* number of bit to start searching at */
unsigned word, bcount;
struct buf *bp;
bitchunk_t *wptr, *wlim, k;
bit_t i, b;
bit_t free_bits;
assert(sp != NULL);
if (map == IMAP) {
start_block = START_BLOCK;
map_bits = (bit_t) (sp->s_ninodes + 1);
bit_blocks = sp->s_imap_blocks;
origin = sp->s_isearch;
} else {
start_block = START_BLOCK + sp->s_imap_blocks;
map_bits = (bit_t) (sp->s_zones - (sp->s_firstdatazone - 1));
bit_blocks = sp->s_zmap_blocks;
origin = sp->s_zsearch;
}
/* Figure out where to start the bit search (depends on 'origin'). */
if (origin >= map_bits) origin = 0; /* for robustness */
free_bits = 0;
/* Locate the starting place. */
block = (block_t) (origin / FS_BITS_PER_BLOCK(sp->s_block_size));
word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
/* Iterate over all blocks plus one, because we start in the middle. */
bcount = bit_blocks;
do {
bp = get_block(sp->s_dev, start_block + block, NORMAL);
assert(bp);
wlim = &b_bitmap(bp)[FS_BITMAP_CHUNKS(sp->s_block_size)];
/* Iterate over the words in block. */
for (wptr = &b_bitmap(bp)[word]; wptr < wlim; wptr++) {
/* Does this word contain a free bit? */
if (*wptr == (bitchunk_t) ~0) continue;
k = (bitchunk_t) conv4(sp->s_native, (int) *wptr);
for (i = 0; i < 8*sizeof(k); ++i) {
/* Bit number from the start of the bit map. */
b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
+ (wptr - &b_bitmap(bp)[0]) * FS_BITCHUNK_BITS
+ i;
/* Don't count bits beyond the end of the map. */
if (b >= map_bits) {
break;
}
if ((k & (1 << i)) == 0) {
free_bits++;
}
}
if (b >= map_bits) break;
}
put_block(bp);
++block;
word = 0;
} while (--bcount > 0);
return free_bits;
}