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

📄 buffer.c

📁 fat32文件系统的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
        }
    }
    return dwError;
}


/*  ModifyStreamBuffer
 *
 *  ENTRY
 *      pstm - pointer to stream
 *      pMod - pointer to modification
 *      cbMod - length of modification (ZERO to prevent logging)
 *
 *  EXIT
 *      ERROR_SUCCESS if the stream's buffer is allowed to be modified, otherwise
 *      some error code (eg, ERROR_WRITE_PROTECT).
 */

DWORD ModifyStreamBuffer(PDSTREAM pstm, PVOID pMod, int cbMod)
{
    PBYTE pbMod = pMod;
    PBUF pbuf = pstm->s_pbufCur;
    DWORD cbBuf = pstm->s_pvol->v_pdsk->d_diActive.di_bytes_per_sect;
    
    // A just-dirtied buffer should also be a held buffer

    DEBUGMSG(ZONE_BUFFERS,(DBGTEXT("FATFS!ModifyStreamBuffer(block %d, stream %.11hs)\r\n"), pbuf->b_blk, pstm->s_achOEM));

    ASSERT(pbuf);
    ASSERT(pstm->s_flags & STF_BUFCURHELD);

    // Make sure the specified address lies within the buffer's range,
    // and then adjust the length if it extends past the end of the buffer

    ASSERT(pbMod >= pbuf->b_pdata && pbMod <= pbuf->b_pdata+cbBuf);

    if (cbMod > 0 && pbMod+cbMod > pbuf->b_pdata+cbBuf)
        cbMod = (pbuf->b_pdata+cbBuf) - pbMod;

    // If this stream contains file system data structures (FAT or directory info),
    // then pass the region being modified to ModifyBuffer so that it can do appropriate
    // buffer logging;  otherwise, pass a zero length to indicate that no logging
    // is required.

    return ModifyBuffer(pbuf, pbMod, (pstm->s_flags & STF_VOLUME)? cbMod : 0);
}




/*  CommitBufferSet
 *
 *  ENTRY
 *      pstm - pointer to stream if iCommit >= 0;
 *             pointer to volume (or NULL) if iCommit < 0
 *
 *      if iCommit >= 0 (ie, pstm points to stream):
 *          1 means release stream buffer; 0 means retain
 *
 *      if iCommit < 0 (ie, pstm points to volume):
 *          -1 means commit everything not held;
 *          -2 means commit everything not held older than msWriteDelayMin
 *
 *  EXIT
 *      ERROR_SUCCESS (0) if successful, non-zero if not.
 *
 *  NOTES
 *      The assumption we make here is that a dirty buffer that is
 *      currently held will be explicitly committed once it is unheld,
 *      so we leave it alone.  Besides, the buffer could be in a
 *      transitional/incomplete state.
 *
 *      This doesn't mean that UnholdBuffer will do the commit for you
 *      either (because it won't).  Callers are allowed to hold/unhold
 *      dirtied buffers repeatedly without incuring the overhead of a
 *      write until they choose to do so, but they must choose to do so
 *      EVENTUALLY, in order to minimize the periods of time where the
 *      file system is in an inconsistent state.
 */

