File:  [MW Coherent from dump] / coherent / b / STREAMS / coh.386 / fs2.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/STREAMS/coh.386/fs2.c,v 1.1.1.1 2019/05/29 04:56:36 root Exp $ */
/* (lgl-
 *	The information contained herein is a trade secret of Mark Williams
 *	Company, and  is confidential information.  It is provided  under a
 *	license agreement,  and may be  copied or disclosed  only under the
 *	terms of  that agreement.  Any  reproduction or disclosure  of this
 *	material without the express written authorization of Mark Williams
 *	Company or persuant to the license agreement is unlawful.
 *
 *	COHERENT Version 2.3.37
 *	Copyright (c) 1982, 1983, 1984.
 *	An unpublished work by Mark Williams Company, Chicago.
 *	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Filesystem (disk inodes).
 *
 * $Log: fs2.c,v $
 * Revision 1.1.1.1  2019/05/29 04:56:36  root
 * coherent
 *
 * Revision 2.3  93/08/09  13:35:33  bin
 * Kernel 82 changes
 * 
 * Revision 2.2  93/07/26  15:19:24  nigel
 * Nigel's R80
 * 
 * Revision 2.2  93/07/26  14:28:32  nigel
 * Nigel's R80
 * 
 * Revision 1.5  93/04/14  10:06:31  root
 * r75
 * 
 * Revision 1.2  92/01/06  11:59:27  hal
 * Compile with cc.mwc.
 * 
 * Revision 1.1	88/03/24  16:13:51	src
 * Initial revision
 *
 * 87/04/29	Allan Cornish		/usr/src/sys/coh/fs2.c
 * Fsminit panic messages now specify the root major and minor device.
 *
 * 86/11/19	Allan Cornish		/usr/src/sys/coh/fs2.c
 * setacct() initializes the (new) (IO).io_flag field to 0.
 *
 * 85/08/08	Allan Cornish
 * ialloc() erroneously did a brelease(NULL) if bclaim() returned NULL.
 * also, sbp->s_fmod was set BEFORE the in-core inode table was updated.
 * This created a critical race with msync() (called by sync system call).
 *
 * 85/04/17	Allan Cornish
 * eliminated test for rootdev in msync()
 */

#include <common/ccompat.h>
#include <sys/debug.h>

#include <sys/coherent.h>
#include <sys/acct.h>
#include <sys/buf.h>
#include <canon.h>
#include <sys/con.h>
#include <sys/errno.h>
#include <sys/filsys.h>
#include <sys/ino.h>
#include <sys/inode.h>
#include <sys/io.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/file.h>

#define _INODE_BUSY_DUMP 1

/*
 * Initialise filesystem.
 */
fsminit()
{
	register MOUNT *mp;
	INODE	      *	ip;

	/*
	 * NIGEL: We begin by setting up all the inodes in the system.
	 */

	for (ip = inodep + NINODE - 1 ; ip >= inodep ; ip --) {
		ip->i_refc = 0;
		__GATE_INIT (ip->i_gate, "inode");
	}


	/*
	 * Mount the root file system.
	 */
	if ((mp = fsmount (rootdev, ronflag)) == NULL)
		panic ("fsminit: no rootdev(%d,%d)",
		       major (rootdev), minor (rootdev));

	/*
	 * Set system time from the super block.
	 */
	timer.t_time = mp->m_super.s_time;

	/*
	 * Access the root directory.
	 */
	if ((u.u_rdir = iattach (rootdev, ROOTIN)) == NULL)
		panic ("fsminit: no / on rootdev(%d,%d)",
		       major (rootdev), minor (rootdev));

	/*
	 * Record current directory.
	 */
	u.u_cdir = u.u_rdir;
	u.u_cdir->i_refc++;
	iunlock (u.u_rdir);
}


/*
 * Mount the given device.
 */
