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

📄 buffer.c

📁 fat32文件系统的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
            DEBUGALLOC(sizeof(BUF));
            pbuf->b_pdata = pbCarve;
            pbuf->b_flags |= BUF_FREE;
            pbuf->b_pvol = pvol;
            pbCarve += pvol->v_pdsk->d_diActive.di_bytes_per_sect;
            AddItem((PDLINK)&pvol->v_dlBufMRU, (PDLINK)&pbuf->b_dlink);
        }

        // Since we have at least MIN_BUFFERS buffers now, calculate
        // the number of threads our buffer pool can handle simultaneously.
        // If DEMAND_PAGING is enabled, we reduce that number by 1 so that
        // a Pagein thread can always assume there are adequate buffers.

#ifdef DEMAND_PAGING
        pvol->v_cBufThreads = pvol->v_cbufTotal / MIN_BUFFERS - 1;
#else
        //32/4=8
        pvol->v_cBufThreads = pvol->v_cbufTotal / MIN_BUFFERS;
#endif
    }

    // For all calls (first time or not), we must invalidate any buffers
    // we retained for an unmounted volume that was subsequently *recycled*
    // instead of *remounted*.

    if (pvol->v_flags & VOLF_RECYCLED)
        InvalidateBufferSet(pvol, TRUE);

    LeaveCriticalSection(&pvol->v_csBuffers);
    return TRUE;
}


/*  FreeBufferPool - free all buffers in buffer pool
 *
 *  ENTRY
 *      pvol - pointer to VOLUME currently being unmounted
 *
 *  EXIT
 *      TRUE if volume can be freed, or FALSE if not (ie, there are still
 *      dirty buffers that could not be committed).  Note that if the volume
 *      wasn't going to be freed to begin with, we always return FALSE.
 *
 *      This module keeps track of the number of buffer clients (volumes),
 *      and only when the last client has called FreeBufferPool will the pool
 *      actually be freed (subject to all buffers being clean, of course).
 */

BOOL FreeBufferPool(PVOLUME pvol)
{
    PBUF pbuf, pbufEnd;

    ASSERT(OWNCRITICALSECTION(&pvol->v_cs));

    // If the current volume isn't even using the buffer pool (yet),
    // then we're done.

    if (!(pvol->v_flags & VOLF_BUFFERED))
        return TRUE;

    EnterCriticalSection(&pvol->v_csBuffers);

    // This is our last chance to commit all dirty buffers.  With any
    // luck, this will clean all the buffers, allowing us to free them all.
    // That will be our assumption at least.  If dirty buffers still remain
    // for this volume, its DIRTY bit will get set again, below.

    CommitVolumeBuffers(pvol);
    pvol->v_flags &= ~VOLF_DIRTY;

    // If we have buffers carved from a single chunk of memory, then
    // quickly walk the entire list and determine if ALL the carved buffers
    // can be freed.  A single dirty or held carved buffer means that NONE
    // of the carved buffers can be freed.

    pbuf = pvol->v_dlBufMRU.pbufNext;
    pbufEnd = (PBUF)&pvol->v_dlBufMRU;
   
    DEBUGFREE(pvol->v_cbufTotal * pvol->v_pdsk->d_diActive.di_bytes_per_sect);
    VERIFYTRUE(VirtualFree(pvol->v_pbBufCarve, 0, MEM_RELEASE));
    pvol->v_pbBufCarve = NULL;

    // Now walk the buffer list again, freeing every buffer that we can.

    pbuf = pvol->v_dlBufMRU.pbufNext;

    while (pbuf != pbufEnd) {

        // The only reason we hold the buffer is so that CleanBuffer
        // won't generate a bogus assertion.  We don't care about the
        // data anymore, so it is otherwise pointless.

        HoldBuffer(pbuf);
        CleanBuffer(pbuf);
        UnholdBuffer(pbuf);

        ASSERT(pbuf->b_pvol == NULL || pbuf->b_pvol == pvol);

        pbuf->b_flags &= BUF_FREE;

        // The current buffer is clean.  Now, if this is NOT a carved
        // buffer, or it is but we can free all the carved buffers anyway,
        // then free the current buffer.

        pvol->v_cbufTotal--;
        RemoveItem((PDLINK)&pbuf->b_dlink);
        DEBUGFREE(sizeof(BUF));
        VERIFYTRUE(HeapFree(hHeap, 0, pbuf));
        pbuf = pvol->v_dlBufMRU.pbufNext;
        continue;
        
        pbuf = pbuf->b_dlink.pbufNext;
    }

    // If there were no dirty buffers for this volume, then we can remove
    // its reference to buffer pool.

    if (!(pvol->v_flags & VOLF_DIRTY)) {
        pvol->v_flags &= ~VOLF_BUFFERED;
    }

    LeaveCriticalSection(&pvol->v_csBuffers);

    return TRUE;
}


