diff options
Diffstat (limited to 'private/utils/fdisk/fdft.c')
-rw-r--r-- | private/utils/fdisk/fdft.c | 1500 |
1 files changed, 1500 insertions, 0 deletions
diff --git a/private/utils/fdisk/fdft.c b/private/utils/fdisk/fdft.c new file mode 100644 index 000000000..5eed40346 --- /dev/null +++ b/private/utils/fdisk/fdft.c @@ -0,0 +1,1500 @@ + +/*++ + +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; + } + } +} |