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
This commit is contained in:
David van Moolenbroek 2015-03-29 15:26:23 +00:00
parent 0314acfb2d
commit 1311233cfb
14 changed files with 99 additions and 99 deletions

View file

@ -232,7 +232,7 @@ struct inode *rip; /* used for preallocation */
gd->free_blocks_count -= EXT2_PREALLOC_BLOCKS;
sp->s_free_blocks_count -= EXT2_PREALLOC_BLOCKS;
lmfs_blockschange(-EXT2_PREALLOC_BLOCKS);
lmfs_change_blockusage(EXT2_PREALLOC_BLOCKS);
group_descriptors_dirty = 1;
return block;
}
@ -257,7 +257,7 @@ struct inode *rip; /* used for preallocation */
gd->free_blocks_count--;
sp->s_free_blocks_count--;
lmfs_blockschange(-1);
lmfs_change_blockusage(1);
group_descriptors_dirty = 1;
if (update_bsearch && block != -1 && block != NO_BLOCK) {
@ -323,7 +323,7 @@ void free_block(struct super_block *sp, bit_t bit_returned)
gd->free_blocks_count++;
sp->s_free_blocks_count++;
lmfs_blockschange(1);
lmfs_change_blockusage(-1);
group_descriptors_dirty = 1;

View file

@ -89,6 +89,8 @@ int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
}
lmfs_set_blocksize(superblock->s_block_size);
lmfs_set_blockusage(superblock->s_blocks_count,
superblock->s_blocks_count - superblock->s_free_blocks_count);
/* Get the root inode of the mounted file system. */
if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) {

View file

@ -71,15 +71,3 @@ int fs_statvfs(struct statvfs *st)
return(OK);
}
/*===========================================================================*
* blockstats *
*===========================================================================*/
void fs_blockstats(u64_t *blocks, u64_t *free)
{
struct super_block *sp = get_super(fs_dev);
*blocks = sp->s_blocks_count;
*free = sp->s_free_blocks_count;
}

View file

@ -25,9 +25,3 @@ int fs_statvfs(struct statvfs *st)
return OK;
}
void fs_blockstats(u64_t *blocks, u64_t *free)
{
*blocks = v_pri.volume_space_size_l;
*free = 0;
}

View file

@ -46,6 +46,8 @@ static int create_vol_pri_desc(struct iso9660_vol_pri_desc *vol_pri, char *buf,
return EINVAL;
lmfs_set_blocksize(vol_pri->logical_block_size_l);
lmfs_set_blockusage(vol_pri->volume_space_size_l,
vol_pri->volume_space_size_l);
/* Read root directory record. */
root_record = (struct iso9660_dir_record *)vol_pri->root_directory;

View file

@ -15,6 +15,8 @@ EXTERN int cch[NR_INODES];
EXTERN dev_t fs_dev; /* The device that is handled by this FS proc.
*/
EXTERN zone_t used_zones;
extern struct fsdriver mfs_table;
#endif

View file

@ -48,8 +48,16 @@ int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
}
printf("MFS: WARNING: FS 0x%llx unclean, mounting readonly\n", fs_dev);
}
lmfs_set_blocksize(superblock.s_block_size);
/* Compute the current number of used zones, and report it to libminixfs.
* Note that libminixfs really wants numbers of *blocks*, but this MFS
* implementation dropped support for differing zone/block sizes a while ago.
*/
used_zones = superblock.s_zones - count_free_bits(&superblock, ZMAP);
lmfs_set_blockusage(superblock.s_zones, used_zones);
/* Get the root inode of the mounted file system. */
if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) {

View file

@ -87,7 +87,6 @@ unsigned int get_block_size(dev_t dev);
struct super_block *get_super(dev_t dev);
int read_super(struct super_block *sp);
int write_super(struct super_block *sp);
u32_t get_used_blocks(struct super_block *sp);
/* stats.c */
bit_t count_free_bits(struct super_block *sp, int map);

View file

@ -89,7 +89,8 @@ int fs_statvfs(struct statvfs *st)
scale = sp->s_log_zone_size;
fs_blockstats(&st->f_blocks, &st->f_bfree);
st->f_blocks = sp->s_zones;
st->f_bfree = sp->s_zones - used_zones;
st->f_bavail = st->f_bfree;
st->f_bsize = sp->s_block_size << scale;

View file

@ -87,22 +87,3 @@ int map; /* IMAP (inode map) or ZMAP (zone map) */
} while (--bcount > 0);
return free_bits;
}
/*===========================================================================*
* blockstats *
*===========================================================================*/
void fs_blockstats(u64_t *blocks, u64_t *free)
{
struct super_block *sp;
sp = get_super(fs_dev);
assert(sp);
assert(!sp->s_log_zone_size);
*blocks = sp->s_zones;
*free = *blocks - get_used_blocks(sp);
return;
}

