mirror of https://github.com/lianthony/NT4.0
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.
1685 lines
42 KiB
1685 lines
42 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1994.
|
|
//
|
|
// File: ft.cxx
|
|
//
|
|
// Contents: This module contains FT support routines for Disk Administrator
|
|
//
|
|
// History: 15-Nov-91 TedM Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "ft.hxx"
|
|
#include "nt.hxx"
|
|
#include "ntlow.hxx"
|
|
#include "windisk.hxx"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// This variable heads a linked list of ft object sets.
|
|
//
|
|
PFT_OBJECT_SET FtObjectList = NULL;
|
|
|
|
//
|
|
// Array of pointers to registry disk descriptors that we
|
|
// remember, ie, save for later use when a disk is not physically
|
|
// present on the machine.
|
|
//
|
|
|
|
PDISK_DESCRIPTION* RememberedDiskArray;
|
|
ULONG RememberedDiskCount;
|
|
|
|
PULONG DiskHadRegistryEntry;
|
|
|
|
|
|
#define MAX_FT_SET_TYPES 4
|
|
|
|
ULONG OrdinalToAllocate[MAX_FT_SET_TYPES] =
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
FdpDetermineDiskDescriptionSize(
|
|
PDISKSTATE DiskState
|
|
);
|
|
|
|
ULONG
|
|
FdpConstructDiskDescription(
|
|
IN PDISKSTATE DiskState,
|
|
OUT PDISK_DESCRIPTION DiskDescription
|
|
);
|
|
|
|
VOID
|
|
FdpRememberDisk(
|
|
IN PDISK_DESCRIPTION DiskDescription
|
|
);
|
|
|
|
VOID
|
|
FdpInitializeMirrors(
|
|
VOID
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
VOID
|
|
MaintainOrdinalTables(
|
|
IN FT_TYPE FtType,
|
|
IN ULONG Ordinal
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Maintain the minimum and maximum Ordinal value recorded.
|
|
|
|
Arguments:
|
|
|
|
FtType - the type of the FT set.
|
|
Ordinal - the in use FtGroup (or ordinal) number
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Ordinal > OrdinalToAllocate[FtType])
|
|
{
|
|
OrdinalToAllocate[FtType] = Ordinal;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
FdftNextOrdinal(
|
|
IN FT_TYPE FtType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a number that will uniquely identify the FT set
|
|
from other sets of the same type. This number must be unique
|
|
from any given or used by FT sets of the same type due to
|
|
requirements of FT dynamic partitioning.
|
|
|
|
Arguments:
|
|
|
|
FtType - The type of the FT set.
|
|
|
|
Return Value:
|
|
|
|
The FtGroup number -- called an "ordinal" in the internal
|
|
structures.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD ordinal;
|
|
PFT_OBJECT_SET ftSet;
|
|
BOOL looping;
|
|
|
|
// The Ordinal value is going to be used as an FtGroup number
|
|
// FtGroups are USHORTs so don't wrap on the Ordinal. Try
|
|
// to keep the next ordinal in the largest opening range, that
|
|
// is if the minimum found is > half way through a USHORT, start
|
|
// the ordinals over at zero.
|
|
|
|
if (OrdinalToAllocate[FtType] > 0x7FFE)
|
|
{
|
|
OrdinalToAllocate[FtType] = 0;
|
|
}
|
|
|
|
ordinal = OrdinalToAllocate[FtType];
|
|
++ordinal;
|
|
|
|
do
|
|
{
|
|
looping = FALSE;
|
|
ftSet = FtObjectList;
|
|
while (NULL != ftSet)
|
|
{
|
|
if ((ftSet->Type == FtType) && (ftSet->Ordinal == ordinal))
|
|
{
|
|
ordinal++;
|
|
looping = TRUE;
|
|
break;
|
|
}
|
|
ftSet = ftSet->Next;
|
|
}
|
|
} while (looping);
|
|
|
|
OrdinalToAllocate[FtType] = (ordinal + 1);
|
|
return ordinal;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FdftCreateFtObjectSet(
|
|
IN FT_TYPE FtType,
|
|
IN PREGION_DESCRIPTOR* RegionArray,
|
|
IN DWORD RegionCount,
|
|
IN FT_SET_STATUS FtStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the FT set structures for the give collection of
|
|
region pointers.
|
|
|
|
Arguments:
|
|
|
|
FtType
|
|
Regions
|
|
RegionCount
|
|
Status
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD regionIndex;
|
|
PFT_OBJECT_SET ftSet;
|
|
PFT_OBJECT ftObject;
|
|
|
|
ftSet = (PFT_OBJECT_SET)Malloc(sizeof(FT_OBJECT_SET));
|
|
|
|
//
|
|
// Figure out an ordinal for the new object set.
|
|
//
|
|
|
|
ftSet->Ordinal = FdftNextOrdinal(FtType);
|
|
ftSet->Type = FtType;
|
|
ftSet->Members = NULL;
|
|
ftSet->Member0 = NULL;
|
|
ftSet->Status = FtStatus;
|
|
|
|
//
|
|
// Link the new object set into the list.
|
|
|
|
ftSet->Next = FtObjectList;
|
|
FtObjectList = ftSet;
|
|
|
|
//
|
|
// For each region in the set, associate the ft info with it.
|
|
//
|
|
|
|
for (regionIndex=0; regionIndex<RegionCount; regionIndex++)
|
|
{
|
|
ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
|
|
|
|
//
|
|
// If this is a creation of a stripe set with parity, then
|
|
// we must mark the 0th item 'Initializing' instead of 'Healthy'.
|
|
//
|
|
|
|
if ((regionIndex == 0)
|
|
&& (FtType == StripeWithParity)
|
|
&& (FtStatus == FtSetNewNeedsInitialization))
|
|
{
|
|
ftObject->State = Initializing;
|
|
}
|
|
else
|
|
{
|
|
ftObject->State = Healthy;
|
|
}
|
|
|
|
if (0 == regionIndex)
|
|
{
|
|
ftSet->Member0 = ftObject;
|
|
}
|
|
|
|
ftObject->Set = ftSet;
|
|
ftObject->MemberIndex = regionIndex;
|
|
ftObject->Next = ftSet->Members;
|
|
ftSet->Members = ftObject;
|
|
|
|
SET_FT_OBJECT(RegionArray[regionIndex], ftObject);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
FdftUpdateFtObjectSet(
|
|
IN PFT_OBJECT_SET FtSet,
|
|
IN FT_SET_STATUS SetState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given an FT set, go back to the registry information and
|
|
update the state of the members with the state in the registry.
|
|
|
|
NOTE: The following condition may exist. It is possible for
|
|
the FtDisk driver to return that the set is in an initializing
|
|
or regenerating state and not have this fact reflected in the
|
|
registry. This can happen when the system has crashed and
|
|
on restart the FtDisk driver started the regeneration of the
|
|
check data (parity).
|
|
|
|
Arguments:
|
|
|
|
FtSet - the set to update.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the set state provided has a strong likelyhood of being correct
|
|
FALSE if the NOTE condition above is occuring.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN allHealthy = TRUE;
|
|
PFT_OBJECT ftObject;
|
|
PDISK_REGISTRY diskRegistry;
|
|
PDISK_PARTITION partition;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
DWORD ec;
|
|
ULONG diskIndex,
|
|
partitionIndex;
|
|
|
|
ec = MyDiskRegistryGet(&diskRegistry);
|
|
if (ec != NO_ERROR)
|
|
{
|
|
// No registry information.
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
diskDescription = diskRegistry->Disks;
|
|
for (diskIndex=0; diskIndex<diskRegistry->NumberOfDisks; diskIndex++)
|
|
{
|
|
for (partitionIndex=0;
|
|
partitionIndex < diskDescription->NumberOfPartitions;
|
|
partitionIndex++)
|
|
{
|
|
partition = &diskDescription->Partitions[partitionIndex];
|
|
if ( (partition->FtType == FtSet->Type)
|
|
&& (partition->FtGroup == (USHORT) FtSet->Ordinal))
|
|
{
|
|
// Have a match for a partition within this set.
|
|
// Find the region descriptor for this partition and
|
|
// update its state accordingly.
|
|
|
|
for (ftObject = FtSet->Members;
|
|
NULL != ftObject;
|
|
ftObject = ftObject->Next)
|
|
{
|
|
if (ftObject->MemberIndex == (ULONG) partition->FtMember)
|
|
{
|
|
ftObject->State = partition->FtState;
|
|
break;
|
|
}
|
|
|
|
if (partition->FtState != Healthy)
|
|
{
|
|
allHealthy = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
|
}
|
|
|
|
Free(diskRegistry);
|
|
|
|
if ((allHealthy) && (SetState != FtSetHealthy))
|
|
{
|
|
// This is a condition where the system must be
|
|
// updating the check data for redundant sets.
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FdftDeleteFtObjectSet(
|
|
IN PFT_OBJECT_SET FtSet,
|
|
IN BOOL OffLineDisksOnly
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an ft set, or rather its internal representation as a linked
|
|
list of ft member structures.
|
|
|
|
Arguments:
|
|
|
|
FtSet - supplies pointer to ft set structure for set to delete.
|
|
|
|
OffLineDisksOnly - if TRUE, then do not delete the set but instead
|
|
scan remembered disks for members of the set and remove such members.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFT_OBJECT ftObject = FtSet->Members;
|
|
PFT_OBJECT nextFtObject;
|
|
PFT_OBJECT_SET ftSetTemp;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PDISK_PARTITION diskPartition;
|
|
ULONG partitionCount;
|
|
ULONG size;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
//
|
|
// Locate any members of the ft set on remembered disks and
|
|
// remove the entries for such partitions.
|
|
//
|
|
|
|
for (i=0; i<RememberedDiskCount; i++)
|
|
{
|
|
diskDescription = RememberedDiskArray[i];
|
|
partitionCount = diskDescription->NumberOfPartitions;
|
|
|
|
for (j=0; j<partitionCount; j++)
|
|
{
|
|
diskPartition = &diskDescription->Partitions[j];
|
|
|
|
if ( (diskPartition->FtType == FtSet->Type)
|
|
&& (diskPartition->FtGroup == (USHORT)FtSet->Ordinal))
|
|
{
|
|
//
|
|
// Found a member of the ft set being deleted on a
|
|
// remembered disk. Remove the partition from the
|
|
// remembered disk.
|
|
//
|
|
|
|
RtlMoveMemory( diskPartition,
|
|
diskPartition+1,
|
|
(partitionCount - j - 1) * sizeof(DISK_PARTITION)
|
|
);
|
|
|
|
partitionCount--;
|
|
j--;
|
|
}
|
|
}
|
|
|
|
if (partitionCount != diskDescription->NumberOfPartitions)
|
|
{
|
|
diskDescription->NumberOfPartitions = (USHORT)partitionCount;
|
|
|
|
size = sizeof(DISK_DESCRIPTION);
|
|
if (partitionCount > 1)
|
|
{
|
|
size += (partitionCount - 1) * sizeof(DISK_PARTITION);
|
|
}
|
|
RememberedDiskArray[i] = (PDISK_DESCRIPTION)Realloc(RememberedDiskArray[i], size);
|
|
}
|
|
}
|
|
|
|
if (OffLineDisksOnly)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// First, free all members of the set
|
|
//
|
|
|
|
while (NULL != ftObject)
|
|
{
|
|
nextFtObject = ftObject->Next;
|
|
Free(ftObject);
|
|
ftObject = nextFtObject;
|
|
}
|
|
|
|
//
|
|
// now, remove the set from the linked list of sets.
|
|
//
|
|
|
|
if (FtObjectList == FtSet)
|
|
{
|
|
FtObjectList = FtSet->Next;
|
|
}
|
|
else
|
|
{
|
|
ftSetTemp = FtObjectList;
|
|
while (1)
|
|
{
|
|
FDASSERT(ftSetTemp);
|
|
if (ftSetTemp == NULL)
|
|
{
|
|
break;
|
|
}
|
|
if (ftSetTemp->Next == FtSet)
|
|
{
|
|
ftSetTemp->Next = FtSet->Next;
|
|
break;
|
|
}
|
|
ftSetTemp = ftSetTemp->Next;
|
|
}
|
|
}
|
|
Free(FtSet);
|
|
}
|
|
|
|
VOID
|
|
FdftExtendFtObjectSet(
|
|
IN OUT PFT_OBJECT_SET FtSet,
|
|
IN OUT PREGION_DESCRIPTOR* RegionArray,
|
|
IN DWORD RegionCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds regions to an existing FT-set.
|
|
|
|
Arguments:
|
|
|
|
FtSet -- Supplies the set to extend.
|
|
RegionArray -- Supplies the regions to add to the set. Note
|
|
that these regions are updated with the FT
|
|
information.
|
|
RegionCount -- Supplies the number of regions to add.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PFT_OBJECT ftObject;
|
|
DWORD i;
|
|
DWORD startingIndex;
|
|
|
|
// Determine the starting member index for the new regions.
|
|
// It is the greatest of the existing member indices plus one.
|
|
//
|
|
startingIndex = 0;
|
|
|
|
for (ftObject = FtSet->Members;
|
|
NULL != ftObject;
|
|
ftObject = ftObject->Next)
|
|
{
|
|
if (ftObject->MemberIndex > startingIndex)
|
|
{
|
|
startingIndex = ftObject->MemberIndex;
|
|
}
|
|
}
|
|
|
|
startingIndex++;
|
|
|
|
// Associate the ft-set's information with each of the
|
|
// new regions.
|
|
//
|
|
for (i = 0; i < RegionCount; i++)
|
|
{
|
|
ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
|
|
|
|
ftObject->Set = FtSet;
|
|
ftObject->MemberIndex = startingIndex + i;
|
|
ftObject->Next = FtSet->Members;
|
|
ftObject->State = Healthy;
|
|
FtSet->Members = ftObject;
|
|
|
|
SET_FT_OBJECT(RegionArray[i], ftObject);
|
|
}
|
|
|
|
FtSet->Status = FtSetExtended;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ActualPartitionCount(
|
|
IN PDISKSTATE DiskState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk, this routine counts the number of partitions on it.
|
|
The number of partitions is the number of regions that appear in
|
|
the NT name space (ie, the maximum value of <x> in
|
|
\device\harddiskn\partition<x>).
|
|
|
|
Arguments:
|
|
|
|
DiskState - descriptor for the disk in question.
|
|
|
|
Return Value:
|
|
|
|
Partition count (may be 0).
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
ULONG partitionCount = 0;
|
|
PREGION_DESCRIPTOR region;
|
|
|
|
for (i=0; i<DiskState->RegionCount; i++)
|
|
{
|
|
region = &DiskState->RegionArray[i];
|
|
if ((region->SysID != PARTITION_ENTRY_UNUSED)
|
|
&& !IsExtended(region->SysID)
|
|
&& IsRecognizedPartition(region->SysID))
|
|
{
|
|
partitionCount++;
|
|
}
|
|
}
|
|
return partitionCount;
|
|
}
|
|
|
|
|
|
PDISKSTATE
|
|
LookUpDiskBySignature(
|
|
IN ULONG Signature
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will look through the disk descriptors created by the
|
|
fdisk back end looking for a disk with a particular signature.
|
|
|
|
Arguments:
|
|
|
|
Signature - signature of disk to locate
|
|
|
|
Return Value:
|
|
|
|
Pointer to disk descriptor or NULL if no disk with the given signature
|
|
was found.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG diskNumber;
|
|
PDISKSTATE diskState;
|
|
|
|
for (diskNumber = 0; diskNumber < DiskCount; diskNumber++)
|
|
{
|
|
diskState = DiskArray[diskNumber];
|
|
if (diskState->Signature == Signature)
|
|
{
|
|
return diskState;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PREGION_DESCRIPTOR
|
|
LookUpPartition(
|
|
IN PDISKSTATE DiskState,
|
|
IN LARGE_INTEGER Offset,
|
|
IN LARGE_INTEGER Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will look through a region descriptor array for a
|
|
partition with a particular length and starting offset.
|
|
|
|
Arguments:
|
|
|
|
DiskState - disk on which to locate the partition
|
|
Offset - offset of partition on the disk to find
|
|
Length - size of the partition to find
|
|
|
|
Return Value:
|
|
|
|
Pointer to region descriptor or NULL if no such partition on that disk
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG regionIndex;
|
|
ULONG maxRegion = DiskState->RegionCount;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
LARGE_INTEGER offset;
|
|
LARGE_INTEGER length;
|
|
|
|
for (regionIndex = 0; regionIndex < maxRegion; regionIndex++)
|
|
{
|
|
regionDescriptor = &DiskState->RegionArray[regionIndex];
|
|
|
|
if ((regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
|
|
&& !IsExtended(regionDescriptor->SysID))
|
|
{
|
|
offset = FdGetExactOffset(regionDescriptor);
|
|
length = FdGetExactSize(regionDescriptor, FALSE);
|
|
|
|
if ( (offset.LowPart == Offset.LowPart)
|
|
&& (offset.HighPart == Offset.HighPart)
|
|
&& (length.LowPart == Length.LowPart)
|
|
&& (length.HighPart == Length.HighPart))
|
|
{
|
|
return regionDescriptor;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
AddObjectToSet(
|
|
IN PFT_OBJECT FtObjectToAdd,
|
|
IN FT_TYPE FtType,
|
|
IN USHORT FtGroup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the FtSet for that this object belongs to and insert
|
|
it into the chain of members. If the set cannot be found
|
|
in the existing collection of sets, create a new one.
|
|
|
|
Arguments:
|
|
|
|
FtObjectToAdd - the object point to be added.
|
|
FtType - the type of the FT set.
|
|
FtGroup - group for this object.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PFT_OBJECT_SET ftSet = FtObjectList;
|
|
|
|
while (NULL != ftSet)
|
|
{
|
|
if ((ftSet->Type == FtType) && (ftSet->Ordinal == FtGroup))
|
|
{
|
|
break;
|
|
}
|
|
ftSet = ftSet->Next;
|
|
}
|
|
|
|
if (NULL == ftSet)
|
|
{
|
|
//
|
|
// There is no such existing ft set. Create one.
|
|
//
|
|
|
|
ftSet = (PFT_OBJECT_SET)Malloc(sizeof(FT_OBJECT_SET));
|
|
|
|
ftSet->Status = FtSetHealthy;
|
|
ftSet->Type = FtType;
|
|
ftSet->Ordinal = FtGroup;
|
|
ftSet->Members = NULL;
|
|
ftSet->Next = FtObjectList;
|
|
ftSet->Member0 = NULL;
|
|
ftSet->NumberOfMembers = 0;
|
|
|
|
FtObjectList = ftSet;
|
|
}
|
|
|
|
FDASSERT(NULL != ftSet);
|
|
|
|
FtObjectToAdd->Next = ftSet->Members;
|
|
ftSet->Members = FtObjectToAdd;
|
|
++ftSet->NumberOfMembers;
|
|
FtObjectToAdd->Set = ftSet;
|
|
|
|
if (FtObjectToAdd->MemberIndex == 0)
|
|
{
|
|
ftSet->Member0 = FtObjectToAdd;
|
|
}
|
|
|
|
if (FtType == StripeWithParity || FtType == Mirror)
|
|
{
|
|
// Update the set's state based on the state of the new member:
|
|
//
|
|
switch (FtObjectToAdd->State)
|
|
{
|
|
case Healthy:
|
|
// Doesn't change state of set.
|
|
break;
|
|
|
|
case Regenerating:
|
|
ftSet->Status = (ftSet->Status == FtSetHealthy ||
|
|
ftSet->Status == FtSetRegenerating)
|
|
? FtSetRegenerating
|
|
: FtSetBroken;
|
|
break;
|
|
|
|
case Initializing:
|
|
ftSet->Status = (ftSet->Status == FtSetHealthy ||
|
|
ftSet->Status == FtSetInitializing)
|
|
? FtSetInitializing
|
|
: FtSetBroken;
|
|
break;
|
|
|
|
default:
|
|
// If only one member is bad, the set is recoverable;
|
|
// otherwise, it's broken.
|
|
//
|
|
ftSet->Status = (ftSet->Status == FtSetHealthy)
|
|
? FtSetRecoverable
|
|
: FtSetDisabled;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
InitializeFt(
|
|
IN BOOL DiskSignaturesCreated
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search the disk registry information to construct the FT
|
|
relationships in the system.
|
|
|
|
Arguments:
|
|
|
|
DiskSignaturesCreated - boolean to indicate that new disks
|
|
were located in the system.
|
|
|
|
Return Value:
|
|
|
|
An error code if the disk registry could not be obtained.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG disk;
|
|
ULONG partitionIndex;
|
|
ULONG partitionCount;
|
|
PDISK_REGISTRY diskRegistry;
|
|
PDISK_PARTITION diskPartition;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PDISKSTATE diskState;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
PFT_OBJECT ftObject;
|
|
DWORD ec;
|
|
BOOL configDiskChanged = FALSE;
|
|
BOOL configMissingDisk = FALSE;
|
|
BOOL configExtraDisk = FALSE;
|
|
BOOL anyDisksOffLine;
|
|
|
|
|
|
RememberedDiskArray = (PDISK_DESCRIPTION*)Malloc(0);
|
|
RememberedDiskCount = 0;
|
|
|
|
ec = MyDiskRegistryGet(&diskRegistry);
|
|
if (ec != NO_ERROR)
|
|
{
|
|
FDLOG((0, "InitializeFt: Error %u from MyDiskRegistryGet\n", ec));
|
|
|
|
return ec;
|
|
}
|
|
|
|
DiskHadRegistryEntry = (PULONG)Malloc(DiskCount * sizeof(ULONG));
|
|
memset(DiskHadRegistryEntry, 0, DiskCount * sizeof(ULONG));
|
|
|
|
diskDescription = diskRegistry->Disks;
|
|
|
|
for (disk = 0; disk < diskRegistry->NumberOfDisks; disk++)
|
|
{
|
|
//
|
|
// For the disk described in the registry, look up the
|
|
// corresponding actual disk found by the fdisk init code.
|
|
//
|
|
|
|
diskState = LookUpDiskBySignature(diskDescription->Signature);
|
|
|
|
if (NULL != diskState)
|
|
{
|
|
FDLOG(( 2,
|
|
"InitializeFt: disk w/ signature %08lx is disk #%u\n",
|
|
diskDescription->Signature,
|
|
diskState->Disk
|
|
));
|
|
|
|
DiskHadRegistryEntry[diskState->Disk]++;
|
|
|
|
partitionCount = ActualPartitionCount(diskState);
|
|
|
|
if (partitionCount != diskDescription->NumberOfPartitions)
|
|
{
|
|
FDLOG(( 1,
|
|
"InitializeFt: partition counts for disk %08lx don't match:\n",
|
|
diskState->Signature));
|
|
|
|
FDLOG((1, " Count from actual disk: %u\n", partitionCount));
|
|
FDLOG((1, " Count from registry : %u\n", diskDescription->NumberOfPartitions));
|
|
|
|
configDiskChanged = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// there's an entry in the registry that does not have a
|
|
// real disk to match. Remember this disk; if it has any
|
|
// FT partitions, we also want to display a message telling
|
|
// the user that something's missing.
|
|
//
|
|
FDLOG((1, "InitializeFt: Entry for disk w/ signature %08lx has no matching real disk\n", diskDescription->Signature));
|
|
|
|
for (partitionIndex = 0;
|
|
partitionIndex < diskDescription->NumberOfPartitions;
|
|
partitionIndex++)
|
|
{
|
|
diskPartition = &diskDescription->Partitions[partitionIndex];
|
|
if (diskPartition->FtType != NotAnFtMember)
|
|
{
|
|
// This disk has an FT partition, so Windisk will
|
|
// want to tell the user that some disks are missing.
|
|
//
|
|
configMissingDisk = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FdpRememberDisk(diskDescription);
|
|
}
|
|
|
|
for (partitionIndex = 0;
|
|
partitionIndex < diskDescription->NumberOfPartitions;
|
|
partitionIndex++)
|
|
{
|
|
diskPartition = &diskDescription->Partitions[partitionIndex];
|
|
|
|
regionDescriptor = NULL;
|
|
|
|
if (NULL != diskState)
|
|
{
|
|
regionDescriptor = LookUpPartition(diskState,
|
|
diskPartition->StartingOffset,
|
|
diskPartition->Length
|
|
);
|
|
}
|
|
|
|
//
|
|
// At this point one of three conditions exists.
|
|
//
|
|
// 1. There is no disk related to this registry information
|
|
// diskState == NULL && regionDescriptor == NULL
|
|
// 2. There is a disk, but no partition related to this information
|
|
// diskState != NULL && regionDescriptor == NULL
|
|
// 3. There is a disk and a partition related to this information
|
|
// diskState != NULL && regionDescriptor != NULL
|
|
//
|
|
// In any of these conditions, if the registry entry is part
|
|
// of an FT set and FT object must be created.
|
|
//
|
|
// that corresponds to a partition's entry in the
|
|
// disk registry database.
|
|
//
|
|
|
|
if (diskPartition->FtType != NotAnFtMember)
|
|
{
|
|
ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
|
|
ftObject->Next = NULL;
|
|
ftObject->Set = NULL;
|
|
ftObject->MemberIndex = diskPartition->FtMember;
|
|
ftObject->State = diskPartition->FtState;
|
|
|
|
// if a partition was actually found there will be a
|
|
// regionDescriptor that needs to be updated.
|
|
|
|
if (regionDescriptor && regionDescriptor->PersistentData)
|
|
{
|
|
FT_SET_STATUS setState;
|
|
ULONG numberOfMembers;
|
|
|
|
SET_FT_OBJECT(regionDescriptor, ftObject);
|
|
|
|
// Before the drive letter is moved into the region
|
|
// data, be certain that the FT volume exists at this
|
|
// drive letter.
|
|
|
|
LowFtVolumeStatusByLetter(diskPartition->DriveLetter,
|
|
&setState,
|
|
&numberOfMembers);
|
|
|
|
// If the numberOfMembers gets set to 1 then
|
|
// this letter is not the letter for the FT set,
|
|
// but rather a default letter assigned because the
|
|
// FT sets letter could not be assigned.
|
|
|
|
if (numberOfMembers > 1)
|
|
{
|
|
PERSISTENT_DATA(regionDescriptor)->DriveLetter = diskPartition->DriveLetter;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// There is no region for this partition
|
|
// so update the set state.
|
|
|
|
ftObject->State = Orphaned;
|
|
}
|
|
|
|
//
|
|
// Now place the ft object in the correct set,
|
|
// creating the set if necessary.
|
|
//
|
|
|
|
AddObjectToSet(
|
|
ftObject,
|
|
diskPartition->FtType,
|
|
diskPartition->FtGroup);
|
|
|
|
MaintainOrdinalTables(
|
|
diskPartition->FtType,
|
|
(ULONG) diskPartition->FtGroup);
|
|
}
|
|
}
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
|
|
}
|
|
|
|
Free(diskRegistry);
|
|
|
|
//
|
|
// Check to see if every disk found by the fdisk back end has a
|
|
// corresponding registry entry.
|
|
//
|
|
|
|
for (disk=0; disk<DiskCount; disk++)
|
|
{
|
|
if (DiskArray[disk]->OffLine)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!DiskHadRegistryEntry[disk] && !IsRemovable(disk))
|
|
{
|
|
//
|
|
// a real disk does not have a matching registry entry.
|
|
//
|
|
|
|
FDLOG((1, "InitializeFt: Disk %u does not have a registry entry (disk sig = %08lx)\n", disk, DiskArray[disk]->Signature));
|
|
|
|
configExtraDisk = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine whether any disks are off line
|
|
//
|
|
|
|
anyDisksOffLine = FALSE;
|
|
for (disk=0; disk<DiskCount; disk++)
|
|
{
|
|
if (DiskArray[disk]->OffLine)
|
|
{
|
|
anyDisksOffLine = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (configMissingDisk || anyDisksOffLine)
|
|
{
|
|
WarningDialog(MSG_CONFIG_MISSING_DISK);
|
|
}
|
|
|
|
if (configDiskChanged)
|
|
{
|
|
RegistryChanged = TRUE;
|
|
WarningDialog(MSG_CONFIG_DISK_CHANGED);
|
|
}
|
|
|
|
if (configExtraDisk || DiskSignaturesCreated)
|
|
{
|
|
BOOL badConfigSet = FALSE;
|
|
|
|
WarningDialog(MSG_CONFIG_EXTRA_DISK);
|
|
|
|
//
|
|
// Update ft signature on each disk for which a new signature
|
|
// was created. and update registry for each disk with
|
|
// DiskHadRegistryEntry[Disk] == 0.
|
|
//
|
|
|
|
for (disk=0; disk<DiskCount; disk++)
|
|
{
|
|
BOOL b1 = TRUE;
|
|
BOOL b2 = TRUE;
|
|
|
|
if (DiskArray[disk]->OffLine)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (DiskArray[disk]->SigWasCreated)
|
|
{
|
|
TCHAR name[100];
|
|
wsprintf(name, DiskN, disk);
|
|
if (IDYES == ConfirmationDialog(
|
|
MSG_NO_SIGNATURE,
|
|
MB_ICONEXCLAMATION | MB_YESNO,
|
|
name))
|
|
{
|
|
b1 = (MasterBootCode(disk, DiskArray[disk]->Signature, TRUE, TRUE) == NO_ERROR);
|
|
}
|
|
else
|
|
{
|
|
DiskArray[disk]->OffLine = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!DiskHadRegistryEntry[disk])
|
|
{
|
|
ULONG size;
|
|
|
|
size = FdpDetermineDiskDescriptionSize(DiskArray[disk]);
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)Malloc(size);
|
|
|
|
FdpConstructDiskDescription(DiskArray[disk], diskDescription);
|
|
|
|
FDLOG((2,
|
|
"InitializeFt: Adding new disk %08lx to registry.\n",
|
|
diskDescription->Signature));
|
|
LOG_ONE_DISK_REGISTRY_DISK_ENTRY("InitializeFt", diskDescription);
|
|
|
|
b2 = (EC(DiskRegistryAddNewDisk(diskDescription)) == NO_ERROR);
|
|
|
|
Free(diskDescription);
|
|
}
|
|
|
|
if (!(b1 && b2))
|
|
{
|
|
badConfigSet = TRUE;
|
|
}
|
|
}
|
|
|
|
if (badConfigSet)
|
|
{
|
|
ErrorDialog(MSG_BAD_CONFIG_SET);
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
NewConfigurationRequiresFt(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search the diskstate and region arrays to determine if a single
|
|
FtDisk element (i.e. stripe, stripe set with parity, mirror or
|
|
volume set) is contained in the configuration.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if the new configuration requires the FtDisk driver.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG disk,
|
|
region;
|
|
PDISKSTATE diskState;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
|
|
// Look at all disks in the system.
|
|
|
|
for (disk = 0; disk < DiskCount; disk++)
|
|
{
|
|
diskState = DiskArray[disk];
|
|
if (diskState->OffLine || IsDiskRemovable[disk])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check each region on the disk.
|
|
|
|
for (region = 0; region < diskState->RegionCount; region++)
|
|
{
|
|
regionDescriptor = &diskState->RegionArray[region];
|
|
if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
|
|
&& !IsExtended(regionDescriptor->SysID)
|
|
&& IsRecognizedPartition(regionDescriptor->SysID))
|
|
{
|
|
// If a single region has an FT Object, then FT
|
|
// is required and the search may be stopped.
|
|
|
|
if (NULL != GET_FT_OBJECT(regionDescriptor))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// no FtObject was found.
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
SaveFt(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine walks all of the internal structures and creates the
|
|
interface structure for the DiskRegistry interface.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
success/failure code. NO_ERROR is success.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
ULONG disk;
|
|
ULONG partitionIndex;
|
|
ULONG size;
|
|
PDISK_REGISTRY diskRegistry;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PBYTE start, end;
|
|
DWORD ec;
|
|
ULONG offLineDiskCount;
|
|
ULONG removableDiskCount;
|
|
|
|
//
|
|
// First count partitions and disks so we can allocate a structure
|
|
// of the correct size.
|
|
//
|
|
|
|
size = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
|
|
offLineDiskCount = 0;
|
|
removableDiskCount = 0;
|
|
|
|
for (i=0; i<DiskCount; i++)
|
|
{
|
|
if (DiskArray[i]->OffLine)
|
|
{
|
|
offLineDiskCount++;
|
|
}
|
|
else if (IsDiskRemovable[i])
|
|
{
|
|
removableDiskCount++;
|
|
}
|
|
else
|
|
{
|
|
size += FdpDetermineDiskDescriptionSize(DiskArray[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Account for remembered disks.
|
|
//
|
|
|
|
size += RememberedDiskCount * sizeof(DISK_DESCRIPTION);
|
|
for (i=0; i<RememberedDiskCount; i++)
|
|
{
|
|
if (RememberedDiskArray[i]->NumberOfPartitions > 1)
|
|
{
|
|
size += (RememberedDiskArray[i]->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
|
|
}
|
|
}
|
|
|
|
diskRegistry = (PDISK_REGISTRY)Malloc(size);
|
|
|
|
diskRegistry->NumberOfDisks = (USHORT)( DiskCount
|
|
+ RememberedDiskCount
|
|
- offLineDiskCount
|
|
- removableDiskCount
|
|
);
|
|
diskRegistry->ReservedShort = 0;
|
|
|
|
diskDescription = diskRegistry->Disks;
|
|
for (disk=0; disk<DiskCount; disk++)
|
|
{
|
|
if (DiskArray[disk]->OffLine || IsDiskRemovable[disk])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
partitionIndex = FdpConstructDiskDescription(DiskArray[disk], diskDescription);
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partitionIndex];
|
|
}
|
|
|
|
//
|
|
// Toss in remembered disks.
|
|
//
|
|
|
|
for (i=0; i<RememberedDiskCount; i++)
|
|
{
|
|
// Compute the beginning and end of this remembered disk's
|
|
// Disk Description:
|
|
//
|
|
partitionIndex = RememberedDiskArray[i]->NumberOfPartitions;
|
|
start = (PBYTE)RememberedDiskArray[i];
|
|
end = (PBYTE)&(RememberedDiskArray[i]->Partitions[partitionIndex]);
|
|
|
|
RtlMoveMemory(diskDescription, RememberedDiskArray[i], end - start);
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partitionIndex];
|
|
}
|
|
|
|
LOG_DISK_REGISTRY("SaveFt", diskRegistry);
|
|
|
|
ec = EC(DiskRegistrySet(diskRegistry));
|
|
|
|
Free(diskRegistry);
|
|
|
|
if (ec == NO_ERROR)
|
|
{
|
|
FdpInitializeMirrors();
|
|
}
|
|
|
|
return ec;
|
|
}
|
|
|
|
|
|
ULONG
|
|
FdpDetermineDiskDescriptionSize(
|
|
PDISKSTATE DiskState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a pointer to a disk and determines how much
|
|
memory is needed to contain the description of the disk by
|
|
counting the number of partitions on the disk and multiplying
|
|
the appropriate counts by the appropriate size of the structures.
|
|
|
|
Arguments:
|
|
|
|
DiskState - the disk in question.
|
|
|
|
Return Value:
|
|
|
|
The memory size needed to contain all of the information on the disk.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG partitionCount;
|
|
ULONG size;
|
|
|
|
if (DiskState->OffLine)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size = sizeof(DISK_DESCRIPTION);
|
|
partitionCount = ActualPartitionCount(DiskState);
|
|
size += (partitionCount ? partitionCount-1 : 0) * sizeof(DISK_PARTITION);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
ULONG
|
|
FdpConstructDiskDescription(
|
|
IN PDISKSTATE DiskState,
|
|
OUT PDISK_DESCRIPTION DiskDescription
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a disk state pointer as input, construct the FtRegistry
|
|
structure to describe the partitions on the disk.
|
|
|
|
Arguments:
|
|
|
|
DiskState - the disk for which to construct the information
|
|
DiskDescription - the memory location where the registry
|
|
structure is to be created.
|
|
|
|
Return Value:
|
|
|
|
The number of partitions described in the DiskDescription.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG partitionIndex;
|
|
ULONG regionIndex;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
PDISK_PARTITION diskPartition;
|
|
WCHAR driveLetter;
|
|
BOOLEAN assignDriveLetter;
|
|
PFT_OBJECT ftObject;
|
|
PFT_OBJECT_SET ftSet;
|
|
|
|
partitionIndex = 0;
|
|
|
|
for (regionIndex = 0; regionIndex < DiskState->RegionCount; regionIndex++)
|
|
{
|
|
regionDescriptor = &DiskState->RegionArray[regionIndex];
|
|
|
|
if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
|
|
&& !IsExtended(regionDescriptor->SysID)
|
|
&& IsRecognizedPartition(regionDescriptor->SysID))
|
|
{
|
|
diskPartition = &DiskDescription->Partitions[partitionIndex++];
|
|
|
|
diskPartition->StartingOffset = FdGetExactOffset(regionDescriptor);
|
|
diskPartition->Length = FdGetExactSize(regionDescriptor, FALSE);
|
|
diskPartition->LogicalNumber = (USHORT)regionDescriptor->PartitionNumber;
|
|
|
|
driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
|
|
switch (driveLetter)
|
|
{
|
|
case NO_DRIVE_LETTER_YET:
|
|
assignDriveLetter = TRUE;
|
|
driveLetter = L'\0';
|
|
break;
|
|
|
|
case NO_DRIVE_LETTER_EVER:
|
|
assignDriveLetter = FALSE;
|
|
driveLetter = L'\0';
|
|
break;
|
|
|
|
default:
|
|
assignDriveLetter = TRUE;
|
|
break;
|
|
}
|
|
|
|
diskPartition->DriveLetter = (UCHAR)driveLetter;
|
|
diskPartition->FtLength.LowPart = 0;
|
|
diskPartition->FtLength.HighPart = 0;
|
|
diskPartition->ReservedTwoLongs[0] = 0;
|
|
diskPartition->ReservedTwoLongs[1] = 0;
|
|
diskPartition->Modified = TRUE;
|
|
diskPartition->ReservedChars[0] = 0;
|
|
diskPartition->ReservedChars[1] = 0;
|
|
diskPartition->ReservedChars[2] = 0;
|
|
|
|
if (NULL != (ftObject = GET_FT_OBJECT(regionDescriptor)))
|
|
{
|
|
ftSet = ftObject->Set;
|
|
|
|
#if 0
|
|
|
|
// need to do something here, but currently this does not work.
|
|
|
|
PREGION_DESCRIPTOR tmpDescriptor;
|
|
STATUS_CODE status;
|
|
FT_SET_STATUS setState;
|
|
ULONG numberOfMembers;
|
|
|
|
tmpDescriptor = LocateRegionForFtObject(ftSet->Member0);
|
|
|
|
// Only update status if member zero is present.
|
|
// otherwise the status is know to be Orphaned or
|
|
// needs regeneration.
|
|
|
|
if (tmpDescriptor)
|
|
{
|
|
// If the partition number is zero, then this set
|
|
// has not been committed to the disk yet. Only
|
|
// update status for existing sets.
|
|
|
|
if ( (0 != tmpDescriptor->PartitionNumber)
|
|
&& (ftSet->Status != FtSetNew)
|
|
&& (ftSet->Status != FtSetNewNeedsInitialization))
|
|
{
|
|
status = LowFtVolumeStatus(tmpDescriptor->Disk,
|
|
tmpDescriptor->PartitionNumber,
|
|
&setState,
|
|
&numberOfMembers);
|
|
if (status == OK_STATUS)
|
|
{
|
|
if (ftSet->Status != setState)
|
|
{
|
|
// Problem here - the FT driver has
|
|
// updated the status of the set after
|
|
// windisk last got the status. Need
|
|
// to restart the process of building
|
|
// the FT information after updating
|
|
// the set to the new state.
|
|
|
|
FdftUpdateFtObjectSet(ftSet, setState);
|
|
|
|
// now recurse and start over
|
|
|
|
status = FdpConstructDiskDescription(
|
|
DiskState,
|
|
DiskDescription);
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
diskPartition->FtState = ftObject->State;
|
|
diskPartition->FtType = ftSet->Type;
|
|
diskPartition->FtGroup = (USHORT)ftSet->Ordinal;
|
|
diskPartition->FtMember = (USHORT)ftObject->MemberIndex;
|
|
if (assignDriveLetter && (ftObject == ftObject->Set->Member0))
|
|
{
|
|
diskPartition->AssignDriveLetter = TRUE;
|
|
}
|
|
else
|
|
{
|
|
diskPartition->AssignDriveLetter = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
diskPartition->FtState = Healthy;
|
|
diskPartition->FtType = NotAnFtMember;
|
|
diskPartition->FtGroup = (USHORT)(-1);
|
|
diskPartition->FtMember = 0;
|
|
diskPartition->AssignDriveLetter = assignDriveLetter;
|
|
}
|
|
}
|
|
}
|
|
|
|
DiskDescription->NumberOfPartitions = (USHORT)partitionIndex;
|
|
DiskDescription->Signature = DiskState->Signature;
|
|
DiskDescription->ReservedShort = 0;
|
|
|
|
return partitionIndex;
|
|
}
|
|
|
|
|
|
VOID
|
|
FdpRememberDisk(
|
|
IN PDISK_DESCRIPTION DiskDescription
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make a copy of a registry disk description structure for later use.
|
|
|
|
Arguments:
|
|
|
|
DiskDescription - supplies pointer to the registry descriptor for
|
|
the disk in question.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISK_DESCRIPTION diskDescription;
|
|
ULONG size;
|
|
|
|
// Only bother remembering disks with at least one partition.
|
|
//
|
|
if (DiskDescription->NumberOfPartitions == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Compute the size of the structure
|
|
//
|
|
|
|
size = sizeof(DISK_DESCRIPTION);
|
|
if (DiskDescription->NumberOfPartitions > 1)
|
|
{
|
|
size += (DiskDescription->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
|
|
}
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)Malloc(size);
|
|
RtlMoveMemory(diskDescription, DiskDescription, size);
|
|
|
|
RememberedDiskArray = (PDISK_DESCRIPTION*)Realloc(
|
|
RememberedDiskArray,
|
|
(RememberedDiskCount+1) * sizeof(PDISK_DESCRIPTION)
|
|
);
|
|
|
|
RememberedDiskArray[RememberedDiskCount++] = diskDescription;
|
|
|
|
FDLOG((2,
|
|
"FdpRememberDisk: remembered disk %08lx, remembered count = %u\n",
|
|
diskDescription->Signature,
|
|
RememberedDiskCount));
|
|
}
|
|
|
|
|
|
VOID
|
|
FdpInitializeMirrors(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
For each existing partition that was mirrored by the user during this
|
|
Disk Administrator session, call the FT driver to register initialization
|
|
of the mirror (ie, cause the primary to be copied to the secondary).
|
|
Perform a similar initialization for each stripe set with parity created
|
|
by the user.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFT_OBJECT_SET ftSet;
|
|
PFT_OBJECT ftObject;
|
|
|
|
//
|
|
// Look through the list of FT sets for mirrored pairs and parity stripes
|
|
//
|
|
|
|
for (ftSet = FtObjectList; NULL != ftSet; ftSet = ftSet->Next)
|
|
{
|
|
//
|
|
// If the set needs initialization, or was recovered,
|
|
// call the FT driver.
|
|
//
|
|
|
|
switch (ftSet->Status)
|
|
{
|
|
case FtSetNewNeedsInitialization:
|
|
|
|
DiskRegistryInitializeSet((USHORT)ftSet->Type,
|
|
(USHORT)ftSet->Ordinal);
|
|
ftSet->Status = FtSetInitializing;
|
|
break;
|
|
|
|
case FtSetRecovered:
|
|
|
|
//
|
|
// Find the member that needs to be addressed.
|
|
//
|
|
|
|
for (ftObject = ftSet->Members;
|
|
NULL != ftObject;
|
|
ftObject=ftObject->Next)
|
|
{
|
|
if (ftObject->State == Regenerating)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
DiskRegistryRegenerateSet((USHORT)ftSet->Type,
|
|
(USHORT)ftSet->Ordinal,
|
|
(USHORT)ftObject->MemberIndex);
|
|
ftSet->Status = FtSetRegenerating;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|