MOUNT *
fsmount(dev, f)
register dev_t dev;
{
	register MOUNT *mp;
	register BUF *bp;

	if ((mp = kalloc (sizeof (MOUNT))) == NULL) {
		printf ("fsmount(%x,%x): kalloc failed ", dev, f);
		return NULL;
	}
	dopen (dev, (f ? IPR : IPR | IPW), DFBLK);
	if (u.u_error) {
		printf("fsmount(%x,%x): dopen failed ", dev, f);
		kfree (mp);
		return NULL;
	}
	if ((bp = bread (dev, (daddr_t) SUPERI, BUF_SYNC)) == NULL) {
		dclose (dev, (f ? IPR : IPR | IPW), DFBLK);	/* NIGEL */
		kfree (mp);
		return NULL;
	}
	memcpy (& mp->m_super, bp->b_vaddr, sizeof (mp->m_super));
	brelease (bp);
	cansuper (& mp->m_super);

	mp->m_ip = NULL;
	mp->m_dev = dev;
	mp->m_flag = f;
	mp->m_super.s_fmod = 0;
	mp->m_next = mountp;

	__GATE_INIT (mp->m_ilock, "mount ilock");
	__GATE_INIT (mp->m_flock, "mount flock");

	mountp = mp;
	return mp;
}


/*
 * Canonize a super block.
 */
cansuper(fsp)
register struct filsys *fsp;
{
	register int i;

	canint (fsp->s_isize);
	candaddr (fsp->s_fsize);
	canshort (fsp->s_nfree);
	for (i = 0 ; i < NICFREE ; i ++)
		candaddr (fsp->s_free [i]);
	canshort (fsp->s_ninode);
	for (i = 0 ; i < NICINOD ; i ++)
		canino (fsp->s_inode [i]);
	cantime (fsp->s_time);
	candaddr (fsp->s_tfree);
	canino (fsp->s_tinode);
	canshort (fsp->s_m);
	canshort (fsp->s_n);
	canlong (fsp->s_unique);
}

/*
 * Given a pointer to a mount entry, write out all inodes on that device.
 */
msync(mp)
register MOUNT *mp;
{
	register struct filsys *sbp;
	register BUF *bp;

	if ((mp->m_flag & MFRON) != 0)
		return;
	isync (mp->m_dev);
	sbp = & mp->m_super;
	if (sbp->s_fmod == 0)
		return;
	bp = bclaim (mp->m_dev, (daddr_t) SUPERI, BUF_SYNC);
	sbp->s_time = timer.t_time;
	sbp->s_fmod = 0;
	memcpy (bp->b_vaddr, sbp, sizeof (* sbp));
	cansuper (bp->b_vaddr);
	bwrite (bp, 1);
	brelease (bp);
}

/*
 * Return the mount entry for the given device.  If `f' is not set
 * and the device is read only, don't set the error status.
 */
MOUNT *
getment(dev, f)
register dev_t dev;
{
	register MOUNT *mp;

	for (mp = mountp ; mp != NULL ; mp = mp->m_next) {
		if (mp->m_dev != dev)
			continue;
		if ((mp->m_flag & MFRON) != 0) {
			if (f != 0)
				u.u_error = EROFS;
			return NULL;
		}
		return mp;
	}
	panic ("getment: dev=0x%x", dev);
}

/*
 * Allocate a new inode with the given mode.  The returned inode is locked.
 */