DWORD CommitBufferSet(PDSTREAM pstm, int iCommit)
{
    DWORD dw, dwError;
    PBUF pbuf, pbufEnd;
    PVOLUME pvol = (iCommit < 0) ? (PVOLUME)pstm : pstm->s_pvol;

    dwError = ERROR_SUCCESS;
    EnterCriticalSection(&pvol->v_csBuffers);

    // If the caller is done with the stream's current buffer, then release
    // it first, so that the logic below (to commit only those buffers that are
    // no longer held) does the right thing.
    
    if (iCommit > 0 && pstm)
        dwError = ReleaseStreamBuffer(pstm, TRUE);

    pbuf = pvol->v_dlBufMRU.pbufPrev;
    pbufEnd = (PBUF)&pvol->v_dlBufMRU;

    while (pbuf != pbufEnd) {

        // If you didn't want to release the current buffer (ie, you want to
        // commit it even though you -- or someone else -- is still holding it)
        // then we'll commit ALL the stream's buffers (held or not), on the premise
        // that what you're *really* trying to do is get the entire stream into a
        // consistent state (eg, a directory stream that was both modified and
        // grown).

        if (!pstm ||
            iCommit >= 0 && pbuf->b_pstm == pstm ||
            iCommit <  0 && pbuf->b_pvol == (PVOLUME)pstm) {

            BOOL fCommit = (iCommit == 0 || !HeldBuffer(pbuf));
            
            //TEST_BREAK
            PWR_BREAK_NOTIFY(61);

            if (fCommit) {
                dw = CommitBuffer(pbuf, TRUE);
                if (!dwError)
                    dwError = dw;
            }
        }
        pbuf = pbuf->b_dlink.pbufPrev;
    }

    LeaveCriticalSection(&pvol->v_csBuffers);

    return dwError;
}
// 通过查询pvol->v_dlBufMRU.pbufNext寻找出对应的pstm在哪个buffer中,然后将对应
// buffer的stream设置为NULL,即pbuf->b_pstm=NULL
DWORD InvalidateSteamBuffer(PDSTREAM pstm)
{
    DWORD dwError = ERROR_SUCCESS;
    PBUF pbuf, pbufEnd;
    PVOLUME pvol = pstm->s_pvol;

    dwError = ERROR_SUCCESS;
    EnterCriticalSection(&pvol->v_csBuffers);

    pbuf = pvol->v_dlBufMRU.pbufNext;
    pbufEnd = (PBUF)&pvol->v_dlBufMRU;

    while (pbuf != pbufEnd) {

        if (pbuf->b_pstm == pstm) { 
            pbuf->b_pstm = NULL;
        }
        pbuf = pbuf->b_dlink.pbufNext;
    }

    LeaveCriticalSection(&pvol->v_csBuffers);

    return dwError;
}


/*  InvalidateBufferSet - Invalidate all buffers for specified volume
 *
 *  ENTRY
 *      pvol -> VOLUME structure
 *      fAll == FALSE to invalidate only clean buffers, TRUE to also invalidate dirty ones
 *
 *  EXIT
 *      None
 */
// 如果fAll为true,则将pvol->v_dlBufMRU上链接的所有的buffer,不管是否包含有
// 有效的数据都将该buffer标记的BUF_DIRTY清除;如果是false,则啥都干
void InvalidateBufferSet(PVOLUME pvol, BOOL fAll)
{
    BOOL fDirty;
    PBUF pbuf, pbufEnd;

    EnterCriticalSection(&pvol->v_csBuffers);

    fDirty = FALSE;
    pbuf = pvol->v_dlBufMRU.pbufNext;
    pbufEnd = (PBUF)&pvol->v_dlBufMRU;

    while (pbuf != pbufEnd) {

        // If this buffer contains data that belonged to the specified
        // volume, and no thread is using that data, invalidate the buffer.
          
        BOOL fInvalidate = !HeldBuffer(pbuf) && (fAll || !(pbuf->b_flags & BUF_DIRTY));

        DEBUGMSG(fInvalidate && (pbuf->b_flags & BUF_DIRTY), (DBGTEXT("FATFS!InvalidateBufferSet: dirty buffer for block %d being invalidated!\r\n"), pbuf->b_blk));

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

        if (fInvalidate) {
            HoldBuffer(pbuf);
            CleanBuffer(pbuf);
            UnholdBuffer(pbuf);
            pbuf->b_flags |= BUF_INVALID;    // invalidated!
        }
        // pbuf中包含有有效的数据
        else if (pbuf->b_flags & BUF_DIRTY)
            fDirty = TRUE;
        
        pbuf = pbuf->b_dlink.pbufNext;
    }

    // If all dirty buffers were invalidated, the volume should no longer be considered dirty.
    // 从下面的代码也可以看到,buffer的相关标记也在v_flags中实现
    if (!fDirty)
        pvol->v_flags &= ~VOLF_DIRTY;

    LeaveCriticalSection(&pvol->v_csBuffers);
}


/*  LockBlocks - Lock a range of blocks for direct (non-buffered) I/O
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - file position of data being requested
 *      len - length of data being requested
 *      pblk - pointer to first unbuffered block (if successful)
 *      pcblk - pointer to count of unbuffered blocks (if successful)
 *      fWrite - FALSE if locking for read, TRUE if write
 *
 *  EXIT
 *      TRUE if successful (ie, the request starts at a buffer-granular
 *      block number and spans some multiple of blocks-per-buffer, none
 *      of which are currently buffered), FALSE if not.
 *
 *  NOTES
 *      If the call returns TRUE, then the caller can issue ReadVolume or
 *      WriteVolume directly.  The buffer critical section is left held on
 *      return for writes only -- to avoid races that might result in
 *      buffer pool inconsistency -- so it is critical that UnlockBlocks(TRUE)
 *      be called when done writing a range of blocks.
 *
 *      As with ReadStreamBuffer, callers promise that the requested POSITION
 *      (pos) lies within the current RUN (pstm->s_run).  The current RUN
 *      starts at some BLOCK (s_run.r_blk).  If the data is buffered, it will
 *      be in a buffer containing block ((pos - s_run.r_start)/BLOCK_SIZE + r_blk).
 */

