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.
1500 lines
40 KiB
1500 lines
40 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fdft.c
|
|
|
|
Abstract:
|
|
|
|
This module contains FT support routines for Disk Administrator
|
|
|
|
Author:
|
|
|
|
Edward (Ted) Miller (TedM) 11/15/91
|
|
|
|
Environment:
|
|
|
|
User process.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
11-Nov-93 (bobri) minor changes - mostly cosmetic.
|
|
|
|
--*/
|
|
|
|
#include "fdisk.h"
|
|
#include <string.h>
|
|
|
|
|
|
// This variable heads a linked list of ft object sets.
|
|
|
|
PFT_OBJECT_SET FtObjects = 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 *RememberedDisks;
|
|
ULONG RememberedDiskCount;
|
|
|
|
|
|
|
|
ULONG
|
|
FdpDetermineDiskDescriptionSize(
|
|
PDISKSTATE DiskState
|
|
);
|
|
|
|
ULONG
|
|
FdpConstructDiskDescription(
|
|
IN PDISKSTATE DiskState,
|
|
OUT PDISK_DESCRIPTION DiskDescription
|
|
);
|
|
|
|
VOID
|
|
FdpRememberDisk(
|
|
IN PDISK_DESCRIPTION DiskDescription
|
|
);
|
|
|
|
VOID
|
|
FdpInitializeMirrors(
|
|
VOID
|
|
);
|
|
|
|
#define MAX_FT_SET_TYPES 4
|
|
ULONG OrdinalToAllocate[MAX_FT_SET_TYPES] = {0, 0, 0, 0};
|
|
|
|
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 ord;
|
|
PFT_OBJECT_SET pftset;
|
|
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;
|
|
}
|
|
|
|
ord = OrdinalToAllocate[FtType];
|
|
ord++;
|
|
|
|
do {
|
|
looping = FALSE;
|
|
pftset = FtObjects;
|
|
while (pftset) {
|
|
if ((pftset->Type == FtType) && (pftset->Ordinal == ord)) {
|
|
ord++;
|
|
looping = TRUE;
|
|
break;
|
|
}
|
|
pftset = pftset->Next;
|
|
}
|
|
} while (looping);
|
|
|
|
OrdinalToAllocate[FtType] = (ord + 1);
|
|
return ord;
|
|
}
|
|
|
|
|
|
VOID
|
|
FdftCreateFtObjectSet(
|
|
IN FT_TYPE FtType,
|
|
IN PREGION_DESCRIPTOR *Regions,
|
|
IN DWORD RegionCount,
|
|
IN FT_SET_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create the FT set structures for the give collection of
|
|
region pointers.
|
|
|
|
Arguments:
|
|
|
|
FtType
|
|
Regions
|
|
RegionCount
|
|
Status
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Ord;
|
|
PFT_OBJECT_SET FtSet;
|
|
PFT_OBJECT FtObject;
|
|
|
|
|
|
FtSet = 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 = Status;
|
|
|
|
// Link the new object set into the list.
|
|
|
|
FtSet->Next = FtObjects;
|
|
FtObjects = FtSet;
|
|
|
|
// For each region in the set, associate the ft info with it.
|
|
|
|
for (Ord=0; Ord<RegionCount; Ord++) {
|
|
|
|
FtObject = 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 ((Ord == 0)
|
|
&& (FtType == StripeWithParity)
|
|
&& (Status == FtSetNewNeedsInitialization)) {
|
|
FtObject->State = Initializing;
|
|
} else {
|
|
FtObject->State = Healthy;
|
|
}
|
|
|
|
if (!Ord) {
|
|
FtSet->Member0 = FtObject;
|
|
}
|
|
|
|
FtObject->Set = FtSet;
|
|
FtObject->MemberIndex = Ord;
|
|
FtObject->Next = FtSet->Members;
|
|
FtSet->Members = FtObject;
|
|
|
|
SET_FT_OBJECT(Regions[Ord],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; 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 next;
|
|
PFT_OBJECT_SET ftSetTemp;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PDISK_PARTITION diskPartition;
|
|
ULONG partitionCount,
|
|
size,
|
|
i,
|
|
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 = RememberedDisks[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);
|
|
}
|
|
RememberedDisks[i] = Realloc(RememberedDisks[i], size);
|
|
}
|
|
}
|
|
|
|
if (OffLineDisksOnly) {
|
|
return;
|
|
}
|
|
|
|
// First, free all members of the set
|
|
|
|
while (ftObject) {
|
|
next = ftObject->Next;
|
|
Free(ftObject);
|
|
ftObject = next;
|
|
}
|
|
|
|
// now, remove the set from the linked list of sets.
|
|
|
|
if (FtObjects == FtSet) {
|
|
FtObjects = FtSet->Next;
|
|
} else {
|
|
ftSetTemp = FtObjects;
|
|
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* Regions,
|
|
IN DWORD RegionCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds regions to an existing FT-set.
|
|
|
|
Arguments:
|
|
|
|
FtSet -- Supplies the set to extend.
|
|
Regions -- 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, 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; 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 = Malloc( sizeof(FT_OBJECT) );
|
|
|
|
FtObject->Set = FtSet;
|
|
FtObject->MemberIndex = StartingIndex + i;
|
|
FtObject->Next = FtSet->Members;
|
|
FtObject->State = Healthy;
|
|
FtSet->Members = FtObject;
|
|
|
|
SET_FT_OBJECT(Regions[i],FtObject);
|
|
}
|
|
|
|
FtSet->Status = FtSetExtended;
|
|
}
|
|
|
|
|
|
PULONG DiskHadRegistryEntry;
|
|
|
|
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,PartitionCount=0;
|
|
PREGION_DESCRIPTOR region;
|
|
|
|
for(i=0; i<DiskState->RegionCount; i++) {
|
|
region = &DiskState->RegionArray[i];
|
|
if((region->SysID != SYSID_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 disk;
|
|
PDISKSTATE ds;
|
|
|
|
for(disk=0; disk<DiskCount; disk++) {
|
|
ds = Disks[disk];
|
|
if(ds->Signature == Signature) {
|
|
return(ds);
|
|
}
|
|
}
|
|
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,
|
|
maxRegion = DiskState->RegionCount;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
LARGE_INTEGER offset,
|
|
length;
|
|
|
|
for (regionIndex=0; regionIndex<maxRegion; regionIndex++) {
|
|
|
|
regionDescriptor = &DiskState->RegionArray[regionIndex];
|
|
|
|
if ((regionDescriptor->SysID != SYSID_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 = FtObjects;
|
|
|
|
while (ftSet) {
|
|
|
|
if ((ftSet->Type == FtType) && (ftSet->Ordinal == FtGroup)) {
|
|
break;
|
|
}
|
|
ftSet = ftSet->Next;
|
|
}
|
|
|
|
if (!ftSet) {
|
|
|
|
// There is no such existing ft set. Create one.
|
|
|
|
ftSet = Malloc(sizeof(FT_OBJECT_SET));
|
|
|
|
ftSet->Status = FtSetHealthy;
|
|
ftSet->Type = FtType;
|
|
ftSet->Ordinal = FtGroup;
|
|
ftSet->Members = NULL;
|
|
ftSet->Next = FtObjects;
|
|
ftSet->Member0 = NULL;
|
|
ftSet->NumberOfMembers = 0;
|
|
FtObjects = ftSet;
|
|
}
|
|
|
|
FDASSERT(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,
|
|
partitionIndex,
|
|
partitionCount;
|
|
PDISK_REGISTRY diskRegistry;
|
|
PDISK_PARTITION partition;
|
|
PDISK_DESCRIPTION diskDescription;
|
|
PDISKSTATE diskState;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
DWORD ec;
|
|
BOOL configDiskChanged = FALSE,
|
|
configMissingDisk = FALSE,
|
|
configExtraDisk = FALSE;
|
|
PFT_OBJECT ftObject;
|
|
BOOL anyDisksOffLine;
|
|
TCHAR name[100];
|
|
|
|
|
|
RememberedDisks = Malloc(0);
|
|
RememberedDiskCount = 0;
|
|
|
|
ec = MyDiskRegistryGet(&diskRegistry);
|
|
if (ec != NO_ERROR) {
|
|
|
|
FDLOG((0,"InitializeFt: Error %u from MyDiskRegistryGet\n",ec));
|
|
|
|
return ec;
|
|
}
|
|
|
|
DiskHadRegistryEntry = 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 (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++) {
|
|
|
|
partition = &diskDescription->Partitions[partitionIndex];
|
|
if (partition->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++) {
|
|
|
|
partition = &diskDescription->Partitions[partitionIndex];
|
|
regionDescriptor = NULL;
|
|
|
|
if (diskState) {
|
|
regionDescriptor = LookUpPartition(diskState,
|
|
partition->StartingOffset,
|
|
partition->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 (partition->FtType != NotAnFtMember) {
|
|
ftObject = Malloc(sizeof(FT_OBJECT));
|
|
ftObject->Next = NULL;
|
|
ftObject->Set = NULL;
|
|
ftObject->MemberIndex = partition->FtMember;
|
|
ftObject->State = partition->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(partition->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 = partition->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, partition->FtType, partition->FtGroup);
|
|
MaintainOrdinalTables(partition->FtType, (ULONG) partition->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 (Disks[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,Disks[disk]->Signature));
|
|
configExtraDisk = TRUE;
|
|
}
|
|
}
|
|
|
|
// Determine whether any disks are off line
|
|
|
|
anyDisksOffLine = FALSE;
|
|
for (disk = 0; disk < DiskCount; disk++) {
|
|
if (Disks[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,
|
|
b2 = TRUE;
|
|
|
|
if (Disks[disk]->OffLine) {
|
|
continue;
|
|
}
|
|
|
|
wsprintf(name, DiskN, disk);
|
|
if (Disks[disk]->SigWasCreated) {
|
|
if (ConfirmationDialog(MSG_NO_SIGNATURE, MB_ICONEXCLAMATION | MB_YESNO, name) == IDYES) {
|
|
b1 = (MasterBootCode(disk, Disks[disk]->Signature, TRUE, TRUE) == NO_ERROR);
|
|
} else {
|
|
Disks[disk]->OffLine = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!DiskHadRegistryEntry[disk]) {
|
|
ULONG size;
|
|
|
|
size = FdpDetermineDiskDescriptionSize(Disks[disk]);
|
|
|
|
diskDescription = Malloc(size);
|
|
FdpConstructDiskDescription(Disks[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 = Disks[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 != SYSID_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 (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,
|
|
partition;
|
|
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 (Disks[i]->OffLine) {
|
|
offLineDiskCount++;
|
|
} else if (IsDiskRemovable[i]) {
|
|
removableDiskCount++;
|
|
} else {
|
|
size += FdpDetermineDiskDescriptionSize(Disks[i]);
|
|
}
|
|
}
|
|
|
|
// Account for remembered disks.
|
|
|
|
size += RememberedDiskCount * sizeof(DISK_DESCRIPTION);
|
|
for (i=0; i<RememberedDiskCount; i++) {
|
|
if (RememberedDisks[i]->NumberOfPartitions > 1) {
|
|
size += (RememberedDisks[i]->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
|
|
}
|
|
}
|
|
|
|
diskRegistry = Malloc(size);
|
|
diskRegistry->NumberOfDisks = (USHORT)( DiskCount
|
|
+ RememberedDiskCount
|
|
- offLineDiskCount
|
|
- removableDiskCount);
|
|
diskRegistry->ReservedShort = 0;
|
|
diskDescription = diskRegistry->Disks;
|
|
for (disk=0; disk<DiskCount; disk++) {
|
|
|
|
if (Disks[disk]->OffLine || IsDiskRemovable[disk]) {
|
|
continue;
|
|
}
|
|
|
|
partition = FdpConstructDiskDescription(Disks[disk], diskDescription);
|
|
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
|
|
}
|
|
|
|
// Toss in remembered disks.
|
|
|
|
for (i=0; i<RememberedDiskCount; i++) {
|
|
|
|
// Compute the beginning and end of this remembered disk's
|
|
// Disk Description:
|
|
|
|
partition = RememberedDisks[i]->NumberOfPartitions;
|
|
start = (PBYTE)RememberedDisks[i];
|
|
end = (PBYTE)&(RememberedDisks[i]->Partitions[partition]);
|
|
|
|
RtlMoveMemory(diskDescription, RememberedDisks[i], end - start);
|
|
diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
|
|
}
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDISKSTATE ds = DiskState;
|
|
ULONG partition,
|
|
region;
|
|
PREGION_DESCRIPTOR regionDescriptor;
|
|
PDISK_PARTITION diskPartition;
|
|
CHAR driveLetter;
|
|
BOOLEAN assignDriveLetter;
|
|
PFT_OBJECT ftObject;
|
|
PFT_OBJECT_SET ftSet;
|
|
|
|
partition = 0;
|
|
|
|
for (region=0; region<ds->RegionCount; region++) {
|
|
|
|
regionDescriptor = &ds->RegionArray[region];
|
|
|
|
if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID) && IsRecognizedPartition(regionDescriptor->SysID)) {
|
|
|
|
diskPartition = &DiskDescription->Partitions[partition++];
|
|
|
|
diskPartition->StartingOffset = FdGetExactOffset(regionDescriptor);
|
|
diskPartition->Length = FdGetExactSize(regionDescriptor, FALSE);
|
|
diskPartition->LogicalNumber = (USHORT)regionDescriptor->PartitionNumber;
|
|
|
|
switch (driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter) {
|
|
case NO_DRIVE_LETTER_YET:
|
|
assignDriveLetter = TRUE;
|
|
driveLetter = 0;
|
|
break;
|
|
case NO_DRIVE_LETTER_EVER:
|
|
assignDriveLetter = FALSE;
|
|
driveLetter = 0;
|
|
break;
|
|
default:
|
|
assignDriveLetter = TRUE;
|
|
break;
|
|
}
|
|
|
|
diskPartition->DriveLetter = driveLetter;
|
|
diskPartition->FtLength.LowPart = 0;
|
|
diskPartition->FtLength.HighPart = 0;
|
|
diskPartition->ReservedTwoLongs[0] = 0;
|
|
diskPartition->ReservedTwoLongs[1] = 0;
|
|
diskPartition->Modified = TRUE;
|
|
|
|
if (ftObject = GET_FT_OBJECT(regionDescriptor)) {
|
|
PREGION_DESCRIPTOR tmpDescriptor;
|
|
|
|
ftSet = ftObject->Set;
|
|
|
|
tmpDescriptor = LocateRegionForFtObject(ftSet->Member0);
|
|
|
|
// Only update status if member zero is present.
|
|
// otherwise the status is know to be Orphaned or
|
|
// needs regeneration.
|
|
#if 0
|
|
|
|
// need to do something here, but currently this does not work.
|
|
|
|
if (tmpDescriptor) {
|
|
ULONG numberOfMembers;
|
|
FT_SET_STATUS setState;
|
|
STATUS_CODE status;
|
|
|
|
// If the partition number is zero, then this set
|
|
// has not been committed to the disk yet. Only
|
|
// update status for existing sets.
|
|
|
|
if ((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)partition;
|
|
DiskDescription->Signature = ds->Signature;
|
|
DiskDescription->ReservedShort = 0;
|
|
return(partition);
|
|
}
|
|
|
|
|
|
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 = Malloc(Size);
|
|
RtlMoveMemory(diskDescription, DiskDescription, Size);
|
|
|
|
RememberedDisks = Realloc(RememberedDisks,
|
|
(RememberedDiskCount + 1) * sizeof(PDISK_DESCRIPTION));
|
|
RememberedDisks[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 Manager
|
|
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 ftMember;
|
|
|
|
// Look through the list of FT sets for mirrored pairs and parity stripes
|
|
|
|
for (ftSet = FtObjects; 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 (ftMember=ftSet->Members; ftMember; ftMember=ftMember->Next) {
|
|
if (ftMember->State == Regenerating) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
DiskRegistryRegenerateSet((USHORT)ftSet->Type,
|
|
(USHORT)ftSet->Ordinal,
|
|
(USHORT)ftMember->MemberIndex);
|
|
ftSet->Status = FtSetRegenerating;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|