INODE *
ialloc(dev, mode)
dev_t dev;
unsigned mode;
{
	register struct dinode *dip;
	register struct filsys *sbp;
	register ino_t *inop;
	register ino_t ino;
	register BUF *bp;
	register daddr_t b;
	register struct dinode *dipe;
	register ino_t *inope;
	register MOUNT *mp;
	register INODE *ip;
#if _INODE_BUSY_DUMP
	int	eninode, etinode;
	int	lninode, ltinode;
	int	xninode, xtinode;
#endif

	if ((mp = getment (dev, 1)) == NULL)
		return NULL;
	sbp = & mp->m_super;

#if _INODE_BUSY_DUMP
	eninode = sbp->s_ninode;
	etinode = sbp->s_tinode;
#endif

	for (;;) {
		lock (mp->m_ilock);

#if _INODE_BUSY_DUMP
		lninode = sbp->s_ninode;
		ltinode = sbp->s_tinode;
#endif

		if (sbp->s_ninode == 0) {
			isync (dev);
			ino = 1;
			inop = sbp->s_inode;
			inope = & sbp->s_inode [NICINOD];
			for (b = INODEI ; b < sbp->s_isize ; b ++) {
				if (bad (dev, b)) {
					ino += INOPB;
					continue;
				}
				if ((bp = bread (dev, b, BUF_SYNC)) == NULL) {
					ino += INOPB;
					continue;
				}
				dip = bp->b_vaddr;
				dipe = & dip [INOPB];
				for (; dip < dipe ; dip ++, ino ++) {
					if (dip->di_mode != 0)
						continue;
					if (inop >= inope)
						break;
					* inop ++ = ino;
				}
				brelease (bp);
				if (inop >= inope)
					break;
			}
			sbp->s_ninode = inop - sbp->s_inode;
			if (sbp->s_ninode == 0) {
				sbp->s_tinode = 0;
				unlock (mp->m_ilock);
				devmsg (dev, "Out of inodes");
				u.u_error = ENOSPC;
				return NULL;
			}
		}

#if _INODE_BUSY_DUMP
		xninode = sbp->s_ninode;
		xtinode = sbp->s_tinode;
#endif

		ino = sbp->s_inode [-- sbp->s_ninode];
		-- sbp->s_tinode;
		sbp->s_fmod = 1;
		unlock (mp->m_ilock);
		if ((ip = iattach(dev, ino)) != NULL) {
			if (ip->i_mode != 0) {
				devmsg(dev, "Inode %u busy", ino);

#if _INODE_BUSY_DUMP
printf("%x %x rf=%x fl=%x md=%x nl=%x en=%x et=%x ln=%x lt=%x xn=%x xt=%x n=%x t=%x\n",
	mode, ino, ip->i_refc, ip->i_flag, ip->i_mode, ip->i_nlink,
	eninode, etinode, lninode, ltinode, xninode, xtinode,
	sbp->s_ninode, sbp->s_tinode);
#endif

				idetach (ip);
				lock (mp->m_ilock);
				++ sbp->s_tinode;
				sbp->s_fmod = 1;
				unlock (mp->m_ilock);
				continue;
			}
			ip->i_flag = 0;
			ip->i_mode = mode;
			ip->i_nlink = 0;
			ip->i_uid = u.u_uid;
			ip->i_gid = u.u_gid;
		}
		return ip;
	}
}

/*
 * Free the inode `ino' on device `dev'.
 */
ifree(dev, ino)
dev_t dev;
ino_t ino;
{
	register struct filsys *sbp;
	register MOUNT *mp;

	if ((mp = getment(dev, 1)) == NULL)
		return;
	lock (mp->m_ilock);
	sbp = & mp->m_super;
	sbp->s_fmod = 1;
	if (sbp->s_ninode < NICINOD)
		sbp->s_inode [sbp->s_ninode ++] = ino;
	sbp->s_tinode ++;
	unlock (mp->m_ilock);
}

/*
 * Free all blocks in the indirect block `b' on the device `dev'.
 * `l' is the level of indirection.
 */
indfree(dev, b, l)
dev_t dev;
daddr_t b;
register unsigned l;
{
	register int i;
	register BUF *bp;
	daddr_t * dp;
	daddr_t b1;

	if (b == 0)
		return;
	if (l -- > 0 && (bp = bread (dev, b, BUF_SYNC)) != NULL) {
		i = NBN;
		while (i -- > 0) {
			dp = bp->b_vaddr;
			if ((b1 = dp [i]) == 0)
				continue;
			candaddr (b1);
			if (l == 0)
				bfree (dev, b1);
			else
				indfree (dev, b1, l);
		}
		brelease (bp);
	}
	bfree (dev, b);
}

/*
 * Experimental routine to read free block lists blocks (ahead of time, but
 * if it works we'll subsume the synchronous read as well).
 */

