📄 mapfile.c
字号:
// Clear the restore flag FlushStruct.dwRestoreFlags = RESTORE_FLAG_NONE; if (!WriteFileWithSeek(lpm->hFile, &FlushStruct.dwRestoreFlags, sizeof(DWORD), &bread, 0, offsetof(fslog_t,dwRestoreFlags), 0) || (bread != sizeof(DWORD))) { ERRORMSG(1,(L"Failed to clear flags on ValidateFile!\r\n")); return FALSE; } FlushFileBuffers(lpm->hFile); } return TRUE;}#define FMBL_FLUSH_SKIP_LIMIT (PAGES_PER_BLOCK*2)BOOL FlushMapBuffersLogged(LPFSMAP lpm, DWORD dwOffset, DWORD dwLength, DWORD dwFlags){ DWORD remain, page, end, dw1, count; BOOL retval = FALSE; HANDLE h; LPBYTE pb; ACCESSKEY ulOldKey; SWITCHKEY(ulOldKey,0xffffffff); // // Figure out where we're starting and stopping, page-aligned // if (!dwLength) dwLength = lpm->length; end = dwOffset+dwLength; dwOffset = PAGEALIGN_DOWN(dwOffset); end = PAGEALIGN_UP(end); if (end > lpm->length) end = lpm->length; if (end < dwOffset) { if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); return FALSE; } if (lpm->pDirty == (LPBYTE)1) { // // Old-style (non-transactionable) file system // ERRORMSG(1,(L"FlushMapBuffersLogged being used on old-style " \ L"(non-transactionable) file system!\r\n")); h = lpm->hFile; pb = lpm->pBase; if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); SetFilePointer(h, dwOffset, 0, FILE_BEGIN); if (!WriteFile(h, pb, end-dwOffset, &remain, 0) || (remain != end-dwOffset)) { DEBUGMSG(ZONE_PAGING,(L"FMB 5\r\n")); DEBUGCHK(0); goto exit; } FlushFileBuffers(h); retval = TRUE; } else if (lpm->pDirty) { // // The file is read/write -- we may have dirty pages to flush // EnterCriticalSection(&WriterCS); if (!(dwFlags & FMB_NOWRITEOUT)) { DWORD dwFilePos, dwMemPos; // This struct is used to communicate with ValidateFile. // Only dwRestoreStart (which we do not modify) is used by any // other part of the file system. struct { DWORD dwRestoreFlags; DWORD dwRestoreStart; DWORD dwRestoreSize; } FlushStruct; // Track pages that are skipped DWORD dwSkippedPage[FMBL_FLUSH_SKIP_LIMIT]; // List of page nums WORD wSkippedPages = 0; // Count of pages WORD wNextSkip; // Used to iterate list count = 0; // // Read and update restore data // DEBUGMSG(ZONE_PAGING, (L"FMB 1\r\n")); if (!ReadFileWithSeek(lpm->hFile,&FlushStruct.dwRestoreStart, sizeof(DWORD), &dw1, 0, offsetof(fslog_t,dwRestoreStart), 0) || (dw1 != sizeof(DWORD))) { // We can exit here because nothing has been changed. RETAILMSG(1,(L"Read 0 failed on attempt at logged flush!\r\n")); LeaveCriticalSection(&WriterCS); if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); // debugchk because this shouldn't happen DEBUGCHK(0); goto exit; } dwFilePos = FlushStruct.dwRestoreStart; FlushStruct.dwRestoreFlags = RESTORE_FLAG_UNFLUSHED; FlushStruct.dwRestoreSize = PAGE_SIZE; if (!WriteFileWithSeek(lpm->hFile, &FlushStruct, sizeof(FlushStruct), &dw1, 0, offsetof(fslog_t,dwRestoreFlags), 0) || (dw1 != sizeof(FlushStruct))) { // We can exit here because nothing has been changed. RETAILMSG(1,(L"Write 0 failed on attempt at logged flush!\r\n")); LeaveCriticalSection(&WriterCS); if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); goto exit; } // // Now flush the pages in memory back to the file. We write the // new pages to the end of the file for safety, and only copy them // into their rightful places when we are done, inside ValidateFile. // We cannot clear the dirty flags until all pages are successfully // flushed, so we only update their dirty flags at the end. // // Flush the dirty blocks in the cache back to the file FlushFileBuffers(lpm->hFile); EnterCriticalSection(&PagerCS); for (page = dwOffset/PAGE_SIZE; (page+1)*PAGE_SIZE <= end; page++) { // Flush the page only if it is dirty if (lpm->pDirty[page/8] & (1<<(page%8))) { // If it's the first page, make sure the restore data is correct. if (!page) memcpy(lpm->pBase + offsetof(fslog_t,dwRestoreFlags), &FlushStruct, sizeof(FlushStruct)); if (VirtualProtect(lpm->pBase+page*PAGE_SIZE, PAGE_SIZE, PAGE_READONLY, &dw1)) { LeaveCriticalSection(&PagerCS); // Write the page's location to the start of the page dwMemPos = page*PAGE_SIZE; if (!WriteFileWithSeek(lpm->hFile, &dwMemPos, sizeof(DWORD), &dw1, 0, dwFilePos, 0) || (dw1 != sizeof(DWORD))) { // We can exit here because nothing has really changed. RETAILMSG(1, (L"Write 1 failed on attempt at logged flush!\r\n")); goto exitUnlock; } // Now write the page of data dwFilePos += sizeof(DWORD); if (!WriteFileWithSeek(lpm->hFile, lpm->pBase+page*PAGE_SIZE, PAGE_SIZE, &dw1, 0, dwFilePos, 0) || (dw1 != PAGE_SIZE)) { // We can exit here because nothing has really changed. RETAILMSG(1,(L"Write 2 failed on attempt at logged flush!\r\n")); goto exitUnlock; } dwFilePos += PAGE_SIZE; count++; EnterCriticalSection(&PagerCS); } else { // Failed the VirtualProtect - skip the page if (wSkippedPages < FMBL_FLUSH_SKIP_LIMIT) { dwSkippedPage[wSkippedPages] = page; wSkippedPages++; } else { // Reached our limit; this shouldn't happen RETAILMSG(1, (TEXT("Logged flush failures exceeded limit! (file 0x%08x)\r\n"), lpm->hFile)); DEBUGCHK(0); } } } } // Flush the incomplete page at the end, if present remain = end - (page*PAGE_SIZE); if (remain && (lpm->pDirty[page/8] & (1<<(page%8)))) { DEBUGCHK(remain <= PAGE_SIZE); // If it's the first page, make sure the restore data is correct. if (!page) memcpy(lpm->pBase + offsetof(fslog_t,dwRestoreFlags), &FlushStruct, sizeof(FlushStruct)); if (VirtualProtect(lpm->pBase+page*PAGE_SIZE, PAGE_SIZE, PAGE_READONLY, &dw1)) { LeaveCriticalSection(&PagerCS); // Write the page's location to the start of the page dwMemPos = page*PAGE_SIZE; if (!WriteFileWithSeek(lpm->hFile, &dwMemPos, sizeof(DWORD), &dw1, 0, dwFilePos, 0) || (dw1 != sizeof(DWORD))) { // We can exit here because nothing has really changed. RETAILMSG(1, (L"Write 3 failed on attempt at logged flush!\r\n")); goto exitUnlock; } // Now write the page of data dwFilePos += sizeof(DWORD); if (!WriteFileWithSeek(lpm->hFile, lpm->pBase+page*PAGE_SIZE, PAGE_SIZE, &dw1, 0, dwFilePos, 0) || (dw1 != PAGE_SIZE)) { // We can exit here because nothing has really changed. RETAILMSG(1, (L"Write 4 failed on attempt at logged flush!\r\n")); goto exitUnlock; } dwFilePos += PAGE_SIZE; count++; } else { // Failed the VirtualProtect - skip the page if (wSkippedPages < FMBL_FLUSH_SKIP_LIMIT) { dwSkippedPage[wSkippedPages] = page; wSkippedPages++; } else { // Reached our limit; this shouldn't happen RETAILMSG(1, (TEXT("Logged flush failures exceeded limit! (file 0x%08x)\r\n"), lpm->hFile)); DEBUGCHK(0); } LeaveCriticalSection(&PagerCS); } } else LeaveCriticalSection(&PagerCS); // Flush the dirty blocks in the cache back to the file FlushFileBuffers(lpm->hFile); // // Update restore data again // FlushStruct.dwRestoreFlags = RESTORE_FLAG_FLUSHED; FlushStruct.dwRestoreSize |= count<<16; if (!WriteFileWithSeek(lpm->hFile, &FlushStruct, sizeof(FlushStruct), &dw1, 0, offsetof(fslog_t,dwRestoreFlags), 0) || (dw1 != sizeof(FlushStruct))) { // We can exit here because nothing has really changed. RETAILMSG(1,(L"Write 5 failed on attempt at logged flush!\r\n")); goto exitUnlock; } // Flush the dirty blocks in the cache back to the file FlushFileBuffers(lpm->hFile); DEBUGMSG(ZONE_PAGING, (L"FMB 4\r\n")); // Commit the flush. if (!ValidateFile(lpm)) { // We cannot validate the file, so we must fail the flush! goto exitUnlock; } // // Now that everything is totally done, we can mark the blocks // as clean. // DEBUGMSG(wSkippedPages, (TEXT("FlushMapBuffersLogged: skipped %u pages\r\n"), wSkippedPages)); if (wSkippedPages > 0) { wNextSkip = 0; } else { wNextSkip = FMBL_FLUSH_SKIP_LIMIT; } EnterCriticalSection(&PagerCS); for (page = dwOffset/PAGE_SIZE; (page+1)*PAGE_SIZE <= end; page++) { if (lpm->pDirty[page/8] & (1<<(page%8))) { if ((wNextSkip < wSkippedPages) && (dwSkippedPage[wNextSkip] == page)) { // The page was skipped -- leave it marked dirty wNextSkip++; } else { // Mark as clean lpm->bRestart = 1; lpm->pDirty[page/8] &= ~(1<<(page%8)); lpm->dwDirty--; DEBUGCHK(!(lpm->dwDirty & 0x80000000)); } } } remain = end - (page*PAGE_SIZE); if (remain && (lpm->pDirty[page/8] & (1<<(page%8)))) { if ((wNextSkip < wSkippedPages) && (dwSkippedPage[wNextSkip] == page)) { // The page was skipped -- leave it marked dirty wNextSkip++; } else { // Mark as clean lpm->bRestart = 1; lpm->pDirty[page/8] &= ~(1<<(page%8)); lpm->dwDirty--; DEBUGCHK(!(lpm->dwDirty & 0x80000000)); } } DEBUGCHK((wNextSkip == wSkippedPages) || (wNextSkip == FMBL_FLUSH_SKIP_LIMIT)); DEBUGCHK(!(lpm->dwDirty) || (wSkippedPages > 0)); LeaveCriticalSection(&PagerCS); } if (dwFlags & FMB_DOFULLDISCARD) DecommitROPages(lpm->pBase, lpm->reslen); LeaveCriticalSection(&WriterCS); if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); } else { // // The file is read-only (no dirty pages to flush) // if ((lpm->hFile != INVALID_HANDLE_VALUE) && (dwFlags & FMB_DOFULLDISCARD)) FSMapMemFree(lpm->pBase, lpm->reslen, MEM_DECOMMIT); if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS); } // Successful return retval = TRUE; goto exit;exitUnlock: // If an error occurred after some pages were VirtualProtected, we must // go back and unlock them. // File must be read/write DEBUGCHK(lpm->pDirty > (LPBYTE)1); RETAILMSG(1, (TEXT("FlushMapBuffersLogged: Unlocking protected pages\r\n"))); EnterCriticalSection(&PagerCS); // Here we assume that all dirty pages should be read/write... for (page = dwOffset/PAGE_SIZE; (page+1)*PAGE_SIZE <= end; page++) { if ((lpm->pDirty[page/8] & (1<<(page%8))) && !VirtualProtect(lpm->pBase + page*PAGE_SIZE, PAGE_SIZE, PAGE_READWRITE, &dw1)) { // Is it possible to fail a call to VirtualProtect? DEBUGCHK(0); } } remain = end - (page*PAGE_SIZE); if (remain && (lpm->pDirty[page/8] & (1<<(page%8))) && !VirtualProtect(lpm->pBase + page*PAGE_SIZE, PAGE_SIZE, PAGE_READWRITE, &dw1)) { // Is it possible to fail a call to VirtualProtect? DEBUGCHK(0); } LeaveCriticalSection(&PagerCS); // Flush the dirty blocks in the cache back to the file FlushFileBuffers(lpm->hFile); LeaveCriticalSection(&WriterCS); if (dwFlags & FMB_LEAVENAMECS) LeaveCriticalSection(&MapNameCS);exit: SETCURKEY(ulOldKey); return retval;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -