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.
 
 
 
 
 
 

401 lines
13 KiB

/*
* WORKGRP.C
*
* RSM Service : Work Groups (collections of work items)
*
* 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"
WORKGROUP *NewWorkGroup()
{
WORKGROUP *workGroup;
workGroup = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(WORKGROUP));
if (workGroup){
workGroup->allWorkItemsCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (workGroup->allWorkItemsCompleteEvent){
InitializeListHead(&workGroup->workItemsList);
InitializeCriticalSection(&workGroup->lock);
}
else {
GlobalFree(workGroup);
workGroup = NULL;
}
}
ASSERT(workGroup);
return workGroup;
}
VOID FreeWorkGroup(WORKGROUP *workGroup)
{
FlushWorkGroup(workGroup);
CloseHandle(workGroup->allWorkItemsCompleteEvent);
DeleteCriticalSection(&workGroup->lock);
GlobalFree(workGroup);
}
/*
* FlushWorkGroup
*
* Release all the workItems in the workGroup.
*/
VOID FlushWorkGroup(WORKGROUP *workGroup)
{
EnterCriticalSection(&workGroup->lock);
while (!IsListEmpty(&workGroup->workItemsList)){
LIST_ENTRY *listEntry;
WORKITEM *workItem;
listEntry = RemoveHeadList(&workGroup->workItemsList);
workItem = CONTAINING_RECORD(listEntry, WORKITEM, workGroupListEntry);
InitializeListHead(&workItem->workGroupListEntry);
workItem->workGroup = NULL;
/*
* Dereference the objects in the workItem.
*/
FlushWorkItem(workItem);
/*
* Get the workItem back in the library's free queue.
*/
switch (workItem->state){
case WORKITEMSTATE_FREE:
break;
case WORKITEMSTATE_PENDING:
// BUGBUG FINISH - have to abort whatever the library thread
// is doing with this workItem.
DequeuePendingWorkItem(workItem->owningLib, workItem);
EnqueueFreeWorkItem(workItem->owningLib, workItem);
break;
case WORKITEMSTATE_COMPLETE:
DequeueCompleteWorkItem(workItem->owningLib, workItem);
EnqueueFreeWorkItem(workItem->owningLib, workItem);
break;
case WORKITEMSTATE_STAGING:
EnqueueFreeWorkItem(workItem->owningLib, workItem);
break;
default:
DBGERR(("bad workItem state in FlushWorkGroup"));
break;
}
}
LeaveCriticalSection(&workGroup->lock);
}
/*
* BuildMountWorkGroup
*
* Build a work group (collection of work items) for a mount
* request, which may include multiple mounts, possibly spanning
* more than one library.
*/
HRESULT BuildMountWorkGroup(WORKGROUP *workGroup,
LPNTMS_GUID lpMediaOrPartitionIds,
LPNTMS_GUID lpDriveIds,
DWORD dwCount,
DWORD dwOptions,
DWORD dwPriority)
{
HRESULT result;
ULONG i;
ASSERT(IsListEmpty(&workGroup->workItemsList));
/*
* 1. Create a workItem for each mount request.
* We will only proceed if all the mount requests are valid.
*/
result = ERROR_SUCCESS;
for (i = 0; i < dwCount; i++){
DRIVE *drive;
/*
* If NTMS_MOUNT_SPECIFIC_DRIVE is set,
* we must mount a specific drive.
* Otherwise, we select the drives and return them in lpDriveIds.
*/
if (dwOptions & NTMS_MOUNT_SPECIFIC_DRIVE){
drive = FindDrive(&lpDriveIds[i]);
}
else {
drive = NULL;
}
if (drive || !(dwOptions & NTMS_MOUNT_SPECIFIC_DRIVE)){
PHYSICAL_MEDIA *physMedia = NULL;
MEDIA_PARTITION *mediaPart = NULL;
/*
* We may be given either a physical media or a
* media partition to mount. Figure out which one
* by trying to resolve the GUID as either.
*/
physMedia = FindPhysicalMedia(&lpMediaOrPartitionIds[i]);
if (!physMedia){
mediaPart = FindMediaPartition(&lpMediaOrPartitionIds[i]);
if (mediaPart){
physMedia = mediaPart->owningPhysicalMedia;
}
}
if (physMedia){
LIBRARY *lib;
BOOLEAN ok;
/*
* Figure out what library we're dealing with.
* Since we may not be given a specific drive,
* we have to figure it out from the media.
* For sanity, check that the media is in a pool.
*
* BUGBUG - how do we keep the media from moving
* before the work item fires ?
*/
ok = LockPhysicalMediaWithLibrary(physMedia);
if (ok){
LIBRARY *lib;
lib = physMedia->owningMediaPool ?
physMedia->owningMediaPool->owningLibrary :
NULL;
if (lib){
/*
* If we're targetting a specific drive, then
* it should be in the same library.
*/
if (!drive || (drive->lib == lib)){
OBJECT_HEADER *mediaOrPartObj =
mediaPart ?
(OBJECT_HEADER *)mediaPart :
(OBJECT_HEADER *)physMedia;
WORKITEM *workItem;
workItem = DequeueFreeWorkItem(lib, TRUE);
if (workItem){
BuildSingleMountWorkItem( workItem,
drive,
mediaOrPartObj,
dwOptions,
dwPriority);
/*
* We've built one of the mount requests.
* Put it in the work group.
*/
InsertTailList( &workGroup->workItemsList,
&workItem->workGroupListEntry);
workItem->workGroup = workGroup;
}
else {
result = ERROR_NOT_ENOUGH_MEMORY;
}
}
else {
result = ERROR_DRIVE_MEDIA_MISMATCH;
}
}
else {
result = ERROR_INVALID_LIBRARY;
}
UnlockPhysicalMediaWithLibrary(physMedia);
}
else {
result = ERROR_DATABASE_FAILURE;
}
}
else {
result = ERROR_INVALID_MEDIA;
}
}
else {
result = ERROR_INVALID_DRIVE;
}
if (result != ERROR_SUCCESS){
break;
}
}
if (result == ERROR_SUCCESS){
workGroup->numTotalWorkItems = workGroup->numPendingWorkItems = dwCount;
}
else {
/*
* If we failed, release any work items that we did create.
*/
FlushWorkGroup(workGroup);
}
return result;
}
/*
* BuildDismountWorkGroup
*
* Build a work group (collection of work items) for a dismount
* request, which may include multiple dismounts, possibly spanning
* more than one library.
*/
HRESULT BuildDismountWorkGroup( WORKGROUP *workGroup,
LPNTMS_GUID lpMediaOrPartitionIds,
DWORD dwCount,
DWORD dwOptions)
{
HRESULT result;
ULONG i;
ASSERT(IsListEmpty(&workGroup->workItemsList));
/*
* 1. Create a workItem for each dismount request.
* We will only proceed if all the dismount requests are valid.
*/
result = ERROR_SUCCESS;
for (i = 0; i < dwCount; i++){
PHYSICAL_MEDIA *physMedia = NULL;
MEDIA_PARTITION *mediaPart = NULL;
/*
* We may be given either a physical media or a
* media partition to mount. Figure out which one
* by trying to resolve the GUID as either.
*/
physMedia = FindPhysicalMedia(&lpMediaOrPartitionIds[i]);
if (!physMedia){
mediaPart = FindMediaPartition(&lpMediaOrPartitionIds[i]);
if (mediaPart){
physMedia = mediaPart->owningPhysicalMedia;
}
}
if (physMedia){
LIBRARY *lib;
BOOLEAN ok;
/*
* Figure out what library we're dealing with.
*/
ok = LockPhysicalMediaWithLibrary(physMedia);
if (ok){
LIBRARY *lib;
lib = physMedia->owningMediaPool ?
physMedia->owningMediaPool->owningLibrary :
NULL;
if (lib){
OBJECT_HEADER *mediaOrPartObj =
mediaPart ?
(OBJECT_HEADER *)mediaPart :
(OBJECT_HEADER *)physMedia;
WORKITEM *workItem;
workItem = DequeueFreeWorkItem(lib, TRUE);
if (workItem){
BuildSingleDismountWorkItem( workItem,
mediaOrPartObj,
dwOptions);
/*
* We've built one of the mount requests.
* Put it in the work group.
*/
InsertTailList( &workGroup->workItemsList,
&workItem->workGroupListEntry);
workItem->workGroup = workGroup;
}
else {
result = ERROR_NOT_ENOUGH_MEMORY;
}
}
else {
result = ERROR_DRIVE_MEDIA_MISMATCH;
}
UnlockPhysicalMediaWithLibrary(physMedia);
}
else {
result = ERROR_DATABASE_FAILURE;
}
}
else {
result = ERROR_INVALID_MEDIA;
}
}
if (result == ERROR_SUCCESS){
workGroup->numTotalWorkItems = workGroup->numPendingWorkItems = dwCount;
}
else {
/*
* If we failed, release any work items that we did create and clean up.
*/
FlushWorkGroup(workGroup);
}
return result;
}
/*
* ScheduleWorkGroup
*
* Submit all the work items in the work group.
*/
HRESULT ScheduleWorkGroup(WORKGROUP *workGroup)
{
LIST_ENTRY *listEntry;
HRESULT result;
EnterCriticalSection(&workGroup->lock);
/*
* Set the workGroup's status to success.
* If any workItems fail, they'll set this to an error code.
*/
workGroup->resultStatus = ERROR_SUCCESS;
listEntry = &workGroup->workItemsList;
while ((listEntry = listEntry->Flink) != &workGroup->workItemsList){
WORKITEM *workItem = CONTAINING_RECORD(listEntry, WORKITEM, workGroupListEntry);
ASSERT(workItem->state == WORKITEMSTATE_STAGING);
/*
* Give this workItem to the library and wake up the library thread.
*/
EnqueuePendingWorkItem(workItem->owningLib, workItem);
}
LeaveCriticalSection(&workGroup->lock);
result = ERROR_SUCCESS;
return result;
}