LSX/sys/bio.c

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

#
/*
 *	Copyright 1975 Bell Telephone Laboratories Inc
 */

#include "param.h"
#include "user.h"
#include "buf.h"
#include "systm.h"
#include "proc.h"

/*
 * This is the set of buffers proper, whose heads
 * were declared in buf.h.  There can exist buffer
 * headers not pointing here that are used purely
 * as arguments to the I/O routines to describe
 * I/O to be done-- e.g. swbuf, just below, for
 * swapping.
 */
char	buffers[NBUF][512];
struct	buf	swbuf;

/*
 * The following several routines allocate and free
 * buffers with various side effects.  In general the
 * arguments to an allocate routine are a device and
 * a block number, and the value is a pointer to
 * to the buffer header; the buffer is marked "busy"
 * so that no on else can touch it.  If the block was
 * already in core, no I/O need be done.
 * The following routines allocate a buffer:
 *	getblk
 *	bread
 * Eventually the buffer must be released, possibly with the
 * side effect of writing it out, by using one of
 *	bwrite
 *	bdwrite
 *	brelse
 */

/*
 * Read in (if necessary) the block and return a buffer pointer.
 */
bread(dev, blkno)
{
	register struct buf *rbp;

	rbp = getblk(dev, blkno);
	if (rbp->b_flags&B_DONE)
		return(rbp);
	rbp->b_flags =| B_READ;
	rbp->b_wcount = -256;
	fdstrategy(rbp);
	iowait(rbp);
	return(rbp);
}

/*
 * Write the buffer, waiting for completion.
 * Then release the buffer.
 */
bwrite(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	rbp->b_flags =& ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
	rbp->b_wcount = -256;
	fdstrategy(rbp);
	iowait(rbp);
	brelse(rbp);
}

/*
 * Release the buffer, marking it so that if it is grabbed
 * for another purpose it will be written out before being
 * given up (e.g. when writing a partial block where it is
 * assumed that another write for the same block will soon follow).
 * This can't be done for magtape, since writes must be done
 * in the same order as requested.
 */
bdwrite(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	rbp->b_flags =| B_DELWRI | B_DONE;
	brelse(rbp);
}

/*
 * release the buffer, with no I/O implied.
 */
brelse(bp)
struct buf *bp;
{
	bp->b_flags =& ~B_BUSY;
}

/*
 * Assign a buffer for the given block.  If the appropriate
 * block is already associated, return it; otherwise search
 * for the oldest non-busy buffer and reassign it.
 * When a 512-byte area is wanted for some random reason
 * (e.g. during exec, for the user arglist) getblk can be called
 * with device NODEV to avoid unwanted associativity.
 */
getblk(dev, blkno)
{
	register struct buf *bp;
	register int *bdp, i;
	int *bdp2;

	bdp = NULL;
	for(i = 0; i < NBUF; i++) {
		bp = bufp[i];
		if((bp->b_flags&B_BUSY) == 0)
			bdp = &bufp[i];
		if(dev == NODEV)
			continue;
		if((bp->b_blkno == blkno) && (bp->b_dev == dev)) {
			bdp = &bufp[i];
			goto fnd;
		}
	}
	if(bdp == NULL)
		panic();
	bp = *bdp;
	if(bp->b_flags&B_DELWRI)
		bwrite(bp);
	bp->b_flags = 0;
	bp->b_blkno = blkno;
	bp->b_dev = dev;
fnd:
	bdp2 = bdp+1;
	while(bdp > &bufp[0])
		*--bdp2 = *--bdp;
	*bdp = bp;
	bp->b_flags =| B_BUSY;
	return(bp);
}

/*
 * Wait for I/O completion on the buffer; return errors
 * to the user.
 */
iowait(bp)
struct buf *bp;
{
	register struct buf *rbp;

	rbp = bp;
	spl7();
	while ((rbp->b_flags&B_DONE)==0)
		sleep(rbp, PRIBIO);
	spl0();
	if (bp->b_flags&B_ERROR)
		if ((u.u_error = bp->b_error)==0)
			u.u_error = EIO;
}

/*
 * Zero the core associated with a buffer.
 */
clrbuf(bp)
int *bp;
{
	register *p;
	register c;

	p = bp->b_addr;
	c = 256;
	do
		*p++ = 0;
	while (--c);
}

/*
 * Initialize the buffer I/O system by freeing
 * all buffers and setting all device buffer lists to empty.
 */
binit()
{
	register struct buf *bp;
	register int i;

	for(i = 0; i < NBUF; i++) {
		bp = bufp[i] = &buf[i];
		bp->b_dev = NODEV;
		bp->b_addr = &buffers[i];
	}
}

/*
 * make sure all write-behind blocks
 * on dev (or NODEV for all)
 * are flushed out.
 * (from umount and update)
 */

bflush(dev)
{
	register struct buf *bp;
	register int i;

	for(bp = &buf[0]; bp < &buf[NBUF]; bp++)
		if((bp->b_flags&B_DELWRI) && (dev == NODEV||dev==bp->b_dev))
			bwrite(bp);
}

/*
 * swap I/O
 */

#define	USTACK	(TOPSYS-12)
struct { int *intp;};
struct { char *chrp;};

#ifdef BGOPTION
struct swtab swtab[] {
	49*256,	0,
	49*256,	49,
	1*256,	49+49,
	49*256,	50+49,
};

swap(rdflg,tab)
{
	register struct swtab *t;

	swbuf.b_flags = B_BUSY | rdflg;
	swbuf.b_dev = SWAPDEV;
	t = &swtab[tab];
	swbuf.b_wcount = -t->sw_size;
	swbuf.b_blkno = t->sw_blk + SWPLO;
	swbuf.b_addr = &u;
	fdstrategy(&swbuf);
	spl7();
	while((swbuf.b_flags&B_DONE)==0)
		sleep(&swbuf, PSWP);
	spl0();
	return(swbuf.b_flags&B_ERROR);
}
#endif

#ifndef BGOPTION
swap(rdflg)
{
	register int *p, *p1, *p2;

	p = &proc[cpid];
	if(rdflg == B_WRITE) {
		p1 = USTACK->integ;
		p2 = TOPSYS + (u.u_dsize<<6) + (p1.integ&077);
		if(p2 <= p1) {
			p->p_size = u.u_dsize + USIZE +
			    ((TOPUSR>>6)&01777) - ((p1.integ>>6)&01777);
			while(p1.chrp < TOPUSR)
				*p2++ = *p1++;
		} else
			p->p_size = SWPSIZ<<3;
	}
	swbuf.b_flags = B_BUSY | rdflg;
	swbuf.b_dev = SWAPDEV;
	swbuf.b_wcount = -(((p->p_size+7)&~07)<<5);	/* 32 words per block */
	swbuf.b_blkno = SWPLO+cpid*SWPSIZ;
	swbuf.b_addr = &u;
	fdstrategy(&swbuf);
	spl7();
	while((swbuf.b_flags&B_DONE)==0)
		sleep(&swbuf, PSWP);
	spl0();
	if(rdflg == B_READ) {
		p1 = TOPUSR;
		p2 = (p->p_size<<6) + TOPSYS - (USIZE<<6);
		if(p2 <= p1)
			while(p1 >= USTACK->integ.intp)
				*--p1 = *--p2;
	}
	return(swbuf.b_flags&B_ERROR);
}
#endif