BOOL LockBlocks(PDSTREAM pstm, DWORD pos, DWORD len, DWORD *pblk, DWORD *pcblk, BOOL fWrite)
{
    PBUF pbuf, pbufEnd;
    DWORD blk, blkBuf, blkBufEnd;
    DWORD offset, cblks;
    PVOLUME pvol = pstm->s_pvol;
    RunInfo RunInfo;
    //首先判断pos在当前的stream的所有run中是否位于有效的位置
    if (pos < pstm->s_runList.r_StartPosition || pos >= pstm->s_runList.r_EndPosition) {
        DEBUGMSGBREAK(ZONE_INIT || ZONE_ERRORS,
                 (DBGTEXT("FATFS!LockBlocks: bad position (%d) for stream %.11hs\r\n"), pos, pstm->s_achOEM));
        return FALSE;
    }
    //获取pos所在run中的信息
    if (ERROR_SUCCESS != GetRunInfo(&pstm->s_runList, pos, &RunInfo)) {
        return FALSE;
    }

    // Compute the stream-relative offset
    // and the corresponding volume-relative block

    offset = pos - RunInfo.StartPosition;
    blk = RunInfo.StartBlock + (offset >> pvol->v_log2cbBlk);

    // Limit the size of the request to what exists in the current run
    // 对len的值进行判断,防止越界
    if (len > (RunInfo.EndPosition - pos)) {
        len = RunInfo.EndPosition - pos;
    }
    
    // Convert the volume-relative block # into a buffer-granular block #
    // 如果len的长度甚至不足一个sector,那么LockBlocks返回错误,即不对底层进行实质性的写入
    // 另外一种情况是,pos距离所在对应的某个run开始偏移不是sector的整数倍也不返回错误,
    // 即不进行实质性的写入工作
    blkBuf = blk;
    if ((offset & (pvol->v_cbBlk - 1)) || (cblks = len >> pvol->v_log2cbBlk) < 1) {

        // The request does not start at the beginning of a buffer-granular
        // block, or does not start at the beginning of that block, or is
        // smaller the number of blocks in a buffer.

        return FALSE;
    }

    // Compute an ending buffer-granular block #, by adding cblks after
    // it has been truncated to the number of blocks in a buffer.

    blkBufEnd = blkBuf + cblks;

    // Now we just need to find the largest cblkBuf chunk of blocks that
    // is not currently buffered.

    EnterCriticalSection(&pvol->v_csBuffers);
    //获取buffer链表的相关信息
    pbuf = pvol->v_dlBufMRU.pbufNext;
    pbufEnd = (PBUF)&pvol->v_dlBufMRU;

    while (pbuf != pbufEnd) {
        //首先进行了一个buffer的有效性判断
        if (!(pbuf->b_flags & BUF_INVALID)) {

            // If the first block is buffered, then fail the request.
            // 循环直到pos处,此处的pos肯定是sector对齐的
            if (pbuf->b_blk == blkBuf) {
                blkBuf = blkBufEnd;
                break;
            }

            // If this buffer contains some information inside the range
            // being requested, then shrink the range down.

            if (pbuf->b_blk > blkBuf && pbuf->b_blk < blkBufEnd) {
                blkBufEnd = pbuf->b_blk;
            }
        }
        pbuf = pbuf->b_dlink.pbufNext;
    }

    if (blkBuf != blkBufEnd) {
        *pblk = blkBuf;
        *pcblk = blkBufEnd - blkBuf;
        if (!fWrite)
            LeaveCriticalSection(&pvol->v_csBuffers);
        return TRUE;
    }

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


void UnlockBlocks(PDSTREAM pstm, DWORD blk, DWORD cblk, BOOL fWrite)
{
    if (fWrite)
        LeaveCriticalSection(&pstm->s_pvol->v_csBuffers);
}

⌨️ 快捷键说明

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