/*static char *SCCSID = "@(#)setdirt.c	6.7 92/01/31";*/
#define INCL_DOSINFOSEG
#include <os2.h>
#include <fsh.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "pb_ifs.h"
#include "lw.h"
#include "frame.h"
#include "superb.h"
#include "fsdata.h"
#include "assert.h"
#include "fnode.h"
#include "strat2.h"
#include "asyncio.h"
#include "pr_CACHE.h"	/* to pick up prototypes */
#include "pr_LAZY.h"	/* for lazy writer calls */
#include "pr_MISC.h"	/* temporary for interr calls */
#include "mmph.h"
#include "pbmacros.h"
#include "log.h"
// @76193  #if defined(DEBUG) || defined(DEBUG_LW)
#include "pr_DEBUG.h"
// @76193  #endif

/*
 ***	SetDirt - Set Buffer as Dirty
 *
 *	SetDirt marks the dirty bits in a buffer header and puts
 *	it on the lazywrite queue, unless writethrough is set in which
 *	case the buffer is written synchronously.
 *
 *	SetDirt YIELDS iff write through is specified, but guarantees
 *	that the buffer being set dirty remains in place across the
 *	yield.
 *
 *	ENTRY	pbChanged = address in sector that was changed
 *		pbufDirtyBuf = buffer header address
 *		fWrtThru = write thru flag: TRUE - write thru
 *					    FALSE - no write thru
 *
 *	EXIT	Buffer is on chain
 *		Yields CPU iff write through
 */

void
SetDirt (pvChanged, pbufDirtyBuf, fWrtThru, pfrm)
PVOID		pvChanged;	/* pointer into data buffer where changed */
PBUFNODE	pbufDirtyBuf;	/* pointer to buffer hdr of changed data buf */
BOOL		fWrtThru;	/* should we write thru? */
PFRAME		pfrm;
{

#ifdef DEBUG
    PFNODE pfn = (PFNODE) ((ULONG) pvChanged & ~(SECSIZE-1));

    if (pfn->sig == FNSIGVAL) {
	AssertFN (__FILE__, pfn);
    }

    /*	This corresponds to the asm routine ChkDirt  */
    if ( (pvChanged < (PBYTE)pbufDirtyBuf->pblkData) ||
	 (((PBYTE)pvChanged) -
	 (PBYTE)pbufDirtyBuf->pblkData > SPB * SECSIZE) ) {

	 INTERR(__FILE__"[SetDirt]:  Bad Address");
    }
#endif

    ASSERT_BUF( pbufDirtyBuf );

    pbufDirtyBuf->bDirtMask = SPBBITS;

    /* mark buffer as dirty for current file */
    pbufDirtyBuf->flDMask |= pfrm->flDMask;

#ifndef MINIFSD
    if (fWrtThru)
      BufWrit(pbufDirtyBuf,pfrm);
     else
	   AddLW (pbufDirtyBuf,pfrm);
#else
      BufWrit(pbufDirtyBuf,pfrm);
#endif

}

#ifndef MINIFSD
/*
 ***	 AddLW - Add to LazyWrite List
 *
 *	 ENTRY	 pbuf = address of buffer header
 *
 *	 EXIT	 added to lazywrite list
 *
 *
 */
void
AddLW (pbuf,pfrm)
PBUFNODE pbuf;		/* address of buffer header */
PFRAME	 pfrm;
{

    USHORT iVol;
    iVol = IVOLFROMLSN (pbuf->lsnSec);
    pfrm->pvol = VolPtr [iVol];

    MMPHPreAddLW();  /* performance hook (3302) */

 if (!fLWDaemon) {
 /* lazy writer turned off */
   BufWrit(pbuf, pfrm);

 } else {

	 if (pbuf->dcbpLru.pbufFwd != pbuf) {

	/*  Take pbuf off the LRU chain.  The buffer's LRU pointers
	 *  point at the buffer itself, so the casual observer can tell
	 *  that it's not on the LRU chain.
	 */
	 DCREM (pbuf, dcbpLru);

	 pbuf->dcbpLru.pbufFwd = pbuf;
	 pbuf->dcbpLru.pbufBak = pbuf;
    }

    IncrHoldsBUF (pbuf);  // @76193

	/* set most recent dirty time */
	pbuf->msLastDirtied = msNow ();

	/* if buffer not already in dirty list, add it */
	if (pbuf->dcbpDirt.pbufFwd == NULL) {

	    /* Set first dirty time */
	    pbuf->msFirstDirtied = pbuf->msLastDirtied;

//test DCF2
       if (pfrm->pvol->VDU) {  // #76575
	    /* (add buffer to VDU LazyWrite chain)			   */
	      DCADDB (pbuf, dcbpDirt, bufLWHeadVDU);
         cbufDirtyVDU++;
       }
        else
	    /* (add buffer to LazyWrite chain)			   */
	    DCADDB (pbuf, dcbpDirt, bufLWHead);
                                              //end #76575

	    /* increment the buffer count (for the dirty buffer chain) */
	    cbufDirty++;

#ifdef DEBUG_LW
	    dprintf ("AddLW: msFirstDirtied=%ld, cbufDirty=%d\n",
		     pbuf->msFirstDirtied, cbufDirty);
#endif

	    /* If no other buffers in the lazy write chain, wake LazyWriter */
	    if (bufLWHead.dcbpDirt.pbufFwd == pbuf) {
         msLastIO = msNow ();
		   LWWakeUp(pfrm);
       } else
//test DCF2
       /* If no other buffers in the VDU lazy write chain, wake VDU LazyWriter */
        if (bufLWHeadVDU.dcbpDirt.pbufFwd == pbuf) {
          msLastIO = msNow ();
          MAYBLOCK (FSH_SEMCLEAR (&semVLW))
        }
	
	  /* if too many buffers in chain, wake the LazyWriter */
	    if ((!fForceLWIO) && (cbufDirty > LWData.cbufDirtyMax)) {
		   LWForceWakeUp(pfrm);
	    }

	} /* end if buffer not already in dirty list, add it */

   DecrHoldsBUF(pbuf);  // @76193
 }

    MMPHPostAddLW()  /* performance hook (3382) */

}
#endif

