SRI-NOSC/ken/alloc.c

Compare this file to the similar file:
Show the results in this format:

#
#include "param.h"
#include "filsys.h"
#include "systm.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");
#ifndef UCBUFMOD
	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];
#endif not UCBUFMOD
#ifdef UCBUFMOD
	btk(bp->b_paddr, &0->s_isize, &mount[0].m_isize, 3);
		/* fetches isize, fsize, and nfree */
	mount[0].m_ninode = fbword(bp->b_paddr, &0->s_ninode);
	f1_copy(bp, cp, mount);	/* copy free lists */
	btk(bp->b_paddr, 0->s_time, time, 2);
	brelse(bp);
	mount[0].m_bufp = cp;
	mount[0].m_dev = rootdev;
	mount[0].m_flock = 0;
	mount[0].m_ilock = 0;
	mount[0].m_ronly = 0;
#endif UCBUFMOD
}

/*
 * 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);
#ifndef UCBUFMOD
	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);
	}
	fp->s_fmod = 1;
#endif not UCBUFMOD
#ifdef UCBUFMOD
	while(fp->m_flock)
		sleep(&fp->m_flock, PINOD);
	do {
		if(fp->m_nfree <= 0)
			goto nospace;
		bno = fbword(fp->m_bufp->b_paddr, &0->s_free[--fp->m_nfree]);
		if(bno == 0)
			goto nospace;
	} while (badblock(fp, bno, dev));
	if(fp->m_nfree <= 0) {
		fp->m_flock++;
		bp = bread(dev, bno);
		ip = bp->b_paddr;
		fp->m_nfree = fbword(ip, 0);
		f_copy(bp, 2, fp->m_bufp, 0->s_free, fp->m_nfree);
		brelse(bp);
		fp->m_flock = 0;
		wakeup(&fp->m_flock);
	}
	fp->m_fmod = 1;
#endif UCBUFMOD
	bp = getblk(dev, bno);
	clrbuf(bp);
	return(bp);

nospace:
#ifndef UCBUFMOD
	fp->s_nfree = 0;
#endif not UCBUFMOD
#ifdef UCBUFMOD
	fp->m_nfree = 0;
#endif UCBUFMOD
	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);
#ifndef UCBUFMOD
	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;
#endif not UCBUFMOD
#ifdef UCBUFMOD
	fp->m_fmod = 1;
	while(fp->m_flock)
		sleep(&fp->m_flock, PINOD);
	if(badblock(fp, bno, dev))
		return;
	if(fp->m_nfree <= 0) {
		fp->m_nfree = 1;
		sbword(fp->m_bufp->b_paddr, &0->s_free[0], 0);
	}
	if(fp->m_nfree >= 100) {
		fp->m_flock++;
		bp = getblk(dev, bno);
		ip = bp->b_paddr;
		sbword(ip, 0, fp->m_nfree);
		f_copy(fp->m_bufp, 0->s_free, bp, 2, fp->m_nfree);
		fp->m_nfree = 0;
		bwrite(bp);
		fp->m_flock = 0;
		wakeup(&fp->m_flock);
	}
	sbword(fp->m_bufp->b_paddr, &0->s_free[fp->m_nfree++], bno);
	fp->m_fmod = 1;
#endif UCBUFMOD
}

/*
 * 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;
#ifndef UCBUFMOD
	if (bn < fp->s_isize+2 || bn >= fp->s_fsize) {
#endif not UCBUFMOD
#ifdef UCBUFMOD
	if(bn < fp->m_isize+2 || bn >= fp->m_fsize) {
#endif UCBUFMOD
		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);
#ifndef UCBUFMOD
	while(fp->s_ilock)
		sleep(&fp->s_ilock, PINOD);
loop:
	if(fp->s_ninode > 0) {
		ino = fp->s_inode[--fp->s_ninode];
#endif not UCBUFMOD
#ifdef UCBUFMOD
	while(fp->m_ilock)
		sleep(&fp->m_ilock, PINOD);
loop:
	if(fp->m_ninode > 0) {
		ino = fbword(fp->m_bufp->b_paddr, &0->s_inode[--fp->m_ninode]);
#endif UCBUFMOD
		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;
#ifndef UCBUFMOD
			fp->s_fmod = 1;
#endif not UCBUFMOD
#ifdef UCBUFMOD
			fp->m_fmod = 1;
#endif UCBUFMOD
			return(ip);
		}
		/*
		 * Inode was allocated after all.
		 * Look some more.
		 */
		iput(ip);
		goto loop;
	}
	ino = 0;
