344 lines
8.2 KiB
C++
344 lines
8.2 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Free blocks, avail list handling
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: fsblk_u.cpp 12282 2006-01-19 14:52:56 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
/****************************************************************************
|
|
Desc: Need to use the current avail block - free up and point to next
|
|
****************************************************************************/
|
|
RCODE FSBlockUseNextAvail(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
SCACHE ** ppSCacheRV)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiPbcAddr;
|
|
SCACHE * pSCache;
|
|
FLMBYTE * pucBlkBuf;
|
|
FLMBOOL bGotBlock = FALSE;
|
|
FLMBYTE * pucLogHdr;
|
|
|
|
pucLogHdr = &pDb->pFile->ucUncommittedLogHdr[0];
|
|
|
|
if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE,
|
|
pDb->LogHdr.uiFirstAvailBlkAddr, NULL, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bGotBlock = TRUE;
|
|
|
|
// A corruption we have seen a couple of times is where a free block
|
|
// points to itself in the free list. This will hang the machine so
|
|
// this check has been added to verify that the block is a free block.
|
|
|
|
if (BH_GET_TYPE( pSCache->pucBlk) != BHT_FREE)
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the block because we are changing it!
|
|
|
|
if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*ppSCacheRV = pSCache;
|
|
pucBlkBuf = pSCache->pucBlk;
|
|
|
|
pDb->LogHdr.uiFirstAvailBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_NEXT_BLK]);
|
|
UD2FBA( pDb->LogHdr.uiFirstAvailBlkAddr, &pucLogHdr[LOG_PF_AVAIL_BLKS]);
|
|
UD2FBA( 0, &pucBlkBuf[BH_NEXT_BLK]);
|
|
|
|
// One less block in the avail list.
|
|
|
|
flmDecrUint( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS], 1);
|
|
|
|
// Decrement so chains are consistent
|
|
|
|
pucLogHdr[LOG_PF_FIRST_BC_CNT]--;
|
|
|
|
if (ALGetNBC( pucBlkBuf) == BT_END)
|
|
{
|
|
|
|
// This is a chain block - so take care of the back chains
|
|
|
|
uiPbcAddr = ALGetPBC( pucBlkBuf);
|
|
ALResetAvailBlk( pucBlkBuf);
|
|
|
|
if (uiPbcAddr == BT_END)
|
|
{
|
|
UD2FBA( BT_END, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]);
|
|
pucLogHdr[LOG_PF_FIRST_BC_CNT] = 0;
|
|
}
|
|
else
|
|
{
|
|
SCACHE * pPbcSCache;
|
|
|
|
// Hit a backchain block Setup backchain links and adjust
|
|
// LOG_PF_FIRST_BC_CNT to BACKCHAIN_CNT This is not perfect
|
|
// because there may be less blocks in that chain than expected.
|
|
//
|
|
// Ensure next block is chained.
|
|
|
|
pucLogHdr[LOG_PF_FIRST_BC_CNT] = BACKCHAIN_CNT;
|
|
UD2FBA( (FLMUINT32) uiPbcAddr, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]);
|
|
|
|
// Read the previous backchain and modify its nextBackchain
|
|
// pointer.
|
|
//
|
|
// Read the old first backchain block and change the NBC.
|
|
|
|
if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, NULL,
|
|
&pPbcSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the block because we are changing it!
|
|
|
|
if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache)))
|
|
{
|
|
ALPutNBC( pPbcSCache->pucBlk, BT_END);
|
|
}
|
|
|
|
ScaReleaseCache( pPbcSCache, FALSE);
|
|
if (RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is an index block, check to see if it is encrypted.
|
|
|
|
if (pLFile && pLFile->pIxd && pLFile->pIxd->uiEncId)
|
|
{
|
|
pucBlkBuf[BH_ENCRYPTED] = 1;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if ((RC_BAD( rc)) && (bGotBlock))
|
|
{
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine puts a block back in a physical file's avail list.
|
|
****************************************************************************/
|
|
RCODE FSBlockFree(
|
|
FDB * pDb,
|
|
SCACHE * pSCache)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiFirstAvailAddress;
|
|
FLMBYTE * pucBlkBuf;
|
|
FLMUINT uiBlkAddress;
|
|
SCACHE * pPbcSCache;
|
|
FLMUINT uiPbcAddr;
|
|
FLMBYTE * pucLogHdr;
|
|
|
|
pucLogHdr = &pDb->pFile->ucUncommittedLogHdr[0];
|
|
|
|
// Log the block before modifying it.
|
|
|
|
if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pucBlkBuf = pSCache->pucBlk;
|
|
|
|
// Set all elements except block address and checkpoint info to zeros.
|
|
// If you add any new block elements please make sure they are taken
|
|
// care of here.
|
|
//
|
|
// Leave block address alone.
|
|
|
|
uiBlkAddress = GET_BH_ADDR( pucBlkBuf);
|
|
|
|
ALResetAvailBlk( pucBlkBuf);
|
|
|
|
uiFirstAvailAddress = pDb->LogHdr.uiFirstAvailBlkAddr;
|
|
UD2FBA( (FLMUINT32) uiFirstAvailAddress, &pucBlkBuf[BH_NEXT_BLK]);
|
|
pucBlkBuf[BH_TYPE] = BHT_FREE;
|
|
pucBlkBuf[BH_LEVEL] = 0;
|
|
UW2FBA( BH_OVHD, &pucBlkBuf[BH_ELM_END]);
|
|
|
|
// Wipe the contents of encrypted blocks...
|
|
|
|
if (pucBlkBuf[BH_ENCRYPTED])
|
|
{
|
|
f_memset( &pucBlkBuf[BH_OVHD], 0,
|
|
pDb->pFile->FileHdr.uiBlockSize - BH_OVHD);
|
|
pucBlkBuf[BH_ENCRYPTED] = 0;
|
|
}
|
|
|
|
// Leave CHECKPOINT, PREV_CP and PREV_BLK_ADDR alone.
|
|
// Update the physical file log information.
|
|
|
|
pDb->LogHdr.uiFirstAvailBlkAddr = uiBlkAddress;
|
|
UD2FBA( (FLMUINT32) uiBlkAddress, &pucLogHdr[LOG_PF_AVAIL_BLKS]);
|
|
|
|
// Is it time to add a new backchain?
|
|
|
|
if (pucLogHdr[LOG_PF_FIRST_BC_CNT] >= BACKCHAIN_CNT ||
|
|
FB2UD( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS]) == 0)
|
|
{
|
|
|
|
// Start over - increments to 1 below.
|
|
|
|
pucLogHdr[LOG_PF_FIRST_BC_CNT] = 0;
|
|
ALPutNBC( pucBlkBuf, BT_END);
|
|
|
|
// Increment and check if no avail blocks
|
|
|
|
if (FB2UD( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS]) == 0)
|
|
{
|
|
ALPutPBC( pucBlkBuf, BT_END);
|
|
}
|
|
else
|
|
{
|
|
uiPbcAddr = (FLMUINT) FB2UD( &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]);
|
|
ALPutPBC( pucBlkBuf, uiPbcAddr);
|
|
|
|
// Read the old first backchain block and change the NBC.
|
|
|
|
if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, NULL,
|
|
&pPbcSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the block because we are changing it!
|
|
|
|
if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache)))
|
|
{
|
|
ALPutNBC( pPbcSCache->pucBlk, uiBlkAddress);
|
|
}
|
|
|
|
ScaReleaseCache( pPbcSCache, FALSE);
|
|
if (RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
UD2FBA( (FLMUINT32) uiBlkAddress, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]);
|
|
}
|
|
|
|
// Be sure to increment these.
|
|
|
|
flmIncrUint( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS], 1);
|
|
pucLogHdr[LOG_PF_FIRST_BC_CNT]++;
|
|
|
|
Exit:
|
|
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
return (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Fix up the previous/next links
|
|
****************************************************************************/
|
|
RCODE FSBlockFixLinks(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
SCACHE * pSCache)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiPrevBlkAddr;
|
|
FLMUINT uiNextBlkAddr;
|
|
FLMBYTE * pucBlkBuf;
|
|
|
|
pucBlkBuf = pSCache->pucBlk;
|
|
uiPrevBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_PREV_BLK]);
|
|
uiNextBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_NEXT_BLK]);
|
|
|
|
// First free block. NOTE: Do NOT access pSCache after this call
|
|
|
|
if (RC_BAD( rc = FSBlockFree( pDb, pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Read the previous block if current is not the left end.
|
|
|
|
if (uiPrevBlkAddr != BT_END)
|
|
{
|
|
if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiPrevBlkAddr, NULL,
|
|
&pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the block before modifying it.
|
|
|
|
if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache)))
|
|
{
|
|
UD2FBA( uiNextBlkAddr, &pSCache->pucBlk[BH_NEXT_BLK]);
|
|
}
|
|
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
if (RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Read the next block if current is not the left end.
|
|
|
|
if (uiNextBlkAddr != BT_END)
|
|
{
|
|
if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiNextBlkAddr,
|
|
NULL, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Log the block before modifying it.
|
|
|
|
if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache)))
|
|
{
|
|
UD2FBA( uiPrevBlkAddr, &pSCache->pucBlk[BH_PREV_BLK]);
|
|
}
|
|
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
if (RC_BAD( rc))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
return (rc);
|
|
}
|