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;
}
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) {
gd->free_blocks_count++;
sp->s_free_blocks_count++;
- lmfs_blockschange(1);
+ lmfs_change_blockusage(-1);
group_descriptors_dirty = 1;
}
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) {
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;
-}
-
return OK;
}
-
-void fs_blockstats(u64_t *blocks, u64_t *free)
-{
- *blocks = v_pri.volume_space_size_l;
- *free = 0;
-}
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;
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
}
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) {
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);
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;
} 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;
-}
#include "super.h"
#include "const.h"
-static u32_t used_blocks = 0;
-
/*===========================================================================*
* alloc_bit *
*===========================================================================*/
MARKDIRTY(bp);
put_block(bp);
if(map == ZMAP) {
- used_blocks++;
- lmfs_blockschange(1);
+ used_zones++;
+ lmfs_change_blockusage(1);
}
return(b);
}
put_block(bp);
if(map == ZMAP) {
- used_blocks--;
- lmfs_blockschange(-1);
+ used_zones--;
+ lmfs_change_blockusage(-1);
}
}
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.
*/
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;
-}
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);
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 */
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
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)
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();
- }
}
/*===========================================================================*
/*===========================================================================*
* 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;
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.
/*===========================================================================*
* 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();
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;
}
/* 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);