]> Zhao Yanbai Git Server - minix.git/commitdiff
libminixfs: keep track of block usage 61/3061/2
authorDavid van Moolenbroek <david@minix3.org>
Sun, 29 Mar 2015 15:26:23 +0000 (15:26 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Fri, 14 Aug 2015 18:39:21 +0000 (18:39 +0000)
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

14 files changed:
minix/fs/ext2/balloc.c
minix/fs/ext2/mount.c
minix/fs/ext2/stadir.c
minix/fs/isofs/stadir.c
minix/fs/isofs/super.c
minix/fs/mfs/glo.h
minix/fs/mfs/mount.c
minix/fs/mfs/proto.h
minix/fs/mfs/stadir.c
minix/fs/mfs/stats.c
minix/fs/mfs/super.c
minix/include/minix/libminixfs.h
minix/lib/libminixfs/cache.c
minix/tests/test72.c

index fd1e18505de6a2922caceeb542a73909ac4508ab..e0d5752037e598a2b2502390898eb287687e5bcb 100644 (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;
 
index f2c619904a0417f61c5ce58bc02b6109f812c072..790e559703890515ac3b2c47782e757c427a3493 100644 (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)  {
index 233705fcb8f04a6331bc92459230c414bef17a84..56bbdfae6d09c17da1200a1b2a3874815ab14afe 100644 (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;
-}
-
index 741f0b9d4a1d03db3405d2ca1b47dc7d2631ec76..6825b1031e74fc3f20978caa1d9b8f65360900a2 100644 (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;
-}
index 83d63ec8f2a227880f699f8138b8842483b6c3bd..b8d7aa5a932cb154109e0f33f7dde8b8aff364b4 100644 (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;
index 8e50d387da185dbfd945783f715f195bec118313..175349230dc766c53977ae846bffedae88adb646 100644 (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
index 4bb751d39a421efba47b471f80cd8ee8d6f18329..3df824e6b9ca5decf459d5df324066f2234687ef 100644 (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)  {
index 10f6707dc83b1b3b2f4e1f1a98a16e4b40915e9c..92a4ad638bb510bad976bef11467a4b2d6de9df9 100644 (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);
index 765e0ea8713dfe1e6cc454cb1c5ab2c82d8e49ba..2e53ee9590f6e334c8d543f221fe6699e4ce9dac 100644 (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;
index d45b92c3f5735991d78a23ebaeb1fe353767869e..cffa10b7e91c4870706eb990f6f6cec2ce6aed2a 100644 (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;
-}
index f50df8425932f23a8441527299ef4ebd41b68267..f5e736a4bf9d258d725c697afa5f12f65f3e9a18 100644 (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;
-}
index e6094515a3b865e753053669c309c680b23b63c3..44aa80e9631fdb69d5240d294470e78e4f46ed78 100644 (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 */
index 3b1aa0dce5f038296043738437fcc70f80c281d5..e7a9fa98c5576e7109fe9d941edeec7268386d20 100644 (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;
 }
index 70552a1c7c41bdcf21d40a55bcba6690f3a21a2b..6c709692b9eadd696e16669a02b073923a2c3af9 100644 (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);