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

📄 buffer.c

📁 从大量的wince源代码中剥离出的fat文件系统源代码.移植性非常高. 里面带有source i.rar
💻 C
📖 第 1 页 / 共 4 页
字号:
#endif

    // If buffer is valid and dirty...

    if (pbuf->b_pvol && (pbuf->b_flags & BUF_DIRTY)) {

        if (pbuf->b_pvol->v_flags & VOLF_READONLY) {
            dwError = ERROR_WRITE_PROTECT;
        }
        
        DEBUGMSG(ZONE_BUFFERS,(DBGTEXT("FATFS!CommitBuffer(block %d)\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);
        dwError = WriteVolume(pbuf->b_pvol, pbuf->b_blk, cblkBuf, pbuf->b_pdata);
        pbuf->b_flags &= ~BUF_BUSY;
        //if (fCS)
        //    EnterCriticalSection(&csBuffers);

        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_pvol = NULL;
            }
            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.
 */

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

    pbuf->b_flags &= ~BUF_DIRTY;

    if (pbuf->b_flags & BUF_ERROR) {

        EnterCriticalSection(&csBuffers);

        if (pbuf->b_flags & BUF_ERROR) {
            cbufError--;
            if (cbufError % MIN_BUFFERS == 0)
                InterlockedIncrement(&cBufThreads);
            pbuf->b_flags &= ~BUF_ERROR;
        }

        LeaveCriticalSection(&csBuffers);
    }
}


/*  ChecksumBuffer
 *
 *  ENTRY
 *      pbuf - pointer to BUF
 *
 *  EXIT
 *      32-bit checksum of data in buffer
 */

DWORD ChecksumBuffer(PBUF pbuf)
{
    DWORD dwSum = 0;
    DWORD cdw = cbBuf / sizeof(DWORD);
    PDWORD pdw = (PDWORD)pbuf->b_pdata;

    ASSERT(cdw*sizeof(DWORD) == cbBuf);

    while (cdw--) {
        dwSum += *pdw++;            }
    return dwSum | 0x80000000;  // insure that the checksum for a buffer is always non-zero
}


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

DWORD FindBuffer(PVOLUME pvol, DWORD blk, PDSTREAM pstm, BOOL fNoRead, PBUF *ppbuf)
{
    PBUF pbuf, pbufOld, pbufEnd;
    DWORD dwError = ERROR_SUCCESS;

    DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): begin entercritsec\n")));
    EnterCriticalSection(&csBuffers);
    DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): end entercritsec\n")));

    DEBUGMSG(ZONE_BUFFERS,(DBGTEXT("FATFS!FindBuffer(block %d, stream %.11hs)\n"), blk, pstm? pstm->s_achOEM : "<NONE>"));

    // Make sure the volume is allowed to use the buffer pool

    if (!(pvol->v_flags & VOLF_BUFFERED)) {
        DEBUGMSG(TRUE,(DBGTEXT("FATFS!FindBuffer: volume not allowed to use buffer pool yet!\n")));
        dwError = ERROR_GEN_FAILURE;
        goto error;
    }

    // If an associated stream is specified, the volume better match

    ASSERT(!pstm || pstm->s_pvol == pvol);

    // If the stream has a valid pbufCur, we'll check that buffer
    // first, but otherwise we'll walk the buffers in MRU order.  If we
    // don't find the desired block, then we'll read the data into the
    // oldest unheld buffer we saw.

    if (pstm && (pbuf = pstm->s_pbufCur)) {
        if (pbuf->b_pvol && pbuf->b_pvol == pvol && pbuf->b_blk == blk)
            goto foundLastBuffer;
        ReleaseStreamBuffer(pstm, TRUE);        }

    // Search the buffer pool in MRU order, and also keep track of
    // a likely candidate to re-use (pbufOld), in case we don't find what 
    // we're looking for.

restart:
    pbuf = dlBufMRU.pbufNext;
    pbufEnd = (PBUF)&dlBufMRU;

    pbufOld = NULL;
    while (pbuf != pbufEnd) {

        if (pbuf->b_pvol && pbuf->b_pvol == pvol && pbuf->b_blk == blk) {

            // An existing buffer might be in the BUF_UNCERTAIN state (ie, if another
            // thread had wanted the same buffer, started reading it, but hadn't finished
            // by the time *we* came along).  In that case, we must block until the
            // BUF_UNCERTAIN flag is cleared.

            while (pbuf->b_flags & BUF_UNCERTAIN) {
                DEBUGMSG(TRUE,(DBGTEXT("FATFS!FindBuffer: waiting for block %d to become certain...\n"), pbuf->b_blk));
                Sleep(2000);
            }

            // Furthermore, if an UNCERTAIN buffer could not be read, then we will have
            // set b_pvol to NULL to invalidate the buffer.  We need to check for that condition
            // now;  it needs to be checked outside the UNCERTAIN loop, since the timing might
            // have been such that we never even saw the UNCERTAIN bit get set.

            if (pbuf->b_pvol == NULL)
                goto restart;
            else
                goto foundBuffer;
        }

        // If this buffer isn't held, pick it.  The only exception is
        // if we already picked (a newer) one and this (older) one's dirty.

        if (!HeldBuffer(pbuf) && !(pbuf->b_flags & BUF_BUSY)) {
            if (!pbufOld || !(pbuf->b_flags & BUF_DIRTY))
                pbufOld = pbuf;
        }

        pbuf = pbuf->b_dlink.pbufNext;
    }

    // There should always be an unheld buffer in the pool (which we
    // now assert).  If there isn't, then MIN_BUFFERS has been set too low
    // (ie, the current thread must already be holding onto at least that
    // many buffers, or some other thread is holding onto more than MIN_BUFFERS).

    if (!pbufOld) {
        DEBUGMSGBREAK(TRUE,(DBGTEXT("FATFS!FindBuffer: buffer pool unexpectedly exhausted!\n")));
        dwError = ERROR_GEN_FAILURE;
        goto error;
    }

    pbuf = pbufOld;

    // Make sure any buffer we're about to (re)use has been committed;  the
    // only time we should end up using a dirty buffer is when no clean ones
    // are available, and if we can't commit a particular buffer, we probably
    // can't commit *any* of them, which is why I just give up.

    DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): begin commitbuffer\n")));
    dwError = CommitBuffer(pbuf, TRUE);
    DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): end commitbuffer\n")));
    if (dwError)
        goto error;

    pbuf->b_pvol = pvol;
    pbuf->b_blk = blk;
