Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

482 lines
14 KiB

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