Пример #1
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;
}
Пример #2
0
/** @brief Finalize a metadata buffer.

    This updates the CRC and the sequence number.  It also sets the signature,
    though this is only truly needed if the buffer is new.

    @param pbBuffer Pointer to the metadata buffer to finalize.
    @param bVolNum  The volume number for the metadata buffer.
    @param uFlags   The associated buffer flags.  Used to determine the expected
                    signature.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL Invalid parameter; or maximum sequence number reached.
*/
static REDSTATUS BufferFinalize(
    uint8_t    *pbBuffer,
    uint8_t     bVolNum,
    uint16_t    uFlags)
{
    REDSTATUS   ret = 0;

    if((pbBuffer == NULL) || (bVolNum >= REDCONF_VOLUME_COUNT) || ((uFlags & BFLAG_MASK) != uFlags))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t ulSignature;

        switch(uFlags & BFLAG_META_MASK)
        {
            case BFLAG_META_MASTER:
                ulSignature = META_SIG_MASTER;
                break;
          #if REDCONF_IMAP_EXTERNAL == 1
            case BFLAG_META_IMAP:
                ulSignature = META_SIG_IMAP;
                break;
          #endif
            case BFLAG_META_INODE:
                ulSignature = META_SIG_INODE;
                break;
          #if DINDIR_POINTERS > 0U
            case BFLAG_META_DINDIR:
                ulSignature = META_SIG_DINDIR;
                break;
          #endif
          #if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
            case BFLAG_META_INDIR:
                ulSignature = META_SIG_INDIR;
                break;
          #endif
            default:
                ulSignature = 0U;
                break;
        }

        if(ulSignature == 0U)
        {
            REDERROR();
            ret = -RED_EINVAL;
        }
        else
        {
            uint64_t ullSeqNum = gaRedVolume[bVolNum].ullSequence;

            ret = RedVolSeqNumIncrement(bVolNum);
            if(ret == 0)
            {
                uint32_t ulCrc;

                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_SIG], &ulSignature, sizeof(ulSignature));
                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_SEQ], &ullSeqNum, sizeof(ullSeqNum));

              #ifdef REDCONF_ENDIAN_SWAP
                BufferEndianSwap(pbBuffer, uFlags);
              #endif

                ulCrc = RedCrcNode(pbBuffer);
              #ifdef REDCONF_ENDIAN_SWAP
                ulCrc = RedRev32(ulCrc);
              #endif
                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_CRC], &ulCrc, sizeof(ulCrc));
            }
        }
    }

    return ret;
}
Пример #3
0
/** @brief Mount the latest metaroot.

    This function also populates the volume contexts.

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

    @retval 0           Operation was successful.
    @retval -RED_EIO    Both metaroots are missing or corrupt.
*/
REDSTATUS RedVolMountMetaroot(void)
{
    REDSTATUS ret;

    ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT, 1U, &gpRedCoreVol->aMR[0U]);

    if(ret == 0)
    {
        ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + 1U, 1U, &gpRedCoreVol->aMR[1U]);
    }

    /*  Determine which metaroot is the most recent copy that was written
        completely.
    */
    if(ret == 0)
    {
        uint8_t bMR = UINT8_MAX;
        bool    fSectorCRCIsValid;

        if(MetarootIsValid(&gpRedCoreVol->aMR[0U], &fSectorCRCIsValid))
        {
            bMR = 0U;

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(&gpRedCoreVol->aMR[0U]);
          #endif
        }
        else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
        {
            ret = -RED_EIO;
        }
        else
        {
            /*  Metaroot is not valid, so it is ignored and there's nothing
                to do here.
            */
        }

        if(ret == 0)
        {
            if(MetarootIsValid(&gpRedCoreVol->aMR[1U], &fSectorCRCIsValid))
            {
              #ifdef REDCONF_ENDIAN_SWAP
                MetaRootEndianSwap(&gpRedCoreVol->aMR[1U]);
              #endif

                if((bMR != 0U) || (gpRedCoreVol->aMR[1U].hdr.ullSequence > gpRedCoreVol->aMR[0U].hdr.ullSequence))
                {
                    bMR = 1U;
                }
            }
            else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
            {
                ret = -RED_EIO;
            }
            else
            {
                /*  Metaroot is not valid, so it is ignored and there's nothing
                    to do here.
                */
            }
        }

        if(ret == 0)
        {
            if(bMR == UINT8_MAX)
            {
                /*  Neither metaroot was valid.
                */
                ret = -RED_EIO;
            }
            else
            {
                gpRedCoreVol->bCurMR = bMR;
                gpRedMR = &gpRedCoreVol->aMR[bMR];
            }
        }
    }

    if(ret == 0)
    {
        /*  Normally the metaroot contains the highest sequence number, but the
            master block is the last block written during format, so on a
            freshly formatted volume the master block sequence number (stored in
            gpRedVolume->ullSequence) will be higher than that in the metaroot.
        */
        if(gpRedMR->hdr.ullSequence > gpRedVolume->ullSequence)
        {
            gpRedVolume->ullSequence = gpRedMR->hdr.ullSequence;
        }

        /*  gpRedVolume->ullSequence stores the *next* sequence number; to avoid
            giving the next node written to disk the same sequence number as the
            metaroot, increment it here.
        */
        ret = RedVolSeqNumIncrement();
    }

    if(ret == 0)
    {
        gpRedVolume->fMounted = true;
      #if REDCONF_READ_ONLY == 0
        gpRedVolume->fReadOnly = false;
      #endif

      #if RESERVED_BLOCKS > 0U
        gpRedCoreVol->fUseReservedBlocks = false;
      #endif
        gpRedCoreVol->ulAlmostFreeBlocks = 0U;

        gpRedCoreVol->aMR[1U - gpRedCoreVol->bCurMR] = *gpRedMR;
        gpRedCoreVol->bCurMR = 1U - gpRedCoreVol->bCurMR;
        gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];
    }

    return ret;
}