⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 block.c

📁 Win9x下文件系统驱动的例子(EXT2)源代码。
💻 C
字号:
#include "vxd.h"

#include "shared\vxddebug.h"
#include "shared\blkdev.h"
#include "cache.h"
#include "block.h"


/*
 * This module administrates all blocks loaded in memory.
 * For each block a TBlock is created; these are looked up
 * via the BlockTable. This is a hashtable of TBlock pointers.
 * Each pointer is a double-linked list of TBlock's with the 
 * same hashvalue.
 *
 * We also maintain a Block cache. When a block is removed
 * from the BlockTable, we add the _pointer_ to the block's
 * data to the cache (no copies are made!).
 *
 * Whenever a client wants a block, we first look if it's already
 * loaded (via the BlockTable). If so, we increase nrClients to 
 * reference count it. If the block is not in the table, we create 
 * a new TBlock structure and add to the BlockTable. Then we get 
 * the block from either the cache or from disk.
 * When getting it from the cache, the cache also removes the entry.
 */
 

#define HASH_QUEUE_SIZE 4

/**********************************
 *
 * GLOBAL DATA
 *
 **********************************/

// none


/**********************************
 *
 * STATIC DATA
 *
 **********************************/

		/*
		 * Mutex is needed for synchronised access to the
		 * sBlockTable and to some fields of a TBlock
		 * object.
		 *
		 * Each TBlock object has a Mutex of it's own.
		 * That Mutex is used to lock/unlock a block
		 */
static MUTEXHANDLE		sMutex = 0;
static TBlock			**sBlockTable = 0;
static UINT				sNrsBlockTable;
static TCache			*sBlockCache;
static char				sBlockCacheName[] = "BlockCache";



/**********************************************
 *
 * STATIC HELPERS
 *
 * For all static function the following PRE CONDITION
 * holds: sMutex is entered, that is, it is safe to
 * alter the sInodeTable
 *
 *********************************************/

static __inline UINT HashFunction(TDevice Device, ULONG BlockNo)
{
	return (UINT) ((((ULONG) Device) ^ BlockNo) % sNrsBlockTable);
}


static TBlock* BlockGetFromTable(TDevice Device, ULONG BlockNo, UINT Hash)
{
	TBlock	*Block, *HashFirst;
	
	VxdDebugPrint(D_BLOCK, "BlockGetFromTable: device=%x, block=%lu, hash=%u", (ULONG) Device, BlockNo, Hash);

	Block = HashFirst = sBlockTable[Hash];
	if(!Block)
	{
		VxdDebugPrint(D_BLOCK, "BlockGetFromTable: done, hash chain empty");
		return 0;
	}

		/*
		 * loop over the (circular) list to see if it's
		 * there
		 */
	do
	{
		if (Block->Device == Device && Block->BlockNo == BlockNo)
			goto getfromtable_done;
	} while ( (Block = Block->BlockNext) != HashFirst);
	Block = 0;

getfromtable_done:
	VxdDebugPrint(D_BLOCK, "BlockGetFromTable: done, block (%s)", Block?"found":"not found");
	
	return Block;
}



static TBlock* BlockCreate(TDevice Device, ULONG BlockNo, ULONG Hash)
{
	TBlock		*Block, *HashFirst;

	VxdDebugPrint(D_BLOCK, "BlockCreate: device=%x, block=%lu", (ULONG) Device, BlockNo);

	Block = (TBlock *) calloc(1, sizeof(TBlock));
	if (!Block)
	{
		VxdDebugPrint(D_ERROR, "BlockCreate: could not alloc TBlock");
		goto blkcreate_err_1;
	}

	Block->Device = Device;
	Block->BlockNo = BlockNo;
	Block->nrClients = 0;

		/*
		 * Link block in BlockTable, put it first in list.
		 * Special treatment for empty linked list
		 */
	if ((HashFirst = sBlockTable[Hash]))
	{
		HashFirst->BlockPrev->BlockNext = Block;
		Block->BlockPrev = HashFirst->BlockPrev;
		Block->BlockNext = HashFirst;
		HashFirst->BlockPrev = Block;
		sBlockTable[Hash] = Block;
	}
	else
	{
		Block->BlockPrev = Block->BlockNext = Block;
		sBlockTable[Hash] = Block;
	}
	
blkcreate_err_1:
	VxdDebugPrint(D_BLOCK, "BlockCreate: done");
	
	return Block;
}



