/*static char *SCCSID = "@(#)getbuf.c   6.2 92/01/31";*/

#define INCL_DOSERRORS
#include <os2def.h>
#include <bse.h>
#include <fsh.h>
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "ea.h"
#include "fnode.h"
#include "volume.h"
#include "tables.h"
#include "frame.h"
#include "pbmacros.h"
#include "lw.h"
#include "fsdata.h"
#include "pr_cache.h"
#include "pr_debug.h"
#include "pr_ea.h"
#include "pr_misc.h"
#include "log.h"

/*
 ***    GetBuf - Get RAM Buffer
 *
 *      GetBuf gets a scratch RAM work buffer.  If the amount requested
 *      is small enough we use a cache buffer for speed.  If not, we
 *      get physical fixed memory from the OS.
 *
 *      ENTRY   cbNeed (eax) = bytes to allocate
 *
 *      RETURNS address of buffer [eax]
 *                *ppbuf (ecx) = address of header, if cache buffer, else NULL
 *              NULL if error
 *
 *      SWAP    This routine must not be swapped-out, or call any swapped code.
 *
 *      HISTORY
 *  @76193  23-Nov-1993 by D.Azzarito - Change holds for LOG support
 *          08-Mar-1990 by JR (John Rogers, JohnRo@Microsoft)
 *              - PTR B788488: avoid non-async I/O swap deadlock.
 *          23-Feb-1990 by JR (John Rogers, JohnRo@Microsoft)
 *              - PTR B788262: fix FS_DoPageIO probs (e.g. nested swap).
 *          19-Sep-89 by JR (John Rogers, JohnRo@Microsoft)
 *              - Avoid warnings from Microsoft C 5.2 (on slash-slash comments).
 */
PBYTE far
GetBuf (cbNeed, ppbuf, pfrm)
USHORT cbNeed;
PBUFNODE far * ppbuf;
PFRAME pfrm;
{
        USHORT sel;     /*  data location for the selector      */
        USHORT usRet;


        PBUFNODE pbuf;


        if ( cbNeed <= SPB * SECSIZE ) {

            /*
             *  Our worst case buffer is small enough to be a
             *  cache block.  Get one and use it.
             *
             */
            while( fGFBActive ) {
                GFBWait(pfrm);
            }
            pbuf = GFB(pfrm);
            /*
             * get rid of the LSN so LSD() won't think this is still
             * the sector data.
             */
            pbuf->lsnSec = LSN_BOGUS;
            CreateBUF(pbuf);  //@114986
            IncrHoldsBUF( pbuf );  // @76193
            *ppbuf = pbuf;

            return ( (PBYTE)(pbuf->pblkData) );
        } else {

            /*
             *  Our EAs occupy more than one cache block can hold.
             *  Get a segment from the system.  We want a non-swappable
             *  GDT from Ring Zero.
        */

            MAYBLOCK( usRet = FSH_SEGALLOC( SA_FRING0, (ULONG)cbNeed, &sel ) )

            /*
             *  If FSH_SEGALLOC returned an error, note it as
             *  a hard error and return NULL to indicate failure.
             */
            if (usRet != NO_ERROR) {
                SETHARDERR(usRet);
                return (PBYTE) NULL;
            }

            /*
             *  Construct a pointer out of the selector we get
             *  back from FSH_SEGALLOC and return it.  Since the
             *  buffer is not a cache block, set the buffer header
             *  pointer to NULL.
             */
            *ppbuf = (PBUFNODE) NULL;
            return ( MAKEP(sel, 0) );
        }

}


/*
 ***    RelBuf - Release RAM Buffer
 *
 *      RelBuf returns a buffer allocated by GetBuf.
 *
 *      ENTRY   pbData (eax) = addresss of buffer
 *              pbuf   (ecx) = address of buffer header, held, if any
 *      RETURNS None
 *
 *      SWAP    This routine must not be swapped-out, or call any swapped code.
 */
void far
RelBuf(pbData, pbuf, pfrm)
PBYTE pbData;
PBUFNODE pbuf;
PFRAME pfrm;
{

        USHORT usRet;

        if ( pbuf != (PBUFNODE) NULL ) {

            /*
             *  The buffer header is not null, which means that the
             *  buffer in question is a cache block, and we can
             *  return it to our buffer pool.
             */
            RetBuf( pbuf );
        } else {

            /*
             *  It's system RAM, so we release it by
             *  freeing the segment
             */
            MAYBLOCK( usRet = FSH_SEGFREE( SELECTOROF( pbData ) ) )

#ifdef DEBUG
            if (usRet != NO_ERROR) {

                INTERR("RelBuf [RetBuf.c] :  FSH_SEGFREE failed.");
            }
#endif
        }
}
