diff --git a/include/minix/libminixfs.h b/include/minix/libminixfs.h index 0be011735..cece2c2f3 100644 --- a/include/minix/libminixfs.h +++ b/include/minix/libminixfs.h @@ -56,6 +56,8 @@ void lmfs_put_block(struct buf *bp, int block_type); void lmfs_rw_scattered(dev_t, struct buf **, int, int); void lmfs_setquiet(int q); int lmfs_do_bpeek(message *); +void lmfs_cache_reevaluate(dev_t dev); +void lmfs_blockschange(dev_t dev, int delta); /* calls that libminixfs does into fs */ void fs_blockstats(u32_t *blocks, u32_t *free, u32_t *used); diff --git a/lib/libminixfs/cache.c b/lib/libminixfs/cache.c index 579a02cfe..ad3c6469b 100644 --- a/lib/libminixfs/cache.c +++ b/lib/libminixfs/cache.c @@ -29,6 +29,7 @@ static void rm_lru(struct buf *bp); static void read_block(struct buf *); static void flushall(dev_t dev); static void freeblock(struct buf *bp); +static void cache_heuristic_check(int major); static int vmcache = 0; /* are we using vm's secondary cache? (initially not) */ @@ -60,13 +61,18 @@ u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree, * portion of the used FS, and at most a certain %age of remaining * memory */ - if((vm_info_stats(&vsi) != OK)) { + if(vm_info_stats(&vsi) != OK) { bufs = 1024; - if(!quiet) printf("fslib: heuristic info fail: default to %d bufs\n", bufs); + if(!quiet) + printf("fslib: heuristic info fail: default to %d bufs\n", bufs); return bufs; } - kbytes_remain_mem = div64u(mul64u(vsi.vsi_free, vsi.vsi_pagesize), 1024); + /* remaining free memory is unused memory plus memory in used for cache, + * as the cache can be evicted + */ + kbytes_remain_mem = (u64_t)(vsi.vsi_free + vsi.vsi_cached) * + vsi.vsi_pagesize / 1024; /* check fs usage. */ kbytes_used_fs = div64u(mul64u(bused, blocksize), 1024); @@ -89,6 +95,23 @@ u32_t fs_bufs_heuristic(int minbufs, u32_t btotal, u32_t bfree, return bufs; } +void lmfs_blockschange(dev_t dev, 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*fs_block_size/1024 > BANDKB || + bitdelta*fs_block_size/1024 < -BANDKB) { + lmfs_cache_reevaluate(dev); + bitdelta = 0; + } +} + void lmfs_markdirty(struct buf *bp) { @@ -455,6 +478,15 @@ int block_type; /* INODE_BLOCK, DIRECTORY_BLOCK, or whatever */ } } bp->lmfs_needsetcache = 0; + +} + +void lmfs_cache_reevaluate(dev_t dev) +{ + if(bufs_in_use == 0 && dev != NO_DEV) { + /* if the cache isn't in use any more, we could resize it. */ + cache_heuristic_check(major(dev)); + } } /*===========================================================================* @@ -734,22 +766,33 @@ static void cache_resize(unsigned int blocksize, unsigned int bufs) fs_block_size = blocksize; } +static void cache_heuristic_check(int major) +{ + int bufs, d; + u32_t btotal, bfree, bused; + + fs_blockstats(&btotal, &bfree, &bused); + + bufs = fs_bufs_heuristic(10, btotal, bfree, + fs_block_size, major); + + /* set the cache to the new heuristic size if the new one + * is more than 10% off from the current one. + */ + d = bufs-nr_bufs; + if(d < 0) d = -d; + if(d*100/nr_bufs > 10) { + cache_resize(fs_block_size, bufs); + } +} + /*===========================================================================* * lmfs_set_blocksize * *===========================================================================*/ void lmfs_set_blocksize(int new_block_size, int major) { - int bufs; - u32_t btotal, bfree, bused; - cache_resize(new_block_size, MINBUFS); - - fs_blockstats(&btotal, &bfree, &bused); - - bufs = fs_bufs_heuristic(10, btotal, bfree, - new_block_size, major); - - cache_resize(new_block_size, bufs); + cache_heuristic_check(major); /* Decide whether to use seconday cache or not. * Only do this if diff --git a/servers/ext2/balloc.c b/servers/ext2/balloc.c index fac377f31..759220c24 100644 --- a/servers/ext2/balloc.c +++ b/servers/ext2/balloc.c @@ -232,6 +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(sp->s_dev, -EXT2_PREALLOC_BLOCKS); group_descriptors_dirty = 1; return block; } @@ -256,6 +257,7 @@ struct inode *rip; /* used for preallocation */ gd->free_blocks_count--; sp->s_free_blocks_count--; + lmfs_blockschange(sp->s_dev, -1); group_descriptors_dirty = 1; if (update_bsearch && block != -1 && block != NO_BLOCK) { @@ -321,6 +323,7 @@ void free_block(struct super_block *sp, bit_t bit_returned) gd->free_blocks_count++; sp->s_free_blocks_count++; + lmfs_blockschange(sp->s_dev, 1); group_descriptors_dirty = 1; diff --git a/servers/mfs/proto.h b/servers/mfs/proto.h index 38e4fc5d5..142c6f125 100644 --- a/servers/mfs/proto.h +++ b/servers/mfs/proto.h @@ -90,6 +90,7 @@ 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); diff --git a/servers/mfs/stats.c b/servers/mfs/stats.c index 55c75fd7d..871576359 100644 --- a/servers/mfs/stats.c +++ b/servers/mfs/stats.c @@ -95,17 +95,15 @@ int map; /* IMAP (inode map) or ZMAP (zone map) */ void fs_blockstats(u32_t *blocks, u32_t *free, u32_t *used) { struct super_block *sp; - int scale; sp = get_super(fs_dev); assert(sp); + assert(!sp->s_log_zone_size); - scale = sp->s_log_zone_size; - - *blocks = sp->s_zones << scale; - *free = count_free_bits(sp, ZMAP) << scale; - *used = *blocks - *free; + *blocks = sp->s_zones; + *used = get_used_blocks(sp); + *free = *blocks - *used; return; } diff --git a/servers/mfs/super.c b/servers/mfs/super.c index 126825334..63084ee8f 100644 --- a/servers/mfs/super.c +++ b/servers/mfs/super.c @@ -22,6 +22,7 @@ #include "super.h" #include "const.h" +static u32_t used_blocks = 0; /*===========================================================================* * alloc_bit * @@ -91,6 +92,10 @@ bit_t origin; /* number of bit to start searching at */ *wptr = (bitchunk_t) conv4(sp->s_native, (int) k); MARKDIRTY(bp); put_block(bp, MAP_BLOCK); + if(map == ZMAP) { + used_blocks++; + lmfs_blockschange(sp->s_dev, 1); + } return(b); } put_block(bp, MAP_BLOCK); @@ -144,8 +149,12 @@ bit_t bit_returned; /* number of bit to insert into the map */ MARKDIRTY(bp); put_block(bp, MAP_BLOCK); -} + if(map == ZMAP) { + used_blocks--; + lmfs_blockschange(sp->s_dev, -1); + } +} /*===========================================================================* * get_super * @@ -365,3 +374,14 @@ int write_super(struct super_block *sp) 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; +}