Source code of Windows XP (NT5)
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
39 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. fdft.c
  5. Abstract:
  6. This module contains FT support routines for Disk Administrator
  7. Author:
  8. Edward (Ted) Miller (TedM) 11/15/91
  9. Environment:
  10. User process.
  11. Notes:
  12. Revision History:
  13. 11-Nov-93 (bobri) minor changes - mostly cosmetic.
  14. --*/
  15. #include "fdisk.h"
  16. #include <string.h>
  17. // This variable heads a linked list of ft object sets.
  18. PFT_OBJECT_SET FtObjects = NULL;
  19. // Array of pointers to registry disk descriptors that we
  20. // remember, ie, save for later use when a disk is not physically
  21. // present on the machine.
  22. PDISK_DESCRIPTION *RememberedDisks;
  23. ULONG RememberedDiskCount;
  24. ULONG
  25. FdpDetermineDiskDescriptionSize(
  26. PDISKSTATE DiskState
  27. );
  28. ULONG
  29. FdpConstructDiskDescription(
  30. IN PDISKSTATE DiskState,
  31. OUT PDISK_DESCRIPTION DiskDescription
  32. );
  33. VOID
  34. FdpRememberDisk(
  35. IN PDISK_DESCRIPTION DiskDescription
  36. );
  37. VOID
  38. FdpInitializeMirrors(
  39. VOID
  40. );
  41. #define MAX_FT_SET_TYPES 4
  42. ULONG OrdinalToAllocate[MAX_FT_SET_TYPES] = {0, 0, 0, 0};
  43. VOID
  44. MaintainOrdinalTables(
  45. IN FT_TYPE FtType,
  46. IN ULONG Ordinal
  47. )
  48. /*++
  49. Routine Description:
  50. Maintain the minimum and maximum Ordinal value recorded.
  51. Arguments:
  52. FtType - the type of the FT set.
  53. Ordinal - the in use FtGroup (or ordinal) number
  54. Return Value:
  55. None
  56. --*/
  57. {
  58. if (Ordinal > OrdinalToAllocate[FtType]) {
  59. OrdinalToAllocate[FtType] = Ordinal;
  60. }
  61. }
  62. DWORD
  63. FdftNextOrdinal(
  64. IN FT_TYPE FtType
  65. )
  66. /*++
  67. Routine Description:
  68. Allocate a number that will uniquely identify the FT set
  69. from other sets of the same type. This number must be unique
  70. from any given or used by FT sets of the same type due to
  71. requirements of FT dynamic partitioning.
  72. Arguments:
  73. FtType - The type of the FT set.
  74. Return Value:
  75. The FtGroup number -- called an "ordinal" in the internal
  76. structures.
  77. --*/
  78. {
  79. DWORD ord;
  80. PFT_OBJECT_SET pftset;
  81. BOOL looping;
  82. // The Ordinal value is going to be used as an FtGroup number
  83. // FtGroups are USHORTs so don't wrap on the Ordinal. Try
  84. // to keep the next ordinal in the largest opening range, that
  85. // is if the minimum found is > half way through a USHORT, start
  86. // the ordinals over at zero.
  87. if (OrdinalToAllocate[FtType] > 0x7FFE) {
  88. OrdinalToAllocate[FtType] = 0;
  89. }
  90. ord = OrdinalToAllocate[FtType];
  91. ord++;
  92. do {
  93. looping = FALSE;
  94. pftset = FtObjects;
  95. while (pftset) {
  96. if ((pftset->Type == FtType) && (pftset->Ordinal == ord)) {
  97. ord++;
  98. looping = TRUE;
  99. break;
  100. }
  101. pftset = pftset->Next;
  102. }
  103. } while (looping);
  104. OrdinalToAllocate[FtType] = (ord + 1);
  105. return ord;
  106. }
  107. VOID
  108. FdftCreateFtObjectSet(
  109. IN FT_TYPE FtType,
  110. IN PREGION_DESCRIPTOR *Regions,
  111. IN DWORD RegionCount,
  112. IN FT_SET_STATUS Status
  113. )
  114. /*++
  115. Routine Description:
  116. Create the FT set structures for the give collection of
  117. region pointers.
  118. Arguments:
  119. FtType
  120. Regions
  121. RegionCount
  122. Status
  123. Return Value:
  124. None
  125. --*/
  126. {
  127. DWORD Ord;
  128. PFT_OBJECT_SET FtSet;
  129. PFT_OBJECT FtObject;
  130. FtSet = Malloc(sizeof(FT_OBJECT_SET));
  131. // Figure out an ordinal for the new object set.
  132. FtSet->Ordinal = FdftNextOrdinal(FtType);
  133. FtSet->Type = FtType;
  134. FtSet->Members = NULL;
  135. FtSet->Member0 = NULL;
  136. FtSet->Status = Status;
  137. // Link the new object set into the list.
  138. FtSet->Next = FtObjects;
  139. FtObjects = FtSet;
  140. // For each region in the set, associate the ft info with it.
  141. for (Ord=0; Ord<RegionCount; Ord++) {
  142. FtObject = Malloc(sizeof(FT_OBJECT));
  143. // If this is a creation of a stripe set with parity, then
  144. // we must mark the 0th item 'Initializing' instead of 'Healthy'.
  145. if ((Ord == 0)
  146. && (FtType == StripeWithParity)
  147. && (Status == FtSetNewNeedsInitialization)) {
  148. FtObject->State = Initializing;
  149. } else {
  150. FtObject->State = Healthy;
  151. }
  152. if (!Ord) {
  153. FtSet->Member0 = FtObject;
  154. }
  155. FtObject->Set = FtSet;
  156. FtObject->MemberIndex = Ord;
  157. FtObject->Next = FtSet->Members;
  158. FtSet->Members = FtObject;
  159. SET_FT_OBJECT(Regions[Ord],FtObject);
  160. }
  161. }
  162. BOOL
  163. FdftUpdateFtObjectSet(
  164. IN PFT_OBJECT_SET FtSet,
  165. IN FT_SET_STATUS SetState
  166. )
  167. /*++
  168. Routine Description:
  169. Given an FT set, go back to the registry information and
  170. update the state of the members with the state in the registry.
  171. NOTE: The following condition may exist. It is possible for
  172. the FtDisk driver to return that the set is in an initializing
  173. or regenerating state and not have this fact reflected in the
  174. registry. This can happen when the system has crashed and
  175. on restart the FtDisk driver started the regeneration of the
  176. check data (parity).
  177. Arguments:
  178. FtSet - the set to update.
  179. Return Value:
  180. TRUE if the set state provided has a strong likelyhood of being correct
  181. FALSE if the NOTE condition above is occuring.
  182. --*/
  183. {
  184. BOOLEAN allHealthy = TRUE;
  185. PFT_OBJECT ftObject;
  186. PDISK_REGISTRY diskRegistry;
  187. PDISK_PARTITION partition;
  188. PDISK_DESCRIPTION diskDescription;
  189. DWORD ec;
  190. ULONG diskIndex,
  191. partitionIndex;
  192. ec = MyDiskRegistryGet(&diskRegistry);
  193. if (ec != NO_ERROR) {
  194. // No registry information.
  195. return TRUE;
  196. }
  197. diskDescription = diskRegistry->Disks;
  198. for (diskIndex=0; diskIndex<diskRegistry->NumberOfDisks; diskIndex++) {
  199. for (partitionIndex=0; partitionIndex<diskDescription->NumberOfPartitions; partitionIndex++) {
  200. partition = &diskDescription->Partitions[partitionIndex];
  201. if ((partition->FtType == FtSet->Type) && (partition->FtGroup == (USHORT) FtSet->Ordinal)) {
  202. // Have a match for a partition within this set.
  203. // Find the region descriptor for this partition and
  204. // update its state accordingly.
  205. for (ftObject = FtSet->Members; ftObject; ftObject = ftObject->Next) {
  206. if (ftObject->MemberIndex == (ULONG) partition->FtMember) {
  207. ftObject->State = partition->FtState;
  208. break;
  209. }
  210. if (partition->FtState != Healthy) {
  211. allHealthy = FALSE;
  212. }
  213. }
  214. }
  215. }
  216. diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
  217. }
  218. Free(diskRegistry);
  219. if ((allHealthy) && (SetState != FtSetHealthy)) {
  220. // This is a condition where the system must be
  221. // updating the check data for redundant sets.
  222. return FALSE;
  223. }
  224. return TRUE;
  225. }
  226. VOID
  227. FdftDeleteFtObjectSet(
  228. IN PFT_OBJECT_SET FtSet,
  229. IN BOOL OffLineDisksOnly
  230. )
  231. /*++
  232. Routine Description:
  233. Delete an ft set, or rather its internal representation as a linked
  234. list of ft member structures.
  235. Arguments:
  236. FtSet - supplies pointer to ft set structure for set to delete.
  237. OffLineDisksOnly - if TRUE, then do not delete the set but instead
  238. scan remembered disks for members of the set and remove such members.
  239. Return Value:
  240. None.
  241. --*/
  242. {
  243. PFT_OBJECT ftObject = FtSet->Members;
  244. PFT_OBJECT next;
  245. PFT_OBJECT_SET ftSetTemp;
  246. PDISK_DESCRIPTION diskDescription;
  247. PDISK_PARTITION diskPartition;
  248. ULONG partitionCount,
  249. size,
  250. i,
  251. j;
  252. // Locate any members of the ft set on remembered disks and
  253. // remove the entries for such partitions.
  254. for (i=0; i<RememberedDiskCount; i++) {
  255. diskDescription = RememberedDisks[i];
  256. partitionCount = diskDescription->NumberOfPartitions;
  257. for (j=0; j<partitionCount; j++) {
  258. diskPartition = &diskDescription->Partitions[j];
  259. if ((diskPartition->FtType == FtSet->Type)
  260. && (diskPartition->FtGroup == (USHORT)FtSet->Ordinal)) {
  261. // Found a member of the ft set being deleted on a
  262. // remembered disk. Remove the partition from the
  263. // remembered disk.
  264. RtlMoveMemory( diskPartition,
  265. diskPartition+1,
  266. (partitionCount - j - 1) * sizeof(DISK_PARTITION)
  267. );
  268. partitionCount--;
  269. j--;
  270. }
  271. }
  272. if (partitionCount != diskDescription->NumberOfPartitions) {
  273. diskDescription->NumberOfPartitions = (USHORT)partitionCount;
  274. size = sizeof(DISK_DESCRIPTION);
  275. if (partitionCount > 1) {
  276. size += (partitionCount - 1) * sizeof(DISK_PARTITION);
  277. }
  278. RememberedDisks[i] = Realloc(RememberedDisks[i], size);
  279. }
  280. }
  281. if (OffLineDisksOnly) {
  282. return;
  283. }
  284. // First, free all members of the set
  285. while (ftObject) {
  286. next = ftObject->Next;
  287. Free(ftObject);
  288. ftObject = next;
  289. }
  290. // now, remove the set from the linked list of sets.
  291. if (FtObjects == FtSet) {
  292. FtObjects = FtSet->Next;
  293. } else {
  294. ftSetTemp = FtObjects;
  295. while (1) {
  296. FDASSERT(ftSetTemp);
  297. if (ftSetTemp == NULL) {
  298. break;
  299. }
  300. if (ftSetTemp->Next == FtSet) {
  301. ftSetTemp->Next = FtSet->Next;
  302. break;
  303. }
  304. ftSetTemp = ftSetTemp->Next;
  305. }
  306. }
  307. Free(FtSet);
  308. }
  309. VOID
  310. FdftExtendFtObjectSet(
  311. IN OUT PFT_OBJECT_SET FtSet,
  312. IN OUT PREGION_DESCRIPTOR* Regions,
  313. IN DWORD RegionCount
  314. )
  315. /*++
  316. Routine Description:
  317. This function adds regions to an existing FT-set.
  318. Arguments:
  319. FtSet -- Supplies the set to extend.
  320. Regions -- Supplies the regions to add to the set. Note
  321. that these regions are updated with the FT
  322. information.
  323. RegionCount -- Supplies the number of regions to add.
  324. Return Value:
  325. None.
  326. --*/
  327. {
  328. PFT_OBJECT FtObject;
  329. DWORD i, StartingIndex;
  330. // Determine the starting member index for the new regions.
  331. // It is the greatest of the existing member indices plus one.
  332. StartingIndex = 0;
  333. for( FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next ) {
  334. if( FtObject->MemberIndex > StartingIndex ) {
  335. StartingIndex = FtObject->MemberIndex;
  336. }
  337. }
  338. StartingIndex++;
  339. // Associate the ft-set's information with each of the
  340. // new regions.
  341. for( i = 0; i < RegionCount; i++ ) {
  342. FtObject = Malloc( sizeof(FT_OBJECT) );
  343. FtObject->Set = FtSet;
  344. FtObject->MemberIndex = StartingIndex + i;
  345. FtObject->Next = FtSet->Members;
  346. FtObject->State = Healthy;
  347. FtSet->Members = FtObject;
  348. SET_FT_OBJECT(Regions[i],FtObject);
  349. }
  350. FtSet->Status = FtSetExtended;
  351. }
  352. PULONG DiskHadRegistryEntry;
  353. ULONG
  354. ActualPartitionCount(
  355. IN PDISKSTATE DiskState
  356. )
  357. /*++
  358. Routine Description:
  359. Given a disk, this routine counts the number of partitions on it.
  360. The number of partitions is the number of regions that appear in
  361. the NT name space (ie, the maximum value of <x> in
  362. \device\harddiskn\partition<x>).
  363. Arguments:
  364. DiskState - descriptor for the disk in question.
  365. Return Value:
  366. Partition count (may be 0).
  367. --*/
  368. {
  369. ULONG i,PartitionCount=0;
  370. PREGION_DESCRIPTOR region;
  371. for(i=0; i<DiskState->RegionCount; i++) {
  372. region = &DiskState->RegionArray[i];
  373. if((region->SysID != SYSID_UNUSED) &&
  374. !IsExtended(region->SysID) &&
  375. IsRecognizedPartition(region->SysID)) {
  376. PartitionCount++;
  377. }
  378. }
  379. return(PartitionCount);
  380. }
  381. PDISKSTATE
  382. LookUpDiskBySignature(
  383. IN ULONG Signature
  384. )
  385. /*++
  386. Routine Description:
  387. This routine will look through the disk descriptors created by the
  388. fdisk back end looking for a disk with a particular signature.
  389. Arguments:
  390. Signature - signature of disk to locate
  391. Return Value:
  392. Pointer to disk descriptor or NULL if no disk with the given signature
  393. was found.
  394. --*/
  395. {
  396. ULONG disk;
  397. PDISKSTATE ds;
  398. for(disk=0; disk<DiskCount; disk++) {
  399. ds = Disks[disk];
  400. if(ds->Signature == Signature) {
  401. return(ds);
  402. }
  403. }
  404. return(NULL);
  405. }
  406. PREGION_DESCRIPTOR
  407. LookUpPartition(
  408. IN PDISKSTATE DiskState,
  409. IN LARGE_INTEGER Offset,
  410. IN LARGE_INTEGER Length
  411. )
  412. /*++
  413. Routine Description:
  414. This routine will look through a region descriptor array for a
  415. partition with a particular length and starting offset.
  416. Arguments:
  417. DiskState - disk on which to locate the partition
  418. Offset - offset of partition on the disk to find
  419. Length - size of the partition to find
  420. Return Value:
  421. Pointer to region descriptor or NULL if no such partition on that disk
  422. --*/
  423. {
  424. ULONG regionIndex,
  425. maxRegion = DiskState->RegionCount;
  426. PREGION_DESCRIPTOR regionDescriptor;
  427. LARGE_INTEGER offset,
  428. length;
  429. for (regionIndex=0; regionIndex<maxRegion; regionIndex++) {
  430. regionDescriptor = &DiskState->RegionArray[regionIndex];
  431. if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID)) {
  432. offset = FdGetExactOffset(regionDescriptor);
  433. length = FdGetExactSize(regionDescriptor, FALSE);
  434. if ((offset.LowPart == Offset.LowPart )
  435. && (offset.HighPart == Offset.HighPart)
  436. && (length.LowPart == Length.LowPart)
  437. && (length.HighPart == Length.HighPart)) {
  438. return regionDescriptor;
  439. }
  440. }
  441. }
  442. return NULL;
  443. }
  444. VOID
  445. AddObjectToSet(
  446. IN PFT_OBJECT FtObjectToAdd,
  447. IN FT_TYPE FtType,
  448. IN USHORT FtGroup
  449. )
  450. /*++
  451. Routine Description:
  452. Find the FtSet for that this object belongs to and insert
  453. it into the chain of members. If the set cannot be found
  454. in the existing collection of sets, create a new one.
  455. Arguments:
  456. FtObjectToAdd - the object point to be added.
  457. FtType - the type of the FT set.
  458. FtGroup - group for this object.
  459. Return Value:
  460. None
  461. --*/
  462. {
  463. PFT_OBJECT_SET ftSet = FtObjects;
  464. while (ftSet) {
  465. if ((ftSet->Type == FtType) && (ftSet->Ordinal == FtGroup)) {
  466. break;
  467. }
  468. ftSet = ftSet->Next;
  469. }
  470. if (!ftSet) {
  471. // There is no such existing ft set. Create one.
  472. ftSet = Malloc(sizeof(FT_OBJECT_SET));
  473. ftSet->Status = FtSetHealthy;
  474. ftSet->Type = FtType;
  475. ftSet->Ordinal = FtGroup;
  476. ftSet->Members = NULL;
  477. ftSet->Next = FtObjects;
  478. ftSet->Member0 = NULL;
  479. ftSet->NumberOfMembers = 0;
  480. FtObjects = ftSet;
  481. }
  482. FDASSERT(ftSet);
  483. FtObjectToAdd->Next = ftSet->Members;
  484. ftSet->Members = FtObjectToAdd;
  485. ftSet->NumberOfMembers++;
  486. FtObjectToAdd->Set = ftSet;
  487. if (FtObjectToAdd->MemberIndex == 0) {
  488. ftSet->Member0 = FtObjectToAdd;
  489. }
  490. if (FtType == StripeWithParity || FtType == Mirror) {
  491. // Update the set's state based on the state of the new member:
  492. switch (FtObjectToAdd->State) {
  493. case Healthy:
  494. // Doesn't change state of set.
  495. break;
  496. case Regenerating:
  497. ftSet->Status = (ftSet->Status == FtSetHealthy ||
  498. ftSet->Status == FtSetRegenerating)
  499. ? FtSetRegenerating
  500. : FtSetBroken;
  501. break;
  502. case Initializing:
  503. ftSet->Status = (ftSet->Status == FtSetHealthy ||
  504. ftSet->Status == FtSetInitializing)
  505. ? FtSetInitializing
  506. : FtSetBroken;
  507. break;
  508. default:
  509. // If only one member is bad, the set is recoverable;
  510. // otherwise, it's broken.
  511. ftSet->Status = (ftSet->Status == FtSetHealthy)
  512. ? FtSetRecoverable
  513. : FtSetDisabled;
  514. break;
  515. }
  516. }
  517. }
  518. ULONG
  519. InitializeFt(
  520. IN BOOL DiskSignaturesCreated
  521. )
  522. /*++
  523. Routine Description:
  524. Search the disk registry information to construct the FT
  525. relationships in the system.
  526. Arguments:
  527. DiskSignaturesCreated - boolean to indicate that new disks
  528. were located in the system.
  529. Return Value:
  530. An error code if the disk registry could not be obtained.
  531. --*/
  532. {
  533. ULONG disk,
  534. partitionIndex,
  535. partitionCount;
  536. PDISK_REGISTRY diskRegistry;
  537. PDISK_PARTITION partition;
  538. PDISK_DESCRIPTION diskDescription;
  539. PDISKSTATE diskState;
  540. PREGION_DESCRIPTOR regionDescriptor;
  541. DWORD ec;
  542. BOOL configDiskChanged = FALSE,
  543. configMissingDisk = FALSE,
  544. configExtraDisk = FALSE;
  545. PFT_OBJECT ftObject;
  546. BOOL anyDisksOffLine;
  547. TCHAR name[100];
  548. RememberedDisks = Malloc(0);
  549. RememberedDiskCount = 0;
  550. ec = MyDiskRegistryGet(&diskRegistry);
  551. if (ec != NO_ERROR) {
  552. FDLOG((0,"InitializeFt: Error %u from MyDiskRegistryGet\n",ec));
  553. return ec;
  554. }
  555. DiskHadRegistryEntry = Malloc(DiskCount * sizeof(ULONG));
  556. memset(DiskHadRegistryEntry,0,DiskCount * sizeof(ULONG));
  557. diskDescription = diskRegistry->Disks;
  558. for (disk = 0; disk < diskRegistry->NumberOfDisks; disk++) {
  559. // For the disk described in the registry, look up the
  560. // corresponding actual disk found by the fdisk init code.
  561. diskState = LookUpDiskBySignature(diskDescription->Signature);
  562. if (diskState) {
  563. FDLOG((2,
  564. "InitializeFt: disk w/ signature %08lx is disk #%u\n",
  565. diskDescription->Signature,
  566. diskState->Disk));
  567. DiskHadRegistryEntry[diskState->Disk]++;
  568. partitionCount = ActualPartitionCount(diskState);
  569. if (partitionCount != diskDescription->NumberOfPartitions) {
  570. FDLOG((1,"InitializeFt: partition counts for disk %08lx don't match:\n", diskState->Signature));
  571. FDLOG((1," Count from actual disk: %u\n",partitionCount));
  572. FDLOG((1," Count from registry : %u\n",diskDescription->NumberOfPartitions));
  573. configDiskChanged = TRUE;
  574. }
  575. } else {
  576. // there's an entry in the registry that does not have a
  577. // real disk to match. Remember this disk; if it has any
  578. // FT partitions, we also want to display a message telling
  579. // the user that something's missing.
  580. FDLOG((1,"InitializeFt: Entry for disk w/ signature %08lx has no matching real disk\n", diskDescription->Signature));
  581. for (partitionIndex = 0; partitionIndex < diskDescription->NumberOfPartitions; partitionIndex++) {
  582. partition = &diskDescription->Partitions[partitionIndex];
  583. if (partition->FtType != NotAnFtMember) {
  584. // This disk has an FT partition, so Windisk will
  585. // want to tell the user that some disks are missing.
  586. configMissingDisk = TRUE;
  587. break;
  588. }
  589. }
  590. FdpRememberDisk(diskDescription);
  591. }
  592. for (partitionIndex = 0; partitionIndex < diskDescription->NumberOfPartitions; partitionIndex++) {
  593. partition = &diskDescription->Partitions[partitionIndex];
  594. regionDescriptor = NULL;
  595. if (diskState) {
  596. regionDescriptor = LookUpPartition(diskState,
  597. partition->StartingOffset,
  598. partition->Length);
  599. }
  600. // At this point one of three conditions exists.
  601. //
  602. // 1. There is no disk related to this registry information
  603. // diskState == NULL && regionDescriptor == NULL
  604. // 2. There is a disk, but no partition related to this information
  605. // diskState != NULL && regionDescriptor == NULL
  606. // 3. There is a disk and a partition related to this information
  607. // diskState != NULL && regionDescriptor != NULL
  608. //
  609. // In any of these conditions, if the registry entry is part
  610. // of an FT set and FT object must be created.
  611. //
  612. // that corresponds to a partition's entry in the
  613. // disk registry database.
  614. if (partition->FtType != NotAnFtMember) {
  615. ftObject = Malloc(sizeof(FT_OBJECT));
  616. ftObject->Next = NULL;
  617. ftObject->Set = NULL;
  618. ftObject->MemberIndex = partition->FtMember;
  619. ftObject->State = partition->FtState;
  620. // if a partition was actually found there will be a
  621. // regionDescriptor that needs to be updated.
  622. if (regionDescriptor && regionDescriptor->PersistentData) {
  623. FT_SET_STATUS setState;
  624. ULONG numberOfMembers;
  625. SET_FT_OBJECT(regionDescriptor, ftObject);
  626. // Before the drive letter is moved into the region
  627. // data, be certain that the FT volume exists at this
  628. // drive letter.
  629. LowFtVolumeStatusByLetter(partition->DriveLetter,
  630. &setState,
  631. &numberOfMembers);
  632. // If the numberOfMembers gets set to 1 then
  633. // this letter is not the letter for the FT set,
  634. // but rather a default letter assigned because the
  635. // FT sets letter could not be assigned.
  636. if (numberOfMembers > 1) {
  637. PERSISTENT_DATA(regionDescriptor)->DriveLetter = partition->DriveLetter;
  638. }
  639. } else {
  640. // There is no region for this partition
  641. // so update the set state.
  642. ftObject->State = Orphaned;
  643. }
  644. // Now place the ft object in the correct set,
  645. // creating the set if necessary.
  646. AddObjectToSet(ftObject, partition->FtType, partition->FtGroup);
  647. MaintainOrdinalTables(partition->FtType, (ULONG) partition->FtGroup);
  648. }
  649. }
  650. diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
  651. }
  652. Free(diskRegistry);
  653. // Check to see if every disk found by the fdisk back end has a
  654. // corresponding registry entry.
  655. for (disk = 0; disk < DiskCount; disk++) {
  656. if (Disks[disk]->OffLine) {
  657. continue;
  658. }
  659. if ((!DiskHadRegistryEntry[disk]) && (!IsRemovable(disk))) {
  660. // a real disk does not have a matching registry entry.
  661. FDLOG((1,"InitializeFt: Disk %u does not have a registry entry (disk sig = %08lx)\n",disk,Disks[disk]->Signature));
  662. configExtraDisk = TRUE;
  663. }
  664. }
  665. // Determine whether any disks are off line
  666. anyDisksOffLine = FALSE;
  667. for (disk = 0; disk < DiskCount; disk++) {
  668. if (Disks[disk]->OffLine) {
  669. anyDisksOffLine = TRUE;
  670. break;
  671. }
  672. }
  673. if (configMissingDisk || anyDisksOffLine) {
  674. WarningDialog(MSG_CONFIG_MISSING_DISK);
  675. }
  676. if (configDiskChanged) {
  677. RegistryChanged = TRUE;
  678. WarningDialog(MSG_CONFIG_DISK_CHANGED);
  679. }
  680. if (configExtraDisk || DiskSignaturesCreated) {
  681. BOOL BadConfigSet = FALSE;
  682. WarningDialog(MSG_CONFIG_EXTRA_DISK);
  683. // Update ft signature on each disk for which a new signature
  684. // was created. and update registry for each disk with
  685. // DiskHadRegistryEntry[Disk] == 0.
  686. for (disk = 0; disk < DiskCount; disk++) {
  687. BOOL b1 = TRUE,
  688. b2 = TRUE;
  689. if (Disks[disk]->OffLine) {
  690. continue;
  691. }
  692. wsprintf(name, DiskN, disk);
  693. if (Disks[disk]->SigWasCreated) {
  694. if (ConfirmationDialog(MSG_NO_SIGNATURE, MB_ICONEXCLAMATION | MB_YESNO, name) == IDYES) {
  695. b1 = (MasterBootCode(disk, Disks[disk]->Signature, TRUE, TRUE) == NO_ERROR);
  696. } else {
  697. Disks[disk]->OffLine = TRUE;
  698. continue;
  699. }
  700. }
  701. if (!DiskHadRegistryEntry[disk]) {
  702. ULONG size;
  703. size = FdpDetermineDiskDescriptionSize(Disks[disk]);
  704. diskDescription = Malloc(size);
  705. FdpConstructDiskDescription(Disks[disk], diskDescription);
  706. FDLOG((2,"InitializeFt: Adding new disk %08lx to registry.\n", diskDescription->Signature));
  707. LOG_ONE_DISK_REGISTRY_DISK_ENTRY("InitializeFt", diskDescription);
  708. b2 = (EC(DiskRegistryAddNewDisk(diskDescription)) == NO_ERROR);
  709. Free(diskDescription);
  710. }
  711. if (!(b1 && b2)) {
  712. BadConfigSet = TRUE;
  713. }
  714. }
  715. if (BadConfigSet) {
  716. ErrorDialog(MSG_BAD_CONFIG_SET);
  717. }
  718. }
  719. return NO_ERROR;
  720. }
  721. BOOLEAN
  722. NewConfigurationRequiresFt(
  723. VOID
  724. )
  725. /*++
  726. Routine Description:
  727. Search the diskstate and region arrays to determine if a single
  728. FtDisk element (i.e. stripe, stripe set with parity, mirror or
  729. volume set) is contained in the configuration.
  730. Arguments:
  731. None
  732. Return Value:
  733. TRUE if the new configuration requires the FtDisk driver.
  734. FALSE otherwise.
  735. --*/
  736. {
  737. ULONG disk,
  738. region;
  739. PDISKSTATE diskState;
  740. PREGION_DESCRIPTOR regionDescriptor;
  741. // Look at all disks in the system.
  742. for (disk = 0; disk < DiskCount; disk++) {
  743. diskState = Disks[disk];
  744. if (diskState->OffLine || IsDiskRemovable[disk]) {
  745. continue;
  746. }
  747. // Check each region on the disk.
  748. for (region = 0; region < diskState->RegionCount; region++) {
  749. regionDescriptor = &diskState->RegionArray[region];
  750. if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID) && IsRecognizedPartition(regionDescriptor->SysID)) {
  751. // If a single region has an FT Object, then FT
  752. // is required and the search may be stopped.
  753. if (GET_FT_OBJECT(regionDescriptor)) {
  754. return TRUE;
  755. }
  756. }
  757. }
  758. }
  759. // no FtObject was found.
  760. return FALSE;
  761. }
  762. ULONG
  763. SaveFt(
  764. VOID
  765. )
  766. /*++
  767. Routine Description:
  768. This routine walks all of the internal structures and creates
  769. the interface structure for the DiskRegistry interface.
  770. Arguments:
  771. None
  772. Return Value:
  773. success/failure code. NO_ERROR is success.
  774. --*/
  775. {
  776. ULONG i;
  777. ULONG disk,
  778. partition;
  779. ULONG size;
  780. PDISK_REGISTRY diskRegistry;
  781. PDISK_DESCRIPTION diskDescription;
  782. PBYTE start,
  783. end;
  784. DWORD ec;
  785. ULONG offLineDiskCount;
  786. ULONG removableDiskCount;
  787. // First count partitions and disks so we can allocate a structure
  788. // of the correct size.
  789. size = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
  790. offLineDiskCount = 0;
  791. removableDiskCount = 0;
  792. for (i=0; i<DiskCount; i++) {
  793. if (Disks[i]->OffLine) {
  794. offLineDiskCount++;
  795. } else if (IsDiskRemovable[i]) {
  796. removableDiskCount++;
  797. } else {
  798. size += FdpDetermineDiskDescriptionSize(Disks[i]);
  799. }
  800. }
  801. // Account for remembered disks.
  802. size += RememberedDiskCount * sizeof(DISK_DESCRIPTION);
  803. for (i=0; i<RememberedDiskCount; i++) {
  804. if (RememberedDisks[i]->NumberOfPartitions > 1) {
  805. size += (RememberedDisks[i]->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
  806. }
  807. }
  808. diskRegistry = Malloc(size);
  809. diskRegistry->NumberOfDisks = (USHORT)( DiskCount
  810. + RememberedDiskCount
  811. - offLineDiskCount
  812. - removableDiskCount);
  813. diskRegistry->ReservedShort = 0;
  814. diskDescription = diskRegistry->Disks;
  815. for (disk=0; disk<DiskCount; disk++) {
  816. if (Disks[disk]->OffLine || IsDiskRemovable[disk]) {
  817. continue;
  818. }
  819. partition = FdpConstructDiskDescription(Disks[disk], diskDescription);
  820. diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
  821. }
  822. // Toss in remembered disks.
  823. for (i=0; i<RememberedDiskCount; i++) {
  824. // Compute the beginning and end of this remembered disk's
  825. // Disk Description:
  826. partition = RememberedDisks[i]->NumberOfPartitions;
  827. start = (PBYTE)RememberedDisks[i];
  828. end = (PBYTE)&(RememberedDisks[i]->Partitions[partition]);
  829. RtlMoveMemory(diskDescription, RememberedDisks[i], end - start);
  830. diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
  831. }
  832. LOG_DISK_REGISTRY("SaveFt", diskRegistry);
  833. ec = EC(DiskRegistrySet(diskRegistry));
  834. Free(diskRegistry);
  835. if (ec == NO_ERROR) {
  836. FdpInitializeMirrors();
  837. }
  838. return(ec);
  839. }
  840. ULONG
  841. FdpDetermineDiskDescriptionSize(
  842. PDISKSTATE DiskState
  843. )
  844. /*++
  845. Routine Description:
  846. This routine takes a pointer to a disk and determines how much
  847. memory is needed to contain the description of the disk by
  848. counting the number of partitions on the disk and multiplying
  849. the appropriate counts by the appropriate size of the structures.
  850. Arguments:
  851. DiskState - the disk in question.
  852. Return Value:
  853. The memory size needed to contain all of the information on the disk.
  854. --*/
  855. {
  856. ULONG partitionCount;
  857. ULONG size;
  858. if (DiskState->OffLine) {
  859. return(0);
  860. }
  861. size = sizeof(DISK_DESCRIPTION);
  862. partitionCount = ActualPartitionCount(DiskState);
  863. size += (partitionCount ? partitionCount-1 : 0) * sizeof(DISK_PARTITION);
  864. return(size);
  865. }
  866. ULONG
  867. FdpConstructDiskDescription(
  868. IN PDISKSTATE DiskState,
  869. OUT PDISK_DESCRIPTION DiskDescription
  870. )
  871. /*++
  872. Routine Description:
  873. Given a disk state pointer as input, construct the FtRegistry
  874. structure to describe the partitions on the disk.
  875. Arguments:
  876. DiskState - the disk for which to construct the information
  877. DiskDescription - the memory location where the registry
  878. structure is to be created.
  879. Return Value:
  880. The number of partitions described in the DiskDescription.
  881. --*/
  882. {
  883. PDISKSTATE ds = DiskState;
  884. ULONG partition,
  885. region;
  886. PREGION_DESCRIPTOR regionDescriptor;
  887. PDISK_PARTITION diskPartition;
  888. CHAR driveLetter;
  889. BOOLEAN assignDriveLetter;
  890. PFT_OBJECT ftObject;
  891. PFT_OBJECT_SET ftSet;
  892. partition = 0;
  893. for (region=0; region<ds->RegionCount; region++) {
  894. regionDescriptor = &ds->RegionArray[region];
  895. if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID) && IsRecognizedPartition(regionDescriptor->SysID)) {
  896. diskPartition = &DiskDescription->Partitions[partition++];
  897. diskPartition->StartingOffset = FdGetExactOffset(regionDescriptor);
  898. diskPartition->Length = FdGetExactSize(regionDescriptor, FALSE);
  899. diskPartition->LogicalNumber = (USHORT)regionDescriptor->PartitionNumber;
  900. switch (driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter) {
  901. case NO_DRIVE_LETTER_YET:
  902. assignDriveLetter = TRUE;
  903. driveLetter = 0;
  904. break;
  905. case NO_DRIVE_LETTER_EVER:
  906. assignDriveLetter = FALSE;
  907. driveLetter = 0;
  908. break;
  909. default:
  910. assignDriveLetter = TRUE;
  911. break;
  912. }
  913. diskPartition->DriveLetter = driveLetter;
  914. diskPartition->FtLength.LowPart = 0;
  915. diskPartition->FtLength.HighPart = 0;
  916. diskPartition->ReservedTwoLongs[0] = 0;
  917. diskPartition->ReservedTwoLongs[1] = 0;
  918. diskPartition->Modified = TRUE;
  919. if (ftObject = GET_FT_OBJECT(regionDescriptor)) {
  920. PREGION_DESCRIPTOR tmpDescriptor;
  921. ftSet = ftObject->Set;
  922. tmpDescriptor = LocateRegionForFtObject(ftSet->Member0);
  923. // Only update status if member zero is present.
  924. // otherwise the status is know to be Orphaned or
  925. // needs regeneration.
  926. #if 0
  927. // need to do something here, but currently this does not work.
  928. if (tmpDescriptor) {
  929. ULONG numberOfMembers;
  930. FT_SET_STATUS setState;
  931. STATUS_CODE status;
  932. // If the partition number is zero, then this set
  933. // has not been committed to the disk yet. Only
  934. // update status for existing sets.
  935. if ((tmpDescriptor->PartitionNumber) &&
  936. (ftSet->Status != FtSetNew) &&
  937. (ftSet->Status != FtSetNewNeedsInitialization)) {
  938. status = LowFtVolumeStatus(tmpDescriptor->Disk,
  939. tmpDescriptor->PartitionNumber,
  940. &setState,
  941. &numberOfMembers);
  942. if (status == OK_STATUS) {
  943. if (ftSet->Status != setState) {
  944. // Problem here - the FT driver has
  945. // updated the status of the set after
  946. // windisk last got the status. Need
  947. // to restart the process of building
  948. // the FT information after updating
  949. // the set to the new state.
  950. FdftUpdateFtObjectSet(ftSet, setState);
  951. // now recurse and start over
  952. status =
  953. FdpConstructDiskDescription(DiskState,
  954. DiskDescription);
  955. return status;
  956. }
  957. }
  958. }
  959. }
  960. #endif
  961. diskPartition->FtState = ftObject->State;
  962. diskPartition->FtType = ftSet->Type;
  963. diskPartition->FtGroup = (USHORT)ftSet->Ordinal;
  964. diskPartition->FtMember = (USHORT)ftObject->MemberIndex;
  965. if (assignDriveLetter && (ftObject == ftObject->Set->Member0)) {
  966. diskPartition->AssignDriveLetter = TRUE;
  967. } else {
  968. diskPartition->AssignDriveLetter = FALSE;
  969. }
  970. } else {
  971. diskPartition->FtState = Healthy;
  972. diskPartition->FtType = NotAnFtMember;
  973. diskPartition->FtGroup = (USHORT)(-1);
  974. diskPartition->FtMember = 0;
  975. diskPartition->AssignDriveLetter = assignDriveLetter;
  976. }
  977. }
  978. }
  979. DiskDescription->NumberOfPartitions = (USHORT)partition;
  980. DiskDescription->Signature = ds->Signature;
  981. DiskDescription->ReservedShort = 0;
  982. return(partition);
  983. }
  984. VOID
  985. FdpRememberDisk(
  986. IN PDISK_DESCRIPTION DiskDescription
  987. )
  988. /*++
  989. Routine Description:
  990. Make a copy of a registry disk description structure for later use.
  991. Arguments:
  992. DiskDescription - supplies pointer to the registry descriptor for
  993. the disk in question.
  994. Return Value:
  995. None.
  996. --*/
  997. {
  998. PDISK_DESCRIPTION diskDescription;
  999. ULONG Size;
  1000. // Only bother remembering disks with at least one partition.
  1001. if (DiskDescription->NumberOfPartitions == 0) {
  1002. return;
  1003. }
  1004. // Compute the size of the structure
  1005. Size = sizeof(DISK_DESCRIPTION);
  1006. if (DiskDescription->NumberOfPartitions > 1) {
  1007. Size += (DiskDescription->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
  1008. }
  1009. diskDescription = Malloc(Size);
  1010. RtlMoveMemory(diskDescription, DiskDescription, Size);
  1011. RememberedDisks = Realloc(RememberedDisks,
  1012. (RememberedDiskCount + 1) * sizeof(PDISK_DESCRIPTION));
  1013. RememberedDisks[RememberedDiskCount++] = diskDescription;
  1014. FDLOG((2,
  1015. "FdpRememberDisk: remembered disk %08lx, remembered count = %u\n",
  1016. diskDescription->Signature,
  1017. RememberedDiskCount));
  1018. }
  1019. VOID
  1020. FdpInitializeMirrors(
  1021. VOID
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. For each existing partition that was mirrored by the user during this Disk Manager
  1026. session, call the FT driver to register initialization of the mirror (ie, cause
  1027. the primary to be copied to the secondary). Perform a similar initialization for
  1028. each stripe set with parity created by the user.
  1029. Arguments:
  1030. None.
  1031. Return Value:
  1032. None.
  1033. --*/
  1034. {
  1035. PFT_OBJECT_SET ftSet;
  1036. PFT_OBJECT ftMember;
  1037. // Look through the list of FT sets for mirrored pairs and parity stripes
  1038. for (ftSet = FtObjects; ftSet; ftSet = ftSet->Next) {
  1039. // If the set needs initialization, or was recovered,
  1040. // call the FT driver.
  1041. switch (ftSet->Status) {
  1042. case FtSetNewNeedsInitialization:
  1043. DiskRegistryInitializeSet((USHORT)ftSet->Type,
  1044. (USHORT)ftSet->Ordinal);
  1045. ftSet->Status = FtSetInitializing;
  1046. break;
  1047. case FtSetRecovered:
  1048. // Find the member that needs to be addressed.
  1049. for (ftMember=ftSet->Members; ftMember; ftMember=ftMember->Next) {
  1050. if (ftMember->State == Regenerating) {
  1051. break;
  1052. }
  1053. }
  1054. DiskRegistryRegenerateSet((USHORT)ftSet->Type,
  1055. (USHORT)ftSet->Ordinal,
  1056. (USHORT)ftMember->MemberIndex);
  1057. ftSet->Status = FtSetRegenerating;
  1058. break;
  1059. default:
  1060. break;
  1061. }
  1062. }
  1063. }