#include "fs.h"
#include <minix/u64.h>
+#include <sys/param.h>
#include <stdlib.h>
#include <assert.h>
+#include <math.h>
#include "buf.h"
#include "super.h"
#include "inode.h"
}
/*===========================================================================*
- * set_blocksize *
+ * cache_resize *
*===========================================================================*/
-PUBLIC void set_blocksize(unsigned int blocksize)
+PRIVATE void cache_resize(unsigned int blocksize, unsigned int bufs)
{
struct buf *bp;
struct inode *rip;
+ int scale, r;
- ASSERT(blocksize > 0);
+#define MINBUFS 10
+ assert(blocksize > 0);
+ assert(bufs >= MINBUFS);
for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++)
if(bp->b_count != 0) panic("change blocksize with buffer in use");
for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
if (rip->i_count > 0) panic("change blocksize with inode in use");
- buf_pool(nr_bufs);
+ buf_pool(bufs);
+
fs_block_size = blocksize;
}
+/*===========================================================================*
+ * bufs_heuristic *
+ *===========================================================================*/
+PRIVATE int bufs_heuristic(struct super_block *sp)
+{
+ struct vm_stats_info vsi;
+ int r, bufs;
+ u32_t btotal, bfree, bused, kbytes_used_fs,
+ kbytes_total_fs, kbcache, kb_fsmax;
+ u32_t kbytes_remain_mem;
+
+ /* but we simply need MINBUFS no matter what, and we don't
+ * want more than that if we're a memory device
+ */
+ if(major(sp->s_dev) == MEMORY_MAJOR) {
+ bufs = MINBUFS;
+ return bufs;
+ }
+
+ /* set a reasonable cache size; cache at most a certain
+ * portion of the used FS, and at most a certain %age of remaining
+ * memory
+ */
+ if((vm_info_stats(&vsi) != OK)) {
+ bufs = 1024;
+ printf("mfs: heuristic info fail: default to %d bufs\n", bufs);
+ return bufs;
+ }
+
+ kbytes_remain_mem = div64u(mul64u(vsi.vsi_free, vsi.vsi_pagesize), 1024);
+
+ /* check fs usage. */
+ blockstats(&btotal, &bfree, &bused);
+ kbytes_used_fs = div64u(mul64u(bused, sp->s_block_size), 1024);
+ kbytes_total_fs = div64u(mul64u(btotal, sp->s_block_size), 1024);
+
+ /* heuristic for a desired cache size based on FS usage;
+ * but never bigger than half of the total filesystem
+ */
+ kb_fsmax = sqrt(kbytes_used_fs)*40;
+ kb_fsmax = MIN(kb_fsmax, kbytes_total_fs/2);
+
+ /* heuristic for a maximum usage - 10% of remaining memory */
+ kbcache = MIN(kbytes_remain_mem/10, kb_fsmax);
+ bufs = kbcache * 1024 / sp->s_block_size;
+
+ /* but we simply need MINBUFS no matter what */
+ if(bufs < MINBUFS)
+ bufs = MINBUFS;
+
+ return bufs;
+}
+
+/*===========================================================================*
+ * set_blocksize *
+ *===========================================================================*/
+PUBLIC void set_blocksize(struct super_block *sp)
+{
+ int bufs;
+
+ cache_resize(sp->s_block_size, MINBUFS);
+ bufs = bufs_heuristic(sp);
+ cache_resize(sp->s_block_size, bufs);
+}
+
/*===========================================================================*
* buf_pool *
*===========================================================================*/
/* Initialize the buffer pool. */
register struct buf *bp;
- assert(new_nr_bufs > 0);
+ assert(new_nr_bufs >= MINBUFS);
if(nr_bufs > 0) {
assert(buf);
_PROTOTYPE( struct buf *get_block, (dev_t dev, block_t block,int only_search));
_PROTOTYPE( void invalidate, (dev_t device) );
_PROTOTYPE( void put_block, (struct buf *bp, int block_type) );
-_PROTOTYPE( void set_blocksize, (unsigned int blocksize) );
+_PROTOTYPE( void set_blocksize, (struct super_block *) );
_PROTOTYPE( void rw_scattered, (dev_t dev,
struct buf **bufq, int bufqsize, int rw_flag) );
/* stats.c */
_PROTOTYPE( bit_t count_free_bits, (struct super_block *sp, int map));
+_PROTOTYPE( void blockstats, (u32_t *total, u32_t *free, u32_t *avail));
/* time.c */
_PROTOTYPE( int fs_utime, (void) );
struct statvfs st;
struct super_block *sp;
int r, scale;
+ u32_t used;
sp = get_super(fs_dev);
scale = sp->s_log_zone_size;
+ blockstats(&st.f_blocks, &st.f_bfree, &used);
+ st.f_bavail = st.f_bfree;
+
st.f_bsize = sp->s_block_size << scale;
st.f_frsize = sp->s_block_size;
- st.f_blocks = sp->s_zones << scale;
- st.f_bfree = count_free_bits(sp, ZMAP) << scale;
- st.f_bavail = st.f_bfree;
st.f_files = sp->s_ninodes;
st.f_ffree = count_free_bits(sp, IMAP);
st.f_favail = st.f_ffree;
} while (--bcount > 0);
return free_bits; /* no bit could be allocated */
}
+
+
+/*===========================================================================*
+ * blockstats *
+ *===========================================================================*/
+PUBLIC void blockstats(u32_t *blocks, u32_t *free, u32_t *used)
+{
+ struct super_block *sp;
+ int scale;
+
+ sp = get_super(fs_dev);
+
+ assert(sp);
+
+ scale = sp->s_log_zone_size;
+
+ *blocks = sp->s_zones << scale;
+ *free = count_free_bits(sp, ZMAP) << scale;
+ *used = *blocks - *free;
+
+ return;
+}