/*  ModifyBuffer - Prepare to dirty buffer
 *
 *  ENTRY
 *      pbuf - pointer to buffer
 *      pMod - pointer to modification
 *      cbMod - length of modification (ZERO to prevent logging)
 *
 *  EXIT
 *      ERROR_SUCCESS if the buffer is allowed to be modified, otherwise
 *      some error code (eg, ERROR_WRITE_PROTECT).
 */

DWORD ModifyBuffer(PBUF pbuf, PVOID pMod, int cbMod)
{
    DWORD dwError = ERROR_SUCCESS;

    ASSERTHELDBUFFER(pbuf);

    if (pbuf->b_pvol->v_flags & VOLF_READONLY) {
        dwError = ERROR_WRITE_PROTECT;
    }

    if (!dwError)
        DirtyBuffer(pbuf);

    return dwError;
}


/*  DirtyBuffer - Dirty a buffer
 *
 *  ENTRY
 *      pbuf - pointer to BUF
 *
 *  EXIT
 *      The buffer is marked DIRTY.
 */

void DirtyBuffer(PBUF pbuf)
{
    ASSERTHELDBUFFER(pbuf);

    pbuf->b_flags |= BUF_DIRTY;
}


/*  DirtyBufferError - Dirty a buffer that cannot be cleaned
 *
 *  ENTRY
 *      pbuf - pointer to BUF
 *      pMod - pointer to modification (NULL if none)
 *      cbMod - length of modification (ZERO if none)
 *
 *  EXIT
 *      The buffer is marked DIRTY, and any error is recorded.
 */

void DirtyBufferError(PBUF pbuf, PVOID pMod, int cbMod)
{
    PVOLUME pvol = pbuf->b_pvol;

    ASSERT (pvol);
    ASSERTHELDBUFFER(pbuf);

    pbuf->b_flags |= BUF_DIRTY;

    EnterCriticalSection(&pvol->v_csBuffers);

    if (!(pbuf->b_flags & BUF_ERROR)) {
        if (pvol->v_cbufError % MIN_BUFFERS == 0)
            InterlockedDecrement(&pvol->v_cBufThreads);
        pvol->v_cbufError++;
        pbuf->b_flags |= BUF_ERROR;
    }
    LeaveCriticalSection(&pvol->v_csBuffers);
}


/*  CommitBuffer - Commit a dirty buffer
 *
 *  ENTRY
 *      pbuf - pointer to BUF
 *      fCS - TRUE if csBuffers is held, FALSE if not
 *
 *  EXIT
 *      ERROR_SUCCESS (0) if successful, non-zero if not.
 *
 *  NOTES
 *      Since we clear BUF_DIRTY before calling WriteVolume, it's important
 *      we do something to prevent FindBuffer from getting any bright ideas
 *      about reusing it before we have finished writing the original dirty
 *      contents.  Furthermore, since we don't want to hold csBuffers across
 *      the potentially lengthy WriteVolume request, applying another hold to
 *      the buffer is really our only option.
 */