View file

@ -24,8 +24,6 @@
#include "super.h"
#include "const.h"
static u32_t used_blocks = 0;
/*===========================================================================*
* alloc_bit *
*===========================================================================*/
@ -95,8 +93,8 @@ bit_t origin; /* number of bit to start searching at */
MARKDIRTY(bp);
put_block(bp);
if(map == ZMAP) {
used_blocks++;
lmfs_blockschange(1);
used_zones++;
lmfs_change_blockusage(1);
}
return(b);
}
@ -153,8 +151,8 @@ bit_t bit_returned; /* number of bit to insert into the map */
put_block(bp);
if(map == ZMAP) {
used_blocks--;
lmfs_blockschange(-1);
used_zones--;
lmfs_change_blockusage(-1);
}
}
@ -281,6 +279,14 @@ int read_super(struct super_block *sp)
sp->s_max_size = (off_t) conv4(native, sp->s_max_size);
sp->s_zones = (zone_t)conv4(native, sp->s_zones);
/* Zones consisting of multiple blocks are longer supported, so fail as early
* as possible. There is still a lot of code cleanup to do here, though.
*/
if (sp->s_log_zone_size != 0) {
printf("MFS: block and zone sizes are different\n");
return EINVAL;
}
/* Calculate some other numbers that depend on the version here too, to
* hide some of the differences.
*/
@ -364,15 +370,3 @@ int write_super(struct super_block *sp)
panic("can't write superblock of readonly filesystem");
return rw_super(sp, 1);
}
static int blocks_known = 0;
u32_t get_used_blocks(struct super_block *sp)
{
if(!blocks_known) {
/* how many blocks are in use? */
used_blocks = sp->s_zones - count_free_bits(sp, ZMAP);
blocks_known = 1;
}
return used_blocks;
}

View file

@ -35,9 +35,9 @@ int lmfs_bufs_in_use(void);
int lmfs_nr_bufs(void);
void lmfs_flushall(void);
void lmfs_flushdev(dev_t dev);
int lmfs_fs_block_size(void);
size_t lmfs_fs_block_size(void);
void lmfs_may_use_vmcache(int);
void lmfs_set_blocksize(int blocksize);
void lmfs_set_blocksize(size_t blocksize);
void lmfs_reset_rdwt_err(void);
int lmfs_rdwt_err(void);
void lmfs_buf_pool(int new_nr_bufs);
@ -50,11 +50,8 @@ void lmfs_zero_block_ino(dev_t dev, ino_t ino, u64_t off);
void lmfs_invalidate(dev_t device);
void lmfs_rw_scattered(dev_t, struct buf **, int, int);
void lmfs_setquiet(int q);
void lmfs_cache_reevaluate(void);
void lmfs_blockschange(int delta);
/* calls that libminixfs does into fs */
void fs_blockstats(u64_t *blocks, u64_t *free);
void lmfs_set_blockusage(fsblkcnt_t btotal, fsblkcnt_t bused);
void lmfs_change_blockusage(int delta);
/* get_block arguments */
#define NORMAL 0 /* forces get_block to do disk read */

View file