#ifdef DEBUG
    pbuf->b_refs = 0;
#endif

    // WARNING: The buffer critical section is not held across the actual
    // read, to insure that critical I/O (like demand-paging) can still occur
    // even if other threads start stacking up inside the driver.  Since
    // BUF_UNCERTAIN is set for the duration, no other threads entering FindBuffer
    // for the same block/buffer should continue until we're done here.

    if (!fNoRead) {
        pbuf->b_flags |= BUF_UNCERTAIN | BUF_BUSY;
        LeaveCriticalSection(&csBuffers);
        DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): begin readvolume\n")));
        dwError = ReadVolume(pvol, pbuf->b_blk, cblkBuf, pbuf->b_pdata);
        DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): end readvolume\n")));
        if (dwError) {
            // Invalidate the buffer if the data could not be read, and do it *before*
            // clearing BUF_UNCERTAIN, so that anyone waiting on BUF_UNCERTAIN cannot miss
            // the fact that this buffer is now invalid.
            pbuf->b_pvol = NULL;
            pbuf->b_flags &= ~(BUF_UNCERTAIN | BUF_BUSY);
            return dwError;
        }
        // We must clear BUF_UNCERTAIN *before* taking csBuffers, because otherwise we could
        // block forever due to another FindBuffer thread waiting for us to clear the same bit
        // on the same buffer.
        pbuf->b_flags &= ~BUF_UNCERTAIN;
        DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): begin entercritsec\n")));
        EnterCriticalSection(&csBuffers);
        DEBUGMSG(ZONE_LOGIO && pstm && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!FindBuffer(DP): end entercritsec\n")));
        // We must clear BUF_BUSY *after* taking csBuffers, because otherwise the buffer is
        // vulnerable to re-use by another thread while (A) we're outside csBuffers and (B) no
        // hold has been applied yet.
        pbuf->b_flags &= ~BUF_BUSY;
    }

    // Move the buffer to MRU position now

  foundBuffer:
    RemoveItem((PDLINK)&pbuf->b_dlink);
    AddItem((PDLINK)&dlBufMRU, (PDLINK)&pbuf->b_dlink);

    // Apply a conventional hold or a stream hold, as appropriate

  foundLastBuffer:
    if (!pstm) {
        HoldBuffer(pbuf);
    }
    else {
        AssignStreamBuffer(pstm, pbuf, TRUE);
    }

