xref: /minix/minix/fs/mfs/cache.c (revision 9f988b79)
1 /* The file system maintains a buffer cache to reduce the number of disk
2  * accesses needed.  Whenever a read or write to the disk is done, a check is
3  * first made to see if the block is in the cache.  This file contains some
4  * related routines, but the cache is now in libminixfs.
5  */
6 
7 #include "fs.h"
8 #include <minix/u64.h>
9 #include <minix/bdev.h>
10 #include <sys/param.h>
11 #include <stdlib.h>
12 #include <assert.h>
13 #include <minix/libminixfs.h>
14 #include <math.h>
15 #include "buf.h"
16 #include "super.h"
17 #include "inode.h"
18 
19 /*===========================================================================*
20  *				get_block				     *
21  *===========================================================================*/
22 struct buf *get_block(dev_t dev, block_t block, int how)
23 {
24 /* Wrapper routine for lmfs_get_block(). This MFS implementation does not deal
25  * well with block read errors pretty much anywhere. To prevent corruption due
26  * to unchecked error conditions, we panic upon an I/O failure here.
27  */
28   struct buf *bp;
29   int r;
30 
31   if ((r = lmfs_get_block(&bp, dev, block, how)) != OK && r != ENOENT)
32 	panic("MFS: error getting block (%llu,%u): %d", dev, block, r);
33 
34   assert(r == OK || how == PEEK);
35 
36   return (r == OK) ? bp : NULL;
37 }
38 
39 /*===========================================================================*
40  *				alloc_zone				     *
41  *===========================================================================*/
42 zone_t alloc_zone(
43   dev_t dev,			/* device where zone wanted */
44   zone_t z			/* try to allocate new zone near this one */
45 )
46 {
47 /* Allocate a new zone on the indicated device and return its number. */
48 
49   bit_t b, bit;
50   struct super_block *sp;
51   static int print_oos_msg = 1;
52 
53   /* Note that the routine alloc_bit() returns 1 for the lowest possible
54    * zone, which corresponds to sp->s_firstdatazone.  To convert a value
55    * between the bit number, 'b', used by alloc_bit() and the zone number, 'z',
56    * stored in the inode, use the formula:
57    *     z = b + sp->s_firstdatazone - 1
58    * Alloc_bit() never returns 0, since this is used for NO_BIT (failure).
59    */
60   sp = &superblock;
61 
62   /* If z is 0, skip initial part of the map known to be fully in use. */
63   if (z == sp->s_firstdatazone) {
64 	bit = sp->s_zsearch;
65   } else {
66 	bit = (bit_t) (z - (sp->s_firstdatazone - 1));
67   }
68   b = alloc_bit(sp, ZMAP, bit);
69   if (b == NO_BIT) {
70 	err_code = ENOSPC;
71 	if (print_oos_msg)
72 		printf("No space on device %d/%d\n", major(sp->s_dev),
73 			minor(sp->s_dev));
74 	print_oos_msg = 0;	/* Don't repeat message */
75 	return(NO_ZONE);
76   }
77   print_oos_msg = 1;
78   if (z == sp->s_firstdatazone) sp->s_zsearch = b;	/* for next time */
79   return( (zone_t) (sp->s_firstdatazone - 1) + (zone_t) b);
80 }
81 
82 /*===========================================================================*
83  *				free_zone				     *
84  *===========================================================================*/
85 void free_zone(
86   dev_t dev,				/* device where zone located */
87   zone_t numb				/* zone to be returned */
88 )
89 {
90 /* Return a zone. */
91 
92   register struct super_block *sp;
93   bit_t bit;
94 
95   /* Locate the appropriate super_block and return bit. */
96   sp = &superblock;
97   if (numb < sp->s_firstdatazone || numb >= sp->s_zones) return;
98   bit = (bit_t) (numb - (zone_t) (sp->s_firstdatazone - 1));
99   free_bit(sp, ZMAP, bit);
100   if (bit < sp->s_zsearch) sp->s_zsearch = bit;
101 
102   /* Also tell libminixfs, so that 1) if it has a block for this bit, it can
103    * mark it as clean, thus reducing useless writes, and 2) it can tell VM that
104    * any previous inode association is to be broken for this block, so that the
105    * block will not be mapped in erroneously later on.
106    */
107   assert(sp->s_log_zone_size == 0); /* otherwise we need a loop here.. */
108   lmfs_free_block(dev, (block_t)numb);
109 }
110