예제 #1
0
/** @brief Determine whether the metaroot is valid.

    @param pMR                  The metaroot buffer.
    @param pfSectorCRCIsValid   Populated with whether the first sector of the
                                metaroot buffer is valid.

    @return Whether the metaroot is valid.

    @retval true    The metaroot buffer is valid.
    @retval false   The metaroot buffer is invalid.
*/
static bool MetarootIsValid(
    METAROOT   *pMR,
    bool       *pfSectorCRCIsValid)
{
    bool        fRet = false;

    if(pfSectorCRCIsValid == NULL)
    {
        REDERROR();
    }
    else if(pMR == NULL)
    {
        REDERROR();
        *pfSectorCRCIsValid = false;
    }
  #ifdef REDCONF_ENDIAN_SWAP
    else if(RedRev32(pMR->hdr.ulSignature) != META_SIG_METAROOT)
  #else
    else if(pMR->hdr.ulSignature != META_SIG_METAROOT)
  #endif
    {
        *pfSectorCRCIsValid = false;
    }
    else
    {
        const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMR);
        uint32_t        ulSectorCRC = pMR->ulSectorCRC;
        uint32_t        ulCRC;

      #ifdef REDCONF_ENDIAN_SWAP
        ulSectorCRC = RedRev32(ulSectorCRC);
      #endif

        /*  The sector CRC was zero when the CRC was computed during the
            transaction, so it must be zero here.
        */
        pMR->ulSectorCRC = 0U;

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

        fRet = ulCRC == ulSectorCRC;
        *pfSectorCRCIsValid = fRet;

        if(fRet)
        {
            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                ulCRC = RedCrc32Update(ulCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }

          #ifdef REDCONF_ENDIAN_SWAP
            ulCRC = RedRev32(ulCRC);
          #endif

            fRet = ulCRC == pMR->hdr.ulCRC;
        }
    }

    return fRet;
}
예제 #2
0
/** @brief Put the cached inode structure.

    This puts all of the buffers in the ::CINODE structure.  Also updates inode
    timestamp fields if requested.

    @param pInode       The cached inode structure.
    @param bTimeFields  The inode timestamp fields to update.
*/
void RedInodePut(
    CINODE  *pInode,
    uint8_t  bTimeFields)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else
    {
        RedInodePutCoord(pInode);

        if(pInode->pInodeBuf != NULL)
        {
          #if (REDCONF_READ_ONLY == 0) && (REDCONF_INODE_TIMESTAMPS == 1)
            if((bTimeFields & IPUT_UPDATE_MASK) != 0U)
            {
                if(!pInode->fBranched || !pInode->fDirty)
                {
                    REDERROR();
                }
                else
                {
                    uint32_t ulNow = RedOsClockGetTime();

                  #if REDCONF_ATIME == 1
                    if((bTimeFields & IPUT_UPDATE_ATIME) != 0U)
                    {
                        pInode->pInodeBuf->ulATime = ulNow;
                    }
                  #endif

                    if((bTimeFields & IPUT_UPDATE_MTIME) != 0U)
                    {
                        pInode->pInodeBuf->ulMTime = ulNow;
                    }

                    if((bTimeFields & IPUT_UPDATE_CTIME) != 0U)
                    {
                        pInode->pInodeBuf->ulCTime = ulNow;
                    }
                }
            }
          #else
            (void)bTimeFields;
          #endif

            RedBufferPut(pInode->pInodeBuf);
            pInode->pInodeBuf = NULL;
        }
    }
}
예제 #3
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;
}
예제 #4
0
/** @brief Write a string to a user-visible output location.

    Write a null-terminated string to the serial port, console, terminal, or
    other display device, such that the text is visible to the user.

    @param pszString    A null-terminated string.
*/
void RedOsOutputString(
    const char *pszString)
{
    if(pszString == NULL)
    {
        REDERROR();
    }
    else
    {
        /*  The arm-atollic-eabi version of putchar has been observed not to
            end up calling __io_putchar() (as would have been expected), so
            we call it directly instead.
        */

        uint32_t ulIdx = 0U;

        while(pszString[ulIdx] != '\0')
        {
            __io_putchar(pszString[ulIdx]);

            /*  Serial output often requires a \r to print newlines correctly.
            */
            if(pszString[ulIdx] == '\n')
            {
                __io_putchar('\r');
            }

            ulIdx++;
        }
    }
}
예제 #5
0
/** @brief Write a string to a user-visible output location.

    Write a null-terminated string to the serial port, console, terminal, or
    other display device, such that the text is visible to the user.

    @param pszString    A null-terminated string.
*/
void RedOsOutputString(
    const char *pszString)
{
    if(pszString == NULL)
    {
        REDERROR();
    }
    else
    {
        uint32_t ulIdx = 0U;

        while(pszString[ulIdx] != '\0')
        {
            OUTPUT_CHARACTER(pszString[ulIdx]);

            /*  Serial output often requires a \r to print newlines correctly.
            */
            if(pszString[ulIdx] == '\n')
            {
                OUTPUT_CHARACTER('\r');
            }

            ulIdx++;
        }
    }
}
예제 #6
0
/** @brief Find a block in the buffers.

    @param ulBlock  The block number to find.
    @param pbIdx    If the block is buffered (true is returned), populated with
                    the index of the buffer.

    @return Boolean indicating whether or not the block is buffered.

    @retval true    @p ulBlock is buffered, and its index has been stored in
                    @p pbIdx.
    @retval false   @p ulBlock is not buffered.
*/
static bool BufferFind(
    uint32_t ulBlock,
    uint8_t *pbIdx)
{
    bool     ret = false;

    if((ulBlock >= gpRedVolume->ulBlockCount) || (pbIdx == NULL))
    {
        REDERROR();
    }
    else
    {
        uint8_t bIdx;

        for(bIdx = 0U; bIdx < REDCONF_BUFFER_COUNT; bIdx++)
        {
            const BUFFERHEAD *pHead = &gBufCtx.aHead[bIdx];

            if((pHead->bVolNum == gbRedVolNum) && (pHead->ulBlock == ulBlock))
            {
                *pbIdx = bIdx;
                ret = true;
                break;
            }
        }
    }

    return ret;
}
예제 #7
0
/** @brief Flush any caches beneath the file system.

    This function must synchronously flush all software and hardware caches
    beneath the file system, ensuring that all sectors written previously are
    committed to permanent storage.

    If the environment has no caching beneath the file system, the
    implementation of this function can do nothing and return success.

    The behavior of calling this function is undefined if the block device is
    closed or if it was opened with ::BDEV_O_RDONLY.

    @param bVolNum  The volume number of the volume whose block device is being
                    flushed.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p bVolNum is an invalid volume number.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedOsBDevFlush(
    uint8_t     bVolNum)
{
    REDSTATUS   ret;

    if((bVolNum >= REDCONF_VOLUME_COUNT) || !gaDisk[bVolNum].fOpen || (gaDisk[bVolNum].mode == BDEV_O_RDONLY))
    {
        ret = -RED_EINVAL;
    }
    else
    {
        switch(gaDisk[bVolNum].type)
        {
            case BDEVTYPE_RAM_DISK:
                ret = RamDiskFlush(bVolNum);
                break;

            case BDEVTYPE_FILE_DISK:
                ret = FileDiskFlush(bVolNum);
                break;

            case BDEVTYPE_RAW_DISK:
                ret = RawDiskFlush(bVolNum);
                break;

            default:
                REDERROR();
                ret = -RED_EINVAL;
                break;
        }
    }

    return ret;
}
예제 #8
0
/** @brief Calculate the block number of the imap node location indicated by the
           given metaroot.

    An imap node has two locations on disk.  A bit in the metaroot bitmap
    indicates which location is the valid one, according to that metaroot.  This
    function returns the block number of the imap node which is valid in the
    given metaroot.

    @param bMR          Which metaroot to examine.
    @param ulImapNode   The imap node for which to calculate the block number.

    @return Block number of the imap node, as indicated by the given metaroot.
*/
uint32_t RedImapNodeBlock(
    uint8_t     bMR,
    uint32_t    ulImapNode)
{
    uint32_t    ulBlock;

    REDASSERT(ulImapNode < gpRedCoreVol->ulImapNodeCount);

    ulBlock = gpRedCoreVol->ulImapStartBN + (ulImapNode * 2U);

    if(bMR > 1U)
    {
        REDERROR();
    }
    else if(RedBitGet(gpRedCoreVol->aMR[bMR].abEntries, ulImapNode))
    {
        /*  Bit is set, so point ulBlock at the second copy of the node.
        */
        ulBlock++;
    }
    else
    {
        /*  ulBlock already points at the first copy of the node.
        */
    }

    return ulBlock;
}
예제 #9
0
/** @brief Determine whether an inode number is available.

    @param ulInode  The node number to examine.
    @param pfFree   On successful return, populated with whether the inode
                    number is available (true) or in use (false).

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p pfFree is `NULL`; or @p ulInode is not a valid inode
                        number.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedInodeIsFree(
    uint32_t    ulInode,
    bool       *pfFree)
{
    REDSTATUS   ret;

    if(pfFree == NULL)
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        bool fSlot0Allocated;

        *pfFree = false;

        ret = RedInodeBitGet(gpRedCoreVol->bCurMR, ulInode, 0U, &fSlot0Allocated);
        if((ret == 0) && !fSlot0Allocated)
        {
            bool fSlot1Allocated;

            ret = RedInodeBitGet(gpRedCoreVol->bCurMR, ulInode, 1U, &fSlot1Allocated);
            if((ret == 0) && !fSlot1Allocated)
            {
                *pfFree = true;
            }
        }
    }

    return ret;
}
예제 #10
0
/** @brief Discard a range of buffers, marking them invalid.

    @param ulBlockStart The starting block number to discard
    @param ulBlockCount The number of blocks, starting at @p ulBlockStart, to
                        discard.  Must not be zero.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL Invalid parameters.
    @retval -RED_EBUSY  A block in the desired range is referenced.
*/
REDSTATUS RedBufferDiscardRange(
    uint32_t    ulBlockStart,
    uint32_t    ulBlockCount)
{
    REDSTATUS   ret = 0;

    if(    (ulBlockStart >= gpRedVolume->ulBlockCount)
        || ((gpRedVolume->ulBlockCount - ulBlockStart) < ulBlockCount)
        || (ulBlockCount == 0U))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint8_t bIdx;

        for(bIdx = 0U; bIdx < REDCONF_BUFFER_COUNT; bIdx++)
        {
            BUFFERHEAD *pHead = &gBufCtx.aHead[bIdx];

            if(    (pHead->bVolNum == gbRedVolNum)
                && (pHead->ulBlock != BBLK_INVALID)
                && (pHead->ulBlock >= ulBlockStart)
                && (pHead->ulBlock < (ulBlockStart + ulBlockCount)))
            {
                if(pHead->bRefCount == 0U)
                {
                    pHead->ulBlock = BBLK_INVALID;

                    BufferMakeLRU(bIdx);
                }
                else
                {
                    /*  This should never happen.  There are three general cases
                        when this function is used:

                        1) Discarding every block, as happens during unmount
                           and at the end of format.  There should no longer be
                           any referenced buffers at those points.
                        2) Discarding a block which has become free.  All
                           buffers for such blocks should be put or branched
                           beforehand.
                        3) Discarding of blocks that were just written straight
                           to disk, leaving stale data in the buffer.  The write
                           code should never reference buffers for these blocks,
                           since they would not be needed or used.
                    */
                    CRITICAL_ERROR();
                    ret = -RED_EBUSY;
                    break;
                }
            }
        }
    }

    return ret;
}
예제 #11
0
/** @brief Uninitialize the mutex.

    The behavior of calling this function when the mutex is not initialized is
    undefined; likewise, the behavior of uninitializing the mutex when it is
    in the acquired state is undefined.

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

    @retval 0   Operation was successful.
*/
REDSTATUS RedOsMutexUninit(void)
{
    REDSTATUS   ret;

    REDERROR();
    ret = -RED_ENOSYS;

    return ret;
}
예제 #12
0
/** @brief Branch an imap node and get a buffer for it.

    If the imap node is already branched, it can be overwritten in its current
    location, and this function just gets it buffered dirty.  If the node is not
    already branched, the metaroot must be updated to toggle the imap node to
    its alternate location, thereby preserving the committed state copy of the
    imap node.

    @param ulImapNode   The imap node to branch and buffer.
    @param ppImap       On successful return, populated with the imap node
                        buffer, which will be marked dirty.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p ulImapNode is out of range; or @p ppImap is `NULL`.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS ImapNodeBranch(
    uint32_t    ulImapNode,
    IMAPNODE  **ppImap)
{
    REDSTATUS   ret;

    if((ulImapNode >= gpRedCoreVol->ulImapNodeCount) || (ppImap == NULL))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else if(ImapNodeIsBranched(ulImapNode))
    {
        /*  Imap node is already branched, so just get it buffered dirty.
        */
        ret = RedBufferGet(RedImapNodeBlock(gpRedCoreVol->bCurMR, ulImapNode), BFLAG_META_IMAP | BFLAG_DIRTY, CAST_VOID_PTR_PTR(ppImap));
    }
    else
    {
        uint32_t    ulBlockCurrent;
        uint32_t    ulBlockOld;

        /*  The metaroot currently points to the committed state imap node.
            Toggle the metaroot to point at the alternate, writeable location.
        */
        if(RedBitGet(gpRedMR->abEntries, ulImapNode))
        {
            RedBitClear(gpRedMR->abEntries, ulImapNode);
        }
        else
        {
            RedBitSet(gpRedMR->abEntries, ulImapNode);
        }

        ulBlockCurrent = RedImapNodeBlock(gpRedCoreVol->bCurMR, ulImapNode);
        ulBlockOld     = RedImapNodeBlock(1U - gpRedCoreVol->bCurMR, ulImapNode);

        ret = RedBufferDiscardRange(ulBlockCurrent, 1U);

        /*  Buffer the committed copy then reassign the block number to the
            writeable location.  This also dirties the buffer.
        */
        if(ret == 0)
        {
            ret = RedBufferGet(ulBlockOld, BFLAG_META_IMAP, CAST_VOID_PTR_PTR(ppImap));

            if(ret == 0)
            {
                RedBufferBranch(*ppImap, ulBlockCurrent);
            }
        }
    }

    return ret;
}
예제 #13
0
/** @brief Mark a buffer as most recently used.

    @param bIdx The index of the buffer to make MRU.
*/
static void BufferMakeMRU(
    uint8_t bIdx)
{
    if(bIdx >= REDCONF_BUFFER_COUNT)
    {
        REDERROR();
    }
    else if(bIdx != gBufCtx.abMRU[0U])
    {
        uint8_t bMruIdx;

        /*  Find the current position of the buffer in the MRU array.  We do not
            need to check the first slot, since we already know from the above
            check that the index is not there.
        */
        for(bMruIdx = 1U; bMruIdx < REDCONF_BUFFER_COUNT; bMruIdx++)
        {
            if(bIdx == gBufCtx.abMRU[bMruIdx])
            {
                break;
            }
        }

        if(bMruIdx < REDCONF_BUFFER_COUNT)
        {
            /*  Move the buffer index to the front of the MRU array, making it
                the MRU buffer.
            */
            RedMemMove(&gBufCtx.abMRU[1U], &gBufCtx.abMRU[0U], bMruIdx);
            gBufCtx.abMRU[0U] = bIdx;
        }
        else
        {
            REDERROR();
        }
    }
    else
    {
        /*  Buffer already MRU, nothing to do.
        */
    }
}
예제 #14
0
/** @brief Determine which copy of the inode is currently writeable.

    @param ulInode  The inode number to examine.
    @param pbWhich  On successful return, populated with which copy of the inode
                    (either 0 or 1) is writeable.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p pbWhich is `NULL`; or ulInode is not a valid inode
                        number.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS InodeGetWriteableCopy(
    uint32_t    ulInode,
    uint8_t    *pbWhich)
{
    REDSTATUS   ret;

    if(pbWhich == NULL)
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        bool fSlot0Allocated;

        /*  The writeable inode slot is the one which is free in the committed
            state, so query the committed state metaroot.
        */
        ret = RedInodeBitGet(1U - gpRedCoreVol->bCurMR, ulInode, 0U, &fSlot0Allocated);

        if(ret == 0)
        {
            if(!fSlot0Allocated)
            {
                *pbWhich = 0U;
            }
            else
            {
                bool fSlot1Allocated;

                ret = RedInodeBitGet(1U - gpRedCoreVol->bCurMR, ulInode, 1U, &fSlot1Allocated);

                if(ret == 0)
                {
                    if(!fSlot1Allocated)
                    {
                        *pbWhich = 1U;
                    }
                    else
                    {
                        /*  Both inode slots were allocated, which should never
                            happen.
                        */
                        CRITICAL_ERROR();
                        ret = -RED_EFUBAR;
                    }
                }
            }
        }
    }

    return ret;
}
예제 #15
0
/** @brief Set the allocation bit of a block in the working-state imap.

    @param ulBlock      The block number to allocate or free.
    @param fAllocated   Whether to allocate the block (true) or free it (false).

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p ulBlock is out of range.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedImapEBlockSet(
    uint32_t    ulBlock,
    bool        fAllocated)
{
    REDSTATUS   ret;

    if(    gpRedCoreVol->fImapInline
        || (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
        || (ulBlock >= gpRedVolume->ulBlockCount))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t    ulOffset = ulBlock - gpRedCoreVol->ulInodeTableStartBN;
        uint32_t    ulImapNode = ulOffset / IMAPNODE_ENTRIES;
        IMAPNODE   *pImap;

        ret = ImapNodeBranch(ulImapNode, &pImap);

        if(ret == 0)
        {
            uint32_t ulImapEntry = ulOffset % IMAPNODE_ENTRIES;

            if(RedBitGet(pImap->abEntries, ulImapEntry) == fAllocated)
            {
                /*  The driver shouldn't ever set a bit in the imap to its
                    current value.  That shouldn't ever be needed, and it
                    indicates that the driver is doing unnecessary I/O, or
                    that the imap is corrupt.
                */
                CRITICAL_ERROR();
                ret = -RED_EFUBAR;
            }
            else if(fAllocated)
            {
                RedBitSet(pImap->abEntries, ulImapEntry);
            }
            else
            {
                RedBitClear(pImap->abEntries, ulImapEntry);
            }

            RedBufferPut(pImap);
        }
    }

    return ret;
}
예제 #16
0
/** @brief Copy memory from one address to another.

    The source and destination memory buffers should not overlap.  If the
    buffers overlap, use RedMemMove() instead.

    @param pDest    The destination buffer.
    @param pSrc     The source buffer.
    @param ulLen    The number of bytes to copy.
*/
void RedMemCpy(
    void       *pDest,
    const void *pSrc,
    uint32_t    ulLen)
{
    if((pDest == NULL) || (pSrc == NULL))
    {
        REDERROR();
    }
    else
    {
        RedMemCpyUnchecked(pDest, pSrc, ulLen);
    }
}
예제 #17
0
/** @brief Find a free inode number.

    @param pulInode On successful return, populated with a free inode number.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p pulInode is `NULL`.
    @retval -RED_EIO    A disk I/O error occurred.
    @retval -RED_ENFILE No available inode numbers.
*/
static REDSTATUS InodeFindFree(
    uint32_t   *pulInode)
{
    REDSTATUS   ret;

    if(pulInode == NULL)
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else if(gpRedMR->ulFreeInodes == 0U)
    {
        ret = -RED_ENFILE;
    }
    else
    {
        uint32_t ulInode;

        ret = 0;

        for(ulInode = INODE_FIRST_FREE; ulInode < (INODE_FIRST_VALID + gpRedVolConf->ulInodeCount); ulInode++)
        {
            bool fFree;

            ret = RedInodeIsFree(ulInode, &fFree);

            if((ret != 0) || fFree)
            {
                break;
            }
        }

        if(ret == 0)
        {
            if(ulInode < (INODE_FIRST_VALID + gpRedVolConf->ulInodeCount))
            {
                *pulInode = ulInode;
            }
            else
            {
                /*  If gpRedMR->ulFreeInodes > 0, we should have found an inode.
                */
                CRITICAL_ERROR();
                ret = -RED_ENFILE;
            }
        }
    }

    return ret;
}
예제 #18
0
/** @brief Determine which copy of the inode is current.

    @param ulInode  The inode number to examine.
    @param pbWhich  On successful return, populated with which copy of the inode
                    (either 0 or 1) is current.

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

    @retval 0           Operation was successful.
    @retval -RED_EBADF  @p ulInode is an unallocated inode number.
    @retval -RED_EINVAL @p pbWhich is `NULL`; or ulInode is not a valid inode
                        number.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS InodeGetCurrentCopy(
    uint32_t    ulInode,
    uint8_t    *pbWhich)
{
    REDSTATUS   ret;

    if(pbWhich == NULL)
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        bool fSlot0Allocated;

        /*  The current inode slot is the one which is allocated in the working
            state metaroot.
        */
        ret = RedInodeBitGet(gpRedCoreVol->bCurMR, ulInode, 0U, &fSlot0Allocated);
        if(ret == 0)
        {
            if(fSlot0Allocated)
            {
                *pbWhich = 0U;
            }
            else
            {
                bool fSlot1Allocated;

                ret = RedInodeBitGet(gpRedCoreVol->bCurMR, ulInode, 1U, &fSlot1Allocated);
                if(ret == 0)
                {
                    if(fSlot1Allocated)
                    {
                        *pbWhich = 1U;
                    }
                    else
                    {
                        /*  Neither slot for this inode was allocated, so the
                            inode is actually free.
                        */
                        ret = -RED_EBADF;
                    }
                }
            }
        }
    }

    return ret;
}
예제 #19
0
/** @brief Initialize a buffer with the specified byte value.

    @param pDest    The buffer to initialize.
    @param bVal     The byte value with which to initialize @p pDest.
    @param ulLen    The number of bytes to initialize.
*/
void RedMemSet(
    void       *pDest,
    uint8_t     bVal,
    uint32_t    ulLen)
{
    if(pDest == NULL)
    {
        REDERROR();
    }
    else
    {
        RedMemSetUnchecked(pDest, bVal, ulLen);
    }
}
예제 #20
0
/** @brief Swap the byte order of a metadata node header

    @param pHeader  Pointer to the metadata node header to swap
*/
static void BufferEndianSwapHeader(
    NODEHEADER *pHeader)
{
    if(pHeader == NULL)
    {
        REDERROR();
    }
    else
    {
        pHeader->ulSignature = RedRev32(pHeader->ulSignature);
        pHeader->ulCRC = RedRev32(pHeader->ulCRC);
        pHeader->ullSequence = RedRev64(pHeader->ullSequence);
    }
}
예제 #21
0
/** @brief Get the allocation bit of a block from the imap as it exists in
           either metaroot.

    @param bMR          The metaroot index: either 0 or 1.
    @param ulBlock      The block number to query.
    @param pfAllocated  On successful exit, populated with the allocation bit
                        of the block.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p bMR is out of range; or @p ulBlock is out of range;
                        or @p pfAllocated is `NULL`.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedImapEBlockGet(
    uint8_t     bMR,
    uint32_t    ulBlock,
    bool       *pfAllocated)
{
    REDSTATUS   ret;

    if(    gpRedCoreVol->fImapInline
        || (bMR > 1U)
        || (ulBlock < gpRedCoreVol->ulInodeTableStartBN)
        || (ulBlock >= gpRedVolume->ulBlockCount)
        || (pfAllocated == NULL))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t    ulOffset = ulBlock - gpRedCoreVol->ulInodeTableStartBN;
        uint32_t    ulImapNode = ulOffset / IMAPNODE_ENTRIES;
        uint8_t     bMRToRead = bMR;
        IMAPNODE   *pImap;

      #if REDCONF_READ_ONLY == 0
        /*  If the imap node is not branched, then both copies of the imap are
            identical.  If the old metaroot copy is requested, use the current
            copy instead, since it is more likely to be buffered.
        */
        if(bMR == (1U - gpRedCoreVol->bCurMR))
        {
            if(!ImapNodeIsBranched(ulImapNode))
            {
                bMRToRead = 1U - bMR;
            }
        }
      #endif

        ret = RedBufferGet(RedImapNodeBlock(bMRToRead, ulImapNode), BFLAG_META_IMAP, CAST_VOID_PTR_PTR(&pImap));

        if(ret == 0)
        {
            *pfAllocated = RedBitGet(pImap->abEntries, ulOffset % IMAPNODE_ENTRIES);

            RedBufferPut(pImap);
        }
    }

    return ret;
}
예제 #22
0
/** @brief Branch an inode.

    A branched inode is one in which the allocation state for one copy is free
    or almost free, and the other copy is in the new state.  The copy which is
    in the new state is the writeable copy, which is also buffered and dirty.

    @param pInode   Pointer to the cached inode structure which has already been
                    mounted.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL Invalid parameters.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedInodeBranch(
    CINODE *pInode)
{
    REDSTATUS ret;

    if(!CINODE_IS_MOUNTED(pInode))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else if(!pInode->fBranched)
    {
        uint8_t bWhich;

        ret = InodeGetWriteableCopy(pInode->ulInode, &bWhich);

        if(ret == 0)
        {
            RedBufferBranch(pInode->pInodeBuf, InodeBlock(pInode->ulInode, bWhich));
            pInode->fBranched = true;
            pInode->fDirty = true;
        }

        /*  Toggle the inode slots: the old slot block becomes almost free
            (still used by the committed state) and the new slot block becomes
            new.
        */
        if(ret == 0)
        {
            ret = InodeBitSet(pInode->ulInode, 1U - bWhich, false);
        }

        if(ret == 0)
        {
            ret = InodeBitSet(pInode->ulInode, bWhich, true);
        }

        CRITICAL_ASSERT(ret == 0);
    }
    else
    {
        RedBufferDirty(pInode->pInodeBuf);
        pInode->fDirty = true;
        ret = 0;
    }

    return ret;
}
예제 #23
0
/** @brief Mark a buffer dirty

    @param pBuffer  The buffer to mark dirty.
*/
void RedBufferDirty(
    const void *pBuffer)
{
    uint8_t     bIdx;

    if(!BufferToIdx(pBuffer, &bIdx))
    {
        REDERROR();
    }
    else
    {
        REDASSERT(gBufCtx.aHead[bIdx].bRefCount > 0U);

        gBufCtx.aHead[bIdx].uFlags |= BFLAG_DIRTY;
    }
}
예제 #24
0
/** @brief Uninitialize a block device.

    This function is called when the file system no longer needs access to a
    block device.  If any resource were allocated by RedOsBDevOpen() to service
    block device requests, they should be freed at this time.

    Upon successful return, the block device must be in such a state that it
    can be opened again.

    The behavior of calling this function on a block device which is already
    closed is undefined.

    @param bVolNum  The volume number of the volume whose block device is being
                    uninitialized.

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

    @retval 0       Operation was successful.
    @retval -RED_EINVAL @p bVolNum is an invalid volume number.
*/
REDSTATUS RedOsBDevClose(
    uint8_t     bVolNum)
{
    REDSTATUS   ret;

    if(bVolNum >= REDCONF_VOLUME_COUNT)
    {
        ret = -RED_EINVAL;
    }
    else
    {
        REDERROR();
        ret = -RED_ENOSYS;
    }

    return ret;
}
예제 #25
0
static void MetaRootEndianSwap(
    METAROOT *pMetaRoot)
{
    if(pMetaRoot == NULL)
    {
        REDERROR();
    }
    else
    {
        pMetaRoot->ulSectorCRC = RedRev32(pMetaRoot->ulSectorCRC);
        pMetaRoot->ulFreeBlocks = RedRev32(pMetaRoot->ulFreeBlocks);
      #if REDCONF_API_POSIX == 1
        pMetaRoot->ulFreeInodes = RedRev32(pMetaRoot->ulFreeInodes);
      #endif
        pMetaRoot->ulAllocNextBlock = RedRev32(pMetaRoot->ulAllocNextBlock);
    }
}
예제 #26
0
/** @brief Swap the byte order of a master block

    @param pMaster  Pointer to the master block to swap
*/
static void BufferEndianSwapMaster(
    MASTERBLOCK *pMaster)
{
    if(pMaster == NULL)
    {
        REDERROR();
    }
    else
    {
        pMaster->ulVersion = RedRev32(pMaster->ulVersion);
        pMaster->ulFormatTime = RedRev32(pMaster->ulFormatTime);
        pMaster->ulInodeCount = RedRev32(pMaster->ulInodeCount);
        pMaster->ulBlockCount = RedRev32(pMaster->ulBlockCount);
        pMaster->uMaxNameLen = RedRev16(pMaster->uMaxNameLen);
        pMaster->uDirectPointers = RedRev16(pMaster->uDirectPointers);
        pMaster->uIndirectPointers = RedRev16(pMaster->uIndirectPointers);
    }
}
예제 #27
0
/** @brief Put all buffers in the cached inode structure except for the inode
           node buffer.

    @param pInode   A pointer to the cached inode structure.
*/
void RedInodePutCoord(
    CINODE *pInode)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else
    {
        RedInodePutData(pInode);
      #if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
        RedInodePutIndir(pInode);
      #endif
      #if DINDIR_POINTERS > 0U
        RedInodePutDindir(pInode);
      #endif
    }
}
예제 #28
0
/** @brief Put the indirect buffer.

    @param pInode   A pointer to the cached inode structure.
*/
void RedInodePutIndir(
    CINODE *pInode)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else if(pInode->pIndir != NULL)
    {
        RedBufferPut(pInode->pIndir);
        pInode->pIndir = NULL;
    }
    else
    {
        /*  No indirect buffer, nothing to put.
        */
    }
}
예제 #29
0
/** @brief Put the inode data buffer.

    @param pInode   A pointer to the cached inode structure.
*/
void RedInodePutData(
    CINODE *pInode)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else if(pInode->pbData != NULL)
    {
        RedBufferPut(pInode->pbData);
        pInode->pbData = NULL;
    }
    else
    {
        /*  No data buffer, nothing to put.
        */
    }
}
예제 #30
0
/** @brief Determine if an inode is branched.

    @param ulInode      The inode number to examine.
    @param pfIsBranched On successful return, populated with whether the inode
                        is branched.

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

    @retval 0           Operation was successful.
    @retval -RED_EINVAL @p pInode is `NULL`; or @p ulInode is not a valid inode
                        number.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS InodeIsBranched(
    uint32_t    ulInode,
    bool       *pfIsBranched)
{
    REDSTATUS   ret;

    if(!INODE_IS_VALID(ulInode) || (pfIsBranched == NULL))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        ALLOCSTATE state;

        ret = RedImapBlockState(InodeBlock(ulInode, 0U), &state);

        if(ret == 0)
        {
            if(state == ALLOCSTATE_NEW)
            {
                *pfIsBranched = true;
            }
            else
            {
                ret = RedImapBlockState(InodeBlock(ulInode, 1U), &state);

                if(ret == 0)
                {
                    if(state == ALLOCSTATE_NEW)
                    {
                        *pfIsBranched = true;
                    }
                    else
                    {
                        *pfIsBranched = false;
                    }
                }
            }
        }
    }

    return ret;
}