static BUF *
read_free_block_list (super, dev, block_no, sync_flag)
struct filsys *	super;
dev_t		dev;
daddr_t		block_no;
int		sync_flag;
{
	return block_no < super->s_fsize && block_no >= super->s_isize ?
			bread (dev, block_no, sync_flag) : NULL;
}


/*
 * Allocate a block from the filesystem mounted of device `dev'.
 */

daddr_t
balloc(dev)
dev_t dev;
{
	register struct filsys *sbp;
	register struct fblk *fbp;
	register daddr_t b;
	register BUF *bp;
	register MOUNT *mp;

	if ((mp = getment(dev, 1)) == NULL)
		return 0;
	lock (mp->m_flock);
	sbp = & mp->m_super;
	if (sbp->s_nfree == 0) {
enospc:
		sbp->s_nfree = 0;
		devmsg (dev, "Out of space");
		u.u_error = ENOSPC;
		b = 0;
	} else {
		sbp->s_fmod = 1;
		if ((b = sbp->s_free [-- sbp->s_nfree]) == 0)
			goto enospc;
		if (sbp->s_nfree == 0) {
			if ((bp = read_free_block_list (sbp, dev, b,
							BUF_SYNC)) == NULL) {
ebadflist:
				devmsg(dev, "Bad free list");
				goto enospc;
			}
			fbp = bp->b_vaddr;
			sbp->s_nfree = fbp->df_nfree;
			canshort (sbp->s_nfree);
			memcpy (sbp->s_free, fbp->df_free,
				sizeof (sbp->s_free));

			if (sbp->s_nfree > NICFREE)
				goto ebadflist;
			brelease (bp);

			canndaddr (sbp->s_free, sbp->s_nfree);

			/*
			 * NIGEL: As an experiment, try reading ahead on the
			 * free block list.
			 */

			if (sbp->s_nfree > 0)
				read_free_block_list (sbp, dev,
						      sbp->s_free [0],
						      BUF_ASYNC);
		}
		-- sbp->s_tfree;
		if (b >= sbp->s_fsize || b < sbp->s_isize)
			goto ebadflist;
	}
	unlock (mp->m_flock);
	return b;
}


/*
 * Flag to say whether we should try and keep the free-block list sorted.
 */

int	t_sortblocks = 0;

/*
 * If we are sorting blocks, this routine can be used to keep blocks in sorted
 * order. Given a fixed-size list in reverse rank order, this routine returns
 * the new element if it is smaller than all others, or the smallest element
 * after the new element has been inserted in position.
 */

#if	__USE_PROTO__
static daddr_t daddr_add (daddr_t * list, int count, daddr_t newblock)
#else
static daddr_t
daddr_add (list, count, newblock)
daddr_t	      *	list;
int		count;
daddr_t		newblock;
#endif
{
	daddr_t	      *	end = list + count;

	ASSERT (count >= 0);

	while (list != end) {
		if (newblock < * list ++) {
			daddr_t	      temp;
			/*
			 * We have found the insertion point... move all the
			 * elements from (list - 1) to (end - 1) up, and put
			 * the new element in place.
			 */

			temp = * -- end;
			list --;

			while (list != end) {
				end --;
				* (end + 1) = * end;
			}
			* list = newblock;
			return temp;
		}
	}

	return newblock;
}


/*
 * Free the block `b' on the device `dev'.
 */
