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