/*static char *SCCSID = "@(#)vbs.c	6.1 90/11/17";*/
/*static char *SCCSID = "@(#)vbs.c 13.2 90/01/25";*/
#include <os2def.h>
#include "heap.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "volume.h"
#include "storage.h"
#include "tables.h"
#include "pb_ifs.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "assert.h"
#include "pr_CACHE.h"
#include "pr_DEBUG.h"
#include "pr_MISC.h"
#include "pr_HEAP.h"


#if defined (DEBUG)

/*
 ***	VBS - Verify Buffer State
 *
 *	VBS performs consistancy checks on the buffer pool.
 *
 *	We verify:
 *
 *	     1) that all buffers w/ dirty sectors are on the lazywrite
 *		queue, and
 *
 *	     2) that all sectors which have been changed are marked dirty
 *
 *	     3) that all buffers are on the lazywrite or the BH_1 queue.
 *
 *	     4) that no buffers are locked or held
 *
 *	NOTE that since VBS is called after every function, it's also
 *	become a catchall for lots of structure checking, not just
 *	the buffers.  Look at the VBS exit code.
 *
 *	ENTRY	NONE
 *	EXIT	NONE
 *
 *      HISTORY
 *	    05-Jun-1989 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B784101: fixed someone's int3() calls (should be Int3()).
 *          03-Oct-1988 10:30 by Bill McJohn [t-billm]
 *				Translated from 9/28/88 assembly code
 */

ULONG flFastFileOld = 0;		/*  previous value		      */
PBYTE pbBufFlg1 = NULL;
PBYTE pbBufFlg2 = NULL;