bfree(dev, b)
dev_t dev;
daddr_t b;
{
	register struct filsys *sbp;
	register struct fblk *fbp;
	register BUF *bp;
	register MOUNT *mp;

	if ((mp = getment (dev, 1)) == NULL)
		return;
	sbp = & mp->m_super;
	if (b >= sbp->s_fsize || b < sbp->s_isize) {
		devmsg (dev, "Bad block %u (free)", (unsigned) b);
		return;
	}

	/*
	 * NIGEL : Are we keeping things in order? If so, insert the new block
	 * in position (the smallest block-number is the new 'b'). Note that
	 * the zero-position of the free-block list never changes... this is
	 * an important invariant, because the block in that position is a
	 * link and *must* be preserved in that position so that the links get
	 * properly followed later on.
	 */

	if (t_sortblocks && sbp->s_nfree > 0)
		b = daddr_add (sbp->s_free + 1, sbp->s_nfree - 1, b);

	lock (mp->m_flock);
	if (sbp->s_nfree == 0 || sbp->s_nfree == NICFREE) {
		bp = bclaim (dev, b, BUF_SYNC);
		fbp = bp->b_vaddr;

		/*
		 * NIGEL: Is there really any reason to do this?
		 */
		memset (bp->b_vaddr, 0, BSIZE);

		fbp->df_nfree = sbp->s_nfree;
		canshort (fbp->df_nfree);
		memcpy (fbp->df_free, sbp->s_free, sizeof (fbp->df_free));
		canndaddr (fbp->df_free, sbp->s_nfree);

		bp->b_flag |= BFMOD;
		brelease (bp);
		sbp->s_nfree = 0;
	}
	sbp->s_free [sbp->s_nfree ++] = b;
	sbp->s_tfree ++;
	sbp->s_fmod = 1;
	unlock (mp->m_flock);
}

/*
 * Determine if the given block is bad.
 */
bad(dev, b)
dev_t dev;
daddr_t b;
{
	register INODE *ip;
	register BUF *bp;
	register int i;
	register int m;
	register int n;
	daddr_t l;

	if ((ip = iattach (dev, 1)) == NULL)
		panic ("bad()");
	n = blockn (ip->i_size);
	if ((m = n) > ND)
		m = ND;
	for (i = 0 ; i < m ; i ++) {
		-- n;
		if (b == ip->i_a.i_addr [i]) {
			idetach (ip);
			return 1;
		}
	}
	l = ip->i_a.i_addr [ND];
	idetach (ip);
	if (n == 0)
		return 0;
	if ((bp = bread (dev, l, BUF_SYNC)) == NULL)
		return 0;
	if ((m = n) > NBN)
		m = NBN;
	for (i = 0 ; i < m ; i ++) {
		l = ((daddr_t *) bp) [i];
		candaddr (l);
		if (b == l) {
			brelease (bp);
			return 1;
		}
	}
	brelease (bp);
	return 0;
}

/*
 * Canonize `n' disk addresses.
 */
canndaddr(dp, n)
register daddr_t *dp;
register int n;
{
	while (n --) {
		candaddr (* dp);
		dp ++;
	}
}

/*
 * Convert long to comp_t style number.
 * A comp_t contains 3 bits of base-8 exponent
 * and a 13-bit mantissa.  Only unsigned
 * numbers can be comp_t numbers.
 */

#define	MAXMANT		017777		/* 2^13-1 = largest mantissa */

static comp_t
ltoc(l)
long l;
{
	register int exp;

	if (l < 0)
		return 0;
	for (exp = 0 ; l > MAXMANT ; exp ++)
		l >>= 3;
	return (exp << 13) | l;
}

/*
 * Write out an accounting record.
 */
setacct()
{
	register PROC *pp;
	struct acct acct;
	IO acctio;

	if (acctip == NULL)
		return;
	pp = SELF;
	kkcopy(u.u_comm, acct.ac_comm, 10);
	acct.ac_utime = ltoc(pp->p_utime);
	acct.ac_stime = ltoc(pp->p_stime);
	acct.ac_etime = ltoc(timer.t_time - u.u_btime);
	acct.ac_btime = u.u_btime;
	acct.ac_uid = u.u_uid;
	acct.ac_gid = u.u_gid;
	acct.ac_mem = 0;
	acct.ac_io = ltoc(u.u_block);
	acct.ac_tty = pp->p_ttdev;
	acct.ac_flag = u.u_flag;
	ilock(acctip);
	acctio.io_seek = acctip->i_size;
	acctio.io_ioc  = sizeof (acct);
	acctio.io.vbase = &acct;
	acctio.io_seg  = IOSYS;
	acctio.io_flag = 0;
	iwrite(acctip, &acctio);
	iunlock(acctip);
	u.u_error = 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.