621 lines
12 KiB
C++
621 lines
12 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-5 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
composit.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code specific to all composite volume objects.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Norbert Kusters 2-Feb-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
kernel mode only
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
This code assumes that the volume array is static. If these values
|
|||
|
changes (as in Stripes or Mirrors) then it is up to the subclass to
|
|||
|
provide the proper synchronization.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ftdisk.h"
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
COMPOSITE_FT_VOLUME::Initialize(
|
|||
|
IN OUT PFT_VOLUME* VolumeArray,
|
|||
|
IN ULONG ArraySize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize routine for FT_VOLUME of type COMPOSITE_FT_VOLUME.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VolumeArray - Supplies the array of volumes for this volume set.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i, secsize;
|
|||
|
|
|||
|
FT_VOLUME::Initialize();
|
|||
|
|
|||
|
_volumeArray = VolumeArray;
|
|||
|
_arraySize = ArraySize;
|
|||
|
|
|||
|
_sectorSize = 0;
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
secsize = _volumeArray[i]->QuerySectorSize();
|
|||
|
if (_sectorSize < secsize) {
|
|||
|
_sectorSize = secsize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
SimpleFtCompletionRoutine(
|
|||
|
IN PVOID CompletionContext,
|
|||
|
IN NTSTATUS Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is a simple completion routine that expects the CompletionContext
|
|||
|
to be a FT_COMPLETION_ROUTINE_CONTEXT. It decrements the ref count and
|
|||
|
consolidates all of the status codes. When the ref count goes to zero it
|
|||
|
call the original completion routine with the result.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CompletionContext - Supplies the completion context.
|
|||
|
|
|||
|
Status - Supplies the status of the request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
|
|||
|
KIRQL oldIrql;
|
|||
|
LONG count;
|
|||
|
|
|||
|
completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT) CompletionContext;
|
|||
|
|
|||
|
KeAcquireSpinLock(&completionContext->SpinLock, &oldIrql);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status) &&
|
|||
|
FtpIsWorseStatus(Status, completionContext->Status)) {
|
|||
|
|
|||
|
completionContext->Status = Status;
|
|||
|
}
|
|||
|
|
|||
|
count = --completionContext->RefCount;
|
|||
|
|
|||
|
KeReleaseSpinLock(&completionContext->SpinLock, oldIrql);
|
|||
|
|
|||
|
if (!count) {
|
|||
|
completionContext->CompletionRoutine(completionContext->Context,
|
|||
|
completionContext->Status);
|
|||
|
ExFreePool(completionContext);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
COMPOSITE_FT_VOLUME::StartSyncOperations(
|
|||
|
IN FT_COMPLETION_ROUTINE CompletionRoutine,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine restarts any regenerate and initialize requests that were
|
|||
|
suspended because of a reboot. The volume examines the member state of
|
|||
|
all of its constituents and restarts any regenerations pending.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CompletionRoutine - Supplies the completion routine.
|
|||
|
|
|||
|
Context - Supplies the context for the completion routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
|
|||
|
ExAllocatePool(NonPagedPool,
|
|||
|
sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
|
|||
|
if (!completionContext) {
|
|||
|
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeSpinLock(&completionContext->SpinLock);
|
|||
|
completionContext->Status = STATUS_SUCCESS;
|
|||
|
completionContext->RefCount = _arraySize;
|
|||
|
completionContext->CompletionRoutine = CompletionRoutine;
|
|||
|
completionContext->Context = Context;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
GetMember(i)->StartSyncOperations(SimpleFtCompletionRoutine,
|
|||
|
completionContext);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
COMPOSITE_FT_VOLUME::Regenerate(
|
|||
|
IN OUT PFT_VOLUME SpareVolume,
|
|||
|
IN FT_COMPLETION_ROUTINE CompletionRoutine,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine uses the given SpareVolume to rebuild after a
|
|||
|
device failure. This routine returns FALSE if the SpareVolume
|
|||
|
is not large enough or if this volume does not support
|
|||
|
any redundancy. Returning TRUE from this routine implies that
|
|||
|
the CompletionRoutine will be called when the operation is
|
|||
|
complete.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SpareVolume - Supplies a spare volume onto which to rebuild.
|
|||
|
|
|||
|
CompletionRoutine - Supplies the completion routine.
|
|||
|
|
|||
|
Context - Supplies the context for the completion routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE - Rebuild is not appropriate for this volume or the given
|
|||
|
SpareVolume is not appropriate for a rebuild.
|
|||
|
|
|||
|
TRUE - The rebuild operation has been kicked off, the completion
|
|||
|
routine will be called when the operation is complete.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
if (GetMember(i)->Regenerate(SpareVolume, CompletionRoutine, Context)) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
COMPOSITE_FT_VOLUME::FlushBuffers(
|
|||
|
IN FT_COMPLETION_ROUTINE CompletionRoutine,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine flushes all buffers. This routine is called before a
|
|||
|
shutdown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CompletionRoutine - Supplies the routine to be called when the operation
|
|||
|
completes.
|
|||
|
|
|||
|
Context - Supplies the completion routine context.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
|
|||
|
ExAllocatePool(NonPagedPool,
|
|||
|
sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
|
|||
|
if (!completionContext) {
|
|||
|
CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
KeInitializeSpinLock(&completionContext->SpinLock);
|
|||
|
completionContext->Status = STATUS_SUCCESS;
|
|||
|
completionContext->RefCount = _arraySize;
|
|||
|
completionContext->CompletionRoutine = CompletionRoutine;
|
|||
|
completionContext->Context = Context;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
GetMember(i)->FlushBuffers(SimpleFtCompletionRoutine,
|
|||
|
completionContext);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
COMPOSITE_FT_VOLUME::IsPartition(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns FALSE since this volume is not a partition.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
COMPOSITE_FT_VOLUME::QueryNumberOfMembers(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the number of member volumes in this composite
|
|||
|
volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The number of member volumes.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return _arraySize;
|
|||
|
}
|
|||
|
|
|||
|
PFT_VOLUME
|
|||
|
COMPOSITE_FT_VOLUME::GetMember(
|
|||
|
IN ULONG MemberNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the 'MemberNumber'th member of this volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemberNumber - Supplies the zero based member number desired.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the 'MemberNumber'th member.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KIRQL irql;
|
|||
|
PFT_VOLUME r;
|
|||
|
|
|||
|
ASSERT(MemberNumber < _arraySize);
|
|||
|
|
|||
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|||
|
r = _volumeArray[MemberNumber];
|
|||
|
KeReleaseSpinLock(&_spinLock, irql);
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
COMPOSITE_FT_VOLUME::QuerySectorSize(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the sector size for the volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The volume sector size in bytes.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return _sectorSize;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
COMPOSITE_FT_VOLUME::QueryAlignmentRequirement(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the alignment requirement for this volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The alignment requirement.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i, a;
|
|||
|
|
|||
|
a = 0;
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
a |= GetMember(i)->QueryAlignmentRequirement();
|
|||
|
}
|
|||
|
|
|||
|
return a;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
COMPOSITE_FT_VOLUME::SetFtBitInPartitionType(
|
|||
|
IN BOOLEAN Value,
|
|||
|
IN BOOLEAN SpecialBitValue
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets (or resets) the high bit (bit 0x80) in the partition type in
|
|||
|
the MBR to indicate that this is (or is not) an FT partition.
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Value - Supplies the value to set the FT bit to.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None - If this routine fails then noone really cares.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
GetMember(i)->SetFtBitInPartitionType(Value, SpecialBitValue);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PPARTITION
|
|||
|
COMPOSITE_FT_VOLUME::FindPartition(
|
|||
|
IN ULONG DiskNumber,
|
|||
|
IN ULONG PartitionNumber
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns whether or not the given partition is contained
|
|||
|
by this volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DiskNumber - Supplies the disk number for the partition.
|
|||
|
|
|||
|
PartitionNumber - Supplies the partition number of the partition.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NULL - The requested partition is not contained by this volume.
|
|||
|
|
|||
|
Otherwise - A pointer to the requested partition.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
PPARTITION p;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
p = GetMember(i)->FindPartition(DiskNumber, PartitionNumber);
|
|||
|
if (p) {
|
|||
|
return p;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
PPARTITION
|
|||
|
COMPOSITE_FT_VOLUME::FindPartition(
|
|||
|
IN ULONG Signature,
|
|||
|
IN LONGLONG Offset
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns whether or not the given partition is contained
|
|||
|
by this volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Signature - Supplies the disk signature for the partition.
|
|||
|
|
|||
|
Offset - Supplies the partition offset of the partition.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NULL - The requested partition is not contained by this volume.
|
|||
|
|
|||
|
Otherwise - A pointer to the requested partition.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
PPARTITION p;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
p = GetMember(i)->FindPartition(Signature, Offset);
|
|||
|
if (p) {
|
|||
|
return p;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
COMPOSITE_FT_VOLUME::OrphanPartition(
|
|||
|
IN PPARTITION Partition
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine orphans the given partition if possible. The partition is
|
|||
|
not orphaned unless the FT_VOLUME has redundancy built in to it.
|
|||
|
If the partition cannot be orphaned then this routine returns FALSE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Partition - Supplies the partition to orphan.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE - The given partition was not orphaned.
|
|||
|
|
|||
|
TRUE - The given partition was orphaned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i = 0; i < _arraySize; i++) {
|
|||
|
if (GetMember(i)->OrphanPartition(Partition)) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
COMPOSITE_FT_VOLUME::~COMPOSITE_FT_VOLUME(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Routine called to cleanup resources being used by the object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (_volumeArray) {
|
|||
|
ExFreePool(_volumeArray);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
COMPOSITE_FT_VOLUME::SetMember(
|
|||
|
IN ULONG MemberNumber,
|
|||
|
IN PFT_VOLUME NewVolume
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the 'MemberNumber'th member of this volume.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MemberNumber - Supplies the zero based member number to set.
|
|||
|
|
|||
|
NewVolume - Supplies the new member volume.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KIRQL irql;
|
|||
|
|
|||
|
ASSERT(MemberNumber < _arraySize);
|
|||
|
|
|||
|
KeAcquireSpinLock(&_spinLock, &irql);
|
|||
|
_volumeArray[MemberNumber] = NewVolume;
|
|||
|
KeReleaseSpinLock(&_spinLock, irql);
|
|||
|
}
|