static REDSTATUS TruncDindir()

in FreeRTOS-Plus/Source/Reliance-Edge/core/driver/inodedata.c [536:650]


static REDSTATUS TruncDindir(
    CINODE     *pInode,
    bool       *pfFreed)
{
    REDSTATUS   ret = 0;

    if(!CINODE_IS_MOUNTED(pInode) || (pfFreed == NULL))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else if(pInode->pDindir == NULL)
    {
        *pfFreed = false;
    }
    else
    {
        bool        fBranch = false;
        uint16_t    uEntry;

        /*  The double indirect is definitely going to be branched (instead of
            deleted) if any of its indirect pointers which are entirely prior to
            the truncation boundary are non-sparse.
        */
        for(uEntry = 0U; !fBranch && (uEntry < pInode->uDindirEntry); uEntry++)
        {
            fBranch = pInode->pDindir->aulEntries[uEntry] != BLOCK_SPARSE;
        }

        /*  Unless we already know for a fact that the double indirect is going
            to be branched, examine the contents of the indirect pointer which
            straddles the truncation boundary.  If the indirect is going to be
            deleted, we know this indirect pointer is going away, and that might
            mean the double indirect is going to be deleted also.
        */
        if(!fBranch && (pInode->pDindir->aulEntries[pInode->uDindirEntry] != BLOCK_SPARSE))
        {
            for(uEntry = 0U; !fBranch && (uEntry < pInode->uIndirEntry); uEntry++)
            {
                fBranch = pInode->pIndir->aulEntries[uEntry] != BLOCK_SPARSE;
            }
        }

        if(fBranch)
        {
            ret = BranchBlock(pInode, BRANCHDEPTH_DINDIR, false);
        }

        if(ret == 0)
        {
            uint32_t ulBlock = pInode->ulLogicalBlock;
            uint16_t uStart = pInode->uDindirEntry; /* pInode->uDindirEntry will change. */

            for(uEntry = uStart; uEntry < INDIR_ENTRIES; uEntry++)
            {
                /*  Seek so that TruncIndir() has the correct indirect
                    buffer and indirect entry.
                */
                ret = RedInodeDataSeek(pInode, ulBlock);

                if(ret == -RED_ENODATA)
                {
                    ret = 0;
                }

                if((ret == 0) && (pInode->ulIndirBlock != BLOCK_SPARSE))
                {
                    bool fIndirFreed;

                    ret = TruncIndir(pInode, &fIndirFreed);

                    if(ret == 0)
                    {
                        /*  All of the indirects after the one which straddles
                            the truncation boundary should definitely end up
                            deleted.
                        */
                        REDASSERT((uEntry == uStart) || fIndirFreed);

                        /*  If the double indirect is being freed, all of the
                            indirects should be freed too.
                        */
                        REDASSERT(fIndirFreed || fBranch);

                        if(fBranch && fIndirFreed)
                        {
                            pInode->pDindir->aulEntries[uEntry] = BLOCK_SPARSE;
                        }
                    }
                }

                if(ret != 0)
                {
                    break;
                }

                ulBlock += (INDIR_ENTRIES - pInode->uIndirEntry);
            }

            if(ret == 0)
            {
                *pfFreed = !fBranch;

                if(!fBranch)
                {
                    RedInodePutDindir(pInode);

                    ret = RedImapBlockSet(pInode->ulDindirBlock, false);
                }
            }
        }
    }

    return ret;
}