@ -58,22 +58,21 @@ static int may_use_vmcache;
static size_t fs_block_size = PAGE_SIZE; /* raw i/o block size */
static fsblkcnt_t fs_btotal = 0, fs_bused = 0;
static int rdwt_err;
static int quiet = 0;
void lmfs_setquiet(int q) { quiet = q; }
static u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u64_t bfree,
int blocksize)
static int fs_bufs_heuristic(int minbufs, fsblkcnt_t btotal,
fsblkcnt_t bused, int blocksize)
{
struct vm_stats_info vsi;
int bufs;
u32_t kbytes_used_fs, kbytes_total_fs, kbcache, kb_fsmax;
u32_t kbytes_remain_mem;
u64_t bused;
bused = btotal-bfree;
/* set a reasonable cache size; cache at most a certain
* portion of the used FS, and at most a certain %age of remaining
@ -113,21 +112,49 @@ static u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u64_t bfree,
return bufs;
}
void lmfs_blockschange(int delta)
void lmfs_change_blockusage(int delta)
{
/* Change the number of allocated blocks by 'delta.'
* Also accumulate the delta since the last cache re-evaluation.
* If it is outside a certain band, ask the cache library to
* re-evaluate the cache size.
*/
static int bitdelta = 0;
bitdelta += delta;
#define BANDKB (10*1024) /* recheck cache every 10MB change */
if(bitdelta*(int)fs_block_size/1024 > BANDKB ||
bitdelta*(int)fs_block_size/1024 < -BANDKB) {
lmfs_cache_reevaluate();
bitdelta = 0;
}
static int bitdelta = 0, warn_low = TRUE, warn_high = TRUE;
/* Adjust the file system block usage counter accordingly. Do bounds
* checking, and report file system misbehavior.
*/
if (delta > 0 && (fsblkcnt_t)delta > fs_btotal - fs_bused) {
if (warn_high) {
printf("libminixfs: block usage overflow\n");
warn_high = FALSE;
}
delta = (int)(fs_btotal - fs_bused);
} else if (delta < 0 && (fsblkcnt_t)-delta > fs_bused) {
if (warn_low) {
printf("libminixfs: block usage underflow\n");
warn_low = FALSE;
}
delta = -(int)fs_bused;
}
fs_bused += delta;
bitdelta += delta;
#define BAND_KB (10*1024) /* recheck cache every 10MB change */
/* If the accumulated delta exceeds the configured threshold, resize
* the cache, but only if the cache isn't in use any more. In order to
* avoid that the latter case blocks a resize forever, we also call
* this function from lmfs_flushall(). Since lmfs_buf_pool() may call
* lmfs_flushall(), reset 'bitdelta' before doing the heuristics check.
*/
if (bufs_in_use == 0 &&
(bitdelta*(int)fs_block_size/1024 > BAND_KB ||
bitdelta*(int)fs_block_size/1024 < -BAND_KB)) {
bitdelta = 0;
cache_heuristic_check();
}
}
void lmfs_markdirty(struct buf *bp)
@ -642,12 +669,16 @@ void lmfs_zero_block_ino(dev_t dev, ino_t ino, u64_t ino_off)
put_block(bp, ONE_SHOT);
}
void lmfs_cache_reevaluate(void)
void lmfs_set_blockusage(fsblkcnt_t btotal, fsblkcnt_t bused)
{
if (bufs_in_use == 0) {
/* if the cache isn't in use any more, we could resize it. */
assert(bused <= btotal);
fs_btotal = btotal;
fs_bused = bused;
/* if the cache isn't in use, we could resize it. */
if (bufs_in_use == 0)
cache_heuristic_check();
}
}
/*===========================================================================*
@ -955,7 +986,7 @@ static void rm_lru(struct buf *bp)
/*===========================================================================*
* cache_resize *
*===========================================================================*/
static void cache_resize(unsigned int blocksize, unsigned int bufs)
static void cache_resize(size_t blocksize, unsigned int bufs)
{
struct buf *bp;
@ -973,11 +1004,8 @@ static void cache_resize(unsigned int blocksize, unsigned int bufs)
static void cache_heuristic_check(void)
{
int bufs, d;
u64_t btotal, bfree;
fs_blockstats(&btotal, &bfree);
bufs = fs_bufs_heuristic(10, btotal, bfree, fs_block_size);
bufs = fs_bufs_heuristic(MINBUFS, fs_btotal, fs_bused, fs_block_size);
/* set the cache to the new heuristic size if the new one
* is more than 10% off from the current one.
@ -992,7 +1020,7 @@ static void cache_heuristic_check(void)
/*===========================================================================*
* lmfs_set_blocksize *
*===========================================================================*/
void lmfs_set_blocksize(int new_block_size)
void lmfs_set_blocksize(size_t new_block_size)
{
cache_resize(new_block_size, MINBUFS);
cache_heuristic_check();
@ -1077,9 +1105,19 @@ void lmfs_flushall(void)
for(bp = &buf[0]; bp < &buf[nr_bufs]; bp++)
if(bp->lmfs_dev != NO_DEV && !lmfs_isclean(bp))
lmfs_flushdev(bp->lmfs_dev);
/* This is the moment where it is least likely (although certainly not
* impossible!) that there are buffers in use, since buffers should not
* be held across file system syncs. See if we already intended to
* resize the buffer cache, but couldn't. Be aware that we may be
* called indirectly from within lmfs_change_blockusage(), so care must
* be taken not to recurse infinitely. TODO: see if it is better to
* resize the cache from here *only*, thus guaranteeing a clean cache.
*/
lmfs_change_blockusage(0);
}
int lmfs_fs_block_size(void)
size_t lmfs_fs_block_size(void)
{
return fs_block_size;
}

View file

@ -90,12 +90,6 @@ void testend(void)
/* Fake some libminixfs client functions */
void
fs_blockstats(u64_t *total, u64_t *free)
{
*total = *free = 0;
}
static void allocate(int b)
{
assert(curblocksize > 0);