//------------------------------------------------------------------------- // 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); }