/*
 * Remove a TBlock object.
 *
 * PRE_CONDITION
 *	Block->nrClient == 0, that is, there are no more
 *	clients holding the block
 */
static void BlockDestroy(TBlock *Block)
{
	UINT		Hash;

	VxdDebugPrint(D_BLOCK, "BlockDestroy: device=%x, block=%lu", (ULONG) Block->Device, Block->BlockNo);

		/*
		 * Remove block from HashTable.
		 * Special treatment if we're last item in list
		 */
	Hash = HashFunction(Block->Device, Block->BlockNo);
	if (Block == Block->BlockNext)
	{
		sBlockTable[Hash] = 0;
	}
	else
	{
			/*
			 * If we're head of the chain, let our
			 * neighbour be the head of the chain
			 */
		if (sBlockTable[Hash] == Block)
			sBlockTable[Hash] = Block->BlockNext;

			/*
			 * Remove us from the list
			 */
		Block->BlockPrev->BlockNext = Block->BlockNext;
		Block->BlockNext->BlockPrev = Block->BlockPrev;
	}
		
		/*
		 * Get rid of the TBlock itself
		 */
	free(Block);

	VxdDebugPrint(D_BLOCK, "BlockDestroy: done");
}





/**************************************
 *
 * INTERFACE ROUNTINES
 *
 **************************************/

/*
 * Get a block identified by its number from a device 
 *
 * PRE CONDITIONS:
 *	Device is a valid reference to a  blockdevice
 *
 * POST CONDITIONS:
 *	If the block is in the blocktable it can be returned
 *	immediately and its reference counted is increased by one.
 *	If not in the blocktable, the block is looked up in the block 
 *	cache, if it in the block cache it is read from disk.
 *	In the last two cases a new TBlock object is created,
 *	initialised with reference count=1 and added to the BlockTable.
 *	If the block is read from disk, it is _not_ added to the 
 *	cache.
 *	
 * IN:
 *	Device:		Valid refenece to a block device
 *	BlockNo:	logical block number
 *
 * OUT:
 *	<none>
 *
 * RETURNS:
 *	success: valid pointer to TBlock object
 *	otherwise: 0
 */
TBlock* BlockGetBlock(TDevice Device, ULONG BlockNo)
{
	TBlock		*Block;
	UINT		Hash;

	EnterMutex(sMutex, BLOCK_THREAD_IDLE);

	VxdDebugPrint(D_BLOCK, "BlockGetBlock: device=%x, block=%lu", (ULONG) Device, BlockNo);

		/*
		 * First, see if it's in the the Table, if not
		 * create a TBlock and get it from either the cache
		 * or from disk
		 */
	Hash = HashFunction(Device, BlockNo);
	if (!(Block = BlockGetFromTable(Device, BlockNo, Hash)))
	{
			/*
			 * First, create a TBlock object
			 */
		if (!(Block = BlockCreate(Device, BlockNo, Hash)))
		{
			VxdDebugPrint(D_ERROR, "BlockGetBlock: could not create a TBlock, device=%lu, block=%lu", (ULONG) Device, BlockNo);
			goto getblock_done;
		}

			/*
			 * Is it in the block cache ?
			 */
		if (CacheLookupById(sBlockCache, (ULONG) Device, BlockNo, &Block->BlockData))
		{
				/*
				 * Yep, blockdata now points to the buffer
				 */
			;
		}
		else
		{

			if (!(Block->BlockData = malloc(DevGetBlockSize(Device))))
			{
				VxdDebugPrint(D_ERROR, "BlockGetBlock: could not malloc blockdata, device=%lu, block=%lu", (ULONG) Device, BlockNo);
				goto getblock_done;
			}

				/*
				 * Get it from disk
				 */
			//LeaveMutex(sMutex);
			
			if (!DevReadBlock(Device, BlockNo, Block->BlockData))
			{
				VxdDebugPrint(D_ERROR, "BlockGetBlock: could not readblock from disk, device=%lu, block=%lu", (ULONG) Device, BlockNo);

				free(Block->BlockData);
			
				BlockDestroy(Block);
				Block = (TBlock *) 0;
				goto getblock_done;
			}
		}

	}

	Block->nrClients++;		// increase reference count for this block

getblock_done:
	VxdDebugPrint(D_BLOCK, "BlockGetBlock: done, Block=%X", Block);
	LeaveMutex(sMutex);

	return Block;
}


