📄 super.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/fs/super.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21900 /* This file manages the super block table and the related data structures,
21901 * namely, the bit maps that keep track of which zones and which inodes are
21902 * allocated and which are free. When a new inode or zone is needed, the
21903 * appropriate bit map is searched for a free entry.
21904 *
21905 * The entry points into this file are
21906 * alloc_bit: somebody wants to allocate a zone or inode; find one
21907 * free_bit: indicate that a zone or inode is available for allocation
21908 * get_super: search the 'superblock' table for a device
21909 * mounted: tells if file inode is on mounted (or ROOT) file system
21910 * read_super: read a superblock
21911 */
21912
21913 #include "fs.h"
21914 #include <string.h>
21915 #include <minix/boot.h>
21916 #include "buf.h"
21917 #include "inode.h"
21918 #include "super.h"
21919
21920 #define BITCHUNK_BITS (usizeof(bitchunk_t) * CHAR_BIT)
21921 #define BITS_PER_BLOCK (BITMAP_CHUNKS * BITCHUNK_BITS)
21922
21923 /*===========================================================================*
21924 * alloc_bit *
21925 *===========================================================================*/
21926 PUBLIC bit_t alloc_bit(sp, map, origin)
21927 struct super_block *sp; /* the filesystem to allocate from */
21928 int map; /* IMAP (inode map) or ZMAP (zone map) */
21929 bit_t origin; /* number of bit to start searching at */
21930 {
21931 /* Allocate a bit from a bit map and return its bit number. */
21932
21933 block_t start_block; /* first bit block */
21934 bit_t map_bits; /* how many bits are there in the bit map? */
21935 unsigned bit_blocks; /* how many blocks are there in the bit map? */
21936 unsigned block, word, bcount, wcount;
21937 struct buf *bp;
21938 bitchunk_t *wptr, *wlim, k;
21939 bit_t i, b;
21940
21941 if (sp->s_rd_only)
21942 panic("can't allocate bit on read-only filesys.", NO_NUM);
21943
21944 if (map == IMAP) {
21945 start_block = SUPER_BLOCK + 1;
21946 map_bits = sp->s_ninodes + 1;
21947 bit_blocks = sp->s_imap_blocks;
21948 } else {
21949 start_block = SUPER_BLOCK + 1 + sp->s_imap_blocks;
21950 map_bits = sp->s_zones - (sp->s_firstdatazone - 1);
21951 bit_blocks = sp->s_zmap_blocks;
21952 }
21953
21954 /* Figure out where to start the bit search (depends on 'origin'). */
21955 if (origin >= map_bits) origin = 0; /* for robustness */
21956
21957 /* Locate the starting place. */
21958 block = origin / BITS_PER_BLOCK;
21959 word = (origin % BITS_PER_BLOCK) / BITCHUNK_BITS;
21960
21961 /* Iterate over all blocks plus one, because we start in the middle. */
21962 bcount = bit_blocks + 1;
21963 do {
21964 bp = get_block(sp->s_dev, start_block + block, NORMAL);
21965 wlim = &bp->b_bitmap[BITMAP_CHUNKS];
21966
21967 /* Iterate over the words in block. */
21968 for (wptr = &bp->b_bitmap[word]; wptr < wlim; wptr++) {
21969
21970 /* Does this word contain a free bit? */
21971 if (*wptr == (bitchunk_t) ~0) continue;
21972
21973 /* Find and allocate the free bit. */
21974 k = conv2(sp->s_native, (int) *wptr);
21975 for (i = 0; (k & (1 << i)) != 0; ++i) {}
21976
21977 /* Bit number from the start of the bit map. */
21978 b = ((bit_t) block * BITS_PER_BLOCK)
21979 + (wptr - &bp->b_bitmap[0]) * BITCHUNK_BITS
21980 + i;
21981
21982 /* Don't allocate bits beyond the end of the map. */
21983 if (b >= map_bits) break;
21984
21985 /* Allocate and return bit number. */
21986 k |= 1 << i;
21987 *wptr = conv2(sp->s_native, (int) k);
21988 bp->b_dirt = DIRTY;
21989 put_block(bp, MAP_BLOCK);
21990 return(b);
21991 }
21992 put_block(bp, MAP_BLOCK);
21993 if (++block >= bit_blocks) block = 0; /* last block, wrap around */
21994 word = 0;
21995 } while (--bcount > 0);
21996 return(NO_BIT); /* no bit could be allocated */
21997 }
22000 /*===========================================================================*
22001 * free_bit *
22002 *===========================================================================*/
22003 PUBLIC void free_bit(sp, map, bit_returned)
22004 struct super_block *sp; /* the filesystem to operate on */
22005 int map; /* IMAP (inode map) or ZMAP (zone map) */
22006 bit_t bit_returned; /* number of bit to insert into the map */
22007 {
22008 /* Return a zone or inode by turning off its bitmap bit. */
22009
22010 unsigned block, word, bit;
22011 struct buf *bp;
22012 bitchunk_t k, mask;
22013 block_t start_block;
22014
22015 if (sp->s_rd_only)
22016 panic("can't free bit on read-only filesys.", NO_NUM);
22017
22018 if (map == IMAP) {
22019 start_block = SUPER_BLOCK + 1;
22020 } else {
22021 start_block = SUPER_BLOCK + 1 + sp->s_imap_blocks;
22022 }
22023 block = bit_returned / BITS_PER_BLOCK;
22024 word = (bit_returned % BITS_PER_BLOCK) / BITCHUNK_BITS;
22025 bit = bit_returned % BITCHUNK_BITS;
22026 mask = 1 << bit;
22027
22028 bp = get_block(sp->s_dev, start_block + block, NORMAL);
22029
22030 k = conv2(sp->s_native, (int) bp->b_bitmap[word]);
22031 if (!(k & mask)) {
22032 panic(map == IMAP ? "tried to free unused inode" :
22033 "tried to free unused block", NO_NUM);
22034 }
22035
22036 k &= ~mask;
22037 bp->b_bitmap[word] = conv2(sp->s_native, (int) k);
22038 bp->b_dirt = DIRTY;
22039
22040 put_block(bp, MAP_BLOCK);
22041 }
22044 /*===========================================================================*
22045 * get_super *
22046 *===========================================================================*/
22047 PUBLIC struct super_block *get_super(dev)
22048 dev_t dev; /* device number whose super_block is sought */
22049 {
22050 /* Search the superblock table for this device. It is supposed to be there. */
22051
22052 register struct super_block *sp;
22053
22054 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
22055 if (sp->s_dev == dev) return(sp);
22056
22057 /* Search failed. Something wrong. */
22058 panic("can't find superblock for device (in decimal)", (int) dev);
22059
22060 return(NIL_SUPER); /* to keep the compiler and lint quiet */
22061 }
22064 /*===========================================================================*
22065 * mounted *
22066 *===========================================================================*/
22067 PUBLIC int mounted(rip)
22068 register struct inode *rip; /* pointer to inode */
22069 {
22070 /* Report on whether the given inode is on a mounted (or ROOT) file system. */
22071
22072 register struct super_block *sp;
22073 register dev_t dev;
22074
22075 dev = (dev_t) rip->i_zone[0];
22076 if (dev == ROOT_DEV) return(TRUE); /* inode is on root file system */
22077
22078 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
22079 if (sp->s_dev == dev) return(TRUE);
22080
22081 return(FALSE);
22082 }
22085 /*===========================================================================*
22086 * read_super *
22087 *===========================================================================*/
22088 PUBLIC int read_super(sp)
22089 register struct super_block *sp; /* pointer to a superblock */
22090 {
22091 /* Read a superblock. */
22092
22093 register struct buf *bp;
22094 dev_t dev;
22095 int magic;
22096 int version, native;
22097
22098 dev = sp->s_dev; /* save device (will be overwritten by copy) */
22099 bp = get_block(sp->s_dev, SUPER_BLOCK, NORMAL);
22100 memcpy( (char *) sp, bp->b_data, (size_t) SUPER_SIZE);
22101 put_block(bp, ZUPER_BLOCK);
22102 sp->s_dev = NO_DEV; /* restore later */
22103 magic = sp->s_magic; /* determines file system type */
22104
22105 /* Get file system version and type. */
22106 if (magic == SUPER_MAGIC || magic == conv2(BYTE_SWAP, SUPER_MAGIC)) {
22107 version = V1;
22108 native = (magic == SUPER_MAGIC);
22109 } else if (magic == SUPER_V2 || magic == conv2(BYTE_SWAP, SUPER_V2)) {
22110 version = V2;
22111 native = (magic == SUPER_V2);
22112 } else {
22113 return(EINVAL);
22114 }
22115
22116 /* If the super block has the wrong byte order, swap the fields; the magic
22117 * number doesn't need conversion. */
22118 sp->s_ninodes = conv2(native, (int) sp->s_ninodes);
22119 sp->s_nzones = conv2(native, (int) sp->s_nzones);
22120 sp->s_imap_blocks = conv2(native, (int) sp->s_imap_blocks);
22121 sp->s_zmap_blocks = conv2(native, (int) sp->s_zmap_blocks);
22122 sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone);
22123 sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size);
22124 sp->s_max_size = conv4(native, sp->s_max_size);
22125 sp->s_zones = conv4(native, sp->s_zones);
22126
22127 /* In V1, the device size was kept in a short, s_nzones, which limited
22128 * devices to 32K zones. For V2, it was decided to keep the size as a
22129 * long. However, just changing s_nzones to a long would not work, since
22130 * then the position of s_magic in the super block would not be the same
22131 * in V1 and V2 file systems, and there would be no way to tell whether
22132 * a newly mounted file system was V1 or V2. The solution was to introduce
22133 * a new variable, s_zones, and copy the size there.
22134 *
22135 * Calculate some other numbers that depend on the version here too, to
22136 * hide some of the differences.
22137 */
22138 if (version == V1) {
22139 sp->s_zones = sp->s_nzones; /* only V1 needs this copy */
22140 sp->s_inodes_per_block = V1_INODES_PER_BLOCK;
22141 sp->s_ndzones = V1_NR_DZONES;
22142 sp->s_nindirs = V1_INDIRECTS;
22143 } else {
22144 sp->s_inodes_per_block = V2_INODES_PER_BLOCK;
22145 sp->s_ndzones = V2_NR_DZONES;
22146 sp->s_nindirs = V2_INDIRECTS;
22147 }
22148
22149 sp->s_isearch = 0; /* inode searches initially start at 0 */
22150 sp->s_zsearch = 0; /* zone searches initially start at 0 */
22151 sp->s_version = version;
22152 sp->s_native = native;
22153
22154 /* Make a few basic checks to see if super block looks reasonable. */
22155 if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
22156 || sp->s_ninodes < 1 || sp->s_zones < 1
22157 || (unsigned) sp->s_log_zone_size > 4) {
22158 return(EINVAL);
22159 }
22160 sp->s_dev = dev; /* restore device number */
22161 return(OK);
22162 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -