/* * Copyright (c) 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ /* * The header for buffers in the buffer pool and otherwise used * to describe a block i/o request is given here. * * Each buffer in the pool is usually doubly linked into 2 lists: * hashed into a chain by so it can be located in the cache, * and (usually) on (one of several) queues. These lists are circular and * doubly linked for easy removal. * * There are currently two queues for buffers: * one for buffers containing ``useful'' information (the cache) * one for buffers containing ``non-useful'' information * (and empty buffers, pushed onto the front) * These queues contain the buffers which are available for * reallocation, are kept in lru order. When not on one of these queues, * the buffers are ``checked out'' to drivers which use the available list * pointers to keep track of them in their i/o active queues. */ /* * Bufhd structures used at the head of the hashed buffer queues. * We only need three words for these, so this abbreviated * definition saves some space. */ struct bufhd { int b_flags; /* see defines below */ struct buf *b_forw, *b_back; /* fwd/bkwd pointer in chain */ }; struct buf { int b_flags; /* see defines below */ struct buf *b_forw, *b_back; /* hash chain (2 way street) */ struct buf *av_forw, *av_back; /* position on free list if not BUSY */ #define b_actf av_forw /* alternate names for driver queue */ #define b_actl av_back /* head - isn't history wonderful */ u_int b_bcount; /* transfer count */ #define b_active b_bcount /* driver queue head: drive active */ int b_error; /* returned after I/O */ dev_t b_dev; /* major+minor device name */ caddr_t b_addr; /* core address */ daddr_t b_blkno; /* block # on device */ u_int b_resid; /* words not transferred after error */ #define b_cylin b_resid /* disksort */ #define b_errcnt b_resid /* while i/o in progress: # retries */ }; /* * We never use BQ_LOCKED or BQ_EMPTY, but if you want the 4.X block I/O * code to drop in, you have to have BQ_AGE and BQ_LRU *after* the first * queue, and it only costs 6 bytes of data space. */ #define BQUEUES 3 /* number of free buffer queues */ #define BQ_LOCKED 0 /* super-blocks &c */ #define BQ_LRU 1 /* lru, useful buffers */ #define BQ_AGE 2 /* rubbish */ #define BQ_EMPTY 3 /* buffer headers with no memory */ /* Flags to low-level allocation routines. */ #define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */ #define B_SYNC 0x02 /* Do all allocations synchronously. */ #define bawrite(bp) { (bp)->b_flags |= B_ASYNC; bwrite(bp); } #define bfree(bp) (bp)->b_bcount = 0 #ifdef KERNEL struct inode; #define BUFHSZ 16 /* must be power of 2 */ #define BUFHASH(dev,bn) ((struct buf*) &bufhash [((dev) + bn) & (BUFHSZ - 1)]) extern struct buf buf[]; /* the buffer pool itself */ extern char bufdata[]; /* core data */ extern struct bufhd bufhash[]; /* heads of hash lists */ extern struct buf bfreelist[]; /* heads of available lists */ /* * Assign a buffer for the given block. If the appropriate */ struct buf *getblk (dev_t dev, daddr_t blkno); /* * Allocate a block in the file system. */ struct buf *balloc (struct inode *ip, int flags); /* * Get an empty block. */ struct buf *geteblk (void); /* * Read in (if necessary) the block and return a buffer pointer. */ struct buf *bread (dev_t dev, daddr_t blkno); /* * Read in the block, like bread, but also start I/O on the * read-ahead block. */ struct buf *breada (dev_t dev, daddr_t blkno, daddr_t rablkno); /* * Write the buffer, waiting for completion. Then release the buffer. */ void bwrite (struct buf *bp); /* * Release the buffer, with delayed write. */ void bdwrite (struct buf *bp); /* * Mark I/O complete on a buffer. */ void biodone (struct buf *bp); /* * Release the buffer, with no I/O implied. */ void brelse (struct buf *bp); /* * Wait for I/O completion on the buffer. */ void biowait (struct buf *bp); /* * See if the block is associated with some buffer. */ int incore (dev_t dev, daddr_t blkno); /* * Make sure all write-behind blocks on dev are flushed out. */ void bflush (dev_t dev); /* * Insure that no part of a specified block is in an incore buffer. */ void blkflush (dev_t dev, daddr_t blkno); /* * Invalidate in core blocks belonging to closed or umounted filesystem. */ void binval (dev_t dev); /* * Pick up the device's error number and pass it to the user. */ int geterror (struct buf *bp); #endif /* KERNEL */ /* * These flags are kept in b_flags. */ #define B_WRITE 0x00000 /* non-read pseudo-flag */ #define B_READ 0x00001 /* read when I/O occurs */ #define B_DONE 0x00002 /* transaction finished */ #define B_ERROR 0x00004 /* transaction aborted */ #define B_BUSY 0x00008 /* not on av_forw/back list */ #define B_PHYS 0x00010 /* physical IO */ #define B_MAP 0x00020 /* alloc UNIBUS */ #define B_WANTED 0x00040 /* issue wakeup when BUSY goes off */ #define B_AGE 0x00080 /* delayed write for correct aging */ #define B_ASYNC 0x00100 /* don't wait for I/O completion */ #define B_DELWRI 0x00200 /* write at exit of avail list */ #define B_TAPE 0x00400 /* this is a magtape (no bdwrite) */ #define B_INVAL 0x00800 /* does not contain valid info */ #define B_BAD 0x01000 /* bad block revectoring in progress */ #define B_LOCKED 0x02000 /* locked in core (not reusable) */ #define B_UBAREMAP 0x04000 /* addr UNIBUS virtual, not physical */ #define B_RAMREMAP 0x08000 /* remapped into ramdisk */ /* * Insq/Remq for the buffer hash lists. */ #define bremhash(bp) { \ (bp)->b_back->b_forw = (bp)->b_forw; \ (bp)->b_forw->b_back = (bp)->b_back; \ } #define binshash(bp, dp) { \ (bp)->b_forw = (dp)->b_forw; \ (bp)->b_back = (dp); \ (dp)->b_forw->b_back = (bp); \ (dp)->b_forw = (bp); \ } /* * Insq/Remq for the buffer free lists. */ #define bremfree(bp) { \ (bp)->av_back->av_forw = (bp)->av_forw; \ (bp)->av_forw->av_back = (bp)->av_back; \ } #define binsheadfree(bp, dp) { \ (dp)->av_forw->av_back = (bp); \ (bp)->av_forw = (dp)->av_forw; \ (dp)->av_forw = (bp); \ (bp)->av_back = (dp); \ } #define binstailfree(bp, dp) { \ (dp)->av_back->av_forw = (bp); \ (bp)->av_back = (dp)->av_back; \ (dp)->av_back = (bp); \ (bp)->av_forw = (dp); \ } /* * Take a buffer off the free list it's on and * mark it as being use (B_BUSY) by a device. */ #define notavail(bp) { \ register int x = splbio(); \ bremfree(bp); \ (bp)->b_flags |= B_BUSY; \ splx(x); \ }