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