⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mapfile.c

📁 可用于嵌入式编程学习
💻 C
📖 第 1 页 / 共 5 页
字号:
        // intentionally fall through

    case RESTORE_FLAG_UNFLUSHED:

        // 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -