|
|
/*
* MEDIA.C * * RSM Service : Physical Media * * Author: ErvinP * * (c) 2001 Microsoft Corporation * */
#include <windows.h>
#include <stdlib.h>
#include <wtypes.h>
#include <ntmsapi.h>
#include "internal.h"
#include "resource.h"
#include "debug.h"
PHYSICAL_MEDIA *NewPhysicalMedia() { PHYSICAL_MEDIA *physMedia;
physMedia = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(PHYSICAL_MEDIA)); if (physMedia){ physMedia->mediaFreeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (physMedia->mediaFreeEvent){ InitializeCriticalSection(&physMedia->lock); InitializeListHead(&physMedia->physMediaListEntry);
physMedia->objHeader.objType = OBJECTTYPE_PHYSICALMEDIA; physMedia->objHeader.refCount = 1; // BUGBUG FINISH
} else { GlobalFree(physMedia); physMedia = NULL; } }
ASSERT(physMedia); return physMedia; }
VOID DestroyPhysicalMedia(PHYSICAL_MEDIA *physMedia) { // BUGBUG FINISH
CloseHandle(physMedia->mediaFreeEvent); DeleteCriticalSection(&physMedia->lock);
GlobalFree(physMedia); }
PHYSICAL_MEDIA *FindPhysicalMedia(LPNTMS_GUID physMediaId) { PHYSICAL_MEDIA *foundPhysMedia = NULL;
if (physMediaId){ OBJECT_HEADER *objHdr; objHdr = FindObjectInGuidHash(physMediaId); if (objHdr){ if (objHdr->objType == OBJECTTYPE_PHYSICALMEDIA){ foundPhysMedia = (PHYSICAL_MEDIA *)objHdr; } else { DerefObject(objHdr); } } } return foundPhysMedia; }
/*
* AllocatePhysicalMediaExclusive * * Allocate a partition on the specified physicalMedia with an exclusive * hold on the other partitions. */ HRESULT AllocatePhysicalMediaExclusive(SESSION *thisSession, PHYSICAL_MEDIA *physMedia, LPNTMS_GUID lpPartitionId, DWORD dwTimeoutMsec) { DWORD startTime = GetTickCount(); HRESULT result;
ASSERT(lpPartitionId); while (TRUE){ BOOL gotMedia; MEDIA_PARTITION *reservedMediaPartition = NULL; ULONG i; EnterCriticalSection(&physMedia->lock);
/*
* Check that the media is not held. */ if (physMedia->owningSession){ ASSERT(physMedia->owningSession != thisSession); gotMedia = FALSE; } else { /*
* Check that none of the partitions are held. */ gotMedia = TRUE; for (i = 0; i < physMedia->numPartitions; i++){ MEDIA_PARTITION *thisPartition = &physMedia->partitions[i]; if (thisPartition->owningSession){ gotMedia = FALSE; break; } else if (RtlEqualMemory(&thisPartition->objHeader.guid, lpPartitionId, sizeof(NTMS_GUID))){ ASSERT(!reservedMediaPartition); reservedMediaPartition = thisPartition; } } }
if (gotMedia){ if (reservedMediaPartition){ physMedia->owningSession = thisSession; reservedMediaPartition->owningSession = thisSession; physMedia->numPartitionsOwnedBySession = 1; RefObject(physMedia); RefObject(reservedMediaPartition); result = ERROR_SUCCESS; } else { result = ERROR_INVALID_MEDIA; } } else { result = ERROR_MEDIA_UNAVAILABLE; } LeaveCriticalSection(&physMedia->lock);
/*
* If appropriate, wait for the media to become free. */ if ((result == ERROR_MEDIA_UNAVAILABLE) && (dwTimeoutMsec > 0)){ /*
* Wait for the media to become available. */ DWORD waitRes = WaitForSingleObject(physMedia->mediaFreeEvent, dwTimeoutMsec); if (waitRes == WAIT_TIMEOUT){ result = ERROR_TIMEOUT; break; } else { /*
* Loop around and try again. */ DWORD timeNow = GetTickCount(); ASSERT(timeNow >= startTime); dwTimeoutMsec -= MIN(dwTimeoutMsec, timeNow-startTime); } } else { break; } }
// BUGBUG FINISH - need to move media to different media pool ?
return result; }
/*
* AllocateNextPartitionOnExclusiveMedia * * The calling session should already hold exclusive access to the media. * This call simply reserves another partition for the caller. */ HRESULT AllocateNextPartitionOnExclusiveMedia(SESSION *thisSession, PHYSICAL_MEDIA *physMedia, MEDIA_PARTITION **ppNextPartition) { MEDIA_PARTITION *reservedMediaPartition = NULL; HRESULT result;
ASSERT(physMedia->numPartitionsOwnedBySession >= 1); EnterCriticalSection(&physMedia->lock);
if (physMedia->owningSession == thisSession){ ULONG i;
/*
* Just reserve the next available partition */ result = ERROR_MEDIA_UNAVAILABLE; for (i = 0; i < physMedia->numPartitions; i++){ MEDIA_PARTITION *thisPartition = &physMedia->partitions[i]; if (thisPartition->owningSession){ ASSERT(thisPartition->owningSession == thisSession); } else { reservedMediaPartition = thisPartition; reservedMediaPartition->owningSession = thisSession; RefObject(reservedMediaPartition); physMedia->numPartitionsOwnedBySession++; result = ERROR_SUCCESS; break; } } } else { ASSERT(physMedia->owningSession == thisSession); result = ERROR_INVALID_MEDIA; } LeaveCriticalSection(&physMedia->lock);
*ppNextPartition = reservedMediaPartition; return result; }
HRESULT AllocateMediaFromPool( SESSION *thisSession, MEDIA_POOL *mediaPool, DWORD dwTimeoutMsec, PHYSICAL_MEDIA **ppPhysMedia, BOOL opReqIfNeeded) { DWORD startTime = GetTickCount(); HRESULT result;
while (TRUE){ PHYSICAL_MEDIA *physMedia = NULL; LIST_ENTRY *listEntry; ULONG i; EnterCriticalSection(&mediaPool->lock);
if (!IsListEmpty(&mediaPool->physMediaList)){ /*
* Remove the media. * Deref both the pool and the media since they no longer * point to each other. */ PLIST_ENTRY listEntry = RemoveHeadList(&mediaPool->physMediaList); physMedia = CONTAINING_RECORD(listEntry, PHYSICAL_MEDIA, physMediaListEntry); DerefObject(mediaPool); DerefObject(physMedia); } LeaveCriticalSection(&mediaPool->lock);
if (physMedia){ // BUGBUG FINISH - enqueue it in a 'inUse' queue, change state ?
*ppPhysMedia = physMedia;
/*
* Reference the media since we're returning a pointer to it. */ RefObject(physMedia); result = ERROR_SUCCESS; break; } else { // BUGBUG FINISH - based on policy, try free/scratch pool
if (opReqIfNeeded){ // BUGBUG FINISH - do op request and try again ...
} result = ERROR_MEDIA_UNAVAILABLE; }
/*
* If appropriate, wait for media to become free. */ if ((result == ERROR_MEDIA_UNAVAILABLE) && (dwTimeoutMsec > 0)){ /*
* Wait on the designated media pool to receive new media. * The media pool's event will get signalled when either it * OR THE SCRATCH POOL receives new media. */ DWORD waitRes = WaitForSingleObject(mediaPool->newMediaEvent, dwTimeoutMsec); if (waitRes == WAIT_TIMEOUT){ result = ERROR_TIMEOUT; break; } else { /*
* Loop around and try again. */ DWORD timeNow = GetTickCount(); dwTimeoutMsec -= MIN(dwTimeoutMsec, timeNow-startTime); } } else { break; } } return result; }
HRESULT DeletePhysicalMedia(PHYSICAL_MEDIA *physMedia) { HRESULT result; // BUGBUG FINISH
DBGERR(("not implemented")); result = ERROR_CALL_NOT_IMPLEMENTED; return result; }
/*
* InsertPhysicalMediaInPool * * Insert the physical media (which may not currently be in any pool) * into the designated media pool. */ VOID InsertPhysicalMediaInPool( MEDIA_POOL *mediaPool, PHYSICAL_MEDIA *physMedia) {
ASSERT(!physMedia->owningMediaPool); EnterCriticalSection(&mediaPool->lock); EnterCriticalSection(&physMedia->lock);
InsertTailList(&mediaPool->physMediaList, &physMedia->physMediaListEntry); mediaPool->numPhysMedia++; physMedia->owningMediaPool = mediaPool;
/*
* Reference both objects since they now point to each other. */ RefObject(mediaPool); RefObject(physMedia); LeaveCriticalSection(&physMedia->lock); LeaveCriticalSection(&mediaPool->lock); }
/*
* RemovePhysicalMediaFromPool * * Remove the physical media from containing media pool (if any). * * Must be called with physical media lock held. * If the media is indeed in a pool, pool lock must be held as well * (use LockPhysicalMediaWithPool). */ VOID RemovePhysicalMediaFromPool(PHYSICAL_MEDIA *physMedia) { MEDIA_POOL *mediaPool = physMedia->owningMediaPool; HRESULT result;
if (mediaPool){ ASSERT(!IsListEmpty(&mediaPool->physMediaList)); ASSERT(!IsListEmpty(&physMedia->physMediaListEntry)); ASSERT(mediaPool->numPhysMedia > 0); RemoveEntryList(&physMedia->physMediaListEntry); InitializeListHead(&physMedia->physMediaListEntry); mediaPool->numPhysMedia--; physMedia->owningMediaPool = NULL;
/*
* Dereference both objects since they no longer point to each other. */ DerefObject(mediaPool); DerefObject(physMedia); } else { /*
* The media is not in any pool. So succeed. */ }
}
/*
* MovePhysicalMediaToPool * * Remove the physical media from whatever pool it is currently in * and move it to destMediaPool. */ HRESULT MovePhysicalMediaToPool( MEDIA_POOL *destMediaPool, PHYSICAL_MEDIA *physMedia, BOOLEAN setMediaTypeToPoolType) { HRESULT result; BOOLEAN allowImport; ULONG i; if (LockPhysicalMediaWithPool(physMedia)){ /*
* We can only move the media if all media partitions are * in an importable state. */ allowImport = TRUE; for (i = 0; i < physMedia->numPartitions; i++){ MEDIA_PARTITION *thisMediaPart = &physMedia->partitions[i]; if (!thisMediaPart->allowImport){ allowImport = FALSE; break; } }
if (allowImport){
// BUGBUG FINISH - also check that media types match, etc.
RemovePhysicalMediaFromPool(physMedia); result = ERROR_SUCCESS; } else { result = ERROR_ACCESS_DENIED; }
/*
* Drop the lock before touching the destination media pool. * We cannot hold locks on two pools at once (may cause deadlock). */ UnlockPhysicalMediaWithPool(physMedia); if (result == ERROR_SUCCESS){ InsertPhysicalMediaInPool(destMediaPool, physMedia);
if (setMediaTypeToPoolType){ /*
* Set the media's type to the media pool's type. * * This part is failable. BUGBUG ? */ if (LockPhysicalMediaWithPool(physMedia)){ /*
* Make sure that the media didn't move while * we dropped the lock. If it did, that's ok; * we can just leave it alone and let the new pool * take over. */ if (physMedia->owningMediaPool == destMediaPool){ SetMediaType(physMedia, destMediaPool->mediaTypeObj); } UnlockPhysicalMediaWithPool(physMedia); } } } } else { result = ERROR_BUSY; } return result; }
|