Exemple #1
0
/** @brief Write out a dirty buffer.

    @param bIdx The index of the buffer to write.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EIO    A disk I/O error occurred.
    @retval -RED_EINVAL Invalid parameters.
*/
static REDSTATUS BufferWrite(
    uint8_t     bIdx)
{
    REDSTATUS   ret = 0;

    if(bIdx < REDCONF_BUFFER_COUNT)
    {
        const BUFFERHEAD *pHead = &gBufCtx.aHead[bIdx];

        REDASSERT((pHead->uFlags & BFLAG_DIRTY) != 0U);

        if((pHead->uFlags & BFLAG_META) != 0U)
        {
            ret = BufferFinalize(gBufCtx.b.aabBuffer[bIdx], pHead->bVolNum, pHead->uFlags);
        }

        if(ret == 0)
        {
            ret = RedIoWrite(pHead->bVolNum, pHead->ulBlock, 1U, gBufCtx.b.aabBuffer[bIdx]);

          #ifdef REDCONF_ENDIAN_SWAP
            BufferEndianSwap(gBufCtx.b.aabBuffer[bIdx], pHead->uFlags);
          #endif
        }
    }
    else
    {
        REDERROR();
        ret = -RED_EINVAL;
    }

    return ret;
}
Exemple #2
0
/** @brief Commit a transaction point.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedVolTransact(void)
{
    REDSTATUS ret = 0;

    REDASSERT(!gpRedVolume->fReadOnly); /* Should be checked by caller. */

    if(gpRedCoreVol->fBranched)
    {
        gpRedMR->ulFreeBlocks += gpRedCoreVol->ulAlmostFreeBlocks;
        gpRedCoreVol->ulAlmostFreeBlocks = 0U;

        ret = RedBufferFlush(0U, gpRedVolume->ulBlockCount);

        if(ret == 0)
        {
            gpRedMR->hdr.ulSignature = META_SIG_METAROOT;
            gpRedMR->hdr.ullSequence = gpRedVolume->ullSequence;

            ret = RedVolSeqNumIncrement();
        }

        if(ret == 0)
        {
            const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(gpRedMR);
            uint32_t        ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif

            gpRedMR->ulSectorCRC = 0U;

            ulSectorCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);

            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                gpRedMR->hdr.ulCRC = RedCrc32Update(ulSectorCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }
            else
            {
                gpRedMR->hdr.ulCRC = ulSectorCRC;
            }

            gpRedMR->ulSectorCRC = ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            gpRedMR->hdr.ulCRC = RedRev32(gpRedMR->hdr.ulCRC);
            gpRedMR->ulSectorCRC = RedRev32(gpRedMR->ulSectorCRC);
          #endif

            /*  Flush the block device before writing the metaroot, so that all
                previously written blocks are guaranteed to be on the media before
                the metaroot is written.  Otherwise, if the block device reorders
                the writes, the metaroot could reach the media before metadata it
                points at, creating a window for disk corruption if power is lost.
            */
            ret = RedIoFlush(gbRedVolNum);
        }

        if(ret == 0)
        {
            ret = RedIoWrite(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + gpRedCoreVol->bCurMR, 1U, gpRedMR);

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif
        }

        /*  Flush the block device to force the metaroot write to the media.  This
            guarantees the transaction point is really complete before we return.
        */
        if(ret == 0)
        {
            ret = RedIoFlush(gbRedVolNum);
        }

        /*  Toggle to the other metaroot buffer.  The working state and committed
            state metaroot buffers exchange places.
        */
        if(ret == 0)
        {
            uint8_t bNextMR = 1U - gpRedCoreVol->bCurMR;

            gpRedCoreVol->aMR[bNextMR] = *gpRedMR;
            gpRedCoreVol->bCurMR = bNextMR;

            gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];

            gpRedCoreVol->fBranched = false;
        }

        CRITICAL_ASSERT(ret == 0);
    }

    return ret;
}