diff --git a/minix/fs/ext2/balloc.c b/minix/fs/ext2/balloc.c index fd1e18505..e0d575203 100644 --- a/minix/fs/ext2/balloc.c +++ b/minix/fs/ext2/balloc.c @@ -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; diff --git a/minix/fs/ext2/mount.c b/minix/fs/ext2/mount.c index f2c619904..790e55970 100644 --- a/minix/fs/ext2/mount.c +++ b/minix/fs/ext2/mount.c @@ -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) { diff --git a/minix/fs/ext2/stadir.c b/minix/fs/ext2/stadir.c index 233705fcb..56bbdfae6 100644 --- a/minix/fs/ext2/stadir.c +++ b/minix/fs/ext2/stadir.c @@ -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; -} - diff --git a/minix/fs/isofs/stadir.c b/minix/fs/isofs/stadir.c index 741f0b9d4..6825b1031 100644 --- a/minix/fs/isofs/stadir.c +++ b/minix/fs/isofs/stadir.c @@ -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; -} diff --git a/minix/fs/isofs/super.c b/minix/fs/isofs/super.c index 83d63ec8f..b8d7aa5a9 100644 --- a/minix/fs/isofs/super.c +++ b/minix/fs/isofs/super.c @@ -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; diff --git a/minix/fs/mfs/glo.h b/minix/fs/mfs/glo.h index 8e50d387d..175349230 100644 --- a/minix/fs/mfs/glo.h +++ b/minix/fs/mfs/glo.h @@ -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 diff --git a/minix/fs/mfs/mount.c b/minix/fs/mfs/mount.c index 4bb751d39..3df824e6b 100644 --- a/minix/fs/mfs/mount.c +++ b/minix/fs/mfs/mount.c @@ -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) { diff --git a/minix/fs/mfs/proto.h b/minix/fs/mfs/proto.h index 10f6707dc..92a4ad638 100644 --- a/minix/fs/mfs/proto.h +++ b/minix/fs/mfs/proto.h @@ -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); diff --git a/minix/fs/mfs/stadir.c b/minix/fs/mfs/stadir.c index 765e0ea87..2e53ee959 100644 --- a/minix/fs/mfs/stadir.c +++ b/minix/fs/mfs/stadir.c @@ -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; diff --git a/minix/fs/mfs/stats.c b/minix/fs/mfs/stats.c index d45b92c3f..cffa10b7e 100644 --- a/minix/fs/mfs/stats.c +++ b/minix/fs/mfs/stats.c @@ -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; -} diff --git a/minix/fs/mfs/super.c b/minix/fs/mfs/super.c index f50df8425..f5e736a4b 100644 --- a/minix/fs/mfs/super.c +++ b/minix/fs/mfs/super.c @@ -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; -} diff --git a/minix/include/minix/libminixfs.h b/minix/include/minix/libminixfs.h index e6094515a..44aa80e96 100644 --- a/minix/include/minix/libminixfs.h +++ b/minix/include/minix/libminixfs.h @@ -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 */ diff --git a/minix/lib/libminixfs/cache.c b/minix/lib/libminixfs/cache.c index 3b1aa0dce..e7a9fa98c 100644 --- a/minix/lib/libminixfs/cache.c +++ b/minix/lib/libminixfs/cache.c @@ -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; } diff --git a/minix/tests/test72.c b/minix/tests/test72.c index 70552a1c7..6c709692b 100644 --- a/minix/tests/test72.c +++ b/minix/tests/test72.c @@ -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);