DWORD CommitBuffer(PBUF pbuf, BOOL fCS)
{
    PBYTE pbMod = NULL;
    int cbMod = 0;
    DWORD dwError = ERROR_SUCCESS;
    PVOLUME pvol = pbuf->b_pvol;
    BOOL fWriteThrough = FALSE;

#ifdef UNDER_CE     ASSERT(fCS == OWNCRITICALSECTION(&pvol->v_csBuffers));
#endif

    // If buffer is valid and dirty...

    if (!(pbuf->b_flags & BUF_INVALID) && (pbuf->b_flags & BUF_DIRTY)) {

        if (pvol->v_flags & VOLF_READONLY) {
            dwError = ERROR_WRITE_PROTECT;
        }
        
        DEBUGMSG(ZONE_BUFFERS,(DBGTEXT("FATFS!CommitBuffer(block %d)\r\n"), pbuf->b_blk));

        // Hold the buffer to insure that FindBuffer won't try to steal
        // it while the DIRTY bit is clear yet the buffer is still dirty.

        HoldBuffer(pbuf);


        // We clear the DIRTY bit before writing the buffer out, to
        // insure that we don't inadvertently lose some other thread's
        // modification to the buffer before our WriteVolume call is
        // complete.

        CleanBuffer(pbuf);

        // If the caller tells us that csBuffers is currently held, release
        // it across the WriteVolume call.

        pbuf->b_flags |= BUF_BUSY;

        // We used to release this critical section across a disk write but it would
        // sometimes cause data corruption on multithreaded writes with odd buffer
        // sizes. Beware if you try to "optimize" by adding the release back in.  
        //if (fCS)
        //    LeaveCriticalSection(&csBuffers);

        fWriteThrough = (pbuf->b_pstm && (pbuf->b_pstm->s_flags & STF_WRITETHRU));       
        dwError = WriteVolume(pvol, pbuf->b_blk, 1, pbuf->b_pdata, fWriteThrough);
        pbuf->b_flags &= ~BUF_BUSY;

        if (dwError) {
            if (dwError == ERROR_WRITE_PROTECT) {

                // Invalidate the buffer, it can't be written and is presumably
                // now out of sync with the disk's actual contents.

                pbuf->b_flags |= BUF_INVALID;
            }
            else {

                // If the cause of failure might simply be that the disk has been
                // yanked, we can always hope that the user will put the disk back
                // in, so let's just re-dirty the buffer.

                DirtyBufferError(pbuf, pbMod, cbMod);
            }
        }
        UnholdBuffer(pbuf);
    }
    return dwError;
}


/*  CleanBuffer
 *
 *  ENTRY
 *      pbuf - pointer to BUF
 *
 *  EXIT
 *      The buffer is marked CLEAN, if it wasn't already.
 */
// 根据实际的标记位进行清除buffer的操作,一次只能操作一个buffer
void CleanBuffer(PBUF pbuf)
{
    PVOLUME pvol = pbuf->b_pvol;
	
    ASSERTHELDBUFFER(pbuf);
    // 清除buffer的标记位,即标记为没有有效数据
    pbuf->b_flags &= ~BUF_DIRTY;

    if (pbuf->b_flags & BUF_ERROR) {

        EnterCriticalSection(&pvol->v_csBuffers);

        if (pbuf->b_flags & BUF_ERROR) {
            //更新标记位并减少pvol->v_cbufError中记录的错误个数
            pvol->v_cbufError--;
            //
            if (pvol->v_cbufError % MIN_BUFFERS == 0)
                InterlockedIncrement(&pvol->v_cBufThreads);
            pbuf->b_flags &= ~BUF_ERROR;
        }

        LeaveCriticalSection(&pvol->v_csBuffers);
    }
}

/*  FindBuffer
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      blk - desired block on VOLUME
 *      pstm - pointer to DSTREAM containing block
 *      fNoRead - TRUE to skip reading the coresponding disk data
 *      ppbuf - pointer to address of BUF (to be returned)
 *
 *  EXIT
 *      ERROR_SUCCESS (0) if successful, non-zero if not.
 */

⌨️ 快捷键说明

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