📄 mapfile.c
字号:
//------------------------------------------------------------------------------
void
FreeMap(
HANDLE hMap
)
{
CLEANEVENT *lpce;
LPFSMAP lpm, lpm2;
HANDLE hm;
DEBUGCHK(MapNameCS.OwnerThread == pCurThread->hTh); // Must own MapNameCS
lpm = HandleToMap(hMap);
if (!lpm) {
// No way to signal an error
DEBUGCHK(0);
return;
}
EnterCriticalSection(&MapCS);
// Remove from the list of maps
if (hMapList == hMap)
hMapList = lpm->hNext;
else {
for (hm = hMapList; hm; hm = lpm2->hNext) {
lpm2 = HandleToMap(hm);
if (lpm2) {
if (lpm2->hNext == hMap) {
lpm2->hNext = lpm->hNext;
break;
}
} else {
// No way to signal an error -- just continue
DEBUGCHK(0);
break;
}
}
DEBUGCHK(hm);
}
LeaveCriticalSection(&MapCS);
// Flush all dirty pages back to the file
if (lpm->bNoAutoFlush) {
if (FlushMapBuffersLogged(lpm, 0, lpm->length, FMB_LEAVENAMECS)) {
FlushSettings FlushStruct;
DWORD dwTemp;
// Remove kernel logging area reserved at the end of the file.
// This must ONLY be done if the flush completed successfully.
// To avoid growing/shrinking/growing/shrinking repeatedly, it is
// only done when the map is freed.
if (ReadFileWithSeek(lpm->hFile, &FlushStruct, sizeof(FlushSettings),
&dwTemp, 0, offsetof(fslog_t, dwRestoreFlags), 0)
&& (dwTemp == sizeof(FlushSettings))
&& (SetFilePointer(lpm->hFile, FlushStruct.dwRestoreStart, NULL,
FILE_BEGIN) == FlushStruct.dwRestoreStart)) {
DEBUGMSG(ZONE_MAPFILE, (TEXT("MMFILE: Removing logging area from flushed map 0x%08x at 0x%08x, old size 0x%08x\r\n"),
lpm, FlushStruct.dwRestoreStart, GetFileSize(lpm->hFile, NULL)));
SetEndOfFile(lpm->hFile);
}
}
} else {
FlushMapBuffers(lpm, 0, lpm->length, FMB_LEAVENAMECS);
}
if ((lpm->hFile != INVALID_HANDLE_VALUE) && !lpm->bNoAutoFlush)
KernelCloseHandle(lpm->hFile);
if (lpm->name)
FreeName(lpm->name);
while (lpm->lpmlist) {
lpce = lpm->lpmlist->ceptr;
FreeMem(lpm->lpmlist, HEAP_CLEANEVENT);
lpm->lpmlist = lpce;
}
{
LPBYTE pBase = (LPBYTE) PAGEALIGN_DOWN((DWORD)lpm->pBase);
DWORD len = PAGEALIGN_UP((DWORD)lpm->pBase + lpm->reslen - (DWORD) pBase);
FSMapMemFree(pBase, len, MEM_DECOMMIT);
FreeAllPagesFromQ (&lpm->pgqueue);
FSMapMemFree(pBase, len, MEM_RELEASE);
}
FreeMem(lpm, HEAP_FSMAP);
FreeHandle(hMap);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
HANDLE
FindMap(
LPBYTE pMem
)
{
HANDLE hm;
LPFSMAP lpm;
EnterCriticalSection(&MapCS);
for (hm = hMapList; hm; hm = lpm->hNext) {
lpm = HandleToMap(hm);
if (lpm) {
if ((lpm->pBase == pMem) || ((lpm->pBase < pMem) && (pMem < lpm->pBase + lpm->length)))
break;
} else {
DEBUGCHK(0);
hm = (HANDLE)0;
break;
}
}
LeaveCriticalSection(&MapCS);
return hm;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
SC_UnmapViewOfFile(
LPVOID lpvAddr
)
{
BOOL retval = FALSE;
HANDLE hm;
BOOL bLeft = 0;
LPFSMAP lpm;
CLEANEVENT *lpce, *lpce2;
DEBUGMSG(ZONE_ENTRY, (L"SC_UnmapViewOfFile entry: %8.8lx\r\n", lpvAddr));
EnterCriticalSection(&MapNameCS);
if ((hm = FindMap(lpvAddr)) && (lpm = HandleToMap(hm))){
lpce2 = NULL;
if (lpce = lpm->lpmlist) {
if ((lpce->base == lpvAddr) && (lpce->size == (DWORD)pCurProc))
lpm->lpmlist = lpce->ceptr;
else {
do {
lpce2 = lpce;
lpce = lpce->ceptr;
} while (lpce && ((lpce->base != lpvAddr)
|| (lpce->size != (DWORD)pCurProc)));
if (lpce)
lpce2->ceptr = lpce->ceptr;
}
}
if (lpce) {
FreeMem(lpce, HEAP_CLEANEVENT);
if (DecRef(hm, pCurProc, FALSE)) {
FreeMap(hm);
bLeft = 1;
}
retval = TRUE;
} else
KSetLastError(pCurThread, ERROR_INVALID_ADDRESS);
} else {
DEBUGCHK(!hm); // DEBUGCHK only if lpm assignment failed
KSetLastError(pCurThread, ERROR_INVALID_ADDRESS);
}
if (!bLeft)
LeaveCriticalSection(&MapNameCS);
DEBUGMSG(ZONE_ENTRY, (L"SC_UnmapViewOfFile exit: %8.8lx -> %8.8lx\r\n",
lpvAddr, retval));
return retval;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
SC_FlushViewOfFile(
LPCVOID lpBaseAddress,
DWORD dwNumberOfBytesToFlush
)
{
BOOL retval = FALSE;
LPFSMAP lpm;
HANDLE hm;
DEBUGMSG(ZONE_ENTRY, (L"SC_FlushViewOfFile entry: %8.8lx %8.8lx\r\n",
lpBaseAddress, dwNumberOfBytesToFlush));
EnterCriticalSection(&MapNameCS);
if ((hm = FindMap((LPBYTE)lpBaseAddress)) && (lpm = HandleToMap(hm))) {
if (lpm->bNoAutoFlush) {
retval = FlushMapBuffersLogged(lpm, (LPBYTE)lpBaseAddress - lpm->pBase,
dwNumberOfBytesToFlush, FMB_LEAVENAMECS);
} else {
retval = FlushMapBuffers(lpm, (LPBYTE)lpBaseAddress - lpm->pBase,
dwNumberOfBytesToFlush, FMB_LEAVENAMECS);
}
} else {
DEBUGCHK(!hm); // DEBUGCHK only if lpm assignment failed
LeaveCriticalSection(&MapNameCS);
}
DEBUGMSG(ZONE_ENTRY, (L"SC_FlushViewOfFile exit: %8.8lx %8.8lx -> %8.8lx\r\n",
lpBaseAddress, dwNumberOfBytesToFlush, retval));
return retval;
}
//------------------------------------------------------------------------------
// Not exposed directly, but through IOCTL_KLIB_CHANGEMAPFLUSHING. Changes the
// flush settings for the mapped view of a file starting at lpBaseAddress.
// The flush settings affect the entire mapping, so no range is given. Flush
// changes are only supported on logged maps. Suspending flushing should not
// be taken lightly: it can lead to data loss, OOM, or ballooned file sizes.
//------------------------------------------------------------------------------
BOOL
ChangeMapFlushing(
LPCVOID lpBaseAddress,
DWORD dwFlags
)
{
BOOL retval = FALSE;
LPFSMAP lpm;
HANDLE hm;
if (SC_CeGetCallerTrust() != OEM_CERTIFY_TRUST) {
KSetLastError(pCurThread, ERROR_ACCESS_DENIED);
return FALSE;
}
EnterCriticalSection(&MapNameCS);
if ((hm = FindMap((LPBYTE)lpBaseAddress)) && (lpm = HandleToMap(hm))) {
// Flush changes are only used for database volumes so they are only
// supported on logged maps
if (lpm->bNoAutoFlush) {
DEBUGMSG(ZONE_MAPFILE, (TEXT("MMFILE: Changing map 0x%08x flush flags 0x%08x (%u dirty)\r\n"),
lpm, dwFlags, lpm->dwDirty));
lpm->bFlushFlags = (BYTE)(dwFlags & FILEMAP_NOBACKGROUNDFLUSH); // Only one flag supported
retval = TRUE;
} else {
KSetLastError(pCurThread, ERROR_ACCESS_DENIED);
}
} else {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
DEBUGCHK(!hm); // DEBUGCHK only if lpm assignment failed
}
LeaveCriticalSection(&MapNameCS);
return retval;
}
#if (PAGE_SIZE == 1024)
#define MAYBE_LIMIT_MEMORY 32
#define MAYBE_LIMIT_DIRTY 72
#else
#define MAYBE_LIMIT_MEMORY 10
#define MAYBE_LIMIT_DIRTY 18
#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
SC_FlushViewOfFileMaybe(
LPCVOID lpBaseAddress,
DWORD dwNumberOfBytesToFlush
)
{
extern long PageOutTrigger;
BOOL retval = FALSE;
LPFSMAP lpm;
HANDLE hm;
DEBUGMSG(ZONE_ENTRY, (L"SC_FlushViewOfFileMaybe entry: %8.8lx %8.8lx\r\n",
lpBaseAddress, dwNumberOfBytesToFlush));
EnterCriticalSection(&MapNameCS);
if ((hm = FindMap((LPBYTE)lpBaseAddress)) && (lpm = HandleToMap(hm))) {
if ((PageFreeCount >= MAYBE_LIMIT_MEMORY + PageOutTrigger)
&& (lpm->dwDirty < MAYBE_LIMIT_DIRTY)) {
LeaveCriticalSection(&MapNameCS);
retval = TRUE;
} else if (lpm->bNoAutoFlush) {
if (lpm->bFlushFlags & FILEMAP_NOBACKGROUNDFLUSH) {
// Skip background flushing
LeaveCriticalSection(&MapNameCS);
retval = TRUE;
} else {
retval = FlushMapBuffersLogged(lpm, (LPBYTE)lpBaseAddress - lpm->pBase,
dwNumberOfBytesToFlush, FMB_LEAVENAMECS);
}
} else {
retval = FlushMapBuffers(lpm, (LPBYTE)lpBaseAddress-lpm->pBase,
dwNumberOfBytesToFlush, FMB_LEAVENAMECS);
}
} else {
DEBUGCHK(!hm); // DEBUGCHK only if lpm assignment failed
LeaveCriticalSection(&MapNameCS);
}
DEBUGMSG(ZONE_ENTRY, (L"SC_FlushViewOfFileMaybe exit: %8.8lx %8.8lx -> %8.8lx\r\n",
lpBaseAddress, dwNumberOfBytesToFlush, retval));
return retval;
}
int MappedPageInPage (LPFSMAP lpm, BOOL bWrite, DWORD addr, LPBYTE pMem)
{
DWORD cbRead, cbToRead;
// Flush logged mapfiles if too many pages are dirty
if (bWrite
&& lpm->bNoAutoFlush
&& (lpm->dwDirty >= MAYBE_LIMIT_DIRTY - 1)
&& !(lpm->bFlushFlags & FILEMAP_NOBACKGROUNDFLUSH)) {
if (FlushMapBuffersLogged(lpm, 0, 0, 0)) {
return PAGEIN_OTHERRETRY;
}
// Continue with pagein if the flush failed
RETAILMSG(1, (TEXT("MMFILE: PageIn continuing after mapped flush failure\r\n")));
}
if ((cbToRead = (DWORD) lpm->pBase + lpm->filelen - addr) > PAGE_SIZE)
cbToRead = PAGE_SIZE;
if (!ReadFileWithSeek (lpm->hFile, pMem, cbToRead, &cbRead, 0, addr - (DWORD)lpm->pBase, 0)) {
DEBUGMSG(ZONE_PAGING || ZONE_MAPFILE,
(L"MappedPageInPage: PageIn failed on ReadFile (0x%08x of 0x%08x read, pos 0x%08x of 0x%08x)\r\n",
cbRead, cbToRead, addr - (DWORD)lpm->pBase, lpm->filelen));
return (KGetLastError (pCurThread) != ERROR_DEVICE_REMOVED)? PAGEIN_RETRY : PAGEIN_FAILURE;
}
// if the mapfile changed underneath, don't bother retrying
return (cbRead == cbToRead)? PAGEIN_SUCCESS : PAGEIN_FAILURE;
}
int MMQueryState (DWORD addr, BOOL bWrite)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD dwOldProtect;
if (!VirtualQuery((LPVOID)addr, &mbi, sizeof(mbi))) {
DEBUGMSG(ZONE_PAGING || ZONE_MAPFILE, (L"MMQueryState: VirtualQuery failed\r\n"));
return PAGEIN_FAILURE;
}
if (MEM_COMMIT == mbi.State) {
// memory already commited, someone else beat us paging the page in.
// Just check/update protection and return accordingly
switch (mbi.Protect & ~(PAGE_NOCACHE|PAGE_GUARD)) {
case PAGE_READWRITE:
case PAGE_EXECUTE_READWRITE:
return PAGEIN_SUCCESS;
case PAGE_READONLY:
case PAGE_EXECUTE_READ:
if (!bWrite
|| VirtualProtect((LPVOID)addr, PAGE_SIZE, PAGE_READWRITE, &dwOldProtect)) {
return PAGEIN_SUCCESS;
}
DEBUGMSG(ZONE_PAGING || ZONE_MAPFILE, (L"MMQueryState: Failed: write on RO pages\r\n"));
// fall through
default:
break;
}
return PAGEIN_FAILURE;
}
// return PAGEIN_RETRY if the memory is not commited (not yet paged in)
return PAGEIN_RETRY;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int MappedPageInHelper (LPFSMAP lpm, BOOL bWrite, DWORD addr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -