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.

1517 lines
32 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. partitio.cxx
  5. Abstract:
  6. This module contains the code specific to partitions for the fault
  7. tolerance driver.
  8. Author:
  9. Bob Rinne (bobri) 2-Feb-1992
  10. Mike Glass (mglass)
  11. Norbert Kusters 2-Feb-1995
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. extern "C" {
  18. #include <ntddk.h>
  19. }
  20. #include <ftdisk.h>
  21. class REPLACE_BAD_SECTOR_CONTEXT : public WORK_QUEUE_ITEM {
  22. public:
  23. PDEVICE_OBJECT TargetObject;
  24. PIRP Irp;
  25. };
  26. typedef REPLACE_BAD_SECTOR_CONTEXT *PREPLACE_BAD_SECTOR_CONTEXT;
  27. NTSTATUS
  28. PartitionBroadcastIrpCompletionRoutine(
  29. IN PDEVICE_OBJECT DeviceObject,
  30. IN PIRP Irp,
  31. IN PVOID CompletionContext
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma code_seg("PAGE")
  35. #endif
  36. NTSTATUS
  37. PARTITION::Initialize(
  38. IN OUT PROOT_EXTENSION RootExtension,
  39. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  40. IN OUT PDEVICE_OBJECT TargetObject,
  41. IN OUT PDEVICE_OBJECT WholeDiskPdo
  42. )
  43. /*++
  44. Routine Description:
  45. Initialize routine for FT_VOLUME of type PARTITION.
  46. Arguments:
  47. RootExtension - Supplies the root device extension.
  48. LogicalDiskId - Supplies the logical disk id for this volume.
  49. TargetObject - Supplies the partition to which transfer requests are
  50. forwarded to.
  51. WholeDiskPdo - Supplies the whole disk for this partition.
  52. Return Value:
  53. None.
  54. --*/
  55. {
  56. KEVENT event;
  57. PIRP irp;
  58. DISK_GEOMETRY geometry;
  59. IO_STATUS_BLOCK ioStatus;
  60. NTSTATUS status;
  61. ULONG diskNumber, otherDiskNumber;
  62. LONGLONG offset, partitionSize;
  63. FT_VOLUME::Initialize(RootExtension, LogicalDiskId);
  64. _targetObject = TargetObject;
  65. _wholeDiskPdo = WholeDiskPdo;
  66. KeInitializeEvent(&event, NotificationEvent, FALSE);
  67. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  68. TargetObject, NULL, 0, &geometry,
  69. sizeof(geometry), FALSE, &event,
  70. &ioStatus);
  71. if (!irp) {
  72. return STATUS_INSUFFICIENT_RESOURCES;
  73. }
  74. status = IoCallDriver(TargetObject, irp);
  75. if (status == STATUS_PENDING) {
  76. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  77. status = ioStatus.Status;
  78. }
  79. if (!NT_SUCCESS(status)) {
  80. return status;
  81. }
  82. _sectorSize = geometry.BytesPerSector;
  83. status = FtpQueryPartitionInformation(RootExtension, TargetObject,
  84. &diskNumber, &_partitionOffset,
  85. NULL, NULL, &_partitionLength,
  86. NULL, NULL, NULL, NULL);
  87. if (!NT_SUCCESS(status)) {
  88. return status;
  89. }
  90. if (!_diskInfoSet->QueryFtPartitionInformation(LogicalDiskId,
  91. &offset, NULL,
  92. &otherDiskNumber, NULL,
  93. &partitionSize)) {
  94. return STATUS_INVALID_PARAMETER;
  95. }
  96. if (partitionSize > 0 && partitionSize <= _partitionLength) {
  97. _partitionLength = partitionSize;
  98. }
  99. if (offset != _partitionOffset || diskNumber != otherDiskNumber) {
  100. return STATUS_INVALID_PARAMETER;
  101. }
  102. _emergencyIrp = IoAllocateIrp(_targetObject->StackSize, FALSE);
  103. if (!_emergencyIrp) {
  104. return STATUS_INSUFFICIENT_RESOURCES;
  105. }
  106. _emergencyIrpInUse = FALSE;
  107. InitializeListHead(&_emergencyIrpQueue);
  108. return STATUS_SUCCESS;
  109. }
  110. FT_LOGICAL_DISK_TYPE
  111. PARTITION::QueryLogicalDiskType(
  112. )
  113. /*++
  114. Routine Description:
  115. This routine returns the type of the logical disk.
  116. Arguments:
  117. None.
  118. Return Value:
  119. The type of the logical disk.
  120. --*/
  121. {
  122. return FtPartition;
  123. }
  124. NTSTATUS
  125. PARTITION::OrphanMember(
  126. IN USHORT MemberNumber,
  127. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  128. IN PVOID Context
  129. )
  130. /*++
  131. Routine Description:
  132. This routine tries to orphan the given member of this logical disk.
  133. A completion routine will be called if and only if this attempt is successful.
  134. Arguments:
  135. MemberNumber - Supplies the member number to orphan.
  136. CompletionRoutine - Supplies the completion routine.
  137. Context - Supplies the completion routine context.
  138. Return Value:
  139. NTSTATUS
  140. --*/
  141. {
  142. return STATUS_INVALID_PARAMETER;
  143. }
  144. NTSTATUS
  145. PARTITION::RegenerateMember(
  146. IN USHORT MemberNumber,
  147. IN OUT PFT_VOLUME NewMember,
  148. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  149. IN PVOID Context
  150. )
  151. /*++
  152. Routine Description:
  153. This routine regenerates the given member of this volume with
  154. the given volume.
  155. Arguments:
  156. MemberNumber - Supplies the member number to regenerate.
  157. NewMember - Supplies the new member to regenerate to.
  158. CompletionRoutine - Supplies the completion routine.
  159. Context - Supplies the completion routine context.
  160. Return Value:
  161. NTSTATUS
  162. --*/
  163. {
  164. return STATUS_INVALID_PARAMETER;
  165. }
  166. VOID
  167. PartitionReplaceBadSectorWorker(
  168. IN PVOID Context
  169. )
  170. {
  171. PREPLACE_BAD_SECTOR_CONTEXT context = (PREPLACE_BAD_SECTOR_CONTEXT) Context;
  172. IoCallDriver(context->TargetObject, context->Irp);
  173. }
  174. VOID
  175. PARTITION::StopSyncOperations(
  176. )
  177. /*++
  178. Routine Description:
  179. This routine stops all sync operations.
  180. Arguments:
  181. None.
  182. Return Value:
  183. None.
  184. --*/
  185. {
  186. }
  187. VOID
  188. PARTITION::BroadcastIrp(
  189. IN PIRP Irp,
  190. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  191. IN PVOID Context
  192. )
  193. /*++
  194. Routine Description:
  195. This routine broadcasts a copy of the given IRP to every partition that
  196. is a member of the logical disk.
  197. Arguments:
  198. Irp - Supplies the I/O request packet.
  199. CompletionRoutine - Supplies the routine to be called when the operation
  200. completes.
  201. Context - Supplies the completion routine context.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. PIRP irp;
  207. PIO_STACK_LOCATION irpSp, sp;
  208. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  209. irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
  210. if (!irp) {
  211. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  212. return;
  213. }
  214. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
  215. ExAllocatePool(NonPagedPool,
  216. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  217. if (!completionContext) {
  218. IoFreeIrp(irp);
  219. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  220. return;
  221. }
  222. completionContext->CompletionRoutine = CompletionRoutine;
  223. completionContext->Context = Context;
  224. irpSp = IoGetNextIrpStackLocation(irp);
  225. sp = IoGetCurrentIrpStackLocation(Irp);
  226. *irpSp = *sp;
  227. IoSetCompletionRoutine(irp, PartitionBroadcastIrpCompletionRoutine,
  228. completionContext, TRUE, TRUE, TRUE);
  229. IoCallDriver(_targetObject, irp);
  230. }
  231. PFT_VOLUME
  232. PARTITION::GetParentLogicalDisk(
  233. IN PFT_VOLUME Volume
  234. )
  235. /*++
  236. Routine Description:
  237. This routine returns the parent of the given logical disk within
  238. this volume.
  239. Arguments:
  240. Volume - Supplies the sub-volume of which we are looking for the parent.
  241. Return Value:
  242. The parent volume or NULL;
  243. --*/
  244. {
  245. return NULL;
  246. }
  247. VOID
  248. PARTITION::SetDirtyBit(
  249. IN BOOLEAN IsDirty,
  250. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  251. IN PVOID Context
  252. )
  253. /*++
  254. Routine Description:
  255. This routine sets the dirty bit on the volume. This bit is used at
  256. startup to determine whether or not there was a clean shutdown.
  257. Arguments:
  258. IsDirty - Supplies the value of the dirty bit.
  259. Return Value:
  260. None.
  261. --*/
  262. {
  263. if (CompletionRoutine) {
  264. CompletionRoutine(Context, STATUS_SUCCESS);
  265. }
  266. }
  267. NTSTATUS
  268. PARTITION::CheckIo(
  269. OUT PBOOLEAN IsIoOk
  270. )
  271. /*++
  272. Routine Description:
  273. This routine returns whether or not IO is possible on the given
  274. partition.
  275. Arguments:
  276. IsIoOk - Returns the state of IO.
  277. Return Value:
  278. NTSTATUS
  279. --*/
  280. {
  281. PVOID buffer;
  282. LARGE_INTEGER offset;
  283. KEVENT event;
  284. PIRP irp;
  285. IO_STATUS_BLOCK ioStatus;
  286. NTSTATUS status;
  287. PIO_STACK_LOCATION irpSp;
  288. buffer = ExAllocatePool(NonPagedPoolCacheAligned, PAGE_SIZE);
  289. if (!buffer) {
  290. return STATUS_INSUFFICIENT_RESOURCES;
  291. }
  292. offset.QuadPart = 0;
  293. KeInitializeEvent(&event, NotificationEvent, FALSE);
  294. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, _targetObject,
  295. buffer, PAGE_SIZE, &offset, &event,
  296. &ioStatus);
  297. if (!irp) {
  298. ExFreePool(buffer);
  299. return STATUS_INSUFFICIENT_RESOURCES;
  300. }
  301. irpSp = IoGetNextIrpStackLocation(irp);
  302. irpSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  303. status = IoCallDriver(_targetObject, irp);
  304. if (status == STATUS_PENDING) {
  305. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  306. status = ioStatus.Status;
  307. }
  308. if (FsRtlIsTotalDeviceFailure(status)) {
  309. *IsIoOk = FALSE;
  310. } else {
  311. *IsIoOk = TRUE;
  312. }
  313. ExFreePool(buffer);
  314. return STATUS_SUCCESS;
  315. }
  316. NTSTATUS
  317. PARTITION::SetPartitionType(
  318. IN UCHAR PartitionType
  319. )
  320. /*++
  321. Routine Description:
  322. This routine sets the partition type on all the members of the
  323. FT set.
  324. Arguments:
  325. PartitionType - Supplies the partition type.
  326. Return Value:
  327. NTSTATUS
  328. --*/
  329. {
  330. KEVENT event;
  331. SET_PARTITION_INFORMATION partInfo;
  332. PIRP irp;
  333. IO_STATUS_BLOCK ioStatus;
  334. NTSTATUS status;
  335. KeInitializeEvent(&event, NotificationEvent, FALSE);
  336. partInfo.PartitionType = (PartitionType | 0x80);
  337. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO,
  338. _targetObject, &partInfo,
  339. sizeof(partInfo), NULL, 0, FALSE,
  340. &event, &ioStatus);
  341. if (!irp) {
  342. return STATUS_INSUFFICIENT_RESOURCES;
  343. }
  344. status = IoCallDriver(_targetObject, irp);
  345. if (status == STATUS_PENDING) {
  346. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  347. status = ioStatus.Status;
  348. }
  349. return status;
  350. }
  351. UCHAR
  352. PARTITION::QueryPartitionType(
  353. )
  354. /*++
  355. Routine Description:
  356. This routine queries the partition type.
  357. Arguments:
  358. None.
  359. Return Value:
  360. The partition type.
  361. --*/
  362. {
  363. KEVENT event;
  364. PIRP irp;
  365. PARTITION_INFORMATION partInfo;
  366. IO_STATUS_BLOCK ioStatus;
  367. NTSTATUS status;
  368. KeInitializeEvent(&event, NotificationEvent, FALSE);
  369. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
  370. _targetObject, NULL, 0, &partInfo,
  371. sizeof(partInfo), FALSE, &event,
  372. &ioStatus);
  373. if (!irp) {
  374. return 0;
  375. }
  376. status = IoCallDriver(_targetObject, irp);
  377. if (status == STATUS_PENDING) {
  378. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  379. status = ioStatus.Status;
  380. }
  381. if (!NT_SUCCESS(status)) {
  382. return 0;
  383. }
  384. return partInfo.PartitionType;
  385. }
  386. UCHAR
  387. PARTITION::QueryStackSize(
  388. )
  389. /*++
  390. Routine Description:
  391. This routine queries IRP stack size.
  392. Arguments:
  393. None.
  394. Return Value:
  395. The IRP stack size.
  396. --*/
  397. {
  398. return _targetObject->StackSize;
  399. }
  400. VOID
  401. PARTITION::CreateLegacyNameLinks(
  402. IN PUNICODE_STRING DeviceName
  403. )
  404. /*++
  405. Routine Description:
  406. This routine creates the \Device\HarddiskN\PartitionM links for
  407. this object to the given device name.
  408. Arguments:
  409. DeviceName - Supplies the device name.
  410. Return Value:
  411. None.
  412. --*/
  413. {
  414. NTSTATUS status;
  415. ULONG diskNumber, partitionNumber;
  416. WCHAR buf[80];
  417. UNICODE_STRING symName;
  418. status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
  419. &diskNumber, NULL, &partitionNumber,
  420. NULL, NULL, NULL, NULL, NULL, NULL);
  421. if (!NT_SUCCESS(status)) {
  422. return;
  423. }
  424. swprintf(buf, L"\\Device\\Harddisk%d\\Partition%d", diskNumber,
  425. partitionNumber);
  426. RtlInitUnicodeString(&symName, buf);
  427. IoDeleteSymbolicLink(&symName);
  428. if (DeviceName) {
  429. IoCreateSymbolicLink(&symName, DeviceName);
  430. }
  431. }
  432. NTSTATUS
  433. PARTITION::QueryPhysicalOffsets(
  434. IN LONGLONG LogicalOffset,
  435. OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
  436. OUT PULONG NumberOfPhysicalOffsets
  437. )
  438. /*++
  439. Routine Description:
  440. This routine returns physical disk and offset for a given volume
  441. logical offset.
  442. Arguments:
  443. LogicalOffset - Supplies the logical offset
  444. PhysicalOffsets - Returns the physical offsets
  445. NumberOfPhysicalOffsets - Returns the number of physical offsets
  446. Return Value:
  447. NTSTATUS
  448. --*/
  449. {
  450. NTSTATUS status;
  451. ULONG diskNumber;
  452. PVOLUME_PHYSICAL_OFFSET physicalOffset;
  453. status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
  454. &diskNumber, NULL, NULL,
  455. NULL, NULL, NULL, NULL, NULL, NULL);
  456. if (!NT_SUCCESS(status)) {
  457. return status;
  458. }
  459. if (LogicalOffset < 0 ||
  460. _partitionLength <= LogicalOffset) {
  461. return STATUS_INVALID_PARAMETER;
  462. }
  463. physicalOffset = (PVOLUME_PHYSICAL_OFFSET) ExAllocatePool(PagedPool, sizeof(VOLUME_PHYSICAL_OFFSET));
  464. if (!physicalOffset) {
  465. return STATUS_INSUFFICIENT_RESOURCES;
  466. }
  467. physicalOffset->DiskNumber = diskNumber;
  468. physicalOffset->Offset = _partitionOffset + LogicalOffset;
  469. *PhysicalOffsets = physicalOffset;
  470. *NumberOfPhysicalOffsets = 1;
  471. return status;
  472. }
  473. NTSTATUS
  474. PARTITION::QueryLogicalOffset(
  475. IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
  476. OUT PLONGLONG LogicalOffset
  477. )
  478. /*++
  479. Routine Description:
  480. This routine returns the volume logical offset for a given disk number
  481. and physical offset.
  482. Arguments:
  483. PhysicalOffset - Supplies the physical offset
  484. LogicalOffset - Returns the logical offset
  485. Return Value:
  486. NTSTATUS
  487. --*/
  488. {
  489. NTSTATUS status;
  490. ULONG diskNumber;
  491. PVOLUME_PHYSICAL_OFFSET physicalOffset;
  492. status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
  493. &diskNumber, NULL, NULL,
  494. NULL, NULL, NULL, NULL, NULL, NULL);
  495. if (!NT_SUCCESS(status)) {
  496. return status;
  497. }
  498. if (PhysicalOffset->DiskNumber != diskNumber ||
  499. PhysicalOffset->Offset < _partitionOffset ||
  500. _partitionOffset + _partitionLength <= PhysicalOffset->Offset) {
  501. return STATUS_INVALID_PARAMETER;
  502. }
  503. *LogicalOffset = PhysicalOffset->Offset - _partitionOffset;
  504. return status;
  505. }
  506. #ifdef ALLOC_PRAGMA
  507. #pragma code_seg("PAGELK")
  508. #endif
  509. PARTITION::~PARTITION(
  510. )
  511. {
  512. if (_emergencyIrp) {
  513. IoFreeIrp(_emergencyIrp);
  514. _emergencyIrp = NULL;
  515. }
  516. }
  517. USHORT
  518. PARTITION::QueryNumberOfMembers(
  519. )
  520. /*++
  521. Routine Description:
  522. This routine returns the number of members in this volume.
  523. Arguments:
  524. None.
  525. Return Value:
  526. 0 - A volume of type partition has no members.
  527. --*/
  528. {
  529. return 0;
  530. }
  531. PFT_VOLUME
  532. PARTITION::GetMember(
  533. IN USHORT MemberNumber
  534. )
  535. /*++
  536. Routine Description:
  537. This routine returns the 'MemberNumber'th member of this volume.
  538. Arguments:
  539. MemberNumber - Supplies the zero based member number desired.
  540. Return Value:
  541. A pointer to the 'MemberNumber'th member or NULL if no such member.
  542. --*/
  543. {
  544. ASSERT(FALSE);
  545. return NULL;
  546. }
  547. NTSTATUS
  548. PartitionTransferCompletionRoutine(
  549. IN PDEVICE_OBJECT DeviceObject,
  550. IN PIRP Irp,
  551. IN PVOID TransferPacket
  552. )
  553. /*++
  554. Routine Description:
  555. Completion routine for PARTITION::Transfer function.
  556. Arguments:
  557. Irp - Supplies the IRP.
  558. TransferPacket - Supplies the transfer packet.
  559. Return Value:
  560. STATUS_MORE_PROCESSING_REQUIRED
  561. --*/
  562. {
  563. PTRANSFER_PACKET transferPacket = (PTRANSFER_PACKET) TransferPacket;
  564. PPARTITION t = (PPARTITION) transferPacket->TargetVolume;
  565. KIRQL irql;
  566. PLIST_ENTRY l;
  567. PIRP irp;
  568. PTRANSFER_PACKET p;
  569. PIO_STACK_LOCATION irpSp;
  570. transferPacket->IoStatus = Irp->IoStatus;
  571. if (Irp == transferPacket->OriginalIrp) {
  572. transferPacket->CompletionRoutine(transferPacket);
  573. return STATUS_MORE_PROCESSING_REQUIRED;
  574. }
  575. if (Irp->AssociatedIrp.SystemBuffer) {
  576. ExFreePool(Irp->AssociatedIrp.SystemBuffer);
  577. }
  578. if (Irp == t->_emergencyIrp) {
  579. for (;;) {
  580. KeAcquireSpinLock(&t->_spinLock, &irql);
  581. if (IsListEmpty(&t->_emergencyIrpQueue)) {
  582. t->_emergencyIrpInUse = FALSE;
  583. KeReleaseSpinLock(&t->_spinLock, irql);
  584. break;
  585. }
  586. l = RemoveHeadList(&t->_emergencyIrpQueue);
  587. KeReleaseSpinLock(&t->_spinLock, irql);
  588. irp = IoAllocateIrp(t->_targetObject->StackSize, FALSE);
  589. if (!irp) {
  590. irp = t->_emergencyIrp;
  591. IoReuseIrp(irp, STATUS_SUCCESS);
  592. }
  593. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  594. irpSp = IoGetNextIrpStackLocation(irp);
  595. irp->MdlAddress = p->Mdl;
  596. irpSp->Parameters.Write.ByteOffset.QuadPart = p->Offset;
  597. irpSp->Parameters.Write.Length = p->Length;
  598. if (p->ReadPacket) {
  599. irpSp->MajorFunction = IRP_MJ_READ;
  600. } else {
  601. irpSp->MajorFunction = IRP_MJ_WRITE;
  602. }
  603. irpSp->DeviceObject = t->_targetObject;
  604. irp->Tail.Overlay.Thread = p->Thread;
  605. irpSp->Flags = p->IrpFlags;
  606. IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
  607. p, TRUE, TRUE, TRUE);
  608. if (irp == Irp) {
  609. IoCallDriver(t->_targetObject, irp);
  610. break;
  611. } else {
  612. IoCallDriver(t->_targetObject, irp);
  613. }
  614. }
  615. } else {
  616. IoFreeIrp(Irp);
  617. }
  618. transferPacket->CompletionRoutine(transferPacket);
  619. return STATUS_MORE_PROCESSING_REQUIRED;
  620. }
  621. VOID
  622. PARTITION::Transfer(
  623. IN OUT PTRANSFER_PACKET TransferPacket
  624. )
  625. /*++
  626. Routine Description:
  627. Transfer routine for PARTITION type FT_VOLUME. Basically,
  628. just pass the request down to the target object.
  629. Arguments:
  630. TransferPacket - Supplies the transfer packet.
  631. Return Value:
  632. None.
  633. --*/
  634. {
  635. KIRQL irql;
  636. PIRP irp;
  637. PIO_STACK_LOCATION irpSp;
  638. PVERIFY_INFORMATION verifyInfo;
  639. irp = TransferPacket->OriginalIrp;
  640. if (!irp) {
  641. irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
  642. if (!irp) {
  643. if (!TransferPacket->Mdl) {
  644. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  645. TransferPacket->IoStatus.Information = 0;
  646. TransferPacket->CompletionRoutine(TransferPacket);
  647. return;
  648. }
  649. KeAcquireSpinLock(&_spinLock, &irql);
  650. if (_emergencyIrpInUse) {
  651. InsertTailList(&_emergencyIrpQueue, &TransferPacket->QueueEntry);
  652. KeReleaseSpinLock(&_spinLock, irql);
  653. return;
  654. }
  655. _emergencyIrpInUse = TRUE;
  656. KeReleaseSpinLock(&_spinLock, irql);
  657. irp = _emergencyIrp;
  658. IoReuseIrp(irp, STATUS_SUCCESS);
  659. }
  660. }
  661. irpSp = IoGetNextIrpStackLocation(irp);
  662. if (TransferPacket->Mdl) {
  663. irp->MdlAddress = TransferPacket->Mdl;
  664. irpSp->Parameters.Write.ByteOffset.QuadPart = TransferPacket->Offset;
  665. irpSp->Parameters.Write.Length = TransferPacket->Length;
  666. if (TransferPacket->ReadPacket) {
  667. irpSp->MajorFunction = IRP_MJ_READ;
  668. } else {
  669. irpSp->MajorFunction = IRP_MJ_WRITE;
  670. }
  671. } else {
  672. // Since there is no MDL, this is a verify request.
  673. verifyInfo = (PVERIFY_INFORMATION)
  674. ExAllocatePool(NonPagedPool, sizeof(VERIFY_INFORMATION));
  675. if (!verifyInfo) {
  676. IoFreeIrp(irp);
  677. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  678. TransferPacket->IoStatus.Information = 0;
  679. TransferPacket->CompletionRoutine(TransferPacket);
  680. return;
  681. }
  682. verifyInfo->StartingOffset.QuadPart = TransferPacket->Offset;
  683. verifyInfo->Length = TransferPacket->Length;
  684. irp->AssociatedIrp.SystemBuffer = verifyInfo;
  685. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  686. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(VERIFY_INFORMATION);
  687. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_VERIFY;
  688. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  689. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  690. }
  691. irpSp->DeviceObject = _targetObject;
  692. irp->Tail.Overlay.Thread = TransferPacket->Thread;
  693. irpSp->Flags = TransferPacket->IrpFlags;
  694. IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
  695. TransferPacket, TRUE, TRUE, TRUE);
  696. IoCallDriver(_targetObject, irp);
  697. }
  698. VOID
  699. PARTITION::ReplaceBadSector(
  700. IN OUT PTRANSFER_PACKET TransferPacket
  701. )
  702. /*++
  703. Routine Description:
  704. This routine attempts to fix the given bad sector by performing
  705. a reassign blocks ioctl.
  706. Arguments:
  707. TransferPacket - Supplies the transfer packet.
  708. Return Value:
  709. None.
  710. --*/
  711. {
  712. PIRP irp;
  713. PIO_STACK_LOCATION irpSp;
  714. PREASSIGN_BLOCKS badBlock;
  715. ULONG n, size, first, i;
  716. PREPLACE_BAD_SECTOR_CONTEXT context;
  717. irp = IoAllocateIrp(_targetObject->StackSize, FALSE);
  718. if (!irp) {
  719. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  720. TransferPacket->IoStatus.Information = 0;
  721. TransferPacket->CompletionRoutine(TransferPacket);
  722. return;
  723. }
  724. n = TransferPacket->Length/_sectorSize;
  725. size = FIELD_OFFSET(REASSIGN_BLOCKS, BlockNumber) + n*sizeof(ULONG);
  726. badBlock = (PREASSIGN_BLOCKS) ExAllocatePool(NonPagedPool, size);
  727. if (!badBlock) {
  728. IoFreeIrp(irp);
  729. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  730. TransferPacket->IoStatus.Information = 0;
  731. TransferPacket->CompletionRoutine(TransferPacket);
  732. return;
  733. }
  734. badBlock->Reserved = 0;
  735. badBlock->Count = 1;
  736. first = (ULONG) ((TransferPacket->Offset + _partitionOffset)/_sectorSize);
  737. for (i = 0; i < n; i++) {
  738. badBlock->BlockNumber[i] = first + i;
  739. }
  740. irp->AssociatedIrp.SystemBuffer = badBlock;
  741. irpSp = IoGetNextIrpStackLocation(irp);
  742. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  743. irpSp->Parameters.DeviceIoControl.InputBufferLength = size;
  744. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_REASSIGN_BLOCKS;
  745. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  746. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  747. irpSp->DeviceObject = _targetObject;
  748. irp->Tail.Overlay.Thread = TransferPacket->Thread;
  749. irpSp->Flags = TransferPacket->IrpFlags;
  750. IoSetCompletionRoutine(irp, PartitionTransferCompletionRoutine,
  751. TransferPacket, TRUE, TRUE, TRUE);
  752. context = (PREPLACE_BAD_SECTOR_CONTEXT)
  753. ExAllocatePool(NonPagedPool, sizeof(REPLACE_BAD_SECTOR_CONTEXT));
  754. if (!context) {
  755. ExFreePool(badBlock);
  756. IoFreeIrp(irp);
  757. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  758. TransferPacket->IoStatus.Information = 0;
  759. TransferPacket->CompletionRoutine(TransferPacket);
  760. return;
  761. }
  762. ExInitializeWorkItem(context, PartitionReplaceBadSectorWorker, context);
  763. context->TargetObject = _targetObject;
  764. context->Irp = irp;
  765. FtpQueueWorkItem(_rootExtension, context);
  766. }
  767. VOID
  768. PARTITION::StartSyncOperations(
  769. IN BOOLEAN RegenerateOrphans,
  770. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  771. IN PVOID Context
  772. )
  773. /*++
  774. Routine Description:
  775. This routine restarts any regenerate or initialize requests that
  776. were suspended because of a reboot. The volume examines the member
  777. state of all of its constituents and restarts any regenerations pending.
  778. Arguments:
  779. RegenerateOrphans - Supplies whether or not to try and regenerate
  780. orphaned members.
  781. CompletionRoutine - Supplies the completion routine.
  782. Context - Supplies the context for the completion routine.
  783. Return Value:
  784. None.
  785. --*/
  786. {
  787. CompletionRoutine(Context, STATUS_SUCCESS);
  788. }
  789. NTSTATUS
  790. PartitionBroadcastIrpCompletionRoutine(
  791. IN PDEVICE_OBJECT DeviceObject,
  792. IN PIRP Irp,
  793. IN PVOID CompletionContext
  794. )
  795. /*++
  796. Routine Description:
  797. Completion routine for PARTITION::BroadcastIrp functions.
  798. Arguments:
  799. Irp - Supplies the IRP.
  800. CompletionContext - Supplies the completion context.
  801. Return Value:
  802. STATUS_MORE_PROCESSING_REQUIRED
  803. --*/
  804. {
  805. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  806. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT) CompletionContext;
  807. completionContext->CompletionRoutine(completionContext->Context,
  808. Irp->IoStatus.Status);
  809. IoFreeIrp(Irp);
  810. ExFreePool(CompletionContext);
  811. return STATUS_MORE_PROCESSING_REQUIRED;
  812. }
  813. ULONG
  814. PARTITION::QuerySectorSize(
  815. )
  816. /*++
  817. Routine Description:
  818. Returns the sector size for the volume.
  819. Arguments:
  820. None.
  821. Return Value:
  822. The volume sector size in bytes.
  823. --*/
  824. {
  825. return _sectorSize;
  826. }
  827. LONGLONG
  828. PARTITION::QueryVolumeSize(
  829. )
  830. /*++
  831. Routine Description:
  832. Returns the number of bytes on the entire volume.
  833. Arguments:
  834. None.
  835. Return Value:
  836. The volume size in bytes.
  837. --*/
  838. {
  839. return _partitionLength;
  840. }
  841. PFT_VOLUME
  842. PARTITION::GetContainedLogicalDisk(
  843. IN FT_LOGICAL_DISK_ID LogicalDiskId
  844. )
  845. /*++
  846. Routine Description:
  847. This routine returns TRUE if the given logical disk id
  848. represents this logical disk or if this logical disk contains
  849. the given logical disk id either directly or indirectly.
  850. Arguments:
  851. LogicalDiskId - Supplies the logical disk id that we are searching for.
  852. Return Value:
  853. FALSE - The given logical disk id is not contained in this logical disk.
  854. TRUE - The given logical disk id is contained in this logical disk.
  855. --*/
  856. {
  857. if (LogicalDiskId == QueryLogicalDiskId()) {
  858. return this;
  859. }
  860. return NULL;
  861. }
  862. PFT_VOLUME
  863. PARTITION::GetContainedLogicalDisk(
  864. IN PDEVICE_OBJECT TargetObject
  865. )
  866. /*++
  867. Routine Description:
  868. This routine returns TRUE if the given logical disk id
  869. represents this logical disk or if this logical disk contains
  870. the given logical disk id either directly or indirectly.
  871. Arguments:
  872. TargetObject - Supplies the target object.
  873. Return Value:
  874. FALSE - The given logical disk id is not contained in this logical disk.
  875. TRUE - The given logical disk id is contained in this logical disk.
  876. --*/
  877. {
  878. if (TargetObject == _targetObject) {
  879. return this;
  880. }
  881. return NULL;
  882. }
  883. PFT_VOLUME
  884. PARTITION::GetContainedLogicalDisk(
  885. IN ULONG Signature,
  886. IN LONGLONG Offset
  887. )
  888. /*++
  889. Routine Description:
  890. This routine returns TRUE if the given logical disk id
  891. represents this logical disk or if this logical disk contains
  892. the given logical disk id either directly or indirectly.
  893. Arguments:
  894. Signature - Supplies the signature.
  895. Offset - Supplies the partition offset.
  896. Return Value:
  897. FALSE - The given logical disk id is not contained in this logical disk.
  898. TRUE - The given logical disk id is contained in this logical disk.
  899. --*/
  900. {
  901. if (Offset != _partitionOffset) {
  902. return NULL;
  903. }
  904. if (Signature == FtpQueryDiskSignature(_wholeDiskPdo)) {
  905. return this;
  906. }
  907. return NULL;
  908. }
  909. VOID
  910. PARTITION::SetMember(
  911. IN USHORT MemberNumber,
  912. IN PFT_VOLUME Member
  913. )
  914. /*++
  915. Routine Description:
  916. This routine sets the given member in this volume.
  917. Arguments:
  918. MemberNumber - Supplies the member number.
  919. Member - Supplies the member.
  920. Return Value:
  921. None.
  922. --*/
  923. {
  924. ASSERT(FALSE);
  925. }
  926. BOOLEAN
  927. PARTITION::IsComplete(
  928. IN BOOLEAN IoPending
  929. )
  930. /*++
  931. Routine Description:
  932. This routine computes whether or not this volume has either all
  933. (if IoPending is FALSE) of its members or enough (if IoPending is TRUE) of
  934. its members.
  935. Arguments:
  936. IoPending - Supplies whether or not there is IO pending.
  937. Return Value:
  938. None.
  939. --*/
  940. {
  941. return TRUE;
  942. }
  943. VOID
  944. PARTITION::CompleteNotification(
  945. IN BOOLEAN IoPending
  946. )
  947. /*++
  948. Routine Description:
  949. This routine is called to notify the volume that it is complete and
  950. to therefore prepare for incoming requests.
  951. Arguments:
  952. IoPending - Supplies whether or not there is IO pending.
  953. Return Value:
  954. None.
  955. --*/
  956. {
  957. }
  958. ULONG
  959. PARTITION::QueryNumberOfPartitions(
  960. )
  961. /*++
  962. Routine Description:
  963. This routine returns the number of partitions covered by this volume
  964. set.
  965. Arguments:
  966. None.
  967. Return Value:
  968. The number of partitions covered by this volume set.
  969. --*/
  970. {
  971. return 1;
  972. }
  973. PDEVICE_OBJECT
  974. PARTITION::GetLeftmostPartitionObject(
  975. )
  976. {
  977. return _targetObject;
  978. }
  979. NTSTATUS
  980. PARTITION::QueryDiskExtents(
  981. OUT PDISK_EXTENT* DiskExtents,
  982. OUT PULONG NumberOfDiskExtents
  983. )
  984. /*++
  985. Routine Description:
  986. This routine returns an array of disk extents that describe the
  987. location of this volume.
  988. Arguments:
  989. DiskExtents - Returns the disk extents.
  990. NumberOfDiskExtents - Returns the number of disk extents.
  991. Return Value:
  992. NTSTATUS
  993. --*/
  994. {
  995. NTSTATUS status;
  996. ULONG diskNumber;
  997. PDISK_EXTENT diskExtent;
  998. status = FtpQueryPartitionInformation(_rootExtension, _targetObject,
  999. &diskNumber, NULL, NULL,
  1000. NULL, NULL, NULL, NULL, NULL, NULL);
  1001. if (!NT_SUCCESS(status)) {
  1002. return status;
  1003. }
  1004. diskExtent = (PDISK_EXTENT) ExAllocatePool(PagedPool, sizeof(DISK_EXTENT));
  1005. if (!diskExtent) {
  1006. return STATUS_INSUFFICIENT_RESOURCES;
  1007. }
  1008. diskExtent->DiskNumber = diskNumber;
  1009. diskExtent->StartingOffset.QuadPart = _partitionOffset;
  1010. diskExtent->ExtentLength.QuadPart = _partitionLength;
  1011. *DiskExtents = diskExtent;
  1012. *NumberOfDiskExtents = 1;
  1013. return status;
  1014. }
  1015. BOOLEAN
  1016. PARTITION::QueryVolumeState(
  1017. IN PFT_VOLUME Volume,
  1018. OUT PFT_MEMBER_STATE State
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine returns the state of the given volume considered as a
  1023. member of this volume.
  1024. Arguments:
  1025. Volume - Supplies the volume to query the state for.
  1026. State - Returns the state.
  1027. Return Value:
  1028. FALSE - The given Volume is not a member of this volume.
  1029. TRUE - The state was successfully computed.
  1030. --*/
  1031. {
  1032. if (Volume != this) {
  1033. return FALSE;
  1034. }
  1035. *State = FtMemberHealthy;
  1036. return TRUE;
  1037. }