void far
VBS ()
{
    register PBUFNODE pbuf;	/*	Used to traverse lists		 */
    USHORT i;			/*	Generic index variable		 */
    USHORT usBufferOrd;		/*	Ordinal number of buffer header  */
    PBUFNODE pb;

    if (!fInit) {
	return;
    }


    /*	If FastFile's FF_CHKSUM and FF_LRUCHK bits are
     *	both clear, call ChkSbdir, call ChkOFT, and return.
     */
    if ((flFastFile & (FF_CHKSUM | FF_LRUCHK)) != 0) {

	/*  Arrays of bit flags to record that we've seen each buffer  */
	if (pbBufFlg1 == NULL)
	    if ((pbBufFlg1 = GHS (cBufs)) == NULL) {
		dprintf ("VBS: can't get enough heap");
		Int3 ();
		return ;
	    }

	if (pbBufFlg2 == NULL)
	    if ((pbBufFlg2 = GHS (cBufs)) == NULL) {
		dprintf ("VBS: can't get enough heap");
		Int3 ();
		return ;
	    }

	memset (pbBufFlg1, 0, cBufs);
	memset (pbBufFlg2, 0, cBufs);

	/*  First, go down the LRU chain, registering who's present
	 *  and who's dirty.  Check sector checksums as we go, if
	 *  checksumming is enabled.
	 */

	pbuf = bufLRUHead.dcbpLru.pbufFwd;

	while (pbuf != &bufLRUHead) {

	    ASSERT_BUF (pbuf);

	    if ((pbuf->cusHolds || pbuf->cLocked) && !fMTFlag) {

		/*  The buffer is locked or held, although we're
		 *  not multitasking.
		 */
		dprintf ("VBS: %x buffer held/locked without multitasking\n",
			 pbuf);
		Int3 ();
	    }

	    /*
	     *	Calculate the buffer's ordinal number, and examine the
	     *	buffer-visited flag (pbBufFlg1).  If the corresponding
	     *	bit is already set, complain--the chain is corrupt.
	     *	Otherwise, set that bit.
	     */
	    /* force the code generator to not do the cwd to sign extend */
	    usBufferOrd = ((USHORT)pbuf - (USHORT)abufCache) / sizeof (BUFNODE);

	    if (usBufferOrd > cBufs) {
		dprintf ("VBS: %x illegitimate LRU buffer ord=%d, cBufs=%d\n",
			 pbuf, usBufferOrd, cBufs);
		Int3 ();
	    }

	    if (pbBufFlg1[usBufferOrd]) {
		dprintf ("VBS: %x Buffer appears twice on the LRU chain\n",
			 pbuf);
		Int3 ();
	    }
	    else
		pbBufFlg1[usBufferOrd] = 1;


	    /*	If checksumming is enabled */
	    if ((flFastFile & FF_CHKSUM) != 0)

		/*  If the buffer is not busy right now */
		if (pbuf->cusHolds == 0 && pbuf->cLocked == 0) {
		    /*	If checksumming was not on previously, our checksums
		     *	likely won't match.  We just recompute the checksum
		     *	for this buffer
		     */
		    if (!(flFastFileOld & FF_CHKSUM))
			RSC (pbuf);
		    else
		    /*	Checksums should match.  Verify that they do.
		     */
		    if (!CSC (pbuf))  {
			dprintf ("VBS: %x buffer checksums do not match\n",
				 pbuf);
			Int3 ();
		    }
		}

	    if (pbuf->bDirtMask) {
		/*  Mark that it's dirty (bufflg2)  */
		pbBufFlg2[usBufferOrd] = 1;
	    }


	    pbuf = pbuf->dcbpLru.pbufFwd;
#ifdef DEBUG2
	    dprintf ("VBS: pbuf=0x%x\n", pbuf);
#endif
	}


	/*  OK, now check the guys on the dirty chain.	Each should
	 *  have its corresponding bit set in the pbBufFlg2 array.
	 *  As we go, we'll reset the corresponding bit for each
	 *  dirty guy we visit, so we'll be able to detect duplicates
	 *  on the dirty chain (they'll show up as unvisited), and
	 *  when we're done we can find dirty guys who aren't on the
	 *  dirty chain (their corresponding flag bit will still be
	 *  1).
	 */


	pbuf = bufLWHead.dcbpDirt.pbufFwd;
//test DCF2  @76575
   if (pbuf == &bufLWHead) {
	  pbuf = bufLWHeadVDU.dcbpDirt.pbufFwd;
   }

	while ((pbuf != &bufLWHead) && (pbuf != &bufLWHeadVDU)) {
//end test DCF2

	    ASSERT_BUF (pbuf);

	    /*	Determine the buffer's ordinal number and
	     *	reset the appropriate bit to zero to signify
	     *	that we've found it on the dirty chain.
	     */
	    usBufferOrd = pbuf - abufCache;

	    if (usBufferOrd > cBufs) {
		dprintf ("VBS: %x Illegitimate dirty buffer ord=%d, cBufs=%d\n",
			 pbuf, usBufferOrd, cBufs);
		Int3 ();
	    }

	    pbBufFlg2[usBufferOrd] = 0;
	    pbuf = pbuf->dcbpDirt.pbufFwd;
	}


	/*  We've seen all the buffers on the queues and they're ok.
	 *  Are any missing?  Scan down through pbBufFlg1 looking
	 *  for unset bits.
	 */

	if (fMTFlag == 0) {
	    for (i = 0; i < cBufs; i++)
		if (pbBufFlg1[i] != 1) {
		    /*  somebody in this byte hasn't been visited!
		     *  the assy code does some work before calling
		     *  INTERR to identify the buffer in question.
		     */
		    dprintf ("VBS: %x Buffer not on LRU chain\n",&abufCache[i]);
		    Int3 ();
		}

	    /*	Check for dirty buffers not on dirty chain.  */
	    for (i = 0; i < cBufs; i++)
		if (pbBufFlg2[i]) {
		    /*	the assy code does some more work, before
		     *	the call to INTERR, to determine which
		     *	buffer is at fault.
		     */
		    dprintf ("VBS: %x Dirty buffer not on dirty chain\n", pbuf);
		    Int3 ();
		}
	}
    }

    /* Check the lsnSec (B_SEC) value in each header for volume info */
    for (pb = bufLRUHead.dcbpLru.pbufFwd;;) {
	if ((pb->lsnSec != LSN_BOGUS) &&
	    ((pb->lsnSec & ((LSN) SVOLMASK << VOLRSHIFT)) == 0)) {
	    INTERR (__FILE__": No volume info in buffer lsn");
	}
	pb = pb->dcbpLru.pbufFwd;

	if (pb = bufLRUHead.dcbpLru.pbufFwd)
	    break;
    }

    ChkBand();
    ChkSbDir();
    ChkHashChain ();
    ChkOFT();

    /* Check to see if we left a SBD held */

    if (pfrm->cusHolds) {
	dprintf (__FILE__": pfrm->cusHolds Holds != 0\n");
	Int3 ();
    }

    /* If we want to check for running out of buffers then do so. */
    if ((flFastFile & FF_GETBUFS) &&
	(pfrm->cFreeBuf != 0)) {
	dprintf (__FILE__": cFreeBuf != 0 (%d)\n", pfrm->cFreeBuf);
	Int3 ();
    }

    flFastFileOld = flFastFile;
}

#endif