/*
 ***	SetDEDirt - Set Directory Entry Dirty
 *
 *	SetDEDirt is identical to SetDirt except that it's called to set
 *	a directory entry dirty.  When we've just changed a directory
 *	entry we don't want to write all the sectors in the dirblk,
 *	but we can't call SetDirt because the changed field(s) might
 *	have straddled a sector boundary.  SetDEDirt understands directory
 *	entries and will mark the minimum number of sectors dirty.
 *
 *	SetDEDirt YIELDS iff write through is specified, but guarantees
 *	that the buffer being set dirty remains in place across the
 *	yield.
 *
 *	ENTRY	pde = address of start of directory entry changed
 *		pbuf = buffer header address
 *		fWrtThru = write thru flag: TRUE - write thru
 *					    FALSE - no write thru
 *	EXIT	Buffer on chain
 *		Yields CPU iff write through
 */

/*  Mask for dirtying to consecutive sectors  */
BYTE amaskDirty[] = {
#if SPB == 4
	    0x3, 0x6, 0xC, 0x8
#elif SPB == 8
	    0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80
#else
#error SETDIRT.C: SPB not 4 or 8.
#endif
		    };


void
SetDEDirt(pde, pbuf, fWrtThru, pfrm)
PDIRENT pde;		/*  dirty DIRENT  */
PBUFNODE pbuf;		/*  pointer to dirty buffer  */
BOOL fWrtThru;		/*  write through flag	*/
PFRAME pfrm;
{

    USHORT lsnoffFirst, lsnoffLast;	/*  lsn offset of first/last byte of
					    DIRENT into DIRBLK. */

#ifdef DEBUG
    /*	This corresponds to the asm routine ChkDirt  */
    if ( ((PBYTE)pde < (PBYTE)pbuf->pblkData) ||
	 ((PBYTE)pde - (PBYTE)pbuf->pblkData > SPB * SECSIZE) ) {

	 INTERR("SetDEDirt [setdirt.c]:  Bad Address");
    }
#endif

    ASSERT_DE (pde);

    /* mark dirblock as dirtied by the current file */
    pbuf->flDMask |= pfrm->flDMask;

    lsnoffFirst = ( (PBYTE)pde - (PBYTE)pbuf->pblkData) >> SECSHIFT;
    lsnoffLast =  ( (PBYTE)pde - (PBYTE)pbuf->pblkData +
				 pde->cchThisEntry - 1) >> SECSHIFT;


    if ( lsnoffFirst == lsnoffLast ) {

	/*  Only one sector to dirty  */
	pbuf->bDirtMask |= 1 << lsnoffFirst;

    } else {

	/*  DIRENT straddles a sector boundary--dirty two sectors.  */
	pbuf->bDirtMask |= amaskDirty[lsnoffFirst];

    }

#ifndef MINIFSD
    if (fWrtThru)
      BufWrit(pbuf,pfrm);
     else
	   AddLW (pbuf,pfrm);
#else
    BufWrit(pbuf,pfrm);
#endif
}


/*
 ***	SetDBDirt - Set Directory Block Dirty
 *
 *	SetDBDirt is called when an entire DIRBLK has been changed.
 *
 *	SetDBDirt YIELDS iff write through is specified, but guarantees
 *	that the buffer being set dirty remains in place across the
 *	yield.
 *
 *	ENTRY	pbuf = buffer header address
 *		fWrtThru = write thru flag: TRUE - write thru
 *					    FALSE - no write thru
 *
 *	EXIT	Buffer on chain
 *		Yields CPU iff write through
 */
void
SetDBDirt(pbuf, fWrtThru, pfrm)
PBUFNODE pbuf;		/*  pointer to dirty buffer  */
BOOL fWrtThru;		/*  write flag		     */
PFRAME pfrm;
{
#if DIRBLKS == SPB * SECSIZE
    ASSERT_DB ((PDIRBLK) (pbuf->pblkData));
#endif

    /* mark dirblock as dirtied by the current file */
    pbuf->flDMask |= pfrm->flDMask;

    /* set all sectors dirty in this block */
    pbuf->bDirtMask = SPBBITS;

#ifndef MINIFSD
    if (fWrtThru)
      BufWrit(pbuf,pfrm);
     else
	   AddLW (pbuf,pfrm);
#else
    BufWrit(pbuf,pfrm);
#endif

}
