/*++ 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 // 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; OrdState = 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; diskIndexNumberOfDisks; diskIndex++) { for (partitionIndex=0; partitionIndexNumberOfPartitions; 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; iNumberOfPartitions; for (j=0; jPartitions[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 in \device\harddiskn\partition). 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; iRegionCount; 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; diskSignature == 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; regionIndexRegionArray[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; iOffLine) { offLineDiskCount++; } else if (IsDiskRemovable[i]) { removableDiskCount++; } else { size += FdpDetermineDiskDescriptionSize(Disks[i]); } } // Account for remembered disks. size += RememberedDiskCount * sizeof(DISK_DESCRIPTION); for (i=0; iNumberOfPartitions > 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; diskOffLine || IsDiskRemovable[disk]) { continue; } partition = FdpConstructDiskDescription(Disks[disk], diskDescription); diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition]; } // Toss in remembered disks. for (i=0; iNumberOfPartitions; 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; regionRegionCount; 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; } } }