|
Packit |
857059 |
/* BEGIN_ICS_COPYRIGHT5 ****************************************
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Copyright (c) 2015, Intel Corporation
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
857059 |
modification, are permitted provided that the following conditions are met:
|
|
Packit |
857059 |
|
|
Packit |
857059 |
* Redistributions of source code must retain the above copyright notice,
|
|
Packit |
857059 |
this list of conditions and the following disclaimer.
|
|
Packit |
857059 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
857059 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
857059 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
857059 |
* Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
857059 |
may be used to endorse or promote products derived from this software
|
|
Packit |
857059 |
without specific prior written permission.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
857059 |
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
857059 |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
857059 |
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
Packit |
857059 |
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
857059 |
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
857059 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
Packit |
857059 |
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
Packit |
857059 |
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
857059 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
857059 |
|
|
Packit |
857059 |
** END_ICS_COPYRIGHT5 ****************************************/
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#include "datatypes.h"
|
|
Packit |
857059 |
#include "imemory.h"
|
|
Packit |
857059 |
#include "imath.h"
|
|
Packit |
857059 |
#include "idebug.h"
|
|
Packit |
857059 |
#include "iquickmap.h"
|
|
Packit |
857059 |
#include "ispinlock.h"
|
|
Packit |
857059 |
#include "errno.h"
|
|
Packit |
857059 |
#include "string.h"
|
|
Packit |
857059 |
#include <sys/mman.h>
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#ifdef IB_STACK_IBACCESS
|
|
Packit |
857059 |
static uint32 s_lock_strategy = 0xffffffff;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/*
|
|
Packit |
857059 |
* Certain redhat kernels use these defines without providing them.
|
|
Packit |
857059 |
* This allows us to support these features with such kernels.
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* Note that this has no impact on kernels that really don't support
|
|
Packit |
857059 |
* this feature.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
#if !defined(MADV_DONTFORK)
|
|
Packit |
857059 |
#define MADV_DONTFORK 10
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
#if !defined(MADV_DOFORK)
|
|
Packit |
857059 |
#define MADV_DOFORK 11
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static FSTATUS
|
|
Packit |
857059 |
MemoryLockPrepareMlock(uintn start, uintn length);
|
|
Packit |
857059 |
static FSTATUS
|
|
Packit |
857059 |
MemoryLockUnprepareMlock(uintn start, uintn length);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#endif /* IB_STACK_IBACCESS */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void*
|
|
Packit |
857059 |
MemoryAllocatePriv( IN uint32 Bytes, IN uint32 flags, IN uint32 Tag )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return malloc( Bytes );
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
MemoryDeallocatePriv( IN void *pMemory )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
free( pMemory );
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
MemoryFill( IN void *pMemory, IN uchar Fill, IN uint32 Bytes )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
memset( pMemory, Fill, Bytes );
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void*
|
|
Packit |
857059 |
MemoryCopy( IN void *pDest, IN const void *pSrc, IN uint32 Bytes )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return memcpy( pDest, pSrc, Bytes );
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
int32
|
|
Packit |
857059 |
MemoryCompare( IN const void *pMemory1, IN const void *pMemory2, IN uint32 Bytes )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return memcmp( pMemory1, pMemory2, Bytes );
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#ifdef IB_STACK_IBACCESS
|
|
Packit |
857059 |
FSTATUS MemoryLockPrepare(uintn buf_org, uintn Length)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
uintn buf_aligned = 0;
|
|
Packit |
857059 |
uintn size = Length;
|
|
Packit |
857059 |
uint32 page_size = getpagesize();
|
|
Packit |
857059 |
uintn tos_aligned;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
buf_aligned = ROUNDDOWNP2(buf_org, page_size);
|
|
Packit |
857059 |
size = size + buf_org - buf_aligned;
|
|
Packit |
857059 |
size = ROUNDUPP2(size, page_size);
|
|
Packit |
857059 |
// This is an odd case, if buf_aligned is on the stack, we need to make sure
|
|
Packit |
857059 |
// the stack itself is at least 1 page beyond the buf itself
|
|
Packit |
857059 |
// we use &tos_aligned as an rough indication of top of stack
|
|
Packit |
857059 |
// if we didn't do this, the VMA created by madvise could actually grow
|
|
Packit |
857059 |
// after we locked the memory, which would confuse the memory locking code
|
|
Packit |
857059 |
|
|
Packit |
857059 |
// for stacks which grow down:
|
|
Packit |
857059 |
tos_aligned = ROUNDDOWNP2(&tos_aligned, page_size);
|
|
Packit |
857059 |
if (tos_aligned == buf_aligned)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
// force stack to grow by 1 page so TOS is on a different page than buf
|
|
Packit |
857059 |
volatile uint8 *temp = (uint8*)alloca(page_size);
|
|
Packit |
857059 |
if (temp == NULL)
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;
|
|
Packit |
857059 |
*temp = 1; // touch new page so stack grows
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if 0
|
|
Packit |
857059 |
// for stacks which grow up:
|
|
Packit |
857059 |
tos_aligned = ROUNDUPP2(&tos_aligned, page_size);
|
|
Packit |
857059 |
if ( buf_aligned + size == tos_aligned)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
// force stack to grow by 1 page so TOS is on a different page than buf
|
|
Packit |
857059 |
volatile uint8 *temp = (uint8*)alloca(page_size);
|
|
Packit |
857059 |
if (temp == NULL)
|
|
Packit |
857059 |
return FINSUFFICIENT_MEMORY;;
|
|
Packit |
857059 |
*(temp+page_size) = 1; // touch new page so stack grows
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
switch (s_lock_strategy) {
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MADVISE:
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: madvise addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,buf_aligned,size);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if(madvise((void *)buf_aligned, (size_t)size, MADV_SEQUENTIAL ))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
MsgOut("%s: madvise failed with buf:0x%"PRIxN" size:%"PRIdN"\n",__func__,buf_aligned,size);
|
|
Packit |
857059 |
return FINSUFFICIENT_RESOURCES;;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MLOCK:
|
|
Packit |
857059 |
return MemoryLockPrepareMlock(buf_aligned, size);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
/* strategy not supported or MemoryLockSetStrategy not called first */
|
|
Packit |
857059 |
return FINVALID_OPERATION;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS MemoryLockUnprepare(uintn buf_org, uintn Length)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
switch (s_lock_strategy) {
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MADVISE:
|
|
Packit |
857059 |
/* no action needed */
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MLOCK:
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
uint32 page_size = getpagesize();
|
|
Packit |
857059 |
uintn buf_aligned = ROUNDDOWNP2(buf_org,page_size);
|
|
Packit |
857059 |
uintn size = Length + buf_org - buf_aligned;
|
|
Packit |
857059 |
size = ROUNDUPP2(size, page_size);
|
|
Packit |
857059 |
return MemoryLockUnprepareMlock(buf_aligned, size);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
/* strategy not supported or MemoryLockSetStrategy not called first */
|
|
Packit |
857059 |
return FINVALID_OPERATION;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* This provides to the User Memory module the memory lock strategy which Uvca
|
|
Packit |
857059 |
* obtained via Vka from the kernel Memory module
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
FSTATUS MemorySetLockStrategy(uint32 strategy)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
switch (strategy) {
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MADVISE:
|
|
Packit |
857059 |
s_lock_strategy = strategy;
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MLOCK:
|
|
Packit |
857059 |
s_lock_strategy = strategy;
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
default:
|
|
Packit |
857059 |
return FINVALID_PARAMETER;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* Tell UVca if MemoryLockUnprepare is necessary for the configured locking
|
|
Packit |
857059 |
* strategy. If not, UVCA has the option of optimizing its operation to
|
|
Packit |
857059 |
* avoid the MemoryLockUnprepare.
|
|
Packit |
857059 |
* However, if unnecessary, MemoryLockUnprepare should be a noop and should
|
|
Packit |
857059 |
* not fail (hence allowing UVCA to choose not to optimize it out).
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
boolean MemoryNeedLockUnprepare(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
switch (s_lock_strategy) {
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MADVISE:
|
|
Packit |
857059 |
return FALSE;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
case MEMORY_LOCK_STRAT_MLOCK:
|
|
Packit |
857059 |
return TRUE;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
default: /* unexpected case, play it safe */
|
|
Packit |
857059 |
return TRUE;
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* ********************************************************************** */
|
|
Packit |
857059 |
/* This implements the MEMORY_LOCK_STRAT_MLOCK core functionality
|
|
Packit |
857059 |
* in this strategy the user space uses mlock and madvise prior to
|
|
Packit |
857059 |
* the kernel MemoryLock being called. Since mlock and madvise do not "stack"
|
|
Packit |
857059 |
* we must track the presently locked regions and only call mlock/madvise for
|
|
Packit |
857059 |
* the "delta" caused by the given lock/unlock of memory.
|
|
Packit |
857059 |
* note that MemoryLockPrepare is called before MemoryLock
|
|
Packit |
857059 |
* and MemoryLockUnprepare is called after MemoryUnlock
|
|
Packit |
857059 |
*
|
|
Packit |
857059 |
* This implementation of MemoryLockPrepare/MemoryLockUnprepare "stacks"
|
|
Packit |
857059 |
* This assumes every MemoryLockUnprepare exactly matches a previous
|
|
Packit |
857059 |
* call to MemoryLockPrepare. It will assert otherwise.
|
|
Packit |
857059 |
* UVCA follows this requirement.
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#define MLOCK_TAG MAKE_MEM_TAG(k,c,l,m)
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* initial testing indicates most applications have relatively few
|
|
Packit |
857059 |
* locked areas at a time, hence the cost of compressing then uncompressing
|
|
Packit |
857059 |
* them (on unlock) is more expensive that having more areas to track and store
|
|
Packit |
857059 |
* especially since the locked_area structure is relatively small and a
|
|
Packit |
857059 |
* cl_qmap is used to search them
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
#define COMPRESS_AREAS 0 /* conserve memory by merging areas when possible */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
typedef struct _locked_area {
|
|
Packit |
857059 |
cl_map_item_t MapItem;
|
|
Packit |
857059 |
uintn start; // virtual address
|
|
Packit |
857059 |
uintn end; // last address included in area
|
|
Packit |
857059 |
uint32 lock_cnt;// number of times locked
|
|
Packit |
857059 |
} LOCKED_AREA;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
typedef struct _addr_range {
|
|
Packit |
857059 |
uintn start; // virtual address
|
|
Packit |
857059 |
uintn end; // last address included in range
|
|
Packit |
857059 |
} ADDR_RANGE;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static cl_qmap_t LockedArea_Map;
|
|
Packit |
857059 |
static SPIN_LOCK LockedAreaMap_Lock;
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
static unsigned s_num_locks = 0; /* count of MemoryLockPrepare calls */
|
|
Packit |
857059 |
static unsigned s_num_split = 0; /* count of LOCKED_AREAs split */
|
|
Packit |
857059 |
static unsigned s_num_merge = 0; /* count of LOCKED_AREAs merged */
|
|
Packit |
857059 |
static unsigned s_max_areas = 0; /* maximum number of areas */
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
/* dump all the locked areas, must be called with LockedAreaMap_Lock held */
|
|
Packit |
857059 |
static void LockedAreaDump(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
cl_map_item_t *pMapItem;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
MsgOut(" start end cnt\n");
|
|
Packit |
857059 |
for (pMapItem = cl_qmap_head(&LockedArea_Map);
|
|
Packit |
857059 |
pMapItem != cl_qmap_end(&LockedArea_Map);
|
|
Packit |
857059 |
pMapItem = cl_qmap_next(pMapItem))
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea = PARENT_STRUCT(pMapItem, LOCKED_AREA, MapItem);
|
|
Packit |
857059 |
|
|
Packit |
857059 |
MsgOut("0x%16.16"PRIxN" 0x%16.16"PRIxN" %10u\n", pArea->start, pArea->end, pArea->lock_cnt);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* compare start addresses of 2 entries in map
|
|
Packit |
857059 |
* used as primary sort for LockedArea_Map. The map should not have any
|
|
Packit |
857059 |
* overlapping areas, hence sort by start address is sufficient
|
|
Packit |
857059 |
* Return:
|
|
Packit |
857059 |
* -1: key1 < key 2
|
|
Packit |
857059 |
* 0: key1 = key 2
|
|
Packit |
857059 |
* 1: key1 > key 2
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int LockedAreaCompare(uint64 key1, uint64 key2)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea1 = (LOCKED_AREA*)(uintn)key1;
|
|
Packit |
857059 |
LOCKED_AREA *pArea2 = (LOCKED_AREA*)(uintn)key2;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (pArea1->start < pArea2->start)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
else if (pArea1->start == pArea2->start)
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* compare address range in key2 against address range in key1
|
|
Packit |
857059 |
* key1 is a LOCKED_AREA*, key2 is a ADDR_RANGE*
|
|
Packit |
857059 |
* Return:
|
|
Packit |
857059 |
* -1: key1 < key 2 (eg. key 2 is above range of key 1)
|
|
Packit |
857059 |
* 0: key1 = key 2 (eg. key 2 overlaps with range of key 1)
|
|
Packit |
857059 |
* 1: key1 > key 2 (eg. key 2 is below range of key 1)
|
|
Packit |
857059 |
* Note that more than 1 range in the LockedArea_Map could overlap
|
|
Packit |
857059 |
* a given value for key2
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static int LockedAreaRangeCompare(uint64 key1, uint64 key2)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea1 = (LOCKED_AREA*)(uintn)key1;
|
|
Packit |
857059 |
ADDR_RANGE *pRange2 = (ADDR_RANGE*)(uintn)key2;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (pArea1->start > pRange2->end)
|
|
Packit |
857059 |
return 1;
|
|
Packit |
857059 |
else if (pArea1->end < pRange2->start)
|
|
Packit |
857059 |
return -1;
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
return 0;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* convert a pMapItem into a pArea, returns NULL if "end marker" */
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaFromMapItem(cl_map_item_t *pMapItem)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
if (pMapItem != cl_qmap_end(&LockedArea_Map)) {
|
|
Packit |
857059 |
return PARENT_STRUCT(pMapItem, LOCKED_AREA, MapItem);
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* next area after pArea, returns NULL if no areas after pArea */
|
|
Packit |
857059 |
static _inline LOCKED_AREA *LockedAreaNext(LOCKED_AREA *pArea)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return (LockedAreaFromMapItem(cl_qmap_next(&pArea->MapItem)));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* prev area before pArea, returns NULL if no areas before pArea */
|
|
Packit |
857059 |
static _inline LOCKED_AREA *LockedAreaPrev(LOCKED_AREA *pArea)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return (LockedAreaFromMapItem(cl_qmap_prev(&pArea->MapItem)));
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* must call with Map locked
|
|
Packit |
857059 |
* merges pArea1 and pArea2 (which must be adjacent areas)
|
|
Packit |
857059 |
* returns resulting merged area (Area2 is freed)
|
|
Packit |
857059 |
* cannot fail
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaMerge(LOCKED_AREA *pArea1, LOCKED_AREA *pArea2)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ASSERT(pArea1->end+1 == pArea2->start);
|
|
Packit |
857059 |
ASSERT(pArea1->lock_cnt == pArea2->lock_cnt);
|
|
Packit |
857059 |
pArea1->end = pArea2->end;
|
|
Packit |
857059 |
cl_qmap_remove_item(&LockedArea_Map, &pArea2->MapItem);
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
s_num_merge++;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
return pArea1;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* create a new LOCKED_AREA and insert it into LockedArea_Map
|
|
Packit |
857059 |
* returns NULL on memory allocation errors, otherwise pointer to new area
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaAlloc(uintn start, uintn end, uint32 lock_cnt)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pNewArea;
|
|
Packit |
857059 |
cl_map_item_t *pMapItem;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
pNewArea = (LOCKED_AREA*)MemoryAllocate2(
|
|
Packit |
857059 |
sizeof(LOCKED_AREA), IBA_MEM_FLAG_NONE, MLOCK_TAG);
|
|
Packit |
857059 |
if (! pNewArea)
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
pNewArea->start = start;
|
|
Packit |
857059 |
pNewArea->end = end;
|
|
Packit |
857059 |
pNewArea->lock_cnt = lock_cnt;
|
|
Packit |
857059 |
pMapItem = cl_qmap_insert(&LockedArea_Map, (uintn)pNewArea, &pNewArea->MapItem);
|
|
Packit |
857059 |
// assert new area is unique
|
|
Packit |
857059 |
ASSERT(pMapItem == &pNewArea->MapItem);
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
if (cl_qmap_count(&LockedArea_Map) > s_max_areas)
|
|
Packit |
857059 |
s_max_areas = cl_qmap_count(&LockedArea_Map);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
return pNewArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* must call with Map locked
|
|
Packit |
857059 |
* splits pArea into 2 areas at addr
|
|
Packit |
857059 |
* 1st area will be pArea->start to addr-1
|
|
Packit |
857059 |
* 2nd area will be addr to pArea->end
|
|
Packit |
857059 |
* returns 2nd area (pArea becomes 1st area)
|
|
Packit |
857059 |
* returns NULL on failure to allocate memory
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaSplit(LOCKED_AREA *pArea, uintn addr)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pNewArea;
|
|
Packit |
857059 |
cl_map_item_t *pMapItem;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
ASSERT(pArea->start < addr);
|
|
Packit |
857059 |
ASSERT(pArea->end >= addr);
|
|
Packit |
857059 |
pNewArea = (LOCKED_AREA*)MemoryAllocate2(
|
|
Packit |
857059 |
sizeof(LOCKED_AREA), IBA_MEM_FLAG_NONE, MLOCK_TAG);
|
|
Packit |
857059 |
if (! pNewArea)
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
pNewArea->start = addr;
|
|
Packit |
857059 |
pNewArea->end = pArea->end;
|
|
Packit |
857059 |
pNewArea->lock_cnt = pArea->lock_cnt;
|
|
Packit |
857059 |
pArea->end = addr-1; // must fixup before insert pNewArea
|
|
Packit |
857059 |
pMapItem = cl_qmap_insert(&LockedArea_Map, (uintn)pNewArea, &pNewArea->MapItem);
|
|
Packit |
857059 |
ASSERT(pMapItem == &pNewArea->MapItem); /* assert new area is unique */
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
s_num_split++;
|
|
Packit |
857059 |
if (cl_qmap_count(&LockedArea_Map) > s_max_areas)
|
|
Packit |
857059 |
s_max_areas = cl_qmap_count(&LockedArea_Map);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
return pNewArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* must call with Map locked
|
|
Packit |
857059 |
* find the 1st area in LockedArea_Map which overlaps start-end
|
|
Packit |
857059 |
* returns NULL if no overlapping area(s)
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static LOCKED_AREA *FindFirstOverlap(uintn start, uintn end)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
ADDR_RANGE Range;
|
|
Packit |
857059 |
cl_map_item_t *pMapItem;
|
|
Packit |
857059 |
LOCKED_AREA *pArea;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
Range.start = start;
|
|
Packit |
857059 |
Range.end = end;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* first find if any locked areas overlap the Range */
|
|
Packit |
857059 |
pMapItem = cl_qmap_get_compare(&LockedArea_Map, (uint64)(uintn)&Range, LockedAreaRangeCompare);
|
|
Packit |
857059 |
if (pMapItem == cl_qmap_end(&LockedArea_Map)) {
|
|
Packit |
857059 |
/* no overlap with existing locks */
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pArea = PARENT_STRUCT(pMapItem, LOCKED_AREA, MapItem);
|
|
Packit |
857059 |
/* because RangeCompare is not unique, we could get any area which
|
|
Packit |
857059 |
* overlaps, so we must back up to find first area which overlaps
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
while ((pMapItem = cl_qmap_prev(&pArea->MapItem)) != cl_qmap_end(&LockedArea_Map)) {
|
|
Packit |
857059 |
if (LockedAreaRangeCompare(cl_qmap_key(pMapItem), (uint64)(uintn)&Range) != 0) {
|
|
Packit |
857059 |
// no overlap, pArea is 1st to overlap Range
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pArea = PARENT_STRUCT(pMapItem, LOCKED_AREA, MapItem);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
/* now pArea is 1st area to overlap Range */
|
|
Packit |
857059 |
return pArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* account for the locking/unlocking of start-end in pArea
|
|
Packit |
857059 |
* as needed we could split pArea into up to 2 pieces
|
|
Packit |
857059 |
* the returned value is the area which overlaps desired start/end
|
|
Packit |
857059 |
* returns NULL on error
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaAddLock(LOCKED_AREA *pArea, uintn start, uintn end, uint32 add)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *p = NULL;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if (pArea->start < start) {
|
|
Packit |
857059 |
ASSERT(pArea->end >= start);
|
|
Packit |
857059 |
p = pArea; // save for recovery
|
|
Packit |
857059 |
pArea = LockedAreaSplit(pArea, start); // 2nd half
|
|
Packit |
857059 |
if (! pArea)
|
|
Packit |
857059 |
return NULL; // failed
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (pArea->end > end) {
|
|
Packit |
857059 |
ASSERT(pArea->start <= end);
|
|
Packit |
857059 |
if (! LockedAreaSplit(pArea, end+1)) {
|
|
Packit |
857059 |
// error, undo split above
|
|
Packit |
857059 |
if (p)
|
|
Packit |
857059 |
(void)LockedAreaMerge(p, pArea);
|
|
Packit |
857059 |
return NULL; // failed
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// pArea is still 1st half
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pArea->lock_cnt += add;
|
|
Packit |
857059 |
return pArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static _inline LOCKED_AREA *LockedAreaIncLock(LOCKED_AREA *pArea, uintn start, uintn end)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return LockedAreaAddLock(pArea, start, end, 1);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
static _inline LOCKED_AREA *LockedAreaDecLock(LOCKED_AREA *pArea, uintn start, uintn end)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
return LockedAreaAddLock(pArea, start, end, (uint32)-1);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* create a new locked area covering start-end */
|
|
Packit |
857059 |
static LOCKED_AREA *LockedAreaCreate(uintn start, uintn end)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea;
|
|
Packit |
857059 |
uintn length = (end-start)+1;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: mlock addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (mlock((void*)start, (size_t)length) < 0) {
|
|
Packit |
857059 |
MsgOut("mlock failed: start=0x%p, len=%u, errno=%s (%d)\n",
|
|
Packit |
857059 |
(void*)start, (unsigned)length, strerror(errno), errno);
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: madvise DONTFORK addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (madvise((void*)start, (size_t)length, MADV_DONTFORK) < 0) {
|
|
Packit |
857059 |
MsgOut("madvise DONTFORK failed: start=0x%p, len=%u, errno=%s (%d)\n",
|
|
Packit |
857059 |
(void*)start, (unsigned)length, strerror(errno), errno);
|
|
Packit |
857059 |
(void)munlock((void*)start, (size_t)length);
|
|
Packit |
857059 |
return NULL;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pArea = LockedAreaAlloc(start, end, 1);
|
|
Packit |
857059 |
if (! pArea) {
|
|
Packit |
857059 |
(void)madvise((void*)start, (size_t)length, MADV_DOFORK);
|
|
Packit |
857059 |
(void)munlock((void*)start, (size_t)length);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
return pArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* destroy a locked area */
|
|
Packit |
857059 |
static void LockedAreaDestroy(LOCKED_AREA *pArea)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
uintn length = (pArea->end - pArea->start)+1;
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: madvise DOFORK addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,pArea->start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
(void)madvise((void*)pArea->start, (size_t)length, MADV_DOFORK);
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: munlock addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,pArea->start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
(void)munlock((void*)pArea->start, (size_t)length);
|
|
Packit |
857059 |
cl_qmap_remove_item(&LockedArea_Map, &pArea->MapItem);
|
|
Packit |
857059 |
MemoryDeallocate(pArea);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
/* merge Areas with same lock count. This saves space but
|
|
Packit |
857059 |
* may make for more work in unlock
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static void CompressAreas(LOCKED_AREA *pFirstArea, uintn end)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
ASSERT(pFirstArea);
|
|
Packit |
857059 |
/* start merge process with 1st area before this lock (if any) */
|
|
Packit |
857059 |
pArea = LockedAreaPrev(pFirstArea);
|
|
Packit |
857059 |
if (pArea)
|
|
Packit |
857059 |
pFirstArea = pArea;
|
|
Packit |
857059 |
while (pFirstArea->start <= end) {
|
|
Packit |
857059 |
pArea = LockedAreaNext(pFirstArea);
|
|
Packit |
857059 |
if (! pArea)
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
if (pArea->lock_cnt == pFirstArea->lock_cnt
|
|
Packit |
857059 |
&& pFirstArea->end+1 == pArea->start)
|
|
Packit |
857059 |
pFirstArea = LockedAreaMerge(pFirstArea, pArea);
|
|
Packit |
857059 |
else
|
|
Packit |
857059 |
pFirstArea = pArea;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif /* COMPRESS_AREAS */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* heart of managing mlock/madvise locked areas.
|
|
Packit |
857059 |
* start and length must be pagesize aligned
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static FSTATUS
|
|
Packit |
857059 |
MemoryLockPrepareMlock(uintn start, uintn length)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea;
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
LOCKED_AREA *pFirstArea;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
uintn end = start + length-1;
|
|
Packit |
857059 |
uintn addr;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (! length)
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
// TBD - should we just mlock and madvise whole area 1st outside spin lock?
|
|
Packit |
857059 |
// however error unwind would be impossible if madvise failed?
|
|
Packit |
857059 |
// does kernel properly count mlock if done twice to same page?
|
|
Packit |
857059 |
SpinLockAcquire(&LockedAreaMap_Lock);
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
s_num_locks++;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
pArea = FindFirstOverlap(start, end);
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
pFirstArea = NULL;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
for (addr=start; addr<=end; ) {
|
|
Packit |
857059 |
if (! pArea) {
|
|
Packit |
857059 |
pArea = LockedAreaCreate(addr, end);
|
|
Packit |
857059 |
} else if (pArea->start > addr) {
|
|
Packit |
857059 |
// fill gap
|
|
Packit |
857059 |
pArea = LockedAreaCreate(addr, MIN(end, pArea->start-1));
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
pArea = LockedAreaIncLock(pArea, addr, end);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
if (! pArea) {
|
|
Packit |
857059 |
// error, unwind what we did so far
|
|
Packit |
857059 |
SpinLockRelease(&LockedAreaMap_Lock);
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
MsgOut("failure for MemoryLockPrepare(0x%"PRIxN", 0x%"PRIxN") for 0x%"PRIxN"-0x%"PRIxN"\n", start, length, addr, end);
|
|
Packit |
857059 |
LockedAreaDump();
|
|
Packit |
857059 |
MsgOut("MemoryLockUnprepare(0x%"PRIxN", 0x%"PRIxN") for 0x%"PRIxN"-0x%"PRIxN"\n", start, length, addr, end);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (addr != start)
|
|
Packit |
857059 |
(void)MemoryLockUnprepareMlock(start, addr-start);
|
|
Packit |
857059 |
return FINSUFFICIENT_RESOURCES;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
// adjust to reflect what is left to do
|
|
Packit |
857059 |
addr = pArea->end+1;
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
if (! pFirstArea)
|
|
Packit |
857059 |
pFirstArea = pArea;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
pArea = LockedAreaNext(pArea);
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
/* merge Areas with same lock count. This saves space but
|
|
Packit |
857059 |
* may make for more work in unlock
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
ASSERT(pFirstArea);
|
|
Packit |
857059 |
CompressAreas(pFirstArea, end);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
LockedAreaDump();
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
SpinLockRelease(&LockedAreaMap_Lock);
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
/* start and length must be pagesize aligned
|
|
Packit |
857059 |
*/
|
|
Packit |
857059 |
static FSTATUS
|
|
Packit |
857059 |
MemoryLockUnprepareMlock(uintn start, uintn length)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
LOCKED_AREA *pArea;
|
|
Packit |
857059 |
LOCKED_AREA *p;
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
LOCKED_AREA *pFirstArea;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
uintn end = start + length-1;
|
|
Packit |
857059 |
uintn addr;
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
MsgOut("%s: addr:0x%"PRIxN" size:0x%"PRIxN"\n",__func__,start,length);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (! length)
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
SpinLockAcquire(&LockedAreaMap_Lock);
|
|
Packit |
857059 |
pArea = FindFirstOverlap(start, end);
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
pFirstArea = NULL;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
for (addr=start; addr<=end; ) {
|
|
Packit |
857059 |
ASSERT(pArea);
|
|
Packit |
857059 |
ASSERT(pArea->start <= addr);
|
|
Packit |
857059 |
pArea = LockedAreaDecLock(pArea, addr, end);
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
if (! pArea) {
|
|
Packit |
857059 |
// stuck, can't really re-lock it, so leave it
|
|
Packit |
857059 |
// partially unlocked and give up
|
|
Packit |
857059 |
DbgOut("Unable to unlock: addr=0x%p, end=0x%p\n",
|
|
Packit |
857059 |
(void*)addr, (void*)end);
|
|
Packit |
857059 |
break;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#else
|
|
Packit |
857059 |
// since never merge, should be no need to split, so should not fail
|
|
Packit |
857059 |
ASSERT(pArea);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
// adjust to reflect what is left to do
|
|
Packit |
857059 |
addr = pArea->end+1;
|
|
Packit |
857059 |
p = LockedAreaNext(pArea);
|
|
Packit |
857059 |
if (! pArea->lock_cnt) {
|
|
Packit |
857059 |
LockedAreaDestroy(pArea);
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
} else {
|
|
Packit |
857059 |
if (! pFirstArea)
|
|
Packit |
857059 |
pFirstArea = pArea;
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
pArea = p;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#if COMPRESS_AREAS
|
|
Packit |
857059 |
/* merge Areas with same lock count */
|
|
Packit |
857059 |
if (pFirstArea)
|
|
Packit |
857059 |
CompressAreas(pFirstArea, end);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
#if MLOCK_DBG > 1
|
|
Packit |
857059 |
LockedAreaDump();
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
SpinLockRelease(&LockedAreaMap_Lock);
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
/* end of MEMORY_LOCK_STRAT_MLOCK specific code */
|
|
Packit |
857059 |
/* ********************************************************************** */
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
FSTATUS
|
|
Packit |
857059 |
MemoryLockPrepareInit(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
|
|
Packit |
857059 |
cl_qmap_init(&LockedArea_Map, LockedAreaCompare);
|
|
Packit |
857059 |
SpinLockInitState( &LockedAreaMap_Lock );
|
|
Packit |
857059 |
|
|
Packit |
857059 |
if ( !SpinLockInit ( &LockedAreaMap_Lock ) )
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
MsgOut ("MemoryLockPrepareInit: Locked Area SpinLock init failed\n");
|
|
Packit |
857059 |
return FERROR;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
|
|
Packit |
857059 |
return FSUCCESS;
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
|
|
Packit |
857059 |
void
|
|
Packit |
857059 |
MemoryLockPrepareCleanup(void)
|
|
Packit |
857059 |
{
|
|
Packit |
857059 |
|
|
Packit |
857059 |
#if MLOCK_DBG
|
|
Packit |
857059 |
MsgOut("MLock Stats: numLocks: %u, maxAreas: %u, numSplit: %u, numMerge: %u\n",
|
|
Packit |
857059 |
s_num_locks, s_max_areas, s_num_split, s_num_merge);
|
|
Packit |
857059 |
#endif
|
|
Packit |
857059 |
if (! cl_is_qmap_empty(&LockedArea_Map)) {
|
|
Packit |
857059 |
DbgOut("MemoryLockPrepareCleanup: Locked Area Map not empty\n");
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
SpinLockDestroy( &LockedAreaMap_Lock );
|
|
Packit |
857059 |
|
|
Packit |
857059 |
}
|
|
Packit |
857059 |
#endif /* IB_STACK_IBACCESS */
|