/*static char *SCCSID = "@(#)clrspare.c	6.3 92/01/31";*/
#define BSWAP1 BSWAP1

#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include <fsh.h>			/* DVIO_OPREAD, etc. */

#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "heap.h"			/* Required by "pr_heap.h". */
#include "volume.h"
#include "pbmacros.h"
#include "storage.h"
#include "tables.h"
#include "superb.h"
#include "pb_ifs.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"
#include "pbmsg.h"

#include "pr_CACHE.h"
#include "pr_DSKIO.h"			/* DoVolIOFar(). */
#include "pr_HEAP.h"			/* GHSFar(), RetHeap(). */
#include "pr_MISC.h"			/* INTERR(), my prototype. */

#ifdef DEBUG
    #include "pr_debug.h"
#endif /* DEBUG */

/*
 ***	ClearSparesFlag - Clears the dirty bit in the spares block on the
 *	specified volume.  This routine will block until the write is finished.
 *
 *	Note that the volume being modified may be different than the volume
 *	referenced in the current frame.  This happens in the case of the
 *	FS_SHUTDOWN routine, where it could modify one or more volumes.
 *
 *	Eventually, this routine could be used to clear other bits in the
 *	spares block.  The caller could clear multiple bits in one call, by
 *	ORing them together.
 *
 *	ENTRY	Pointer to the volume table entry for the volume to be written.
 *		BYTE with bits to get rid of (e.g. SPF_DIRT).
 *		Pointer to frame (pfrm) must be initialized.
 *	EXIT	Spares flag on disk and in volume table entry will be updated.
 *
 *	Yields CPU (IO)
 *
 *	HISTORY
 *	    21-Jul-1989 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B704867: Prevent deadlock when writing dirty bit to disk.
 *		- Commented-out check of pfrm, as frame is static now.
 *		- Changed PANICs to INTERRs, per JonPa.
 *		- Moved change history here.
 *	    14-Jun-1989 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B784106: Implemented volume dirty bit on disk.
 */

void
ClearSparesFlag (PVOLTAB pvolToBeChanged, BYTE bFlag, PFRAME pfrm)
{
    LSN lsnSpare = (pvolToBeChanged->ulVolBits) | SEC_SPAREB;
    PSPAREB psb;
    PVOLTAB pvolSave;

    if (pfrm == NULL) {
	INTERR(__FILE__": pfrm is null!");
    }

    /* Setup contents of frame (using pfrm) */
    pvolSave = pfrm->pvol;
    pfrm->pvol = pvolToBeChanged;


    /*
     *	Begin critical section:	 establish sole right to
     *	the hotfix buffer
     */
    SemRequestFar(&semHotFix,pfrm);

    psb = RdHF (lsnSpare,pfrm);

    /*
     * NOTE: even if psb == NULL, we DO NOT want to INTERR here,
     * doing so would not only cause the one read error for this
     * volume to make this disk unusable, but would also cause
     * all volumes mounted after this volume to be marked dirty.
     *
     * In the case of a read error, we will just leave the
     * volume marked dirty, and let the next AUTOCHECK clean it up.
     */

    if( psb != NULL ) {

	/*
	 *  AND out the flags the caller wants to clear and update the
	 *  volume table copy of the spares flag.
	 */
	psb->bFlag &= ~bFlag;

	/* Write modified flags to disk.  */
	WtHF(lsnSpare,pfrm);

	/*
	 *  Note that we have to update the volume table flags
	 *  after the actual write, in order to avoid DoVolIO
	 *  setting the dirty flag when we are trying to clear it.
	 */
	pfrm->pvol->bSpareFlags = psb->bFlag;
    }

    /* end of critical section */
    SemClear (&semHotFix);

    /* Restore caller's frame. */
    pfrm->pvol = pvolSave;
}
