text: #
  /*
   */
  
  #include "../param.h"
  #include "../systm.h"
  #include "../filsys.h"
  #include "../conf.h"
  #include "../buf.h"
  #include "../inode.h"
  #include "../user.h"
  
  /*
   * iinit is called once (from main)
   * very early in initialization.
   * It reads the root's super block
   * and initializes the current date
   * from the last modified date.
   *
   * panic: iinit -- cannot read the super
   * block. Usually because of an IO error.
   */
  iinit()
  {
  	register *cp, *bp;
  
  	(*bdevsw[rootdev.d_major].d_open)(rootdev, 1);
  	bp = bread(rootdev, 1);
  	cp = getblk(NODEV);
  	if(u.u_error)
  		panic("iinit");
  	bcopy(bp->b_addr, cp->b_addr, 256);
  	brelse(bp);
  	mount[0].m_bufp = cp;
  	mount[0].m_dev = rootdev;
  	cp = cp->b_addr;
  	cp->s_flock = 0;
  	cp->s_ilock = 0;
  	cp->s_ronly = 0;
  	time[0] = cp->s_time[0];
  	time[1] = cp->s_time[1];
  }
  
  /*
   * alloc will obtain the next available
   * free disk block from the free list of
   * the specified device.
   * The super block has up to 100 remembered
   * free blocks; the last of these is read to
   * obtain 100 more . . .
   *
   * no space on dev x/y -- when
   * the free list is exhausted.
   */
  alloc(dev)
  {
  	int bno;
  	register *bp, *ip, *fp;
  
  	fp = getfs(dev);
  	while(fp->s_flock)
  		sleep(&fp->s_flock, PINOD);
  	do {
  		if(fp->s_nfree <= 0)
  			goto nospace;
  		bno = fp->s_free[--fp->s_nfree];
  		if(bno == 0)
  			goto nospace;
  	} while (badblock(fp, bno, dev));
  	if(fp->s_nfree <= 0) {
  		fp->s_flock++;
  		bp = bread(dev, bno);
  		ip = bp->b_addr;
  		fp->s_nfree = *ip++;
  		bcopy(ip, fp->s_free, 100);
  		brelse(bp);
  		fp->s_flock = 0;
  		wakeup(&fp->s_flock);
  	}
  	bp = getblk(dev, bno);
  	clrbuf(bp);
  	fp->s_fmod = 1;
  	return(bp);
  
  nospace:
  	fp->s_nfree = 0;
  	prdev("no space", dev);
  	u.u_error = ENOSPC;
  	return(NULL);
  }
  
  /*
   * place the specified disk block
   * back on the free list of the
   * specified device.
   */
  free(dev, bno)
  {
  	register *fp, *bp, *ip;
  
  	fp = getfs(dev);
  	fp->s_fmod = 1;
  	while(fp->s_flock)
  		sleep(&fp->s_flock, PINOD);
  	if (badblock(fp, bno, dev))
  		return;
  	if(fp->s_nfree <= 0) {
  		fp->s_nfree = 1;
  		fp->s_free[0] = 0;
  	}
  	if(fp->s_nfree >= 100) {
  		fp->s_flock++;
  		bp = getblk(dev, bno);
  		ip = bp->b_addr;
  		*ip++ = fp->s_nfree;
  		bcopy(fp->s_free, ip, 100);
  		fp->s_nfree = 0;
  		bwrite(bp);
  		fp->s_flock = 0;
  		wakeup(&fp->s_flock);
  	}
  	fp->s_free[fp->s_nfree++] = bno;
  	fp->s_fmod = 1;
  }
  
  /*
   * Check that a block number is in the
   * range between the I list and the size
   * of the device.
   * This is used mainly to check that a
   * garbage file system has not been mounted.
   *
   * bad block on dev x/y -- not in range
   */
  badblock(afp, abn, dev)
  {
  	register struct filsys *fp;
  	register char *bn;
  
  	fp = afp;
  	bn = abn;
  	if (bn < fp->s_isize+2 || bn >= fp->s_fsize) {
  		prdev("bad block", dev);
  		return(1);
  	}
  	return(0);
  }
  
  /*
   * Allocate an unused I node
   * on the specified device.
   * Used with file creation.
   * The algorithm keeps up to
   * 100 spare I nodes in the
   * super block. When this runs out,
   * a linear search through the
   * I list is instituted to pick
   * up 100 more.
   */
  ialloc(dev)
  {
  	register *fp, *bp, *ip;
  	int i, j, k, ino;
  
  	fp = getfs(dev);
  	while(fp->s_ilock)
  		sleep(&fp->s_ilock, PINOD);
  loop:
  	if(fp->s_ninode > 0) {
  		ino = fp->s_inode[--fp->s_ninode];
  		ip = iget(dev, ino);
  		if (ip==NULL)
  			return(NULL);
  		if(ip->i_mode == 0) {
  			for(bp = &ip->i_mode; bp < &ip->i_addr[8];)
  				*bp++ = 0;
  			fp->s_fmod = 1;
  			return(ip);
  		}
  		/*
  		 * Inode was allocated after all.
  		 * Look some more.
  		 */
  		iput(ip);
  		goto loop;
  	}
  	fp->s_ilock++;
  	ino = 0;
  	for(i=0; i<fp->s_isize; i++) {
  		bp = bread(dev, i+2);
  		ip = bp->b_addr;
  		for(j=0; j<256; j=+16) {
  			ino++;
  			if(ip[j] != 0)
  				continue;
  			for(k=0; k<NINODE; k++)
  			if(dev==inode[k].i_dev && ino==inode[k].i_number)
  				goto cont;
  			fp->s_inode[fp->s_ninode++] = ino;
  			if(fp->s_ninode >= 100)
  				break;
  		cont:;
  		}
  		brelse(bp);
  		if(fp->s_ninode >= 100)
  			break;
  	}
  	fp->s_ilock = 0;
  	wakeup(&fp->s_ilock);
  	if (fp->s_ninode > 0)
  		goto loop;
  	prdev("Out of inodes", dev);
  	u.u_error = ENOSPC;
  	return(NULL);
  }
  
  /*
   * Free the specified I node
   * on the specified device.
   * The algorithm stores up
   * to 100 I nodes in the super
   * block and throws away any more.
   */
  ifree(dev, ino)
  {
  	register *fp;
  
  	fp = getfs(dev);
  	if(fp->s_ilock)
  		return;
  	if(fp->s_ninode >= 100)
  		return;
  	fp->s_inode[fp->s_ninode++] = ino;
  	fp->s_fmod = 1;
  }
  
  /*
   * getfs maps a device number into
   * a pointer to the incore super
   * block.
   * The algorithm is a linear
   * search through the mount table.
   * A consistency check of the
   * in core free-block and i-node
   * counts.
   *
   * bad count on dev x/y -- the count
   *	check failed. At this point, all
   *	the counts are zeroed which will
   *	almost certainly lead to "no space"
   *	diagnostic
   * panic: no fs -- the device is not mounted.
   *	this "cannot happen"
   */
  getfs(dev)
  {
  	register struct mount *p;
  	register char *n1, *n2;
  
  	for(p = &mount[0]; p < &mount[NMOUNT]; p++)
  	if(p->m_bufp != NULL && p->m_dev == dev) {
  		p = p->m_bufp->b_addr;
  		n1 = p->s_nfree;
  		n2 = p->s_ninode;
  		if(n1 > 100 || n2 > 100) {
  			prdev("bad count", dev);
  			p->s_nfree = 0;
  			p->s_ninode = 0;
  		}
  		return(p);
  	}
  	panic("no fs");
  }
  
  /*
   * update is the internal name of
   * 'sync'. It goes through the disk
   * queues to initiate sandbagged IO;
   * goes through the I nodes to write
   * modified nodes; and it goes through
   * the mount table to initiate modified
   * super blocks.
   */
  update()
  {
  	register struct inode *ip;
  	register struct mount *mp;
  	register *bp;
  
  	if(updlock)
  		return;
  	updlock++;
  	for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
  		if(mp->m_bufp != NULL) {
  			ip = mp->m_bufp->b_addr;
  			if(ip->s_fmod==0 || ip->s_ilock!=0 ||
  			   ip->s_flock!=0 || ip->s_ronly!=0)
  				continue;
  			bp = getblk(mp->m_dev, 1);
  			ip->s_fmod = 0;
  			ip->s_time[0] = time[0];
  			ip->s_time[1] = time[1];
  			bcopy(ip, bp->b_addr, 256);
  			bwrite(bp);
  		}
  	for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
  		if((ip->i_flag&ILOCK) == 0) {
  			ip->i_flag =| ILOCK;
  			iupdat(ip, time);
  			prele(ip);
  		}
  	updlock = 0;
  	bflush(NODEV);
  }
  