#ifdef DEBUG
    pbuf->b_refs++;
#endif

    // Last but not least, return a pointer to the buffer structure

    *ppbuf = pbuf;

  error:
    LeaveCriticalSection(&csBuffers);
    return dwError;
}


/*  AssignStreamBuffer
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pbuf - pointer to buffer to assign to stream
 *      fCS - TRUE if csBuffers is held, FALSE if not
 *
 *  EXIT
 *      The buffer is held and assigned as the stream's current buffer.
 *
 *  NOTES
 *      Any caller messing with a stream's current buffer must also
 *      currently own the stream's critical section.
 */

void AssignStreamBuffer(PDSTREAM pstm, PBUF pbuf, BOOL fCS)
{
    ASSERT(OWNCRITICALSECTION(&pstm->s_cs));

    // If a buffer is changing hands, commit it first, because
    // CommitStreamBuffers for a given stream will only commit buffers
    // still associated with that stream, and we want to guarantee that
    // a stream is FULLY committed after calling CommitStreamBuffers.

    // We don't care if there's an error, because CommitBuffer no longer
    // invalidates a buffer on error;  it simply marks the buffer dirty again.

    if (pbuf->b_pstm != pstm) {
        if (pstm->s_flags & STF_WRITETHRU)
            CommitBuffer(pbuf, fCS);
    }

    pbuf->b_pstm = pstm;

#ifdef DEBUG
    memcpy(pbuf->b_achName, pstm->s_achOEM, min(sizeof(pbuf->b_achName),sizeof(pstm->s_achOEM)));
#endif

    if (!(pstm->s_flags & STF_BUFCURHELD)) {
        HoldBuffer(pbuf);
        pstm->s_pbufCur = pbuf;
        pstm->s_flags |= STF_BUFCURHELD;
    }
    else
        ASSERT(pstm->s_pbufCur == pbuf);
}


/*  ReleaseStreamBuffer
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      fCS - TRUE if csBuffers is held, FALSE if not
 *
 *  EXIT
 *      The stream's current buffer is unheld, if it was currently in use.
 *
 *  NOTES
 *      Any caller messing with a stream's current buffer must also
 *      currently own the stream's critical section.
 */

DWORD ReleaseStreamBuffer(PDSTREAM pstm, BOOL fCS)
{
    DWORD dwError = ERROR_SUCCESS;

    ASSERT(OWNCRITICALSECTION(&pstm->s_cs));

    if (pstm->s_flags & STF_BUFCURHELD) {

        if (pstm->s_flags & STF_WRITETHRU)
            dwError = CommitBuffer(pstm->s_pbufCur, fCS);

        pstm->s_flags &= ~STF_BUFCURHELD;
        UnholdBuffer(pstm->s_pbufCur);

        // Zap the buffer pointer to prevent anyone from misusing it

        pstm->s_pbufCur = NULL;
    }
    return dwError;
}


/*  ReadStreamBuffer
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM

⌨️ 快捷键说明

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