extern struct bio_ops bioops;
struct bio_ops bioops;
LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash;u_long	bufhash;/* * Insq/Remq for the buffer hash lists. */#define	binshash(bp, dp)	LIST_INSERT_HEAD(dp, bp, b_hash)#define	bremhash(bp)		LIST_REMOVE(bp, b_hash)/* * Definitions for the buffer free lists. */#define	BQUEUES		4		/* number of free buffer queues */#define	BQ_LOCKED	0		/* super-blocks &c */#define	BQ_CLEAN	1		/* LRU queue with clean buffers */#define	BQ_DIRTY	2		/* LRU queue with dirty buffers */#define	BQ_EMPTY	3		/* buffer headers with no memory */TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];int needbuffer;int nobuffers;extern struct bio_ops bioops;/* * Buffer pool for I/O buffers. */struct pool bufpool;/* * Insq/Remq for the buffer free lists. */#define	binsheadfree(bp, dp)	TAILQ_INSERT_HEAD(dp, bp, b_freelist)#define	binstailfree(bp, dp)	TAILQ_INSERT_TAIL(dp, bp, b_freelist)static __inline struct buf *bio_doread(struct vnode *, daddr_t, int, int);int getnewbuf(int slpflag, int slptimeo, struct buf **);/* * We keep a few counters to monitor the utilization of the buffer cache * *  numdirtypages - number of pages on BQ_DIRTY queue. *  lodirtypages  - low water mark for buffer cleaning daemon. *  hidirtypages  - high water mark for buffer cleaning daemon. *  numfreepages  - number of pages on BQ_CLEAN and BQ_DIRTY queues. unused. *  numcleanpages - number of pages on BQ_CLEAN queue. *		    Used to track the need to speedup the cleaner and  *		    as a reserve for special processes like syncer. *  mincleanpages - the lowest byte count on BQ_CLEAN. *  numemptybufs  - number of buffers on BQ_EMPTY. unused. */long numdirtypages;long lodirtypages;long hidirtypages;long numfreepages;long numcleanpages;long locleanpages;int numemptybufs;#ifdef DEBUGlong mincleanpages;#endifstruct proc *cleanerproc;int bd_req;			/* Sleep point for cleaner daemon. */voidbremfree(struct buf *bp){	struct bqueues *dp = NULL;	/*	 * We only calculate the head of the freelist when removing	 * the last element of the list as that is the only time that	 * it is needed (e.g. to reset the tail pointer).	 *	 * NB: This makes an assumption about how tailq's are implemented.	 */	if (bp->b_freelist.tqe_next == NULL) {		for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)			if (dp->tqh_last == &bp->b_freelist.tqe_next)				break;		if (dp == &bufqueues[BQUEUES])			panic("bremfree: lost tail");	}	if (bp->b_bufsize <= 0) {		numemptybufs--;	} else if (!ISSET(bp->b_flags, B_LOCKED)) {		numfreepages -= btoc(bp->b_bufsize);		if (!ISSET(bp->b_flags, B_DELWRI)) {			numcleanpages -= btoc(bp->b_bufsize);#ifdef DEBUG			if (mincleanpages > numcleanpages)				mincleanpages = numcleanpages;#endif		} else {			numdirtypages -= btoc(bp->b_bufsize);		}	}	TAILQ_REMOVE(dp, bp, b_freelist);}