421 lines
8.4 KiB
C++
421 lines
8.4 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-5 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ftvol.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code specific to all volume objects.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Norbert Kusters 2-Feb-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ftdisk.h"
|
|||
|
|
|||
|
typedef struct _STATE_CHANGE_CONTEXT {
|
|||
|
WORK_QUEUE_ITEM WorkQueueItem;
|
|||
|
PFT_VOLUME MemberVolume;
|
|||
|
PFT_VOLUME ParentVolume;
|
|||
|
FT_PARTITION_STATE NewState;
|
|||
|
} STATE_CHANGE_CONTEXT, *PSTATE_CHANGE_CONTEXT;
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
FT_BASE_CLASS::operator new(
|
|||
|
IN unsigned int Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the memory allocator for all classes derived from
|
|||
|
FT_VOLUME.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies the number of bytes to allocate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to Size bytes of non-paged pool.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return ExAllocatePool(NonPagedPool, Size);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FT_BASE_CLASS::operator delete(
|
|||
|
IN PVOID MemPtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine frees memory allocated for all classes derived from
|
|||
|
FT_VOLUME.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemPtr - Supplies a pointer to the memory to free.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (MemPtr) {
|
|||
|
ExFreePool(MemPtr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FT_VOLUME::Initialize(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the init routine for an FT_VOLUME. It must be called before
|
|||
|
the FT_VOLUME is used.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KeInitializeSpinLock(&_spinLock);
|
|||
|
_memberState = Healthy;
|
|||
|
_parentVolume = NULL;
|
|||
|
_memberExtension = NULL;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
SetMemberStateWorker(
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PSTATE_CHANGE_CONTEXT context = (PSTATE_CHANGE_CONTEXT) Context;
|
|||
|
PFT_VOLUME ChangedMember = context->MemberVolume;
|
|||
|
PFT_VOLUME t = context->ParentVolume;
|
|||
|
FT_PARTITION_STATE newState = context->NewState;
|
|||
|
ULONG signature;
|
|||
|
LONGLONG startOffset;
|
|||
|
PDISK_CONFIG_HEADER registry;
|
|||
|
PDISK_REGISTRY diskRegistry;
|
|||
|
PDISK_DESCRIPTION diskDescription;
|
|||
|
PVOID freePoolAddress;
|
|||
|
USHORT i;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
ExFreePool(context);
|
|||
|
|
|||
|
if (!ChangedMember->IsPartition()) {
|
|||
|
// This is a no-op for the stacking case until registry structures
|
|||
|
// exist for describing stacks of FT sets.
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
signature = ((PPARTITION) ChangedMember)->QueryDiskSignature();
|
|||
|
startOffset = ((PPARTITION) ChangedMember)->QueryPartitionOffset();
|
|||
|
|
|||
|
status = FtpReturnRegistryInformation(DISK_REGISTRY_VALUE,
|
|||
|
&freePoolAddress,
|
|||
|
(PVOID*) ®istry);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// No registry data.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"FtpChangeMemberStateInRegistry: No Value => 0x%x\n",
|
|||
|
status));
|
|||
|
ASSERT(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (registry->FtInformationSize == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// No FT components in the registry.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(freePoolAddress);
|
|||
|
DebugPrint((1, "FtpChangeMemberStateInRegistry: No FT components.\n"));
|
|||
|
ASSERT(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the registry information for the disk partition.
|
|||
|
//
|
|||
|
|
|||
|
diskRegistry = (PDISK_REGISTRY)
|
|||
|
((PUCHAR)registry + registry->DiskInformationOffset);
|
|||
|
diskDescription = &diskRegistry->Disks[0];
|
|||
|
|
|||
|
for (i = 0; i < diskRegistry->NumberOfDisks; i++) {
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"FtpChangeMemberStateInRegistry: Checking disk %x\n",
|
|||
|
diskDescription->Signature));
|
|||
|
|
|||
|
if (diskDescription->Signature == signature) {
|
|||
|
USHORT j;
|
|||
|
PDISK_PARTITION diskPartition;
|
|||
|
|
|||
|
for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
|
|||
|
|
|||
|
diskPartition = &diskDescription->Partitions[j];
|
|||
|
|
|||
|
if (diskPartition->StartingOffset.QuadPart == startOffset) {
|
|||
|
|
|||
|
//
|
|||
|
// Found the member.
|
|||
|
//
|
|||
|
|
|||
|
diskPartition->FtState = newState;
|
|||
|
|
|||
|
DebugPrint((2,
|
|||
|
"FtpChangeMemberStateInRegistry: Writing new info %x\n",
|
|||
|
signature));
|
|||
|
FtpWriteRegistryInformation(DISK_REGISTRY_VALUE,
|
|||
|
registry,
|
|||
|
registry->FtInformationOffset +
|
|||
|
registry->FtInformationSize);
|
|||
|
ExFreePool(freePoolAddress);
|
|||
|
|
|||
|
goto registryUpdateComplete;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
diskDescription = (PDISK_DESCRIPTION)
|
|||
|
&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((1,
|
|||
|
"FtpChangeMemberStateInRegistry: Did not update registry\n"));
|
|||
|
ExFreePool(freePoolAddress);
|
|||
|
|
|||
|
registryUpdateComplete:
|
|||
|
|
|||
|
if (newState == Orphaned) {
|
|||
|
IoRaiseInformationalHardError(STATUS_FT_ORPHANING,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (ChangedMember->_memberExtension) {
|
|||
|
FtpLogError(ChangedMember->_memberExtension,
|
|||
|
FT_ORPHANING,
|
|||
|
STATUS_SUCCESS,
|
|||
|
0,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FT_VOLUME::MemberStateChangeNotification(
|
|||
|
IN PFT_VOLUME ChangedMember
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called on the parent volume when a member volume
|
|||
|
changes it's member state. This routine records the changed information
|
|||
|
for posterity.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ChangedMember - Supplies the member that has changed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PSTATE_CHANGE_CONTEXT context;
|
|||
|
|
|||
|
context = (PSTATE_CHANGE_CONTEXT)
|
|||
|
ExAllocatePool(NonPagedPool, sizeof(STATE_CHANGE_CONTEXT));
|
|||
|
if (!context) {
|
|||
|
context = (PSTATE_CHANGE_CONTEXT)
|
|||
|
ExAllocatePool(NonPagedPoolMustSucceed,
|
|||
|
sizeof(STATE_CHANGE_CONTEXT));
|
|||
|
if (!context) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExInitializeWorkItem(&context->WorkQueueItem,
|
|||
|
SetMemberStateWorker, context);
|
|||
|
context->MemberVolume = ChangedMember;
|
|||
|
context->ParentVolume = this;
|
|||
|
context->NewState = ChangedMember->QueryMemberState();
|
|||
|
|
|||
|
ExQueueWorkItem(&context->WorkQueueItem, CriticalWorkQueue);
|
|||
|
}
|
|||
|
|
|||
|
FT_PARTITION_STATE
|
|||
|
FT_VOLUME::QueryMemberState(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the member state stored in this object. A member
|
|||
|
is either Healthy, Orphaned, or Regenerating with respect to the
|
|||
|
composite object which contains it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The member state for this member.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
FT_PARTITION_STATE r;
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|||
|
r = _memberState;
|
|||
|
KeReleaseSpinLock(&_spinLock, irql);
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FT_VOLUME::SetMemberState(
|
|||
|
IN FT_PARTITION_STATE MemberState
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the state of this member for the composite
|
|||
|
object that contains it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemberState - Supplies the new member state.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KIRQL irql;
|
|||
|
FT_PARTITION_STATE oldState;
|
|||
|
|
|||
|
if (MemberState != Healthy &&
|
|||
|
MemberState != Regenerating &&
|
|||
|
MemberState != Initializing) {
|
|||
|
|
|||
|
MemberState = Orphaned;
|
|||
|
}
|
|||
|
|
|||
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|||
|
oldState = _memberState;
|
|||
|
_memberState = MemberState;
|
|||
|
KeReleaseSpinLock(&_spinLock, irql);
|
|||
|
|
|||
|
if (oldState == MemberState || !_parentVolume) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
_parentVolume->MemberStateChangeNotification(this);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
FT_VOLUME::SetMemberStateWithoutNotification(
|
|||
|
IN FT_PARTITION_STATE MemberState
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the state of this member for the composite
|
|||
|
object that contains it without sending any notification to
|
|||
|
the parent.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemberState - Supplies the new member state.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|||
|
_memberState = MemberState;
|
|||
|
KeReleaseSpinLock(&_spinLock, irql);
|
|||
|
}
|
|||
|
|
|||
|
FT_VOLUME::~FT_VOLUME(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Desctructor for FT_VOLUME.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
}
|