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

/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/kernel/coh.386/fs2.c,v 1.1.1.1 2019/05/29 04:56:37 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:37  root
 * coherent
 *
 * Revision 1.10  93/06/14  13:34:40  bin
 * Hal: kernel 78 update
 * 
 * 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 <sys/coherent.h>
#include <sys/acct.h>
#include <sys/buf.h>
#include <canon.h>
#include <sys/con.h>
#include <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>

#define _INODE_BUSY_DUMP 1

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

	/*
	 * 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, 1)) == NULL) {
		dclose(dev, (f?IPR:IPR|IPW), DFBLK);	/* NIGEL */
		kfree(mp);
		return NULL;
	}
	kkcopy(bp->b_vaddr, &mp->m_super, sizeof(struct filsys));
	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;
	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);
	sbp->s_time = timer.t_time;
	sbp->s_fmod = 0;
	kkcopy(sbp, bp->b_vaddr, 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, 1)) == 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, 1))!=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);
}

/*
 * 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 (b >= sbp->s_fsize
			 || b < sbp->s_isize
			 || (bp = bread(dev, b, 1)) == NULL) {
ebadflist:
				devmsg(dev, "Bad free list");
				goto enospc;
			}
			fbp = bp->b_vaddr;
			sbp->s_nfree = fbp->df_nfree;
			canshort(sbp->s_nfree);
			if ((unsigned)sbp->s_nfree > NICFREE)
				goto ebadflist;
			kkcopy(fbp->df_free, sbp->s_free, sizeof(sbp->s_free));
			canndaddr(sbp->s_free, sbp->s_nfree);
			brelease(bp);
		}
		--sbp->s_tfree;
		if (b >= sbp->s_fsize || b < sbp->s_isize)
			goto ebadflist;
	}
	unlock(mp->m_flock);
	return (b);
}

/*
 * 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;
	}
	lock(mp->m_flock);
	if (sbp->s_nfree == 0 || sbp->s_nfree == NICFREE) {
		bp = bclaim(dev, b);
		kclear(bp->b_vaddr, BSIZE);
		fbp = bp->b_vaddr;
		fbp->df_nfree = sbp->s_nfree;
		canshort(fbp->df_nfree);
		kkcopy(sbp->s_free, fbp->df_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, 1)) == 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.