#ifndef UCBUFMOD
	fp->s_ilock++;
	for(i=0; i<fp->s_isize; i++) {
#endif not UCBUFMOD
#ifdef UCBUFMOD
	fp->m_ilock++;
	for(i=0; i<fp->m_isize; i++) {
#endif UCBUFMOD
		bp = bread(dev, i+2);
#ifndef UCBUFMOD
		ip = bp->b_addr;
		for(j=0; j<256; j=+16) {
			ino++;
			if(ip[j] != 0)
#endif not UCBUFMOD
#ifdef UCBUFMOD
		ip = bp->b_paddr;
		for(j=0; j<512; j=+32) {
			ino++;
			if(fbword(ip, j) != 0)
#endif UCBUFMOD
				continue;
			for(k=0; k<NINODE; k++)
			if(dev==inode[k].i_dev && ino==inode[k].i_number)
				goto cont;
#ifndef UCBUFMOD
			fp->s_inode[fp->s_ninode++] = ino;
			if(fp->s_ninode >= 100)
#endif not UCBUFMOD
#ifdef UCBUFMOD
			sbword(fp->m_bufp->b_paddr, &0->s_inode[fp->m_ninode++], ino);
			if(fp->m_ninode >= 100)
#endif UCBUFMOD
				break;
		cont:;
		}
		brelse(bp);
#ifndef UCBUFMOD
		if(fp->s_ninode >= 100)
#endif not UCBUFMOD
#ifdef UCBUFMOD
		if(fp->m_ninode >= 100)
#endif UCBUFMOD
			break;
	}
#ifndef UCBUFMOD
	fp->s_ilock = 0;
	wakeup(&fp->s_ilock);
	if (fp->s_ninode > 0)
#endif not UCBUFMOD
#ifdef UCBUFMOD
	fp->m_ilock = 0;
	wakeup(&fp->m_ilock);
	if(fp->m_ninode > 0)
#endif UCBUFMOD
		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);
#ifndef UCBUFMOD
	if(fp->s_ilock)
		return;
	if(fp->s_ninode >= 100)
		return;
	fp->s_inode[fp->s_ninode++] = ino;
	fp->s_fmod = 1;
#endif not UCBUFMOD
#ifdef UCBUFMOD
	if(fp->m_ilock)
		return;
	if(fp->m_ninode >= 100)
		return;
	sbword(fp->m_bufp->b_paddr, &0->s_inode[fp->m_ninode++], ino);
	fp->m_fmod = 1;
#endif UCBUFMOD
}

/*
 * 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) {
#ifndef UCBUFMOD
		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;
#endif not UCBUFMOD
#ifdef UCBUFMOD
		n1 = p->m_nfree;
		n2 = p->m_ninode;
		if(n1 > 100 || n2 > 100) {
			prdev("bad count", dev);
			p->m_nfree = 0;
			p->m_ninode = 0;
#endif UCBUFMOD
		}
		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) {
#ifndef UCBUFMOD
			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);
#endif not UCBUFMOD
#ifdef UCBUFMOD
			if(mp->m_fmod==0 || mp->m_ilock!=0 ||
			   mp->m_flock!=0 || mp->m_ronly!=0)
				continue;
			bp = getblk(mp->m_dev, 1);
			ip = mp->m_bufp;
			mp->m_fmod = 0;
			ktb(bp->b_paddr, 0->s_time, time, 2);
			ktb(bp->b_paddr, &0->s_isize, &mp->m_isize, 3);
				/* stores isize, fsize, and nfree */
			sbword(bp->b_paddr, &0->s_ninode, mp->m_ninode);
			f1_copy(ip, bp, mp);	/* copy free lists */
#endif UCBUFMOD
			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);
}

#ifdef UCBUFMOD
/*
 * f1_copy copies the free lists from one buffer
 * to another using f_copy.
 */
f1_copy(from, to, mnt)
struct buf *from, *to;
struct mount *mnt;
{
	register struct mount *rmnt;

	rmnt = mnt;
	f_copy(from, 0->s_free, to, 0->s_free, rmnt->m_nfree);
	f_copy(from, 0->s_inode, to, 0->s_inode, rmnt->m_ninode);
}
/*
 * f_copy copies a free list from one
 * buffer to another buffer through
 * a 100 word temporary area in the
 * kernel
 */
int	supfree[100];		/* temporary for free lists */

f_copy(f_buf, f_off, t_buf, t_off, count)
{
	btk(f_buf->b_paddr, f_off, supfree, count);
	ktb(t_buf->b_paddr, t_off, supfree, count);
}
#endif UCBUFMOD