The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/servers/fs/super.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* This file manages the super block table and the related data structures,
    2  * namely, the bit maps that keep track of which zones and which inodes are
    3  * allocated and which are free.  When a new inode or zone is needed, the
    4  * appropriate bit map is searched for a free entry.
    5  *
    6  * The entry points into this file are
    7  *   alloc_bit:       somebody wants to allocate a zone or inode; find one
    8  *   free_bit:        indicate that a zone or inode is available for allocation
    9  *   get_super:       search the 'superblock' table for a device
   10  *   mounted:         tells if file inode is on mounted (or ROOT) file system
   11  *   read_super:      read a superblock
   12  */
   13 
   14 #include "fs.h"
   15 #include <string.h>
   16 #include <minix/com.h>
   17 #include "buf.h"
   18 #include "inode.h"
   19 #include "super.h"
   20 #include "const.h"
   21 
   22 /*===========================================================================*
   23  *                              alloc_bit                                    *
   24  *===========================================================================*/
   25 PUBLIC bit_t alloc_bit(sp, map, origin)
   26 struct super_block *sp;         /* the filesystem to allocate from */
   27 int map;                        /* IMAP (inode map) or ZMAP (zone map) */
   28 bit_t origin;                   /* number of bit to start searching at */
   29 {
   30 /* Allocate a bit from a bit map and return its bit number. */
   31 
   32   block_t start_block;          /* first bit block */
   33   bit_t map_bits;               /* how many bits are there in the bit map? */
   34   unsigned bit_blocks;          /* how many blocks are there in the bit map? */
   35   unsigned block, word, bcount;
   36   struct buf *bp;
   37   bitchunk_t *wptr, *wlim, k;
   38   bit_t i, b;
   39 
   40   if (sp->s_rd_only)
   41         panic(__FILE__,"can't allocate bit on read-only filesys.", NO_NUM);
   42 
   43   if (map == IMAP) {
   44         start_block = START_BLOCK;
   45         map_bits = sp->s_ninodes + 1;
   46         bit_blocks = sp->s_imap_blocks;
   47   } else {
   48         start_block = START_BLOCK + sp->s_imap_blocks;
   49         map_bits = sp->s_zones - (sp->s_firstdatazone - 1);
   50         bit_blocks = sp->s_zmap_blocks;
   51   }
   52 
   53   /* Figure out where to start the bit search (depends on 'origin'). */
   54   if (origin >= map_bits) origin = 0;   /* for robustness */
   55 
   56   /* Locate the starting place. */
   57   block = origin / FS_BITS_PER_BLOCK(sp->s_block_size);
   58   word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
   59 
   60   /* Iterate over all blocks plus one, because we start in the middle. */
   61   bcount = bit_blocks + 1;
   62   do {
   63         bp = get_block(sp->s_dev, start_block + block, NORMAL);
   64         wlim = &bp->b_bitmap[FS_BITMAP_CHUNKS(sp->s_block_size)];
   65 
   66         /* Iterate over the words in block. */
   67         for (wptr = &bp->b_bitmap[word]; wptr < wlim; wptr++) {
   68 
   69                 /* Does this word contain a free bit? */
   70                 if (*wptr == (bitchunk_t) ~0) continue;
   71 
   72                 /* Find and allocate the free bit. */
   73                 k = conv2(sp->s_native, (int) *wptr);
   74                 for (i = 0; (k & (1 << i)) != 0; ++i) {}
   75 
   76                 /* Bit number from the start of the bit map. */
   77                 b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
   78                     + (wptr - &bp->b_bitmap[0]) * FS_BITCHUNK_BITS
   79                     + i;
   80 
   81                 /* Don't allocate bits beyond the end of the map. */
   82                 if (b >= map_bits) break;
   83 
   84                 /* Allocate and return bit number. */
   85                 k |= 1 << i;
   86                 *wptr = conv2(sp->s_native, (int) k);
   87                 bp->b_dirt = DIRTY;
   88                 put_block(bp, MAP_BLOCK);
   89                 return(b);
   90         }
   91         put_block(bp, MAP_BLOCK);
   92         if (++block >= bit_blocks) block = 0;   /* last block, wrap around */
   93         word = 0;
   94   } while (--bcount > 0);
   95   return(NO_BIT);               /* no bit could be allocated */
   96 }
   97 
   98 /*===========================================================================*
   99  *                              free_bit                                     *
  100  *===========================================================================*/
  101 PUBLIC void free_bit(sp, map, bit_returned)
  102 struct super_block *sp;         /* the filesystem to operate on */
  103 int map;                        /* IMAP (inode map) or ZMAP (zone map) */
  104 bit_t bit_returned;             /* number of bit to insert into the map */
  105 {
  106 /* Return a zone or inode by turning off its bitmap bit. */
  107 
  108   unsigned block, word, bit;
  109   struct buf *bp;
  110   bitchunk_t k, mask;
  111   block_t start_block;
  112 
  113   if (sp->s_rd_only)
  114         panic(__FILE__,"can't free bit on read-only filesys.", NO_NUM);
  115 
  116   if (map == IMAP) {
  117         start_block = START_BLOCK;
  118   } else {
  119         start_block = START_BLOCK + sp->s_imap_blocks;
  120   }
  121   block = bit_returned / FS_BITS_PER_BLOCK(sp->s_block_size);
  122   word = (bit_returned % FS_BITS_PER_BLOCK(sp->s_block_size))
  123          / FS_BITCHUNK_BITS;
  124 
  125   bit = bit_returned % FS_BITCHUNK_BITS;
  126   mask = 1 << bit;
  127 
  128   bp = get_block(sp->s_dev, start_block + block, NORMAL);
  129 
  130   k = conv2(sp->s_native, (int) bp->b_bitmap[word]);
  131   if (!(k & mask)) {
  132         panic(__FILE__,map == IMAP ? "tried to free unused inode" :
  133               "tried to free unused block", NO_NUM);
  134   }
  135 
  136   k &= ~mask;
  137   bp->b_bitmap[word] = conv2(sp->s_native, (int) k);
  138   bp->b_dirt = DIRTY;
  139 
  140   put_block(bp, MAP_BLOCK);
  141 }
  142 
  143 /*===========================================================================*
  144  *                              get_super                                    *
  145  *===========================================================================*/
  146 PUBLIC struct super_block *get_super(dev)
  147 dev_t dev;                      /* device number whose super_block is sought */
  148 {
  149 /* Search the superblock table for this device.  It is supposed to be there. */
  150 
  151   register struct super_block *sp;
  152 
  153   if (dev == NO_DEV)
  154         panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
  155 
  156   for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
  157         if (sp->s_dev == dev) return(sp);
  158 
  159   /* Search failed.  Something wrong. */
  160   panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev);
  161 
  162   return(NIL_SUPER);            /* to keep the compiler and lint quiet */
  163 }
  164 
  165 /*===========================================================================*
  166  *                              get_block_size                               *
  167  *===========================================================================*/
  168 PUBLIC int get_block_size(dev_t dev)
  169 {
  170 /* Search the superblock table for this device. */
  171 
  172   register struct super_block *sp;
  173 
  174   if (dev == NO_DEV)
  175         panic(__FILE__,"request for block size of NO_DEV", NO_NUM);
  176 
  177   for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
  178         if (sp->s_dev == dev) {
  179                 return(sp->s_block_size);
  180         }
  181   }
  182 
  183   /* no mounted filesystem? use this block size then. */
  184   return MIN_BLOCK_SIZE;
  185 }
  186 
  187 /*===========================================================================*
  188  *                              mounted                                      *
  189  *===========================================================================*/
  190 PUBLIC int mounted(rip)
  191 register struct inode *rip;     /* pointer to inode */
  192 {
  193 /* Report on whether the given inode is on a mounted (or ROOT) file system. */
  194 
  195   register struct super_block *sp;
  196   register dev_t dev;
  197 
  198   dev = (dev_t) rip->i_zone[0];
  199   if (dev == root_dev) return(TRUE);    /* inode is on root file system */
  200 
  201   for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
  202         if (sp->s_dev == dev) return(TRUE);
  203 
  204   return(FALSE);
  205 }
  206 
  207 /*===========================================================================*
  208  *                              read_super                                   *
  209  *===========================================================================*/
  210 PUBLIC int read_super(sp)
  211 register struct super_block *sp; /* pointer to a superblock */
  212 {
  213 /* Read a superblock. */
  214   dev_t dev;
  215   int magic;
  216   int version, native, r;
  217   static char sbbuf[MIN_BLOCK_SIZE];
  218 
  219   dev = sp->s_dev;              /* save device (will be overwritten by copy) */
  220   if (dev == NO_DEV)
  221         panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
  222   r = dev_io(DEV_READ, dev, FS_PROC_NR,
  223         sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0);
  224   if (r != MIN_BLOCK_SIZE) {
  225         return EINVAL;
  226   }
  227   memcpy(sp, sbbuf, sizeof(*sp));
  228   sp->s_dev = NO_DEV;           /* restore later */
  229   magic = sp->s_magic;          /* determines file system type */
  230 
  231   /* Get file system version and type. */
  232   if (magic == SUPER_MAGIC || magic == conv2(BYTE_SWAP, SUPER_MAGIC)) {
  233         version = V1;
  234         native  = (magic == SUPER_MAGIC);
  235   } else if (magic == SUPER_V2 || magic == conv2(BYTE_SWAP, SUPER_V2)) {
  236         version = V2;
  237         native  = (magic == SUPER_V2);
  238   } else if (magic == SUPER_V3) {
  239         version = V3;
  240         native = 1;
  241   } else {
  242         return(EINVAL);
  243   }
  244 
  245   /* If the super block has the wrong byte order, swap the fields; the magic
  246    * number doesn't need conversion. */
  247   sp->s_ninodes =       conv4(native, sp->s_ninodes);
  248   sp->s_nzones =        conv2(native, (int) sp->s_nzones);
  249   sp->s_imap_blocks =   conv2(native, (int) sp->s_imap_blocks);
  250   sp->s_zmap_blocks =   conv2(native, (int) sp->s_zmap_blocks);
  251   sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone);
  252   sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size);
  253   sp->s_max_size =      conv4(native, sp->s_max_size);
  254   sp->s_zones =         conv4(native, sp->s_zones);
  255 
  256   /* In V1, the device size was kept in a short, s_nzones, which limited
  257    * devices to 32K zones.  For V2, it was decided to keep the size as a
  258    * long.  However, just changing s_nzones to a long would not work, since
  259    * then the position of s_magic in the super block would not be the same
  260    * in V1 and V2 file systems, and there would be no way to tell whether
  261    * a newly mounted file system was V1 or V2.  The solution was to introduce
  262    * a new variable, s_zones, and copy the size there.
  263    *
  264    * Calculate some other numbers that depend on the version here too, to
  265    * hide some of the differences.
  266    */
  267   if (version == V1) {
  268         sp->s_block_size = STATIC_BLOCK_SIZE;
  269         sp->s_zones = sp->s_nzones;     /* only V1 needs this copy */
  270         sp->s_inodes_per_block = V1_INODES_PER_BLOCK;
  271         sp->s_ndzones = V1_NR_DZONES;
  272         sp->s_nindirs = V1_INDIRECTS;
  273   } else {
  274         if (version == V2)
  275                 sp->s_block_size = STATIC_BLOCK_SIZE;
  276         if (sp->s_block_size < MIN_BLOCK_SIZE)
  277                 return EINVAL;
  278         sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
  279         sp->s_ndzones = V2_NR_DZONES;
  280         sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
  281   }
  282 
  283   if (sp->s_block_size < MIN_BLOCK_SIZE) {
  284         return EINVAL;
  285   }
  286   if (sp->s_block_size > MAX_BLOCK_SIZE) {
  287         printf("Filesystem block size is %d kB; maximum filesystem\n"
  288         "block size is %d kB. This limit can be increased by recompiling.\n",
  289         sp->s_block_size/1024, MAX_BLOCK_SIZE/1024);
  290         return EINVAL;
  291   }
  292   if ((sp->s_block_size % 512) != 0) {
  293         return EINVAL;
  294   }
  295   if (SUPER_SIZE > sp->s_block_size) {
  296         return EINVAL;
  297   }
  298   if ((sp->s_block_size % V2_INODE_SIZE) != 0 ||
  299      (sp->s_block_size % V1_INODE_SIZE) != 0) {
  300         return EINVAL;
  301   }
  302 
  303   sp->s_isearch = 0;            /* inode searches initially start at 0 */
  304   sp->s_zsearch = 0;            /* zone searches initially start at 0 */
  305   sp->s_version = version;
  306   sp->s_native  = native;
  307 
  308   /* Make a few basic checks to see if super block looks reasonable. */
  309   if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
  310                                 || sp->s_ninodes < 1 || sp->s_zones < 1
  311                                 || (unsigned) sp->s_log_zone_size > 4) {
  312         printf("not enough imap or zone map blocks, \n");
  313         printf("or not enough inodes, or not enough zones, "
  314                 "or zone size too large\n");
  315         return(EINVAL);
  316   }
  317   sp->s_dev = dev;              /* restore device number */
  318   return(OK);
  319 }

Cache object: 31cae6fbcec3fae950bde444e8ba535f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.