/*
 * Release a TBlock object
 *
 * PRE CONDITIONS:
 *	Block is a valid TBlock object
 *
 * POST CONDITIONS:
 *	First, the the TBlock's object reference count is decreased
 *	by one. If the reference count reaches 0, the Tblock is
 *	removed from the BlockTable and the actual block is added
 *	to the cache.
 *	
 * IN:
 *	Block:	valid reference to a TBlock object
 *
 * OUT:
 *	<none>
 *
 * RETURNS:
 *	<none>
 */
void BlockRelease(TBlock *Block)
{
	EnterMutex(sMutex, BLOCK_THREAD_IDLE);

	VxdDebugPrint(D_BLOCK, "BlockReleaseBlock: device=%x, block=%lu, block=%X", 
		(ULONG) Block->Device, 
		Block->BlockNo,
		Block);

	if (--(Block->nrClients) == 0)
	{
			/*
			 * Don't free the actual diskblock but add it to the cache.
			 * Also note that we don't actually copy the block but rahther
			 * the pointer to the block.
			 */
		CacheAddById(sBlockCache, (ULONG) Block->Device, Block->BlockNo, Block->BlockData);

			/*
			 * Remove the TBlock object from the BlockTable
			 */
		BlockDestroy(Block);
	}
	
	VxdDebugPrint(D_BLOCK, "BlockReleaseBlock: done");
	
	LeaveMutex(sMutex);
}


/*
 * Locks a TBlock object
 */
VOID* BlockLock(TBlock *Block)
{
		/*
		 * In the future we should use a Mutex to lock
		 * the block
		 */
	return Block->BlockData;
}

/*
 * Unlocks a TBlock object
 */
void BlockUnlock(TBlock *Block)
{
}


/*
 * Initialises the block module
 *
 * PRE CONDITIONS:
 *	<none>
 *
 * POST CONDITIONS:
 *	The block table and the block cache are created and
 *	initialised.
 *
 * IN:
 *	EstimatedBlocksResident:	Estimate number of blocks that should
 *								be resident at any given moment.
 *	BlockCacheSize:				Number of objects that should fit
 *								in the cache
 */
 BOOL BlockInitialise(UINT EstimatedBlocksResident, UINT BlockCacheSize)
{
	sNrsBlockTable = EstimatedBlocksResident / HASH_QUEUE_SIZE;

	VxdDebugPrint(D_SYSTEM, "BlockInitialise: resident=%u, cache=%u", EstimatedBlocksResident, BlockCacheSize);

		/*
		 * Create sBlockTable
		 */
	if (!(sBlockTable = (TBlock **) calloc(sNrsBlockTable, sizeof(TBlock *))))
	{
		VxdDebugPrint(D_ERROR, "BlockInitialse: could not alloc sBlockTable");
		goto blk_init_1;
	}

		/*
		 * Create a diskblock cache, this means the cache only 
		 * stores pointers and we are responsible for the block's 
		 * memory space.
		 */
	if (! (sBlockCache = CacheCreate(sBlockCacheName, BlockCacheSize, 0)))
	{
		VxdDebugPrint(D_ERROR, "BlockInitialse: could not create block cache");
		goto blk_init_2;
	}

	sMutex = CreateMutex(0, MUTEX_MUST_COMPLETE);

	VxdDebugPrint(D_SYSTEM, "BlockInitialise: done");

	return TRUE;

blk_init_2:
	free(sBlockTable);

blk_init_1:

	VxdDebugPrint(D_SYSTEM, "BlockInitialise: done");

	return FALSE;
}


void BlockCleanup()
{
	VxdDebugPrint(D_SYSTEM, "BlockCleanUp");
	
	CacheDestroy(sBlockCache);

	EnterMutex(sMutex, BLOCK_THREAD_IDLE);

	free(sBlockTable);

	LeaveMutex(sMutex);

	DestroyMutex(sMutex);

	VxdDebugPrint(D_SYSTEM, "BlockCleanUp: done");
}

void BlockCacheInfo()
{
	unsigned long	Lookups;
	unsigned long	Hits;

	CacheGetStats(sBlockCache, &Lookups, &Hits);
	VxdDebugPrint(D_SYSTEM, "BlockCacheInfo: lookup=%lu, hit=%lu, ratio=%lu",
			Lookups, Hits, 
			Lookups? Hits*100/ Lookups: 0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -