Leaked source code of windows server 2003
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.

22225 lines
712 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. volsnap.cxx
  5. Abstract:
  6. This driver provides volume snapshot capabilities.
  7. Author:
  8. Norbert P. Kusters (norbertk) 22-Jan-1999
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. extern "C" {
  15. #define RTL_USE_AVL_TABLES 0
  16. #include <stdio.h>
  17. #include <ntosp.h>
  18. #include <zwapi.h>
  19. #include <snaplog.h>
  20. #include <initguid.h>
  21. #include <ntddsnap.h>
  22. #include <volsnap.h>
  23. #include <mountdev.h>
  24. #include <ntddvol.h>
  25. #include <ntdddisk.h>
  26. #include <ioevent.h>
  27. #include <wdmguid.h>
  28. #ifndef IRP_HIGH_PRIORITY_PAGING_IO
  29. #define IRP_HIGH_PRIORITY_PAGING_IO 0x00008000
  30. #endif
  31. #if defined(_WIN64)
  32. #define ERROR_LOG_ENTRY_SIZE (0x30)
  33. #else
  34. #define ERROR_LOG_ENTRY_SIZE (0x20)
  35. #endif
  36. static const SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
  37. NTSTATUS
  38. DriverEntry(
  39. IN PDRIVER_OBJECT DriverObject,
  40. IN PUNICODE_STRING RegistryPath
  41. );
  42. NTKERNELAPI
  43. KPRIORITY
  44. KeQueryPriorityThread (
  45. IN PKTHREAD Thread
  46. );
  47. BOOLEAN
  48. VspIsSetup(
  49. );
  50. }
  51. #define OLD_IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS CTL_CODE(VOLSNAPCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS)
  52. #define OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA CTL_CODE(VOLSNAPCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS)
  53. #define OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES CTL_CODE(VOLSNAPCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS)
  54. #define OLD_IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME CTL_CODE(VOLSNAPCONTROLTYPE, 100, METHOD_BUFFERED, FILE_READ_ACCESS)
  55. #define OLD_IOCTL_VOLSNAP_QUERY_CONFIG_INFO CTL_CODE(VOLSNAPCONTROLTYPE, 101, METHOD_BUFFERED, FILE_READ_ACCESS)
  56. #define OLD_IOCTL_VOLSNAP_QUERY_APPLICATION_INFO CTL_CODE(VOLSNAPCONTROLTYPE, 103, METHOD_BUFFERED, FILE_READ_ACCESS)
  57. ULONG VsErrorLogSequence = 0;
  58. VOID
  59. VspWriteVolume(
  60. IN PVOID Context
  61. );
  62. VOID
  63. VspWorkerThread(
  64. IN PVOID RootExtension
  65. );
  66. VOID
  67. VspCleanupInitialSnapshot(
  68. IN PVOLUME_EXTENSION Extension,
  69. IN BOOLEAN NeedLock,
  70. IN BOOLEAN IsFinalRemove
  71. );
  72. VOID
  73. VspWriteVolumePhase1(
  74. IN PVOID TableEntry
  75. );
  76. VOID
  77. VspFreeCopyIrp(
  78. IN PVOLUME_EXTENSION Extension,
  79. IN PIRP CopyIrp
  80. );
  81. NTSTATUS
  82. VspAbortPreparedSnapshot(
  83. IN PFILTER_EXTENSION Filter,
  84. IN BOOLEAN NeedLock,
  85. IN BOOLEAN IsFinalRemove
  86. );
  87. NTSTATUS
  88. VspReleaseWrites(
  89. IN PFILTER_EXTENSION Filter
  90. );
  91. NTSTATUS
  92. VspSetApplicationInfo(
  93. IN PVOLUME_EXTENSION Extension,
  94. IN PIRP Irp
  95. );
  96. NTSTATUS
  97. VspWriteContextCompletionRoutine(
  98. IN PDEVICE_OBJECT DeviceObject,
  99. IN PIRP Irp,
  100. IN PVOID Filter
  101. );
  102. NTSTATUS
  103. VspRefCountCompletionRoutine(
  104. IN PDEVICE_OBJECT DeviceObject,
  105. IN PIRP Irp,
  106. IN PVOID Filter
  107. );
  108. VOID
  109. VspCleanupFilter(
  110. IN PFILTER_EXTENSION Filter,
  111. IN BOOLEAN IsOffline,
  112. IN BOOLEAN IsFinalRemove
  113. );
  114. VOID
  115. VspDecrementRefCount(
  116. IN PFILTER_EXTENSION Filter
  117. );
  118. NTSTATUS
  119. VspSignalCompletion(
  120. IN PDEVICE_OBJECT DeviceObject,
  121. IN PIRP Irp,
  122. IN PVOID Event
  123. );
  124. NTSTATUS
  125. VspMarkFreeSpaceInBitmap(
  126. IN PVOLUME_EXTENSION Extension,
  127. IN HANDLE UseThisHandle,
  128. IN PRTL_BITMAP BitmapToSet
  129. );
  130. VOID
  131. VspAndBitmaps(
  132. IN OUT PRTL_BITMAP BaseBitmap,
  133. IN PRTL_BITMAP FactorBitmap
  134. );
  135. NTSTATUS
  136. VspDeleteOldestSnapshot(
  137. IN PFILTER_EXTENSION Filter,
  138. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose,
  139. IN OUT PLIST_ENTRY LisfOfDeviceObjectsToDelete,
  140. IN BOOLEAN KeepOnDisk,
  141. IN BOOLEAN DontWakePnp
  142. );
  143. VOID
  144. VspCloseDiffAreaFiles(
  145. IN PLIST_ENTRY ListOfDiffAreaFilesToClose,
  146. IN PLIST_ENTRY ListOfDeviceObjectsToDelete
  147. );
  148. NTSTATUS
  149. VspComputeIgnorableProduct(
  150. IN PVOLUME_EXTENSION Extension
  151. );
  152. NTSTATUS
  153. VspIoControlItem(
  154. IN PFILTER_EXTENSION Filter,
  155. IN ULONG ControlItemType,
  156. IN GUID* SnapshotGuid,
  157. IN BOOLEAN IsSet,
  158. IN OUT PVOID ControlItem,
  159. IN BOOLEAN AcquireLock
  160. );
  161. NTSTATUS
  162. VspCleanupControlItemsForSnapshot(
  163. IN PVOLUME_EXTENSION Extension
  164. );
  165. VOID
  166. VspWriteTableUpdates(
  167. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  168. );
  169. VOID
  170. VspKillTableUpdates(
  171. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  172. );
  173. NTSTATUS
  174. VspAllocateDiffAreaSpace(
  175. IN PVOLUME_EXTENSION Extension,
  176. OUT PLONGLONG TargetOffset,
  177. OUT PLONGLONG FileOffset,
  178. IN OUT PDIFF_AREA_FILE_ALLOCATION* CurrentFileAllocation,
  179. IN OUT PLONGLONG CurrentOffset
  180. );
  181. VOID
  182. VspResumeVolumeIo(
  183. IN PFILTER_EXTENSION Filter
  184. );
  185. VOID
  186. VspPauseVolumeIo(
  187. IN PFILTER_EXTENSION Filter
  188. );
  189. NTSTATUS
  190. VspCreateDiffAreaFileName(
  191. IN PDEVICE_OBJECT DeviceObject,
  192. IN PVOLUME_EXTENSION Extension,
  193. OUT PUNICODE_STRING DiffAreaFileName,
  194. IN BOOLEAN ValidateSystemVolumeInformationFolder,
  195. IN GUID* SnapshotGuid
  196. );
  197. VOID
  198. VspDeleteDiffAreaFilesTimerDpc(
  199. IN struct _KDPC *Dpc,
  200. IN PVOID DeferredContext,
  201. IN PVOID SystemArgument1,
  202. IN PVOID SystemArgument2
  203. );
  204. VOID
  205. VspAcquireNonPagedResource(
  206. IN PDEVICE_EXTENSION Extension,
  207. IN PWORK_QUEUE_ITEM WorkItem,
  208. IN BOOLEAN AlwaysPost
  209. );
  210. VOID
  211. VspReleaseNonPagedResource(
  212. IN PDEVICE_EXTENSION Extension
  213. );
  214. NTSTATUS
  215. VspDeleteControlItemsWithGuid(
  216. IN PFILTER_EXTENSION Filter,
  217. IN GUID* SnapshotGuid,
  218. IN BOOLEAN NonPagedResourceHeld
  219. );
  220. NTSTATUS
  221. VspCreateStartBlock(
  222. IN PFILTER_EXTENSION Filter,
  223. IN LONGLONG ControlBlockOffset,
  224. IN LONGLONG MaximumDiffAreaSpace
  225. );
  226. NTSTATUS
  227. VspPinFile(
  228. IN PDEVICE_OBJECT TargetObject,
  229. IN HANDLE FileHandle
  230. );
  231. NTSTATUS
  232. VspReadDiffAreaTable(
  233. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  234. );
  235. PVSP_LOOKUP_TABLE_ENTRY
  236. VspFindLookupTableItem(
  237. IN PDO_EXTENSION RootExtension,
  238. IN GUID* SnapshotGuid
  239. );
  240. BOOLEAN
  241. VspIsNtfsBootSector(
  242. IN PFILTER_EXTENSION Filter,
  243. IN PVOID BootSector
  244. );
  245. NTSTATUS
  246. VspIsNtfs(
  247. IN HANDLE FileHandle,
  248. OUT PBOOLEAN IsNtfs
  249. );
  250. NTSTATUS
  251. VspOptimizeDiffAreaFileLocation(
  252. IN PFILTER_EXTENSION Filter,
  253. IN HANDLE FileHandle,
  254. IN PVOLUME_EXTENSION BitmapExtension,
  255. IN LONGLONG StartingOffset,
  256. IN LONGLONG FileSize
  257. );
  258. VOID
  259. VspReadSnapshotPhase1(
  260. IN PVOID Context
  261. );
  262. VOID
  263. VspWriteVolumePhase12(
  264. IN PVOID TableEntry
  265. );
  266. NTSTATUS
  267. VspComputeIgnorableBitmap(
  268. IN PVOLUME_EXTENSION Extension,
  269. IN OUT PRTL_BITMAP Bitmap
  270. );
  271. NTSTATUS
  272. VspMarkFileAllocationInBitmap(
  273. IN PVOLUME_EXTENSION Extension,
  274. IN HANDLE FileHandle,
  275. IN PVSP_DIFF_AREA_FILE DiffAreaFile,
  276. IN PRTL_BITMAP BitmapToSet
  277. );
  278. NTSTATUS
  279. VolSnapWrite(
  280. IN PDEVICE_OBJECT DeviceObject,
  281. IN PIRP Irp
  282. );
  283. VOID
  284. VspStartCopyOnWrite(
  285. IN PVOID Context
  286. );
  287. VOID
  288. VspOnlineWorker(
  289. IN PVOID Context
  290. );
  291. VOID
  292. VspOfflineWorker(
  293. IN PVOID Context
  294. );
  295. VOID
  296. VspStartCopyOnWriteCache(
  297. IN PVOID Filter
  298. );
  299. VOID
  300. VspQueueLowPriorityWorkItem(
  301. IN PDO_EXTENSION RootExtension,
  302. IN PWORK_QUEUE_ITEM WorkItem
  303. );
  304. VOID
  305. VspCleanupPreamble(
  306. IN PFILTER_EXTENSION Filter
  307. );
  308. #ifdef ALLOC_PRAGMA
  309. #pragma alloc_text(INIT, DriverEntry)
  310. #pragma alloc_text(INIT, VspIsSetup)
  311. #endif
  312. #ifdef ALLOC_PRAGMA
  313. #pragma code_seg("PAGELK")
  314. #endif
  315. VOID
  316. VspAcquire(
  317. IN PDO_EXTENSION RootExtension
  318. )
  319. {
  320. KeWaitForSingleObject(&RootExtension->Semaphore, Executive, KernelMode,
  321. FALSE, NULL);
  322. }
  323. VOID
  324. VspRelease(
  325. IN PDO_EXTENSION RootExtension
  326. )
  327. {
  328. KeReleaseSemaphore(&RootExtension->Semaphore, IO_NO_INCREMENT, 1, FALSE);
  329. }
  330. VOID
  331. VspAcquireCritical(
  332. IN PFILTER_EXTENSION Filter
  333. )
  334. {
  335. KeWaitForSingleObject(&Filter->CriticalOperationSemaphore, Executive,
  336. KernelMode, FALSE, NULL);
  337. }
  338. VOID
  339. VspReleaseCritical(
  340. IN PFILTER_EXTENSION Filter
  341. )
  342. {
  343. KeReleaseSemaphore(&Filter->CriticalOperationSemaphore, IO_NO_INCREMENT, 1, FALSE);
  344. }
  345. PVSP_CONTEXT
  346. VspAllocateContext(
  347. IN PDO_EXTENSION RootExtension
  348. )
  349. {
  350. PVSP_CONTEXT context;
  351. context = (PVSP_CONTEXT) ExAllocateFromNPagedLookasideList(
  352. &RootExtension->ContextLookasideList);
  353. return context;
  354. }
  355. VOID
  356. VspFreeContext(
  357. IN PDO_EXTENSION RootExtension,
  358. IN PVSP_CONTEXT Context
  359. )
  360. {
  361. KIRQL irql;
  362. PLIST_ENTRY l;
  363. PIRP irp;
  364. PIO_STACK_LOCATION irpSp;
  365. if (RootExtension->EmergencyContext == Context) {
  366. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  367. RootExtension->EmergencyContextInUse = FALSE;
  368. if (IsListEmpty(&RootExtension->IrpWaitingList)) {
  369. InterlockedExchange(&RootExtension->IrpWaitingListNeedsChecking,
  370. FALSE);
  371. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  372. return;
  373. }
  374. l = RemoveHeadList(&RootExtension->IrpWaitingList);
  375. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  376. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  377. irpSp = IoGetCurrentIrpStackLocation(irp);
  378. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  379. irpSp->DeviceObject, irp);
  380. return;
  381. }
  382. ExFreeToNPagedLookasideList(&RootExtension->ContextLookasideList,
  383. Context);
  384. if (!RootExtension->IrpWaitingListNeedsChecking) {
  385. return;
  386. }
  387. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  388. if (IsListEmpty(&RootExtension->IrpWaitingList)) {
  389. InterlockedExchange(&RootExtension->IrpWaitingListNeedsChecking,
  390. FALSE);
  391. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  392. return;
  393. }
  394. l = RemoveHeadList(&RootExtension->IrpWaitingList);
  395. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  396. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  397. irpSp = IoGetCurrentIrpStackLocation(irp);
  398. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  399. irpSp->DeviceObject, irp);
  400. }
  401. PVSP_WRITE_CONTEXT
  402. VspAllocateWriteContext(
  403. IN PDO_EXTENSION RootExtension
  404. )
  405. {
  406. PVSP_WRITE_CONTEXT writeContext;
  407. writeContext = (PVSP_WRITE_CONTEXT) ExAllocateFromNPagedLookasideList(
  408. &RootExtension->WriteContextLookasideList);
  409. return writeContext;
  410. }
  411. VOID
  412. VspFreeWriteContext(
  413. IN PDO_EXTENSION RootExtension,
  414. IN PVSP_WRITE_CONTEXT WriteContext
  415. )
  416. {
  417. KIRQL irql;
  418. PLIST_ENTRY l;
  419. PIRP irp;
  420. PIO_STACK_LOCATION irpSp;
  421. if (RootExtension->EmergencyWriteContext == WriteContext) {
  422. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  423. RootExtension->EmergencyWriteContextInUse = FALSE;
  424. if (IsListEmpty(&RootExtension->WriteContextIrpWaitingList)) {
  425. InterlockedExchange(
  426. &RootExtension->WriteContextIrpWaitingListNeedsChecking,
  427. FALSE);
  428. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  429. return;
  430. }
  431. l = RemoveHeadList(&RootExtension->WriteContextIrpWaitingList);
  432. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  433. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  434. irpSp = IoGetCurrentIrpStackLocation(irp);
  435. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  436. irpSp->DeviceObject, irp);
  437. return;
  438. }
  439. ExFreeToNPagedLookasideList(&RootExtension->WriteContextLookasideList,
  440. WriteContext);
  441. if (!RootExtension->WriteContextIrpWaitingListNeedsChecking) {
  442. return;
  443. }
  444. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  445. if (IsListEmpty(&RootExtension->WriteContextIrpWaitingList)) {
  446. InterlockedExchange(
  447. &RootExtension->WriteContextIrpWaitingListNeedsChecking,
  448. FALSE);
  449. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  450. return;
  451. }
  452. l = RemoveHeadList(&RootExtension->WriteContextIrpWaitingList);
  453. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  454. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  455. irpSp = IoGetCurrentIrpStackLocation(irp);
  456. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  457. irpSp->DeviceObject, irp);
  458. }
  459. PVOID
  460. VspAllocateTempTableEntry(
  461. IN PDO_EXTENSION RootExtension
  462. )
  463. {
  464. PVOID tempTableEntry;
  465. tempTableEntry = ExAllocateFromNPagedLookasideList(
  466. &RootExtension->TempTableEntryLookasideList);
  467. return tempTableEntry;
  468. }
  469. VOID
  470. VspQueueWorkItem(
  471. IN PDO_EXTENSION RootExtension,
  472. IN PWORK_QUEUE_ITEM WorkItem,
  473. IN ULONG QueueNumber
  474. )
  475. {
  476. KIRQL irql;
  477. ASSERT(QueueNumber < NUMBER_OF_THREAD_POOLS);
  478. KeAcquireSpinLock(&RootExtension->SpinLock[QueueNumber], &irql);
  479. InsertTailList(&RootExtension->WorkerQueue[QueueNumber], &WorkItem->List);
  480. KeReleaseSpinLock(&RootExtension->SpinLock[QueueNumber], irql);
  481. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[QueueNumber],
  482. IO_NO_INCREMENT, 1, FALSE);
  483. }
  484. VOID
  485. VspFreeTempTableEntry(
  486. IN PDO_EXTENSION RootExtension,
  487. IN PVOID TempTableEntry
  488. )
  489. {
  490. KIRQL irql;
  491. PLIST_ENTRY l;
  492. PWORK_QUEUE_ITEM workItem;
  493. if (RootExtension->EmergencyTableEntry == TempTableEntry) {
  494. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  495. RootExtension->EmergencyTableEntryInUse = FALSE;
  496. if (IsListEmpty(&RootExtension->WorkItemWaitingList)) {
  497. InterlockedExchange(
  498. &RootExtension->WorkItemWaitingListNeedsChecking, FALSE);
  499. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  500. return;
  501. }
  502. l = RemoveHeadList(&RootExtension->WorkItemWaitingList);
  503. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  504. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  505. VspQueueWorkItem(RootExtension, workItem, 2);
  506. return;
  507. }
  508. ExFreeToNPagedLookasideList(&RootExtension->TempTableEntryLookasideList,
  509. TempTableEntry);
  510. if (!RootExtension->WorkItemWaitingListNeedsChecking) {
  511. return;
  512. }
  513. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  514. if (IsListEmpty(&RootExtension->WorkItemWaitingList)) {
  515. InterlockedExchange(&RootExtension->WorkItemWaitingListNeedsChecking,
  516. FALSE);
  517. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  518. return;
  519. }
  520. l = RemoveHeadList(&RootExtension->WorkItemWaitingList);
  521. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  522. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  523. VspQueueWorkItem(RootExtension, workItem, 2);
  524. }
  525. VOID
  526. VspLogErrorWorker(
  527. IN PVOID Context
  528. )
  529. {
  530. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  531. PVOLUME_EXTENSION extension = context->ErrorLog.Extension;
  532. PFILTER_EXTENSION diffAreaFilter = context->ErrorLog.DiffAreaFilter;
  533. PFILTER_EXTENSION filter;
  534. NTSTATUS status;
  535. UNICODE_STRING filterDosName, diffAreaFilterDosName;
  536. USHORT systemStringLength, myStringLength, allocSize;
  537. USHORT allStringsLimit;
  538. USHORT limit;
  539. WCHAR buffer[100];
  540. UNICODE_STRING deviceName;
  541. PIO_ERROR_LOG_PACKET errorLogPacket;
  542. PWCHAR p;
  543. ASSERT(context->Type == VSP_CONTEXT_TYPE_ERROR_LOG);
  544. if (extension) {
  545. filter = extension->Filter;
  546. } else {
  547. filter = diffAreaFilter;
  548. diffAreaFilter = NULL;
  549. }
  550. status = IoVolumeDeviceToDosName(filter->DeviceObject, &filterDosName);
  551. if (!NT_SUCCESS(status)) {
  552. goto Cleanup;
  553. }
  554. myStringLength = filterDosName.Length + sizeof(WCHAR);
  555. if (diffAreaFilter) {
  556. status = IoVolumeDeviceToDosName(diffAreaFilter->DeviceObject,
  557. &diffAreaFilterDosName);
  558. if (!NT_SUCCESS(status)) {
  559. ExFreePool(filterDosName.Buffer);
  560. goto Cleanup;
  561. }
  562. myStringLength += diffAreaFilterDosName.Length + sizeof(WCHAR);
  563. }
  564. systemStringLength = 8*sizeof(WCHAR); // Space required for VOLSNAP driver name.
  565. if (extension) {
  566. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  567. extension->VolumeNumber);
  568. RtlInitUnicodeString(&deviceName, buffer);
  569. systemStringLength += deviceName.Length + sizeof(WCHAR);
  570. } else {
  571. systemStringLength += sizeof(WCHAR);
  572. }
  573. limit = ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET);
  574. allStringsLimit = IO_ERROR_LOG_MESSAGE_LENGTH -
  575. sizeof(IO_ERROR_LOG_MESSAGE) - ERROR_LOG_ENTRY_SIZE;
  576. ASSERT(allStringsLimit > systemStringLength);
  577. if (limit > allStringsLimit - systemStringLength) {
  578. limit = allStringsLimit - systemStringLength;
  579. }
  580. if (myStringLength > limit) {
  581. if (diffAreaFilter) {
  582. limit /= 2;
  583. }
  584. limit &= ~1;
  585. limit -= sizeof(WCHAR);
  586. if (filterDosName.Length > limit) {
  587. filterDosName.Buffer[3] = '.';
  588. filterDosName.Buffer[4] = '.';
  589. filterDosName.Buffer[5] = '.';
  590. RtlMoveMemory(&filterDosName.Buffer[6],
  591. (PCHAR) filterDosName.Buffer + filterDosName.Length -
  592. limit + 6*sizeof(WCHAR), limit - 6*sizeof(WCHAR));
  593. filterDosName.Length = limit;
  594. filterDosName.Buffer[filterDosName.Length/sizeof(WCHAR)] = 0;
  595. }
  596. if (diffAreaFilter && diffAreaFilterDosName.Length > limit) {
  597. diffAreaFilterDosName.Buffer[3] = '.';
  598. diffAreaFilterDosName.Buffer[4] = '.';
  599. diffAreaFilterDosName.Buffer[5] = '.';
  600. RtlMoveMemory(&diffAreaFilterDosName.Buffer[6],
  601. (PCHAR) diffAreaFilterDosName.Buffer +
  602. diffAreaFilterDosName.Length - limit +
  603. 6*sizeof(WCHAR), limit - 6*sizeof(WCHAR));
  604. diffAreaFilterDosName.Length = limit;
  605. diffAreaFilterDosName.Buffer[
  606. diffAreaFilterDosName.Length/sizeof(WCHAR)] = 0;
  607. }
  608. }
  609. errorLogPacket = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(extension ?
  610. extension->DeviceObject : filter->DeviceObject,
  611. ERROR_LOG_MAXIMUM_SIZE);
  612. if (!errorLogPacket) {
  613. if (diffAreaFilter) {
  614. ExFreePool(diffAreaFilterDosName.Buffer);
  615. }
  616. ExFreePool(filterDosName.Buffer);
  617. goto Cleanup;
  618. }
  619. errorLogPacket->ErrorCode = context->ErrorLog.SpecificIoStatus;
  620. errorLogPacket->SequenceNumber = VsErrorLogSequence++;
  621. errorLogPacket->FinalStatus = context->ErrorLog.FinalStatus;
  622. errorLogPacket->UniqueErrorValue = context->ErrorLog.UniqueErrorValue;
  623. errorLogPacket->DumpDataSize = 0;
  624. errorLogPacket->RetryCount = 0;
  625. errorLogPacket->NumberOfStrings = 1;
  626. errorLogPacket->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
  627. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET));
  628. RtlCopyMemory(p, filterDosName.Buffer, filterDosName.Length);
  629. p[filterDosName.Length/sizeof(WCHAR)] = 0;
  630. if (diffAreaFilter) {
  631. errorLogPacket->NumberOfStrings = 2;
  632. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET) +
  633. filterDosName.Length + sizeof(WCHAR));
  634. RtlCopyMemory(p, diffAreaFilterDosName.Buffer,
  635. diffAreaFilterDosName.Length);
  636. p[diffAreaFilterDosName.Length/sizeof(WCHAR)] = 0;
  637. }
  638. IoWriteErrorLogEntry(errorLogPacket);
  639. if (diffAreaFilter) {
  640. ExFreePool(diffAreaFilterDosName.Buffer);
  641. }
  642. ExFreePool(filterDosName.Buffer);
  643. Cleanup:
  644. VspFreeContext(filter->Root, context);
  645. if (extension) {
  646. ObDereferenceObject(extension->DeviceObject);
  647. }
  648. ObDereferenceObject(filter->TargetObject);
  649. ObDereferenceObject(filter->DeviceObject);
  650. if (diffAreaFilter) {
  651. ObDereferenceObject(diffAreaFilter->TargetObject);
  652. ObDereferenceObject(diffAreaFilter->DeviceObject);
  653. }
  654. }
  655. VOID
  656. VspLogError(
  657. IN PVOLUME_EXTENSION Extension,
  658. IN PFILTER_EXTENSION DiffAreaFilter,
  659. IN NTSTATUS SpecificIoStatus,
  660. IN NTSTATUS FinalStatus,
  661. IN ULONG UniqueErrorValue,
  662. IN BOOLEAN PerformSynchronously
  663. )
  664. {
  665. PDO_EXTENSION root;
  666. PVSP_CONTEXT context;
  667. if (FinalStatus == STATUS_DEVICE_OFF_LINE) {
  668. return;
  669. }
  670. if (Extension) {
  671. root = Extension->Root;
  672. } else {
  673. root = DiffAreaFilter->Root;
  674. }
  675. context = VspAllocateContext(root);
  676. if (!context) {
  677. return;
  678. }
  679. context->Type = VSP_CONTEXT_TYPE_ERROR_LOG;
  680. context->ErrorLog.Extension = Extension;
  681. context->ErrorLog.DiffAreaFilter = DiffAreaFilter;
  682. context->ErrorLog.SpecificIoStatus = SpecificIoStatus;
  683. context->ErrorLog.FinalStatus = FinalStatus;
  684. context->ErrorLog.UniqueErrorValue = UniqueErrorValue;
  685. if (Extension) {
  686. ObReferenceObject(Extension->DeviceObject);
  687. ObReferenceObject(Extension->Filter->DeviceObject);
  688. ObReferenceObject(Extension->Filter->TargetObject);
  689. }
  690. if (DiffAreaFilter) {
  691. ObReferenceObject(DiffAreaFilter->DeviceObject);
  692. ObReferenceObject(DiffAreaFilter->TargetObject);
  693. }
  694. if (PerformSynchronously) {
  695. VspLogErrorWorker(context);
  696. return;
  697. }
  698. ExInitializeWorkItem(&context->WorkItem, VspLogErrorWorker, context);
  699. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  700. }
  701. VOID
  702. VspWaitForWorkerThreadsToExit(
  703. IN PDO_EXTENSION RootExtension
  704. )
  705. {
  706. PVOID threadObject;
  707. CCHAR i, j;
  708. if (!RootExtension->WorkerThreadObjects ||
  709. RootExtension->ThreadsRefCount) {
  710. return;
  711. }
  712. threadObject = RootExtension->WorkerThreadObjects[0];
  713. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE, NULL);
  714. ObDereferenceObject(threadObject);
  715. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  716. for (j = 0; j < KeNumberProcessors; j++) {
  717. threadObject = RootExtension->WorkerThreadObjects[
  718. (i - 1)*KeNumberProcessors + j + 1];
  719. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE,
  720. NULL);
  721. ObDereferenceObject(threadObject);
  722. }
  723. }
  724. ExFreePool(RootExtension->WorkerThreadObjects);
  725. RootExtension->WorkerThreadObjects = NULL;
  726. }
  727. NTSTATUS
  728. VspCreateWorkerThread(
  729. IN PDO_EXTENSION RootExtension
  730. )
  731. /*++
  732. Routine Description:
  733. This routine will create a new thread for a new volume snapshot. Since
  734. a minimum of 2 threads are needed to prevent deadlocks, if there are
  735. no threads then 2 threads will be created by this routine.
  736. Arguments:
  737. RootExtension - Supplies the root extension.
  738. Return Value:
  739. NTSTATUS
  740. Notes:
  741. The caller must be holding 'Root->Semaphore'.
  742. --*/
  743. {
  744. OBJECT_ATTRIBUTES oa;
  745. PVSP_CONTEXT context;
  746. NTSTATUS status;
  747. HANDLE handle;
  748. PVOID threadObject;
  749. CCHAR i, j, k;
  750. KeWaitForSingleObject(&RootExtension->ThreadsRefCountSemaphore,
  751. Executive, KernelMode, FALSE, NULL);
  752. if (RootExtension->ThreadsRefCount) {
  753. RootExtension->ThreadsRefCount++;
  754. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  755. IO_NO_INCREMENT, 1, FALSE);
  756. return STATUS_SUCCESS;
  757. }
  758. VspWaitForWorkerThreadsToExit(RootExtension);
  759. InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
  760. context = VspAllocateContext(RootExtension);
  761. if (!context) {
  762. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  763. IO_NO_INCREMENT, 1, FALSE);
  764. return STATUS_INSUFFICIENT_RESOURCES;
  765. }
  766. context->Type = VSP_CONTEXT_TYPE_THREAD_CREATION;
  767. context->ThreadCreation.RootExtension = RootExtension;
  768. context->ThreadCreation.QueueNumber = 0;
  769. ASSERT(!RootExtension->WorkerThreadObjects);
  770. RootExtension->WorkerThreadObjects = (PVOID*)
  771. ExAllocatePoolWithTag(NonPagedPool,
  772. (KeNumberProcessors*2 + 1)*sizeof(PVOID),
  773. VOLSNAP_TAG_IO_STATUS);
  774. if (!RootExtension->WorkerThreadObjects) {
  775. VspFreeContext(RootExtension, context);
  776. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  777. IO_NO_INCREMENT, 1, FALSE);
  778. return STATUS_INSUFFICIENT_RESOURCES;
  779. }
  780. status = PsCreateSystemThread(&handle, 0, &oa, 0, NULL, VspWorkerThread,
  781. context);
  782. if (!NT_SUCCESS(status)) {
  783. ExFreePool(RootExtension->WorkerThreadObjects);
  784. RootExtension->WorkerThreadObjects = NULL;
  785. VspFreeContext(RootExtension, context);
  786. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  787. IO_NO_INCREMENT, 1, FALSE);
  788. return status;
  789. }
  790. status = ObReferenceObjectByHandle(handle, THREAD_ALL_ACCESS, NULL,
  791. KernelMode, &threadObject, NULL);
  792. if (!NT_SUCCESS(status)) {
  793. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0],
  794. IO_NO_INCREMENT, 1, FALSE);
  795. ZwWaitForSingleObject(handle, FALSE, NULL);
  796. ExFreePool(RootExtension->WorkerThreadObjects);
  797. RootExtension->WorkerThreadObjects = NULL;
  798. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  799. IO_NO_INCREMENT, 1, FALSE);
  800. return status;
  801. }
  802. RootExtension->WorkerThreadObjects[0] = threadObject;
  803. ZwClose(handle);
  804. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  805. for (j = 0; j < KeNumberProcessors; j++) {
  806. context = VspAllocateContext(RootExtension);
  807. if (!context) {
  808. status = STATUS_INSUFFICIENT_RESOURCES;
  809. handle = NULL;
  810. break;
  811. }
  812. context->Type = VSP_CONTEXT_TYPE_THREAD_CREATION;
  813. context->ThreadCreation.RootExtension = RootExtension;
  814. context->ThreadCreation.QueueNumber = i;
  815. status = PsCreateSystemThread(&handle, 0, &oa, 0, NULL,
  816. VspWorkerThread, context);
  817. if (!NT_SUCCESS(status)) {
  818. VspFreeContext(RootExtension, context);
  819. handle = NULL;
  820. break;
  821. }
  822. status = ObReferenceObjectByHandle(
  823. handle, THREAD_ALL_ACCESS, NULL, KernelMode,
  824. &threadObject, NULL);
  825. if (!NT_SUCCESS(status)) {
  826. break;
  827. }
  828. RootExtension->WorkerThreadObjects[
  829. KeNumberProcessors*(i - 1) + j + 1] = threadObject;
  830. ZwClose(handle);
  831. }
  832. if (j < KeNumberProcessors) {
  833. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i],
  834. IO_NO_INCREMENT, j, FALSE);
  835. if (handle) {
  836. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i],
  837. IO_NO_INCREMENT, 1, FALSE);
  838. ZwWaitForSingleObject(handle, FALSE, NULL);
  839. ZwClose(handle);
  840. }
  841. for (k = 0; k < j; k++) {
  842. threadObject = RootExtension->WorkerThreadObjects[
  843. KeNumberProcessors*(i - 1) + k + 1];
  844. KeWaitForSingleObject(threadObject, Executive, KernelMode,
  845. FALSE, NULL);
  846. ObDereferenceObject(threadObject);
  847. }
  848. break;
  849. }
  850. }
  851. if (i < NUMBER_OF_THREAD_POOLS) {
  852. for (k = 1; k < i; k++) {
  853. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[k],
  854. IO_NO_INCREMENT, KeNumberProcessors, FALSE);
  855. for (j = 0; j < KeNumberProcessors; j++) {
  856. threadObject = RootExtension->WorkerThreadObjects[
  857. KeNumberProcessors*(k - 1) + j + 1];
  858. KeWaitForSingleObject(threadObject, Executive, KernelMode,
  859. FALSE, NULL);
  860. ObDereferenceObject(threadObject);
  861. }
  862. }
  863. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0],
  864. IO_NO_INCREMENT, 1, FALSE);
  865. threadObject = RootExtension->WorkerThreadObjects[0];
  866. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE, NULL);
  867. ObDereferenceObject(threadObject);
  868. ExFreePool(RootExtension->WorkerThreadObjects);
  869. RootExtension->WorkerThreadObjects = NULL;
  870. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  871. IO_NO_INCREMENT, 1, FALSE);
  872. return status;
  873. }
  874. RootExtension->ThreadsRefCount++;
  875. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  876. IO_NO_INCREMENT, 1, FALSE);
  877. return STATUS_SUCCESS;
  878. }
  879. VOID
  880. VspWaitForWorkerThreadsToExitWorker(
  881. IN PVOID RootExtension
  882. )
  883. {
  884. PDO_EXTENSION rootExtension = (PDO_EXTENSION) RootExtension;
  885. KeWaitForSingleObject(&rootExtension->ThreadsRefCountSemaphore,
  886. Executive, KernelMode, FALSE, NULL);
  887. VspWaitForWorkerThreadsToExit(rootExtension);
  888. rootExtension->WaitForWorkerThreadsToExitWorkItemInUse = FALSE;
  889. KeReleaseSemaphore(&rootExtension->ThreadsRefCountSemaphore,
  890. IO_NO_INCREMENT, 1, FALSE);
  891. }
  892. NTSTATUS
  893. VspDeleteWorkerThread(
  894. IN PDO_EXTENSION RootExtension
  895. )
  896. /*++
  897. Routine Description:
  898. This routine will delete a worker thread.
  899. Arguments:
  900. RootExtension - Supplies the root extension.
  901. Return Value:
  902. NTSTATUS
  903. Notes:
  904. The caller must be holding 'Root->Semaphore'.
  905. --*/
  906. {
  907. CCHAR i, j;
  908. KeWaitForSingleObject(&RootExtension->ThreadsRefCountSemaphore,
  909. Executive, KernelMode, FALSE, NULL);
  910. RootExtension->ThreadsRefCount--;
  911. if (RootExtension->ThreadsRefCount) {
  912. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  913. IO_NO_INCREMENT, 1, FALSE);
  914. return STATUS_SUCCESS;
  915. }
  916. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0], IO_NO_INCREMENT, 1,
  917. FALSE);
  918. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  919. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i], IO_NO_INCREMENT,
  920. KeNumberProcessors, FALSE);
  921. }
  922. if (RootExtension->WaitForWorkerThreadsToExitWorkItemInUse) {
  923. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  924. IO_NO_INCREMENT, 1, FALSE);
  925. return STATUS_SUCCESS;
  926. }
  927. RootExtension->WaitForWorkerThreadsToExitWorkItemInUse = TRUE;
  928. ExInitializeWorkItem(&RootExtension->WaitForWorkerThreadsToExitWorkItem,
  929. VspWaitForWorkerThreadsToExitWorker, RootExtension);
  930. ExQueueWorkItem(&RootExtension->WaitForWorkerThreadsToExitWorkItem,
  931. DelayedWorkQueue);
  932. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  933. IO_NO_INCREMENT, 1, FALSE);
  934. return STATUS_SUCCESS;
  935. }
  936. VOID
  937. VspQueryDiffAreaFileIncrease(
  938. IN PVOLUME_EXTENSION Extension,
  939. OUT PULONG Increase
  940. )
  941. {
  942. LONGLONG r;
  943. r = (LONGLONG) Extension->MaximumNumberOfTempEntries;
  944. r <<= BLOCK_SHIFT;
  945. r = (r + LARGEST_NTFS_CLUSTER - 1)&(~(LARGEST_NTFS_CLUSTER - 1));
  946. if (r < NOMINAL_DIFF_AREA_FILE_GROWTH) {
  947. r = NOMINAL_DIFF_AREA_FILE_GROWTH;
  948. } else if (r > MAXIMUM_DIFF_AREA_FILE_GROWTH) {
  949. r = MAXIMUM_DIFF_AREA_FILE_GROWTH;
  950. }
  951. *Increase = (ULONG) r;
  952. }
  953. NTSTATUS
  954. VolSnapDefaultDispatch(
  955. IN PDEVICE_OBJECT DeviceObject,
  956. IN PIRP Irp
  957. )
  958. /*++
  959. Routine Description:
  960. This routine is the default dispatch which passes down to the next layer.
  961. Arguments:
  962. DeviceObject - Supplies the device object.
  963. Irp - Supplies the IO request packet.
  964. Return Value:
  965. NTSTATUS
  966. --*/
  967. {
  968. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  969. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  970. NTSTATUS status;
  971. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  972. IoSkipCurrentIrpStackLocation(Irp);
  973. return IoCallDriver(filter->TargetObject, Irp);
  974. }
  975. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  976. if (irpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL) {
  977. status = Irp->IoStatus.Status;
  978. } else {
  979. status = STATUS_INVALID_DEVICE_REQUEST;
  980. }
  981. Irp->IoStatus.Status = status;
  982. Irp->IoStatus.Information = 0;
  983. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  984. return status;
  985. }
  986. BOOLEAN
  987. VspAreBitsClear(
  988. IN PRTL_BITMAP Bitmap,
  989. IN PIRP Irp
  990. )
  991. {
  992. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  993. LONGLONG start;
  994. ULONG startBlock, endBlock;
  995. BOOLEAN b;
  996. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  997. if (start < 0) {
  998. return FALSE;
  999. }
  1000. startBlock = (ULONG) (start >> BLOCK_SHIFT);
  1001. endBlock = (ULONG) ((start + irpSp->Parameters.Read.Length - 1) >>
  1002. BLOCK_SHIFT);
  1003. b = RtlAreBitsClear(Bitmap, startBlock, endBlock - startBlock + 1);
  1004. return b;
  1005. }
  1006. BOOLEAN
  1007. VspAreBitsSet(
  1008. IN PVOLUME_EXTENSION Extension,
  1009. IN PIRP Irp
  1010. )
  1011. {
  1012. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1013. LONGLONG start;
  1014. ULONG startBlock, endBlock;
  1015. BOOLEAN b;
  1016. if (!Extension->VolumeBlockBitmap) {
  1017. return FALSE;
  1018. }
  1019. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  1020. if (start < 0) {
  1021. return FALSE;
  1022. }
  1023. startBlock = (ULONG) (start >> BLOCK_SHIFT);
  1024. endBlock = (ULONG) ((start + irpSp->Parameters.Read.Length - 1) >>
  1025. BLOCK_SHIFT);
  1026. b = RtlAreBitsSet(Extension->VolumeBlockBitmap, startBlock,
  1027. endBlock - startBlock + 1);
  1028. return b;
  1029. }
  1030. VOID
  1031. VspDecrementVolumeRefCount(
  1032. IN PVOLUME_EXTENSION Extension
  1033. )
  1034. {
  1035. if (InterlockedDecrement(&Extension->RefCount)) {
  1036. return;
  1037. }
  1038. ASSERT(Extension->HoldIncomingRequests);
  1039. KeSetEvent(&Extension->ZeroRefEvent, IO_NO_INCREMENT, FALSE);
  1040. }
  1041. NTSTATUS
  1042. VspIncrementVolumeRefCount(
  1043. IN PVOLUME_EXTENSION Extension
  1044. )
  1045. {
  1046. InterlockedIncrement(&Extension->RefCount);
  1047. if (Extension->IsDead) {
  1048. VspDecrementVolumeRefCount(Extension);
  1049. return STATUS_NO_SUCH_DEVICE;
  1050. }
  1051. ASSERT(!Extension->HoldIncomingRequests);
  1052. return STATUS_SUCCESS;
  1053. }
  1054. VOID
  1055. VspSignalContext(
  1056. IN PVOID Context
  1057. )
  1058. {
  1059. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1060. ASSERT(context->Type == VSP_CONTEXT_TYPE_EVENT);
  1061. KeSetEvent(&context->Event.Event, IO_NO_INCREMENT, FALSE);
  1062. }
  1063. VOID
  1064. VspAcquirePagedResource(
  1065. IN PVOLUME_EXTENSION Extension,
  1066. IN PWORK_QUEUE_ITEM WorkItem
  1067. )
  1068. {
  1069. PFILTER_EXTENSION filter = Extension->Filter;
  1070. KIRQL irql;
  1071. VSP_CONTEXT context;
  1072. BOOLEAN synchronousCall;
  1073. if (WorkItem) {
  1074. synchronousCall = FALSE;
  1075. } else {
  1076. WorkItem = &context.WorkItem;
  1077. context.Type = VSP_CONTEXT_TYPE_EVENT;
  1078. KeInitializeEvent(&context.Event.Event, NotificationEvent, FALSE);
  1079. ExInitializeWorkItem(&context.WorkItem, VspSignalContext, &context);
  1080. synchronousCall = TRUE;
  1081. }
  1082. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1083. if (filter->PagedResourceInUse) {
  1084. InsertTailList(&filter->PagedResourceList, &WorkItem->List);
  1085. KeReleaseSpinLock(&filter->SpinLock, irql);
  1086. if (synchronousCall) {
  1087. KeWaitForSingleObject(&context.Event.Event, Executive,
  1088. KernelMode, FALSE, NULL);
  1089. }
  1090. return;
  1091. }
  1092. filter->PagedResourceInUse = TRUE;
  1093. KeReleaseSpinLock(&filter->SpinLock, irql);
  1094. if (!synchronousCall) {
  1095. VspQueueWorkItem(filter->Root, WorkItem, 1);
  1096. }
  1097. }
  1098. VOID
  1099. VspReleasePagedResource(
  1100. IN PVOLUME_EXTENSION Extension
  1101. )
  1102. {
  1103. PFILTER_EXTENSION filter = Extension->Filter;
  1104. KIRQL irql;
  1105. PLIST_ENTRY l;
  1106. PWORK_QUEUE_ITEM workItem;
  1107. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1108. if (IsListEmpty(&filter->PagedResourceList)) {
  1109. filter->PagedResourceInUse = FALSE;
  1110. KeReleaseSpinLock(&filter->SpinLock, irql);
  1111. return;
  1112. }
  1113. l = RemoveHeadList(&filter->PagedResourceList);
  1114. KeReleaseSpinLock(&filter->SpinLock, irql);
  1115. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  1116. if (workItem->WorkerRoutine == VspSignalContext) {
  1117. workItem->WorkerRoutine(workItem->Parameter);
  1118. } else {
  1119. VspQueueWorkItem(Extension->Root, workItem, 1);
  1120. }
  1121. }
  1122. NTSTATUS
  1123. VspQueryListOfExtents(
  1124. IN HANDLE FileHandle,
  1125. IN LONGLONG FileOffset,
  1126. OUT PLIST_ENTRY ExtentList,
  1127. IN PVOLUME_EXTENSION BitmapExtension,
  1128. IN BOOLEAN ReturnRawValues
  1129. )
  1130. {
  1131. NTSTATUS status;
  1132. IO_STATUS_BLOCK ioStatus;
  1133. FILE_FS_SIZE_INFORMATION fsSize;
  1134. ULONG bpc;
  1135. STARTING_VCN_INPUT_BUFFER input;
  1136. RETRIEVAL_POINTERS_BUFFER output;
  1137. LONGLONG start, length, delta, end, roundedStart, roundedEnd, s;
  1138. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1139. PLIST_ENTRY l;
  1140. KIRQL irql;
  1141. BOOLEAN isNegative, isNtfs;
  1142. InitializeListHead(ExtentList);
  1143. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  1144. &fsSize, sizeof(fsSize),
  1145. FileFsSizeInformation);
  1146. if (!NT_SUCCESS(status)) {
  1147. while (!IsListEmpty(ExtentList)) {
  1148. l = RemoveHeadList(ExtentList);
  1149. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1150. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1151. ExFreePool(diffAreaFileAllocation);
  1152. }
  1153. return status;
  1154. }
  1155. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  1156. input.StartingVcn.QuadPart = FileOffset/bpc;
  1157. for (;;) {
  1158. status = ZwFsControlFile(FileHandle, NULL, NULL, NULL, &ioStatus,
  1159. FSCTL_GET_RETRIEVAL_POINTERS, &input,
  1160. sizeof(input), &output, sizeof(output));
  1161. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
  1162. if (status == STATUS_END_OF_FILE) {
  1163. status = STATUS_SUCCESS;
  1164. }
  1165. break;
  1166. }
  1167. if (!output.ExtentCount) {
  1168. status = STATUS_INVALID_PARAMETER;
  1169. break;
  1170. }
  1171. if (output.Extents[0].Lcn.QuadPart == -1) {
  1172. if (status != STATUS_BUFFER_OVERFLOW) {
  1173. break;
  1174. }
  1175. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  1176. continue;
  1177. }
  1178. delta = input.StartingVcn.QuadPart - output.StartingVcn.QuadPart;
  1179. start = (output.Extents[0].Lcn.QuadPart + delta)*bpc;
  1180. length = (output.Extents[0].NextVcn.QuadPart -
  1181. input.StartingVcn.QuadPart)*bpc;
  1182. end = start + length;
  1183. if (ReturnRawValues) {
  1184. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1185. ExAllocatePoolWithTag(NonPagedPool,
  1186. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1187. VOLSNAP_TAG_BIT_HISTORY);
  1188. if (!diffAreaFileAllocation) {
  1189. status = STATUS_INSUFFICIENT_RESOURCES;
  1190. break;
  1191. }
  1192. diffAreaFileAllocation->Offset = start;
  1193. diffAreaFileAllocation->NLength = length;
  1194. InsertTailList(ExtentList, &diffAreaFileAllocation->ListEntry);
  1195. if (status != STATUS_BUFFER_OVERFLOW) {
  1196. break;
  1197. }
  1198. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  1199. continue;
  1200. }
  1201. roundedStart = start&(~(BLOCK_SIZE - 1));
  1202. roundedEnd = end&(~(BLOCK_SIZE - 1));
  1203. if (start != roundedStart) {
  1204. roundedStart += BLOCK_SIZE;
  1205. }
  1206. if (roundedStart > start) {
  1207. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1208. ExAllocatePoolWithTag(NonPagedPool,
  1209. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1210. VOLSNAP_TAG_BIT_HISTORY);
  1211. if (!diffAreaFileAllocation) {
  1212. status = STATUS_INSUFFICIENT_RESOURCES;
  1213. break;
  1214. }
  1215. diffAreaFileAllocation->Offset = start;
  1216. diffAreaFileAllocation->NLength = -(roundedStart - start);
  1217. if (roundedStart > end) {
  1218. diffAreaFileAllocation->NLength += roundedStart - end;
  1219. }
  1220. ASSERT(diffAreaFileAllocation->NLength);
  1221. InsertTailList(ExtentList, &diffAreaFileAllocation->ListEntry);
  1222. }
  1223. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1224. ExAllocatePoolWithTag(NonPagedPool,
  1225. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1226. VOLSNAP_TAG_BIT_HISTORY);
  1227. if (!diffAreaFileAllocation) {
  1228. status = STATUS_INSUFFICIENT_RESOURCES;
  1229. break;
  1230. }
  1231. diffAreaFileAllocation->Offset = roundedStart;
  1232. diffAreaFileAllocation->NLength = 0;
  1233. for (s = roundedStart; s < roundedEnd; s += BLOCK_SIZE) {
  1234. isNegative = FALSE;
  1235. if (BitmapExtension) {
  1236. KeAcquireSpinLock(&BitmapExtension->SpinLock, &irql);
  1237. if (BitmapExtension->VolumeBlockBitmap &&
  1238. !RtlCheckBit(BitmapExtension->VolumeBlockBitmap,
  1239. s>>BLOCK_SHIFT)) {
  1240. isNegative = TRUE;
  1241. }
  1242. KeReleaseSpinLock(&BitmapExtension->SpinLock, irql);
  1243. }
  1244. if (isNegative) {
  1245. if (diffAreaFileAllocation->NLength <= 0) {
  1246. diffAreaFileAllocation->NLength -= BLOCK_SIZE;
  1247. } else {
  1248. InsertTailList(ExtentList,
  1249. &diffAreaFileAllocation->ListEntry);
  1250. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1251. ExAllocatePoolWithTag(NonPagedPool,
  1252. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1253. VOLSNAP_TAG_BIT_HISTORY);
  1254. if (!diffAreaFileAllocation) {
  1255. status = STATUS_INSUFFICIENT_RESOURCES;
  1256. break;
  1257. }
  1258. diffAreaFileAllocation->Offset = s;
  1259. diffAreaFileAllocation->NLength = -BLOCK_SIZE;
  1260. }
  1261. } else {
  1262. if (diffAreaFileAllocation->NLength >= 0) {
  1263. diffAreaFileAllocation->NLength += BLOCK_SIZE;
  1264. } else {
  1265. InsertTailList(ExtentList,
  1266. &diffAreaFileAllocation->ListEntry);
  1267. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1268. ExAllocatePoolWithTag(NonPagedPool,
  1269. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1270. VOLSNAP_TAG_BIT_HISTORY);
  1271. if (!diffAreaFileAllocation) {
  1272. status = STATUS_INSUFFICIENT_RESOURCES;
  1273. break;
  1274. }
  1275. diffAreaFileAllocation->Offset = s;
  1276. diffAreaFileAllocation->NLength = BLOCK_SIZE;
  1277. }
  1278. }
  1279. }
  1280. if (s < roundedEnd) {
  1281. break;
  1282. }
  1283. if (diffAreaFileAllocation->NLength) {
  1284. InsertTailList(ExtentList, &diffAreaFileAllocation->ListEntry);
  1285. } else {
  1286. ExFreePool(diffAreaFileAllocation);
  1287. }
  1288. if (end > roundedEnd && roundedEnd >= roundedStart) {
  1289. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  1290. ExAllocatePoolWithTag(NonPagedPool,
  1291. sizeof(DIFF_AREA_FILE_ALLOCATION),
  1292. VOLSNAP_TAG_BIT_HISTORY);
  1293. if (!diffAreaFileAllocation) {
  1294. status = STATUS_INSUFFICIENT_RESOURCES;
  1295. break;
  1296. }
  1297. diffAreaFileAllocation->Offset = roundedEnd;
  1298. diffAreaFileAllocation->NLength = -(end - roundedEnd);
  1299. InsertTailList(ExtentList, &diffAreaFileAllocation->ListEntry);
  1300. }
  1301. if (status != STATUS_BUFFER_OVERFLOW) {
  1302. break;
  1303. }
  1304. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  1305. }
  1306. if (!NT_SUCCESS(status)) {
  1307. while (!IsListEmpty(ExtentList)) {
  1308. l = RemoveHeadList(ExtentList);
  1309. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1310. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1311. ExFreePool(diffAreaFileAllocation);
  1312. }
  1313. }
  1314. return status;
  1315. }
  1316. NTSTATUS
  1317. VspQueryFileSize(
  1318. IN HANDLE FileHandle,
  1319. IN PLONGLONG FileSize
  1320. )
  1321. {
  1322. FILE_STANDARD_INFORMATION allocInfo;
  1323. NTSTATUS status;
  1324. IO_STATUS_BLOCK ioStatus;
  1325. status = ZwQueryInformationFile(FileHandle, &ioStatus,
  1326. &allocInfo, sizeof(allocInfo),
  1327. FileStandardInformation);
  1328. *FileSize = allocInfo.AllocationSize.QuadPart;
  1329. return status;
  1330. }
  1331. NTSTATUS
  1332. VspSetFileSize(
  1333. IN HANDLE FileHandle,
  1334. IN LONGLONG FileSize
  1335. )
  1336. {
  1337. FILE_ALLOCATION_INFORMATION allocInfo;
  1338. FILE_END_OF_FILE_INFORMATION eofInfo;
  1339. NTSTATUS status;
  1340. IO_STATUS_BLOCK ioStatus;
  1341. allocInfo.AllocationSize.QuadPart = FileSize;
  1342. eofInfo.EndOfFile.QuadPart = FileSize;
  1343. status = ZwSetInformationFile(FileHandle, &ioStatus,
  1344. &eofInfo, sizeof(eofInfo),
  1345. FileEndOfFileInformation);
  1346. if (!NT_SUCCESS(status)) {
  1347. return status;
  1348. }
  1349. status = ZwSetInformationFile(FileHandle, &ioStatus,
  1350. &allocInfo, sizeof(allocInfo),
  1351. FileAllocationInformation);
  1352. return status;
  1353. }
  1354. NTSTATUS
  1355. VspSynchronousIo(
  1356. IN PIRP Irp,
  1357. IN PDEVICE_OBJECT TargetObject,
  1358. IN UCHAR MajorFunction,
  1359. IN LONGLONG Offset,
  1360. IN ULONG Length
  1361. )
  1362. {
  1363. PIO_STACK_LOCATION nextSp;
  1364. KEVENT event;
  1365. if (!Length) {
  1366. Length = BLOCK_SIZE;
  1367. }
  1368. nextSp = IoGetNextIrpStackLocation(Irp);
  1369. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1370. nextSp->Parameters.Read.ByteOffset.QuadPart = Offset;
  1371. nextSp->Parameters.Read.Length = Length;
  1372. nextSp->MajorFunction = MajorFunction;
  1373. nextSp->DeviceObject = TargetObject;
  1374. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  1375. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1376. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event, TRUE,
  1377. TRUE, TRUE);
  1378. IoCallDriver(nextSp->DeviceObject, Irp);
  1379. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1380. return Irp->IoStatus.Status;
  1381. }
  1382. VOID
  1383. VspFreeUsedDiffAreaSpaceFromPointers(
  1384. IN PVOLUME_EXTENSION Extension,
  1385. IN PDIFF_AREA_FILE_ALLOCATION CurrentFileAllocation,
  1386. IN LONGLONG CurrentOffset
  1387. )
  1388. {
  1389. PVSP_DIFF_AREA_FILE diffAreaFile = Extension->DiffAreaFile;
  1390. PLIST_ENTRY l;
  1391. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1392. ASSERT(diffAreaFile);
  1393. for (;;) {
  1394. if (IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  1395. return;
  1396. }
  1397. l = diffAreaFile->UnusedAllocationList.Flink;
  1398. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1399. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1400. if (diffAreaFileAllocation == CurrentFileAllocation) {
  1401. break;
  1402. }
  1403. RemoveEntryList(l);
  1404. ExFreePool(diffAreaFileAllocation);
  1405. }
  1406. ASSERT(diffAreaFileAllocation->NLength >= 0 || !CurrentOffset);
  1407. diffAreaFileAllocation->Offset += CurrentOffset;
  1408. diffAreaFileAllocation->NLength -= CurrentOffset;
  1409. ASSERT(diffAreaFileAllocation->NLength >= 0 || !CurrentOffset);
  1410. }
  1411. NTSTATUS
  1412. VspAddLocationDescription(
  1413. IN PVSP_DIFF_AREA_FILE DiffAreaFile,
  1414. IN LONGLONG OldAllocatedFileSize
  1415. )
  1416. {
  1417. PVOLUME_EXTENSION extension = DiffAreaFile->Extension;
  1418. LONGLONG fileOffset, t, f;
  1419. PLIST_ENTRY l;
  1420. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1421. PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION locationBlock;
  1422. PVSP_DIFF_AREA_LOCATION_DESCRIPTOR locationDescriptor;
  1423. ULONG blockOffset;
  1424. ULONG totalNumEntries, numEntriesPerBlock, numBlocks, i;
  1425. PLONGLONG fileOffsetArray, targetOffsetArray;
  1426. NTSTATUS status;
  1427. PDIFF_AREA_FILE_ALLOCATION allocationBlock;
  1428. LONGLONG allocationOffset;
  1429. fileOffset = DiffAreaFile->NextAvailable;
  1430. for (l = DiffAreaFile->UnusedAllocationList.Flink;
  1431. l != &DiffAreaFile->UnusedAllocationList; l = l->Flink) {
  1432. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1433. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1434. if (fileOffset == OldAllocatedFileSize) {
  1435. break;
  1436. }
  1437. if (diffAreaFileAllocation->NLength < 0) {
  1438. fileOffset -= diffAreaFileAllocation->NLength;
  1439. } else {
  1440. fileOffset += diffAreaFileAllocation->NLength;
  1441. }
  1442. }
  1443. ASSERT(l != &DiffAreaFile->UnusedAllocationList);
  1444. locationBlock = (PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION)
  1445. MmGetMdlVirtualAddress(DiffAreaFile->TableUpdateIrp->MdlAddress);
  1446. allocationOffset = 0;
  1447. allocationBlock = CONTAINING_RECORD(
  1448. DiffAreaFile->UnusedAllocationList.Flink,
  1449. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1450. for (;;) {
  1451. status = VspSynchronousIo(
  1452. DiffAreaFile->TableUpdateIrp,
  1453. DiffAreaFile->Filter->TargetObject,
  1454. IRP_MJ_READ,
  1455. DiffAreaFile->DiffAreaLocationDescriptionTargetOffset, 0);
  1456. if (!NT_SUCCESS(status)) {
  1457. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1458. VspLogError(extension, DiffAreaFile->Filter,
  1459. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 1, FALSE);
  1460. }
  1461. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1462. allocationOffset);
  1463. return status;
  1464. }
  1465. for (blockOffset = VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR;
  1466. blockOffset + sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR) <= BLOCK_SIZE;
  1467. blockOffset += sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR)) {
  1468. locationDescriptor = (PVSP_DIFF_AREA_LOCATION_DESCRIPTOR)
  1469. ((PCHAR) locationBlock + blockOffset);
  1470. if (locationDescriptor->VolumeOffset) {
  1471. continue;
  1472. }
  1473. while (diffAreaFileAllocation->NLength <= 0) {
  1474. fileOffset -= diffAreaFileAllocation->NLength;
  1475. l = l->Flink;
  1476. if (l == &DiffAreaFile->UnusedAllocationList) {
  1477. break;
  1478. }
  1479. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1480. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1481. }
  1482. if (l == &DiffAreaFile->UnusedAllocationList) {
  1483. break;
  1484. }
  1485. locationDescriptor->VolumeOffset = diffAreaFileAllocation->Offset;
  1486. locationDescriptor->FileOffset = fileOffset;
  1487. locationDescriptor->Length = diffAreaFileAllocation->NLength;
  1488. fileOffset += locationDescriptor->Length;
  1489. l = l->Flink;
  1490. if (l == &DiffAreaFile->UnusedAllocationList) {
  1491. break;
  1492. }
  1493. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1494. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1495. }
  1496. status = VspSynchronousIo(
  1497. DiffAreaFile->TableUpdateIrp,
  1498. DiffAreaFile->Filter->TargetObject,
  1499. IRP_MJ_WRITE,
  1500. DiffAreaFile->DiffAreaLocationDescriptionTargetOffset, 0);
  1501. if (!NT_SUCCESS(status)) {
  1502. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1503. VspLogError(extension, DiffAreaFile->Filter,
  1504. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 22, FALSE);
  1505. }
  1506. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1507. allocationOffset);
  1508. return status;
  1509. }
  1510. if (l == &DiffAreaFile->UnusedAllocationList) {
  1511. break;
  1512. }
  1513. status = VspAllocateDiffAreaSpace(extension, &t, &f, &allocationBlock,
  1514. &allocationOffset);
  1515. if (!NT_SUCCESS(status)) {
  1516. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1517. VspLogError(extension, NULL,
  1518. VS_ABORT_SNAPSHOTS_OUT_OF_DIFF_AREA,
  1519. STATUS_SUCCESS, 5, FALSE);
  1520. }
  1521. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1522. allocationOffset);
  1523. return status;
  1524. }
  1525. RtlZeroMemory(locationBlock, BLOCK_SIZE);
  1526. locationBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  1527. locationBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  1528. locationBlock->Header.BlockType =
  1529. VSP_BLOCK_TYPE_DIFF_AREA_LOCATION_DESCRIPTION;
  1530. locationBlock->Header.ThisFileOffset = f;
  1531. locationBlock->Header.ThisVolumeOffset = t;
  1532. status = VspSynchronousIo(
  1533. DiffAreaFile->TableUpdateIrp,
  1534. DiffAreaFile->Filter->TargetObject,
  1535. IRP_MJ_WRITE, t, 0);
  1536. if (!NT_SUCCESS(status)) {
  1537. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1538. VspLogError(extension, DiffAreaFile->Filter,
  1539. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 23, FALSE);
  1540. }
  1541. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1542. allocationOffset);
  1543. return status;
  1544. }
  1545. status = VspSynchronousIo(
  1546. DiffAreaFile->TableUpdateIrp,
  1547. DiffAreaFile->Filter->TargetObject,
  1548. IRP_MJ_READ,
  1549. DiffAreaFile->DiffAreaLocationDescriptionTargetOffset, 0);
  1550. if (!NT_SUCCESS(status)) {
  1551. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1552. VspLogError(extension, DiffAreaFile->Filter,
  1553. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 24, FALSE);
  1554. }
  1555. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1556. allocationOffset);
  1557. return status;
  1558. }
  1559. locationBlock->Header.NextVolumeOffset = t;
  1560. status = VspSynchronousIo(
  1561. DiffAreaFile->TableUpdateIrp,
  1562. DiffAreaFile->Filter->TargetObject,
  1563. IRP_MJ_WRITE,
  1564. DiffAreaFile->DiffAreaLocationDescriptionTargetOffset, 0);
  1565. if (!NT_SUCCESS(status)) {
  1566. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1567. VspLogError(extension, DiffAreaFile->Filter,
  1568. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 25, FALSE);
  1569. }
  1570. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1571. allocationOffset);
  1572. return status;
  1573. }
  1574. DiffAreaFile->DiffAreaLocationDescriptionTargetOffset = t;
  1575. }
  1576. VspFreeUsedDiffAreaSpaceFromPointers(extension, allocationBlock,
  1577. allocationOffset);
  1578. status = VspSynchronousIo(
  1579. DiffAreaFile->TableUpdateIrp, DiffAreaFile->Filter->TargetObject,
  1580. IRP_MJ_READ, DiffAreaFile->TableTargetOffset, 0);
  1581. if (!NT_SUCCESS(status)) {
  1582. if (!extension->Filter->DestroyAllSnapshotsPending) {
  1583. VspLogError(extension, DiffAreaFile->Filter,
  1584. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 26, FALSE);
  1585. }
  1586. return status;
  1587. }
  1588. return STATUS_SUCCESS;
  1589. }
  1590. VOID
  1591. VspReleaseDiffAreaSpaceWaiters(
  1592. IN PVOLUME_EXTENSION Extension
  1593. )
  1594. {
  1595. KIRQL irql;
  1596. BOOLEAN emptyQueue;
  1597. LIST_ENTRY q;
  1598. PLIST_ENTRY l;
  1599. PWORK_QUEUE_ITEM workItem;
  1600. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  1601. if (Extension->GrowDiffAreaFilePending) {
  1602. Extension->GrowDiffAreaFilePending = FALSE;
  1603. if (IsListEmpty(&Extension->WaitingForDiffAreaSpace)) {
  1604. emptyQueue = FALSE;
  1605. } else {
  1606. emptyQueue = TRUE;
  1607. q = Extension->WaitingForDiffAreaSpace;
  1608. InitializeListHead(&Extension->WaitingForDiffAreaSpace);
  1609. }
  1610. } else {
  1611. emptyQueue = FALSE;
  1612. }
  1613. KeReleaseSpinLock(&Extension->SpinLock, irql);
  1614. if (emptyQueue) {
  1615. q.Flink->Blink = &q;
  1616. q.Blink->Flink = &q;
  1617. while (!IsListEmpty(&q)) {
  1618. l = RemoveHeadList(&q);
  1619. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  1620. VspAcquireNonPagedResource(Extension, workItem, FALSE);
  1621. }
  1622. }
  1623. }
  1624. VOID
  1625. VspGrowDiffAreaPhase2(
  1626. IN PVOID Context
  1627. )
  1628. {
  1629. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1630. PVOLUME_EXTENSION extension = context->GrowDiffArea.Extension;
  1631. PVSP_DIFF_AREA_FILE diffAreaFile = extension->DiffAreaFile;
  1632. PFILTER_EXTENSION filter = extension->Filter;
  1633. PLIST_ENTRY extentList = &context->GrowDiffArea.ExtentList;
  1634. LONGLONG current = context->GrowDiffArea.Current;
  1635. ULONG increase = context->GrowDiffArea.Increase;
  1636. NTSTATUS status = context->GrowDiffArea.ResultStatus;
  1637. PLIST_ENTRY l;
  1638. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1639. KIRQL irql;
  1640. BOOLEAN dontNeedWrite;
  1641. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  1642. if (!NT_SUCCESS(status)) {
  1643. VspReleaseNonPagedResource(extension);
  1644. VspFreeContext(extension->Root, context);
  1645. VspReleaseDiffAreaSpaceWaiters(extension);
  1646. VspDecrementVolumeRefCount(extension);
  1647. return;
  1648. }
  1649. while (!IsListEmpty(extentList)) {
  1650. l = RemoveHeadList(extentList);
  1651. InsertTailList(&diffAreaFile->UnusedAllocationList, l);
  1652. }
  1653. diffAreaFile->AllocatedFileSize += increase;
  1654. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1655. filter->AllocatedVolumeSpace += increase;
  1656. KeReleaseSpinLock(&filter->SpinLock, irql);
  1657. if (extension->IsPersistent && diffAreaFile->TableUpdateIrp) {
  1658. KeAcquireSpinLock(&extension->SpinLock, &irql);
  1659. dontNeedWrite = diffAreaFile->TableUpdateInProgress;
  1660. diffAreaFile->TableUpdateInProgress = TRUE;
  1661. if (dontNeedWrite) {
  1662. KeInitializeEvent(&diffAreaFile->IrpReady, NotificationEvent, FALSE);
  1663. ASSERT(!diffAreaFile->IrpNeeded);
  1664. diffAreaFile->IrpNeeded = TRUE;
  1665. }
  1666. KeReleaseSpinLock(&extension->SpinLock, irql);
  1667. if (dontNeedWrite) {
  1668. KeWaitForSingleObject(&diffAreaFile->IrpReady, Executive,
  1669. KernelMode, FALSE, NULL);
  1670. }
  1671. status = VspAddLocationDescription(diffAreaFile, current);
  1672. if (NT_SUCCESS(status)) {
  1673. VspWriteTableUpdates(diffAreaFile);
  1674. } else {
  1675. VspKillTableUpdates(diffAreaFile);
  1676. }
  1677. }
  1678. VspReleaseNonPagedResource(extension);
  1679. VspFreeContext(extension->Root, context);
  1680. VspReleaseDiffAreaSpaceWaiters(extension);
  1681. VspDecrementVolumeRefCount(extension);
  1682. }
  1683. NTSTATUS
  1684. VspDiffAreaFileFillCompletion(
  1685. IN PDEVICE_OBJECT DeviceObject,
  1686. IN PIRP Irp,
  1687. IN PVOID Context
  1688. )
  1689. {
  1690. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1691. LONGLONG offset = 0;
  1692. KIRQL irql;
  1693. PLIST_ENTRY l;
  1694. PDIFF_AREA_FILE_ALLOCATION diffAreaAllocation;
  1695. PIO_STACK_LOCATION nextSp;
  1696. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  1697. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  1698. KeAcquireSpinLock(&context->GrowDiffArea.SpinLock, &irql);
  1699. context->GrowDiffArea.CurrentEntry = &context->GrowDiffArea.ExtentList;
  1700. context->GrowDiffArea.CurrentEntryOffset = 0;
  1701. KeReleaseSpinLock(&context->GrowDiffArea.SpinLock, irql);
  1702. context->GrowDiffArea.ResultStatus = Irp->IoStatus.Status;
  1703. }
  1704. KeAcquireSpinLock(&context->GrowDiffArea.SpinLock, &irql);
  1705. for (l = context->GrowDiffArea.CurrentEntry;
  1706. l != &context->GrowDiffArea.ExtentList; l = l->Flink) {
  1707. diffAreaAllocation = CONTAINING_RECORD(l, DIFF_AREA_FILE_ALLOCATION,
  1708. ListEntry);
  1709. if (diffAreaAllocation->NLength <= 0) {
  1710. ASSERT(!context->GrowDiffArea.CurrentEntryOffset);
  1711. continue;
  1712. }
  1713. if (context->GrowDiffArea.CurrentEntryOffset ==
  1714. diffAreaAllocation->NLength) {
  1715. context->GrowDiffArea.CurrentEntryOffset = 0;
  1716. continue;
  1717. }
  1718. ASSERT(context->GrowDiffArea.CurrentEntryOffset <
  1719. diffAreaAllocation->NLength);
  1720. offset = diffAreaAllocation->Offset +
  1721. context->GrowDiffArea.CurrentEntryOffset;
  1722. context->GrowDiffArea.CurrentEntryOffset += BLOCK_SIZE;
  1723. break;
  1724. }
  1725. context->GrowDiffArea.CurrentEntry = l;
  1726. KeReleaseSpinLock(&context->GrowDiffArea.SpinLock, irql);
  1727. if (l == &context->GrowDiffArea.ExtentList) {
  1728. if (!InterlockedDecrement(&context->GrowDiffArea.RefCount)) {
  1729. ExFreePool(MmGetMdlVirtualAddress(Irp->MdlAddress));
  1730. IoFreeMdl(Irp->MdlAddress);
  1731. VspAcquireNonPagedResource(context->GrowDiffArea.Extension,
  1732. &context->WorkItem, TRUE);
  1733. }
  1734. IoFreeIrp(Irp);
  1735. return STATUS_MORE_PROCESSING_REQUIRED;
  1736. }
  1737. nextSp = IoGetNextIrpStackLocation(Irp);
  1738. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1739. nextSp->Parameters.Write.ByteOffset.QuadPart = offset;
  1740. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  1741. nextSp->MajorFunction = IRP_MJ_WRITE;
  1742. nextSp->DeviceObject = context->GrowDiffArea.TargetObject;
  1743. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  1744. IoSetCompletionRoutine(Irp, VspDiffAreaFileFillCompletion, context, TRUE,
  1745. TRUE, TRUE);
  1746. IoCallDriver(nextSp->DeviceObject, Irp);
  1747. return STATUS_MORE_PROCESSING_REQUIRED;
  1748. }
  1749. VOID
  1750. VspLaunchDiffAreaFill(
  1751. IN PVOID Context
  1752. )
  1753. {
  1754. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1755. ULONG i;
  1756. PVOID buffer;
  1757. PMDL mdl;
  1758. PIRP irp;
  1759. PIO_STACK_LOCATION nextSp;
  1760. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  1761. context->GrowDiffArea.ResultStatus = STATUS_SUCCESS;
  1762. buffer = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  1763. VOLSNAP_TAG_BUFFER);
  1764. if (!buffer) {
  1765. context->GrowDiffArea.ResultStatus = STATUS_INSUFFICIENT_RESOURCES;
  1766. VspAcquireNonPagedResource(context->GrowDiffArea.Extension,
  1767. &context->WorkItem, TRUE);
  1768. return;
  1769. }
  1770. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  1771. if (!mdl) {
  1772. ExFreePool(buffer);
  1773. context->GrowDiffArea.ResultStatus = STATUS_INSUFFICIENT_RESOURCES;
  1774. VspAcquireNonPagedResource(context->GrowDiffArea.Extension,
  1775. &context->WorkItem, TRUE);
  1776. return;
  1777. }
  1778. MmBuildMdlForNonPagedPool(mdl);
  1779. ASSERT(SMALLEST_NTFS_CLUSTER < BLOCK_SIZE);
  1780. RtlZeroMemory(buffer, BLOCK_SIZE);
  1781. for (i = 0; i < BLOCK_SIZE; i += SMALLEST_NTFS_CLUSTER) {
  1782. RtlCopyMemory((PCHAR) buffer + i, &VSP_DIFF_AREA_FILE_GUID,
  1783. sizeof(GUID));
  1784. }
  1785. context->GrowDiffArea.RefCount = 1;
  1786. for (i = 0; i < 32; i++) {
  1787. irp = IoAllocateIrp(
  1788. (CCHAR) context->GrowDiffArea.Extension->Root->StackSize, FALSE);
  1789. if (!irp) {
  1790. if (!i) {
  1791. context->GrowDiffArea.ResultStatus =
  1792. STATUS_INSUFFICIENT_RESOURCES;
  1793. }
  1794. break;
  1795. }
  1796. irp->MdlAddress = mdl;
  1797. irp->IoStatus.Status = STATUS_SUCCESS;
  1798. InterlockedIncrement(&context->GrowDiffArea.RefCount);
  1799. VspDiffAreaFileFillCompletion(NULL, irp, context);
  1800. }
  1801. if (!InterlockedDecrement(&context->GrowDiffArea.RefCount)) {
  1802. ExFreePool(buffer);
  1803. IoFreeMdl(mdl);
  1804. VspAcquireNonPagedResource(context->GrowDiffArea.Extension,
  1805. &context->WorkItem, TRUE);
  1806. }
  1807. }
  1808. VOID
  1809. VspGrowDiffArea(
  1810. IN PVOID Context
  1811. )
  1812. {
  1813. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1814. PVOLUME_EXTENSION extension = context->GrowDiffArea.Extension;
  1815. PVSP_DIFF_AREA_FILE diffAreaFile = extension->DiffAreaFile;
  1816. PFILTER_EXTENSION filter = extension->Filter;
  1817. LONGLONG usableSpace = 0;
  1818. PFILTER_EXTENSION diffFilter;
  1819. HANDLE handle, h;
  1820. NTSTATUS status, status2;
  1821. KIRQL irql;
  1822. LIST_ENTRY extentList;
  1823. PLIST_ENTRY l;
  1824. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1825. ULONG increase, increaseDelta;
  1826. LONGLONG current;
  1827. PVOLUME_EXTENSION bitmapExtension;
  1828. LIST_ENTRY listOfDiffAreaFilesToClose;
  1829. LIST_ENTRY listOfDeviceObjectsToDelete;
  1830. BOOLEAN reduceIncreaseOk;
  1831. PVOLUME_EXTENSION e;
  1832. KPRIORITY oldPriority;
  1833. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  1834. status = VspIncrementVolumeRefCount(extension);
  1835. if (!NT_SUCCESS(status)) {
  1836. VspFreeContext(extension->Root, context);
  1837. VspReleaseDiffAreaSpaceWaiters(extension);
  1838. ObDereferenceObject(extension->DeviceObject);
  1839. return;
  1840. }
  1841. ASSERT(diffAreaFile);
  1842. current = diffAreaFile->AllocatedFileSize;
  1843. increaseDelta = extension->DiffAreaFileIncrease;
  1844. increase = 2*increaseDelta;
  1845. diffFilter = diffAreaFile->Filter;
  1846. handle = diffAreaFile->FileHandle;
  1847. reduceIncreaseOk = TRUE;
  1848. for (;;) {
  1849. KeAcquireSpinLock(&diffFilter->SpinLock, &irql);
  1850. if (filter->MaximumVolumeSpace &&
  1851. filter->AllocatedVolumeSpace + increase >
  1852. filter->MaximumVolumeSpace) {
  1853. KeReleaseSpinLock(&diffFilter->SpinLock, irql);
  1854. status = STATUS_DISK_FULL;
  1855. extension->UserImposedLimit = TRUE;
  1856. } else {
  1857. KeReleaseSpinLock(&diffFilter->SpinLock, irql);
  1858. status = ZwDuplicateObject(NtCurrentProcess(), handle,
  1859. NtCurrentProcess(), &h, 0, 0,
  1860. DUPLICATE_SAME_ACCESS |
  1861. DUPLICATE_SAME_ATTRIBUTES);
  1862. if (NT_SUCCESS(status)) {
  1863. ObReferenceObject(diffFilter->DeviceObject);
  1864. InterlockedIncrement(&diffFilter->FSRefCount);
  1865. VspDecrementVolumeRefCount(extension);
  1866. status = VspSetFileSize(h, current + increase);
  1867. ZwClose(h);
  1868. InterlockedDecrement(&diffFilter->FSRefCount);
  1869. ObDereferenceObject(diffFilter->DeviceObject);
  1870. status2 = VspIncrementVolumeRefCount(extension);
  1871. if (!NT_SUCCESS(status2)) {
  1872. VspFreeContext(extension->Root, context);
  1873. VspReleaseDiffAreaSpaceWaiters(extension);
  1874. ObDereferenceObject(extension->DeviceObject);
  1875. return;
  1876. }
  1877. }
  1878. if (NT_SUCCESS(status)) {
  1879. break;
  1880. }
  1881. extension->UserImposedLimit = FALSE;
  1882. }
  1883. if (increaseDelta > NOMINAL_DIFF_AREA_FILE_GROWTH &&
  1884. reduceIncreaseOk) {
  1885. increase = 2*NOMINAL_DIFF_AREA_FILE_GROWTH;
  1886. increaseDelta = NOMINAL_DIFF_AREA_FILE_GROWTH;
  1887. reduceIncreaseOk = FALSE;
  1888. continue;
  1889. }
  1890. VspDecrementVolumeRefCount(extension);
  1891. VspReleaseDiffAreaSpaceWaiters(extension);
  1892. VspAcquire(extension->Root);
  1893. if (extension->IsDead) {
  1894. InterlockedExchange(&extension->GrowFailed, TRUE);
  1895. VspRelease(extension->Root);
  1896. VspFreeContext(extension->Root, context);
  1897. ObDereferenceObject(extension->DeviceObject);
  1898. return;
  1899. }
  1900. if (status != STATUS_DISK_FULL) {
  1901. InterlockedExchange(&extension->GrowFailed, TRUE);
  1902. VspLogError(extension, diffFilter,
  1903. VS_GROW_DIFF_AREA_FAILED, status, 1, FALSE);
  1904. VspRelease(extension->Root);
  1905. VspFreeContext(extension->Root, context);
  1906. ObDereferenceObject(extension->DeviceObject);
  1907. return;
  1908. }
  1909. if (extension->ListEntry.Blink == &filter->VolumeList) {
  1910. InterlockedExchange(&extension->GrowFailed, TRUE);
  1911. if (extension->UserImposedLimit) {
  1912. VspLogError(extension, diffFilter,
  1913. VS_GROW_DIFF_AREA_FAILED_LOW_DISK_SPACE_USER_IMPOSED,
  1914. STATUS_DISK_FULL, 0, FALSE);
  1915. } else {
  1916. VspLogError(extension, diffFilter,
  1917. VS_GROW_DIFF_AREA_FAILED_LOW_DISK_SPACE,
  1918. STATUS_DISK_FULL, 0, FALSE);
  1919. }
  1920. VspRelease(extension->Root);
  1921. VspFreeContext(extension->Root, context);
  1922. ObDereferenceObject(extension->DeviceObject);
  1923. return;
  1924. }
  1925. e = CONTAINING_RECORD(filter->VolumeList.Flink, VOLUME_EXTENSION,
  1926. ListEntry);
  1927. VspLogError(e, NULL, VS_DELETE_TO_TRIM_SPACE, STATUS_SUCCESS, 1,
  1928. TRUE);
  1929. InitializeListHead(&listOfDiffAreaFilesToClose);
  1930. InitializeListHead(&listOfDeviceObjectsToDelete);
  1931. VspDeleteOldestSnapshot(filter, &listOfDiffAreaFilesToClose,
  1932. &listOfDeviceObjectsToDelete, FALSE,
  1933. FALSE);
  1934. VspRelease(extension->Root);
  1935. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  1936. &listOfDeviceObjectsToDelete);
  1937. status = VspIncrementVolumeRefCount(extension);
  1938. if (!NT_SUCCESS(status)) {
  1939. VspFreeContext(extension->Root, context);
  1940. ObDereferenceObject(extension->DeviceObject);
  1941. return;
  1942. }
  1943. }
  1944. VspDecrementVolumeRefCount(extension);
  1945. if (extension->IsDead) {
  1946. VspFreeContext(extension->Root, context);
  1947. VspReleaseDiffAreaSpaceWaiters(extension);
  1948. ObDereferenceObject(extension->DeviceObject);
  1949. return;
  1950. }
  1951. KeAcquireSpinLock(&diffFilter->SpinLock, &irql);
  1952. if (IsListEmpty(&diffFilter->VolumeList)) {
  1953. bitmapExtension = NULL;
  1954. } else {
  1955. bitmapExtension = CONTAINING_RECORD(diffFilter->VolumeList.Blink,
  1956. VOLUME_EXTENSION, ListEntry);
  1957. if (bitmapExtension->IsDead) {
  1958. bitmapExtension = NULL;
  1959. } else {
  1960. ObReferenceObject(bitmapExtension->DeviceObject);
  1961. }
  1962. }
  1963. KeReleaseSpinLock(&diffFilter->SpinLock, irql);
  1964. status = VspIncrementVolumeRefCount(extension);
  1965. if (!NT_SUCCESS(status)) {
  1966. if (bitmapExtension) {
  1967. ObDereferenceObject(bitmapExtension->DeviceObject);
  1968. }
  1969. VspFreeContext(extension->Root, context);
  1970. VspReleaseDiffAreaSpaceWaiters(extension);
  1971. ObDereferenceObject(extension->DeviceObject);
  1972. return;
  1973. }
  1974. status = VspQueryListOfExtents(handle, current, &extentList,
  1975. bitmapExtension, FALSE);
  1976. if (!NT_SUCCESS(status)) {
  1977. if (bitmapExtension) {
  1978. ObDereferenceObject(bitmapExtension->DeviceObject);
  1979. }
  1980. VspFreeContext(extension->Root, context);
  1981. VspReleaseDiffAreaSpaceWaiters(extension);
  1982. VspDecrementVolumeRefCount(extension);
  1983. ObDereferenceObject(extension->DeviceObject);
  1984. return;
  1985. }
  1986. usableSpace = 0;
  1987. for (l = extentList.Flink; l != &extentList; l = l->Flink) {
  1988. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1989. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1990. if (diffAreaFileAllocation->NLength > 0) {
  1991. usableSpace += diffAreaFileAllocation->NLength;
  1992. }
  1993. }
  1994. if (usableSpace < increaseDelta) {
  1995. while (!IsListEmpty(&extentList)) {
  1996. l = RemoveHeadList(&extentList);
  1997. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1998. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1999. ExFreePool(diffAreaFileAllocation);
  2000. }
  2001. oldPriority = KeQueryPriorityThread(KeGetCurrentThread());
  2002. KeSetPriorityThread(KeGetCurrentThread(), VSP_LOWER_PRIORITY);
  2003. VspOptimizeDiffAreaFileLocation(diffFilter, handle, bitmapExtension,
  2004. current, current + increase);
  2005. status = VspQueryListOfExtents(handle, current, &extentList,
  2006. bitmapExtension, FALSE);
  2007. KeSetPriorityThread(KeGetCurrentThread(), oldPriority);
  2008. if (!NT_SUCCESS(status)) {
  2009. if (bitmapExtension) {
  2010. ObDereferenceObject(bitmapExtension->DeviceObject);
  2011. }
  2012. VspFreeContext(extension->Root, context);
  2013. VspReleaseDiffAreaSpaceWaiters(extension);
  2014. VspDecrementVolumeRefCount(extension);
  2015. ObDereferenceObject(extension->DeviceObject);
  2016. return;
  2017. }
  2018. usableSpace = 0;
  2019. for (l = extentList.Flink; l != &extentList; l = l->Flink) {
  2020. diffAreaFileAllocation = CONTAINING_RECORD(l,
  2021. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  2022. if (diffAreaFileAllocation->NLength > 0) {
  2023. usableSpace += diffAreaFileAllocation->NLength;
  2024. }
  2025. }
  2026. if (!usableSpace) {
  2027. if (bitmapExtension) {
  2028. ObDereferenceObject(bitmapExtension->DeviceObject);
  2029. }
  2030. VspFreeContext(extension->Root, context);
  2031. VspReleaseDiffAreaSpaceWaiters(extension);
  2032. VspDecrementVolumeRefCount(extension);
  2033. ObDereferenceObject(extension->DeviceObject);
  2034. return;
  2035. }
  2036. }
  2037. if (bitmapExtension) {
  2038. ObDereferenceObject(bitmapExtension->DeviceObject);
  2039. }
  2040. ObDereferenceObject(extension->DeviceObject);
  2041. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2042. extension->PastFileSystemOperations = TRUE;
  2043. KeReleaseSpinLock(&extension->SpinLock, irql);
  2044. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffAreaPhase2, context);
  2045. ASSERT(!IsListEmpty(&extentList));
  2046. context->GrowDiffArea.ExtentList = extentList;
  2047. context->GrowDiffArea.ExtentList.Flink->Blink =
  2048. &context->GrowDiffArea.ExtentList;
  2049. context->GrowDiffArea.ExtentList.Blink->Flink =
  2050. &context->GrowDiffArea.ExtentList;
  2051. context->GrowDiffArea.Current = current;
  2052. context->GrowDiffArea.Increase = increase;
  2053. context->GrowDiffArea.ResultStatus = STATUS_SUCCESS;
  2054. if (extension->IsPersistent && !extension->NoDiffAreaFill) {
  2055. KeInitializeSpinLock(&context->GrowDiffArea.SpinLock);
  2056. context->GrowDiffArea.CurrentEntry =
  2057. context->GrowDiffArea.ExtentList.Flink;
  2058. context->GrowDiffArea.CurrentEntryOffset = 0;
  2059. context->GrowDiffArea.TargetObject = diffFilter->TargetObject;
  2060. VspLaunchDiffAreaFill(context);
  2061. return;
  2062. }
  2063. VspAcquireNonPagedResource(extension, &context->WorkItem, FALSE);
  2064. }
  2065. VOID
  2066. VspWaitForInstall(
  2067. IN PVOID Context
  2068. )
  2069. {
  2070. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2071. PVOLUME_EXTENSION extension = context->GrowDiffArea.Extension;
  2072. PFILTER_EXTENSION filter = extension->Filter;
  2073. NTSTATUS status;
  2074. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  2075. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  2076. KernelMode, FALSE, NULL);
  2077. status = VspIncrementVolumeRefCount(extension);
  2078. if (!NT_SUCCESS(status)) {
  2079. VspFreeContext(extension->Root, context);
  2080. VspReleaseDiffAreaSpaceWaiters(extension);
  2081. ObDereferenceObject(extension->DeviceObject);
  2082. ObDereferenceObject(filter->DeviceObject);
  2083. return;
  2084. }
  2085. if (!extension->OkToGrowDiffArea) {
  2086. VspLogError(extension, extension->DiffAreaFile->Filter,
  2087. VS_GROW_BEFORE_FREE_SPACE, STATUS_SUCCESS, 1, FALSE);
  2088. VspDecrementVolumeRefCount(extension);
  2089. VspFreeContext(extension->Root, context);
  2090. VspReleaseDiffAreaSpaceWaiters(extension);
  2091. ObDereferenceObject(extension->DeviceObject);
  2092. ObDereferenceObject(filter->DeviceObject);
  2093. return;
  2094. }
  2095. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea, context);
  2096. VspQueueWorkItem(filter->Root, &context->WorkItem, 0);
  2097. VspDecrementVolumeRefCount(extension);
  2098. ObDereferenceObject(filter->DeviceObject);
  2099. }
  2100. NTSTATUS
  2101. VspAllocateDiffAreaSpace(
  2102. IN PVOLUME_EXTENSION Extension,
  2103. OUT PLONGLONG TargetOffset,
  2104. OUT PLONGLONG FileOffset,
  2105. IN OUT PDIFF_AREA_FILE_ALLOCATION* CurrentFileAllocation,
  2106. IN OUT PLONGLONG CurrentOffset
  2107. )
  2108. /*++
  2109. Routine Description:
  2110. This routine allocates file space in a diff area file. The algorithm
  2111. for this allocation is round robin which means that different size
  2112. allocations can make the various files grow to be different sizes. The
  2113. earmarked file is used and grown as necessary to get the space desired.
  2114. Only if it is impossible to use the current file would the allocator go
  2115. to the next one. If a file needs to be grown, the allocator will
  2116. try to grow by 10 MB.
  2117. Arguments:
  2118. Extension - Supplies the volume extension.
  2119. DiffAreaFile - Returns the diff area file used in the allocation.
  2120. FileOffset - Returns the file offset in the diff area file used.
  2121. Return Value:
  2122. NTSTATUS
  2123. Notes:
  2124. Callers of this routine must be holding 'NonPagedResource'.
  2125. --*/
  2126. {
  2127. PFILTER_EXTENSION filter = Extension->Filter;
  2128. LONGLONG targetOffset;
  2129. PVSP_DIFF_AREA_FILE diffAreaFile;
  2130. LONGLONG delta;
  2131. PLIST_ENTRY l;
  2132. PVSP_CONTEXT context;
  2133. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  2134. KIRQL irql;
  2135. targetOffset = 0;
  2136. diffAreaFile = Extension->DiffAreaFile;
  2137. ASSERT(diffAreaFile);
  2138. delta = 0;
  2139. if (CurrentFileAllocation) {
  2140. diffAreaFileAllocation = *CurrentFileAllocation;
  2141. for (;;) {
  2142. if (diffAreaFileAllocation->NLength - *CurrentOffset <= 0) {
  2143. delta -= diffAreaFileAllocation->NLength - *CurrentOffset;
  2144. *CurrentOffset = 0;
  2145. l = diffAreaFileAllocation->ListEntry.Flink;
  2146. if (l == &diffAreaFile->UnusedAllocationList) {
  2147. break;
  2148. }
  2149. diffAreaFileAllocation = CONTAINING_RECORD(l,
  2150. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  2151. continue;
  2152. }
  2153. targetOffset = diffAreaFileAllocation->Offset + *CurrentOffset;
  2154. *CurrentFileAllocation = diffAreaFileAllocation;
  2155. *CurrentOffset += BLOCK_SIZE;
  2156. break;
  2157. }
  2158. } else {
  2159. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  2160. l = diffAreaFile->UnusedAllocationList.Flink;
  2161. diffAreaFileAllocation = CONTAINING_RECORD(l,
  2162. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  2163. if (diffAreaFileAllocation->NLength <= 0) {
  2164. delta -= diffAreaFileAllocation->NLength;
  2165. RemoveEntryList(l);
  2166. ExFreePool(diffAreaFileAllocation);
  2167. continue;
  2168. }
  2169. targetOffset = diffAreaFileAllocation->Offset;
  2170. diffAreaFileAllocation->Offset += BLOCK_SIZE;
  2171. diffAreaFileAllocation->NLength -= BLOCK_SIZE;
  2172. break;
  2173. }
  2174. }
  2175. if (diffAreaFile->NextAvailable + delta + BLOCK_SIZE +
  2176. Extension->DiffAreaFileIncrease <=
  2177. diffAreaFile->AllocatedFileSize) {
  2178. goto Finish;
  2179. }
  2180. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease >
  2181. diffAreaFile->AllocatedFileSize) {
  2182. goto Finish;
  2183. }
  2184. context = VspAllocateContext(Extension->Root);
  2185. if (!context) {
  2186. if (!Extension->OkToGrowDiffArea) {
  2187. VspLogError(Extension, diffAreaFile->Filter,
  2188. VS_GROW_BEFORE_FREE_SPACE, STATUS_SUCCESS, 2, FALSE);
  2189. }
  2190. goto Finish;
  2191. }
  2192. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2193. ASSERT(!Extension->GrowDiffAreaFilePending);
  2194. ASSERT(IsListEmpty(&Extension->WaitingForDiffAreaSpace));
  2195. Extension->PastFileSystemOperations = FALSE;
  2196. Extension->GrowDiffAreaFilePending = TRUE;
  2197. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2198. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  2199. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea, context);
  2200. context->GrowDiffArea.Extension = Extension;
  2201. ObReferenceObject(Extension->DeviceObject);
  2202. if (!Extension->OkToGrowDiffArea) {
  2203. ObReferenceObject(filter->DeviceObject);
  2204. ExInitializeWorkItem(&context->WorkItem, VspWaitForInstall, context);
  2205. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  2206. goto Finish;
  2207. }
  2208. VspQueueWorkItem(Extension->Root, &context->WorkItem, 0);
  2209. Finish:
  2210. if (targetOffset) {
  2211. *TargetOffset = targetOffset;
  2212. *FileOffset = diffAreaFile->NextAvailable + delta;
  2213. }
  2214. diffAreaFile->NextAvailable += delta;
  2215. if (targetOffset) {
  2216. diffAreaFile->NextAvailable += BLOCK_SIZE;
  2217. }
  2218. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2219. filter->UsedVolumeSpace += delta;
  2220. if (targetOffset) {
  2221. filter->UsedVolumeSpace += BLOCK_SIZE;
  2222. }
  2223. KeReleaseSpinLock(&filter->SpinLock, irql);
  2224. return targetOffset ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
  2225. }
  2226. VOID
  2227. VspDecrementVolumeIrpRefCount(
  2228. IN PVOID Irp
  2229. )
  2230. {
  2231. PIRP irp = (PIRP) Irp;
  2232. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  2233. PIO_STACK_LOCATION irpSp;
  2234. PVOLUME_EXTENSION extension;
  2235. if (InterlockedDecrement((PLONG) &nextSp->Parameters.Read.Length)) {
  2236. return;
  2237. }
  2238. irpSp = IoGetCurrentIrpStackLocation(irp);
  2239. extension = (PVOLUME_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  2240. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  2241. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  2242. VspDecrementVolumeRefCount(extension);
  2243. }
  2244. VOID
  2245. VspDecrementIrpRefCount(
  2246. IN PVOID Irp
  2247. )
  2248. {
  2249. PIRP irp = (PIRP) Irp;
  2250. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  2251. PIO_STACK_LOCATION irpSp;
  2252. PFILTER_EXTENSION filter;
  2253. PVOLUME_EXTENSION extension;
  2254. PLIST_ENTRY l;
  2255. PVSP_DIFF_AREA_FILE diffAreaFile;
  2256. KIRQL irql;
  2257. PVSP_WRITE_CONTEXT writeContext;
  2258. PDO_EXTENSION rootExtension;
  2259. if (InterlockedDecrement((PLONG) &nextSp->Parameters.Read.Length)) {
  2260. return;
  2261. }
  2262. irpSp = IoGetCurrentIrpStackLocation(irp);
  2263. filter = (PFILTER_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  2264. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  2265. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  2266. VOLUME_EXTENSION, ListEntry);
  2267. diffAreaFile = extension->DiffAreaFile;
  2268. ASSERT(diffAreaFile);
  2269. VspDecrementRefCount(diffAreaFile->Filter);
  2270. if (!irp->MdlAddress) {
  2271. IoCompleteRequest(irp, IO_NO_INCREMENT);
  2272. VspDecrementRefCount(filter);
  2273. return;
  2274. }
  2275. writeContext = VspAllocateWriteContext(filter->Root);
  2276. if (!writeContext) {
  2277. rootExtension = filter->Root;
  2278. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  2279. if (rootExtension->EmergencyWriteContextInUse) {
  2280. InsertTailList(&rootExtension->WriteContextIrpWaitingList,
  2281. &irp->Tail.Overlay.ListEntry);
  2282. if (!rootExtension->WriteContextIrpWaitingListNeedsChecking) {
  2283. InterlockedExchange(
  2284. &rootExtension->WriteContextIrpWaitingListNeedsChecking,
  2285. TRUE);
  2286. }
  2287. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  2288. VspDecrementRefCount(filter);
  2289. return;
  2290. }
  2291. rootExtension->EmergencyWriteContextInUse = TRUE;
  2292. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  2293. writeContext = rootExtension->EmergencyWriteContext;
  2294. }
  2295. writeContext->Filter = filter;
  2296. writeContext->Extension = extension;
  2297. writeContext->Irp = irp;
  2298. InitializeListHead(&writeContext->CompletionRoutines);
  2299. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2300. InsertTailList(&extension->WriteContextList, &writeContext->ListEntry);
  2301. KeReleaseSpinLock(&extension->SpinLock, irql);
  2302. IoCopyCurrentIrpStackLocationToNext(irp);
  2303. IoSetCompletionRoutine(irp, VspWriteContextCompletionRoutine,
  2304. writeContext, TRUE, TRUE, TRUE);
  2305. IoCallDriver(filter->TargetObject, irp);
  2306. }
  2307. VOID
  2308. VspDecrementIrpRefCountWorker(
  2309. IN PVOID Context
  2310. )
  2311. {
  2312. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2313. PVOLUME_EXTENSION extension = context->Extension.Extension;
  2314. PIRP irp = context->Extension.Irp;
  2315. if (context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME) {
  2316. ExInitializeWorkItem(&context->WorkItem, VspWriteVolume, context);
  2317. VspAcquireNonPagedResource(extension, &context->WorkItem, TRUE);
  2318. } else {
  2319. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  2320. VspFreeContext(extension->Root, context);
  2321. }
  2322. VspDecrementIrpRefCount(irp);
  2323. }
  2324. VOID
  2325. VspSignalCallback(
  2326. IN PFILTER_EXTENSION Filter
  2327. )
  2328. {
  2329. KeSetEvent((PKEVENT) Filter->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  2330. }
  2331. VOID
  2332. VspCleanupVolumeSnapshot(
  2333. IN PVOLUME_EXTENSION Extension,
  2334. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose,
  2335. IN BOOLEAN KeepOnDisk
  2336. )
  2337. /*++
  2338. Routine Description:
  2339. This routine kills an existing volume snapshot.
  2340. Arguments:
  2341. Extension - Supplies the volume extension.
  2342. Return Value:
  2343. NTSTATUS
  2344. Notes:
  2345. Root->Semaphore required for calling this routine.
  2346. --*/
  2347. {
  2348. PFILTER_EXTENSION filter = Extension->Filter;
  2349. PLIST_ENTRY l, ll;
  2350. PVSP_DIFF_AREA_FILE diffAreaFile;
  2351. KIRQL irql;
  2352. POLD_HEAP_ENTRY oldHeapEntry;
  2353. NTSTATUS status;
  2354. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  2355. PVOID p;
  2356. FILE_DISPOSITION_INFORMATION dispInfo;
  2357. IO_STATUS_BLOCK ioStatus;
  2358. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  2359. VspAcquirePagedResource(Extension, NULL);
  2360. if (Extension->DiffAreaFileMap) {
  2361. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  2362. Extension->DiffAreaFileMap);
  2363. ASSERT(NT_SUCCESS(status));
  2364. Extension->DiffAreaFileMap = NULL;
  2365. }
  2366. if (Extension->NextDiffAreaFileMap) {
  2367. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  2368. Extension->NextDiffAreaFileMap);
  2369. ASSERT(NT_SUCCESS(status));
  2370. Extension->NextDiffAreaFileMap = NULL;
  2371. }
  2372. while (!IsListEmpty(&Extension->OldHeaps)) {
  2373. l = RemoveHeadList(&Extension->OldHeaps);
  2374. oldHeapEntry = CONTAINING_RECORD(l, OLD_HEAP_ENTRY, ListEntry);
  2375. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  2376. oldHeapEntry->DiffAreaFileMap);
  2377. ASSERT(NT_SUCCESS(status));
  2378. ExFreePool(oldHeapEntry);
  2379. }
  2380. VspReleasePagedResource(Extension);
  2381. if (Extension->IsPersistent && !KeepOnDisk) {
  2382. VspCleanupControlItemsForSnapshot(Extension);
  2383. }
  2384. if (Extension->DiffAreaFile) {
  2385. diffAreaFile = Extension->DiffAreaFile;
  2386. Extension->DiffAreaFile = NULL;
  2387. KeAcquireSpinLock(&diffAreaFile->Filter->SpinLock, &irql);
  2388. if (diffAreaFile->FilterListEntryBeingUsed) {
  2389. RemoveEntryList(&diffAreaFile->FilterListEntry);
  2390. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  2391. }
  2392. KeReleaseSpinLock(&diffAreaFile->Filter->SpinLock, irql);
  2393. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2394. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  2395. filter->UsedVolumeSpace -= diffAreaFile->NextAvailable;
  2396. KeReleaseSpinLock(&filter->SpinLock, irql);
  2397. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  2398. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  2399. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  2400. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  2401. ExFreePool(diffAreaFileAllocation);
  2402. }
  2403. if (diffAreaFile->TableUpdateIrp) {
  2404. ExFreePool(MmGetMdlVirtualAddress(
  2405. diffAreaFile->TableUpdateIrp->MdlAddress));
  2406. IoFreeMdl(diffAreaFile->TableUpdateIrp->MdlAddress);
  2407. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  2408. }
  2409. if (ListOfDiffAreaFilesToClose) {
  2410. if (KeepOnDisk && Extension->IsPersistent) {
  2411. lookupEntry = VspFindLookupTableItem(
  2412. Extension->Root, &Extension->SnapshotGuid);
  2413. ASSERT(lookupEntry);
  2414. lookupEntry->DiffAreaHandle = diffAreaFile->FileHandle;
  2415. ExFreePool(diffAreaFile);
  2416. } else {
  2417. InsertTailList(ListOfDiffAreaFilesToClose,
  2418. &diffAreaFile->ListEntry);
  2419. }
  2420. } else {
  2421. ASSERT(!diffAreaFile->FileHandle);
  2422. ExFreePool(diffAreaFile);
  2423. }
  2424. }
  2425. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2426. if (Extension->VolumeBlockBitmap) {
  2427. ExFreePool(Extension->VolumeBlockBitmap->Buffer);
  2428. ExFreePool(Extension->VolumeBlockBitmap);
  2429. Extension->VolumeBlockBitmap = NULL;
  2430. }
  2431. if (Extension->IgnorableProduct) {
  2432. ExFreePool(Extension->IgnorableProduct->Buffer);
  2433. ExFreePool(Extension->IgnorableProduct);
  2434. Extension->IgnorableProduct = NULL;
  2435. }
  2436. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2437. VspAcquirePagedResource(Extension, NULL);
  2438. if (Extension->ApplicationInformation) {
  2439. Extension->ApplicationInformationSize = 0;
  2440. ExFreePool(Extension->ApplicationInformation);
  2441. Extension->ApplicationInformation = NULL;
  2442. }
  2443. VspReleasePagedResource(Extension);
  2444. if (Extension->EmergencyCopyIrp) {
  2445. ExFreePool(MmGetMdlVirtualAddress(
  2446. Extension->EmergencyCopyIrp->MdlAddress));
  2447. IoFreeMdl(Extension->EmergencyCopyIrp->MdlAddress);
  2448. IoFreeIrp(Extension->EmergencyCopyIrp);
  2449. Extension->EmergencyCopyIrp = NULL;
  2450. }
  2451. VspDeleteWorkerThread(filter->Root);
  2452. if (Extension->IgnoreCopyDataReference) {
  2453. Extension->IgnoreCopyDataReference = FALSE;
  2454. InterlockedDecrement(&filter->IgnoreCopyData);
  2455. }
  2456. }
  2457. VOID
  2458. VspEmptyIrpQueue(
  2459. IN PDRIVER_OBJECT DriverObject,
  2460. IN PLIST_ENTRY IrpQueue
  2461. )
  2462. {
  2463. PLIST_ENTRY l;
  2464. PIRP irp;
  2465. PIO_STACK_LOCATION irpSp;
  2466. while (!IsListEmpty(IrpQueue)) {
  2467. l = RemoveHeadList(IrpQueue);
  2468. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  2469. irpSp = IoGetCurrentIrpStackLocation(irp);
  2470. DriverObject->MajorFunction[irpSp->MajorFunction](irpSp->DeviceObject,
  2471. irp);
  2472. }
  2473. }
  2474. VOID
  2475. VspEmptyWorkerQueue(
  2476. IN PLIST_ENTRY WorkerQueue
  2477. )
  2478. {
  2479. PLIST_ENTRY l;
  2480. PWORK_QUEUE_ITEM workItem;
  2481. while (!IsListEmpty(WorkerQueue)) {
  2482. l = RemoveHeadList(WorkerQueue);
  2483. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  2484. workItem->WorkerRoutine(workItem->Parameter);
  2485. }
  2486. }
  2487. VOID
  2488. VspResumeSnapshotIo(
  2489. IN PVOLUME_EXTENSION Extension
  2490. )
  2491. {
  2492. KIRQL irql;
  2493. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2494. InterlockedIncrement(&Extension->RefCount);
  2495. InterlockedExchange(&Extension->HoldIncomingRequests, FALSE);
  2496. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2497. }
  2498. VOID
  2499. VspPauseSnapshotIo(
  2500. IN PVOLUME_EXTENSION Extension
  2501. )
  2502. {
  2503. KIRQL irql;
  2504. VspReleaseWrites(Extension->Filter);
  2505. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2506. ASSERT(!Extension->HoldIncomingRequests);
  2507. KeInitializeEvent(&Extension->ZeroRefEvent, NotificationEvent, FALSE);
  2508. InterlockedExchange(&Extension->HoldIncomingRequests, TRUE);
  2509. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2510. VspDecrementVolumeRefCount(Extension);
  2511. KeWaitForSingleObject(&Extension->ZeroRefEvent, Executive, KernelMode,
  2512. FALSE, NULL);
  2513. }
  2514. NTSTATUS
  2515. VspDeleteOldestSnapshot(
  2516. IN PFILTER_EXTENSION Filter,
  2517. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose,
  2518. IN OUT PLIST_ENTRY LisfOfDeviceObjectsToDelete,
  2519. IN BOOLEAN KeepOnDisk,
  2520. IN BOOLEAN DontWakePnp
  2521. )
  2522. /*++
  2523. Routine Description:
  2524. This routine deletes the oldest volume snapshot on the given volume.
  2525. Arguments:
  2526. Filter - Supplies the filter extension.
  2527. Return Value:
  2528. NTSTATUS
  2529. Notes:
  2530. This routine assumes that Root->Semaphore is being held.
  2531. --*/
  2532. {
  2533. PFILTER_EXTENSION filter = Filter;
  2534. PLIST_ENTRY l;
  2535. PVOLUME_EXTENSION extension;
  2536. KIRQL irql;
  2537. if (IsListEmpty(&filter->VolumeList)) {
  2538. return STATUS_INVALID_PARAMETER;
  2539. }
  2540. l = filter->VolumeList.Flink;
  2541. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  2542. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2543. InterlockedExchange(&extension->IsDead, TRUE);
  2544. InterlockedExchange(&extension->IsStarted, FALSE);
  2545. KeReleaseSpinLock(&extension->SpinLock, irql);
  2546. VspPauseSnapshotIo(extension);
  2547. VspResumeSnapshotIo(extension);
  2548. VspPauseVolumeIo(filter);
  2549. ObReferenceObject(extension->DeviceObject);
  2550. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2551. RemoveEntryList(&extension->ListEntry);
  2552. if (IsListEmpty(&filter->VolumeList)) {
  2553. InterlockedExchange(&filter->SnapshotsPresent, FALSE);
  2554. }
  2555. InterlockedIncrement(&Filter->EpicNumber);
  2556. KeReleaseSpinLock(&filter->SpinLock, irql);
  2557. VspResumeVolumeIo(filter);
  2558. VspCleanupVolumeSnapshot(extension, ListOfDiffAreaFilesToClose,
  2559. KeepOnDisk);
  2560. if (extension->AliveToPnp) {
  2561. InsertTailList(&filter->DeadVolumeList, &extension->ListEntry);
  2562. if (!DontWakePnp) {
  2563. IoInvalidateDeviceRelations(filter->Pdo, BusRelations);
  2564. }
  2565. } else {
  2566. RtlDeleteElementGenericTable(&filter->Root->UsedDevnodeNumbers,
  2567. &extension->DevnodeNumber);
  2568. IoDeleteDevice(extension->DeviceObject);
  2569. }
  2570. InsertTailList(LisfOfDeviceObjectsToDelete, &extension->AnotherListEntry);
  2571. return STATUS_SUCCESS;
  2572. }
  2573. VOID
  2574. VspCloseDiffAreaFiles(
  2575. IN PLIST_ENTRY ListOfDiffAreaFilesToClose,
  2576. IN PLIST_ENTRY ListOfDeviceObjectsToDelete
  2577. )
  2578. {
  2579. PLIST_ENTRY l;
  2580. PVSP_DIFF_AREA_FILE diffAreaFile;
  2581. PVOLUME_EXTENSION extension;
  2582. while (!IsListEmpty(ListOfDiffAreaFilesToClose)) {
  2583. l = RemoveHeadList(ListOfDiffAreaFilesToClose);
  2584. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE, ListEntry);
  2585. ZwClose(diffAreaFile->FileHandle);
  2586. ExFreePool(diffAreaFile);
  2587. }
  2588. while (!IsListEmpty(ListOfDeviceObjectsToDelete)) {
  2589. l = RemoveHeadList(ListOfDeviceObjectsToDelete);
  2590. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, AnotherListEntry);
  2591. ObDereferenceObject(extension->DeviceObject);
  2592. }
  2593. }
  2594. VOID
  2595. VspDestroyAllSnapshotsWorker(
  2596. IN PVOID Context
  2597. )
  2598. /*++
  2599. Routine Description:
  2600. This routine will delete all of the snapshots in the system.
  2601. Arguments:
  2602. Filter - Supplies the filter extension.
  2603. Return Value:
  2604. None.
  2605. --*/
  2606. {
  2607. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2608. PFILTER_EXTENSION filter = context->DestroyAllSnapshots.Filter;
  2609. BOOLEAN keepOnDisk = context->DestroyAllSnapshots.KeepOnDisk;
  2610. BOOLEAN synchronousCall = context->DestroyAllSnapshots.SynchronousCall;
  2611. LIST_ENTRY listOfDiffAreaFilesToClose;
  2612. LIST_ENTRY listOfDeviceObjectToDelete;
  2613. BOOLEAN b;
  2614. ASSERT(context->Type == VSP_CONTEXT_TYPE_DESTROY_SNAPSHOTS);
  2615. if (!synchronousCall) {
  2616. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  2617. KernelMode, FALSE, NULL);
  2618. }
  2619. InitializeListHead(&listOfDiffAreaFilesToClose);
  2620. InitializeListHead(&listOfDeviceObjectToDelete);
  2621. VspAcquire(filter->Root);
  2622. b = FALSE;
  2623. while (!IsListEmpty(&filter->VolumeList)) {
  2624. VspDeleteOldestSnapshot(filter, &listOfDiffAreaFilesToClose,
  2625. &listOfDeviceObjectToDelete, keepOnDisk,
  2626. TRUE);
  2627. b = TRUE;
  2628. }
  2629. if (b) {
  2630. IoInvalidateDeviceRelations(filter->Pdo, BusRelations);
  2631. }
  2632. InterlockedExchange(&filter->DestroyAllSnapshotsPending, FALSE);
  2633. VspRelease(filter->Root);
  2634. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  2635. &listOfDeviceObjectToDelete);
  2636. ObDereferenceObject(filter->DeviceObject);
  2637. }
  2638. VOID
  2639. VspAbortTableEntryWorker(
  2640. IN PVOID TableEntry
  2641. )
  2642. {
  2643. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  2644. PVOLUME_EXTENSION extension = tableEntry->Extension;
  2645. PIRP irp;
  2646. PKEVENT event;
  2647. if (extension->IsPersistent) {
  2648. VspDeleteControlItemsWithGuid(extension->Filter, NULL, TRUE);
  2649. }
  2650. VspEmptyWorkerQueue(&tableEntry->WaitingQueueDpc);
  2651. irp = tableEntry->WriteIrp;
  2652. tableEntry->WriteIrp = NULL;
  2653. if (irp) {
  2654. VspDecrementIrpRefCount(irp);
  2655. }
  2656. event = tableEntry->WaitEvent;
  2657. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable,
  2658. tableEntry);
  2659. if (event) {
  2660. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  2661. }
  2662. VspReleaseNonPagedResource(extension);
  2663. ObDereferenceObject(extension->Filter->DeviceObject);
  2664. ObDereferenceObject(extension->DeviceObject);
  2665. }
  2666. BOOLEAN
  2667. VspDestroyAllSnapshots(
  2668. IN PFILTER_EXTENSION Filter,
  2669. IN PTEMP_TRANSLATION_TABLE_ENTRY TableEntry,
  2670. IN BOOLEAN KeepOnDisk,
  2671. IN BOOLEAN PerformSynchronously
  2672. )
  2673. /*++
  2674. Routine Description:
  2675. This routine will delete all of the snapshots in the system.
  2676. Arguments:
  2677. Filter - Supplies the filter extension.
  2678. Return Value:
  2679. None.
  2680. --*/
  2681. {
  2682. LONG destroyInProgress;
  2683. KIRQL irql;
  2684. PLIST_ENTRY l;
  2685. PVOLUME_EXTENSION extension;
  2686. PWORK_QUEUE_ITEM workItem;
  2687. NTSTATUS status;
  2688. PVSP_CONTEXT context;
  2689. destroyInProgress = InterlockedExchange(
  2690. &Filter->DestroyAllSnapshotsPending, TRUE);
  2691. if (!destroyInProgress) {
  2692. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  2693. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  2694. l = l->Flink) {
  2695. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  2696. InterlockedExchange(&extension->IsStarted, FALSE);
  2697. InterlockedExchange(&extension->IsDead, TRUE);
  2698. }
  2699. KeReleaseSpinLock(&Filter->SpinLock, irql);
  2700. }
  2701. if (TableEntry) {
  2702. extension = TableEntry->Extension;
  2703. if (TableEntry->IsMoveEntry) {
  2704. ASSERT(TableEntry->WaitEvent);
  2705. KeSetEvent(TableEntry->WaitEvent, IO_NO_INCREMENT, FALSE);
  2706. } else {
  2707. if (TableEntry->CopyIrp) {
  2708. VspFreeCopyIrp(extension, TableEntry->CopyIrp);
  2709. TableEntry->CopyIrp = NULL;
  2710. }
  2711. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2712. RtlSetBit(extension->VolumeBlockBitmap,
  2713. (ULONG) (TableEntry->VolumeOffset>>BLOCK_SHIFT));
  2714. TableEntry->IsComplete = TRUE;
  2715. if (TableEntry->InTableUpdateQueue) {
  2716. TableEntry->InTableUpdateQueue = FALSE;
  2717. RemoveEntryList(&TableEntry->TableUpdateListEntry);
  2718. }
  2719. KeReleaseSpinLock(&extension->SpinLock, irql);
  2720. ObReferenceObject(extension->DeviceObject);
  2721. ObReferenceObject(extension->Filter->DeviceObject);
  2722. workItem = &TableEntry->WorkItem;
  2723. ExInitializeWorkItem(workItem, VspAbortTableEntryWorker,
  2724. TableEntry);
  2725. VspAcquireNonPagedResource(extension, workItem, TRUE);
  2726. }
  2727. }
  2728. if (destroyInProgress) {
  2729. return FALSE;
  2730. }
  2731. context = &Filter->DestroyContext;
  2732. context->Type = VSP_CONTEXT_TYPE_DESTROY_SNAPSHOTS;
  2733. context->DestroyAllSnapshots.Filter = Filter;
  2734. context->DestroyAllSnapshots.KeepOnDisk = KeepOnDisk;
  2735. context->DestroyAllSnapshots.SynchronousCall = PerformSynchronously;
  2736. ObReferenceObject(Filter->DeviceObject);
  2737. ExInitializeWorkItem(&context->WorkItem, VspDestroyAllSnapshotsWorker,
  2738. context);
  2739. if (PerformSynchronously) {
  2740. VspDestroyAllSnapshotsWorker(context);
  2741. } else {
  2742. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  2743. }
  2744. return TRUE;
  2745. }
  2746. VOID
  2747. VspWriteVolumePhase5(
  2748. IN PVOID TableEntry
  2749. )
  2750. {
  2751. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  2752. PVOLUME_EXTENSION extension = tableEntry->Extension;
  2753. PKEVENT event;
  2754. event = tableEntry->WaitEvent;
  2755. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable,
  2756. tableEntry);
  2757. if (event) {
  2758. KeSetEvent(event, IO_NO_INCREMENT, FALSE);
  2759. }
  2760. VspReleaseNonPagedResource(extension);
  2761. VspDecrementVolumeRefCount(extension);
  2762. }
  2763. VOID
  2764. VspWriteVolumePhase4(
  2765. IN PVOID TableEntry
  2766. )
  2767. /*++
  2768. Routine Description:
  2769. This routine is queued from the completion of writting a block to
  2770. make up a table entry for the write. This routine will create and
  2771. insert the table entry.
  2772. Arguments:
  2773. Context - Supplies the context.
  2774. Return Value:
  2775. None.
  2776. --*/
  2777. {
  2778. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  2779. PVOLUME_EXTENSION extension = tableEntry->Extension;
  2780. PFILTER_EXTENSION filter = extension->Filter;
  2781. TRANSLATION_TABLE_ENTRY keyTableEntry;
  2782. PTRANSLATION_TABLE_ENTRY backPointer, finalTableEntry;
  2783. PVOID r;
  2784. PVOID nodeOrParent;
  2785. TABLE_SEARCH_RESULT searchResult;
  2786. KIRQL irql;
  2787. RtlZeroMemory(&keyTableEntry, sizeof(TRANSLATION_TABLE_ENTRY));
  2788. keyTableEntry.VolumeOffset = tableEntry->VolumeOffset;
  2789. keyTableEntry.TargetObject = tableEntry->TargetObject;
  2790. keyTableEntry.TargetOffset = tableEntry->TargetOffset;
  2791. _try {
  2792. backPointer = (PTRANSLATION_TABLE_ENTRY)
  2793. RtlLookupElementGenericTable(&extension->CopyBackPointerTable,
  2794. &keyTableEntry);
  2795. if (backPointer) {
  2796. keyTableEntry.VolumeOffset = backPointer->TargetOffset;
  2797. }
  2798. r = RtlLookupElementGenericTableFull(&extension->VolumeBlockTable,
  2799. &keyTableEntry, &nodeOrParent,
  2800. &searchResult);
  2801. ASSERT(!backPointer || r);
  2802. if (r) {
  2803. ASSERT(backPointer);
  2804. RtlDeleteElementGenericTable(&extension->CopyBackPointerTable,
  2805. backPointer);
  2806. finalTableEntry = (PTRANSLATION_TABLE_ENTRY) r;
  2807. ASSERT(finalTableEntry->Flags&
  2808. VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY);
  2809. finalTableEntry->TargetObject = tableEntry->TargetObject;
  2810. finalTableEntry->Flags &=
  2811. ~VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY;
  2812. finalTableEntry->TargetOffset = tableEntry->TargetOffset;
  2813. } else {
  2814. r = RtlInsertElementGenericTableFull(
  2815. &extension->VolumeBlockTable, &keyTableEntry,
  2816. sizeof(TRANSLATION_TABLE_ENTRY), NULL, nodeOrParent,
  2817. searchResult);
  2818. }
  2819. } _except (EXCEPTION_EXECUTE_HANDLER) {
  2820. r = NULL;
  2821. }
  2822. VspReleasePagedResource(extension);
  2823. if (!r) {
  2824. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2825. if (extension->PageFileSpaceCreatePending) {
  2826. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase4,
  2827. tableEntry);
  2828. InsertTailList(&extension->WaitingForPageFileSpace,
  2829. &tableEntry->WorkItem.List);
  2830. KeReleaseSpinLock(&extension->SpinLock, irql);
  2831. return;
  2832. }
  2833. KeReleaseSpinLock(&extension->SpinLock, irql);
  2834. if (VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE)) {
  2835. VspLogError(extension, NULL, VS_ABORT_SNAPSHOTS_NO_HEAP,
  2836. STATUS_SUCCESS, 0, FALSE);
  2837. }
  2838. VspDecrementVolumeRefCount(extension);
  2839. return;
  2840. }
  2841. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase5,
  2842. tableEntry);
  2843. VspAcquireNonPagedResource(extension, &tableEntry->WorkItem, FALSE);
  2844. }
  2845. VOID
  2846. VspWriteVolumePhase35(
  2847. IN PTEMP_TRANSLATION_TABLE_ENTRY TableEntry
  2848. )
  2849. {
  2850. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = TableEntry;
  2851. PVOLUME_EXTENSION extension = tableEntry->Extension;
  2852. PFILTER_EXTENSION filter = extension->Filter;
  2853. KIRQL irql;
  2854. BOOLEAN emptyQueue;
  2855. PLIST_ENTRY l;
  2856. PWORK_QUEUE_ITEM workItem;
  2857. PVSP_CONTEXT context;
  2858. PIRP irp;
  2859. NTSTATUS status;
  2860. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2861. RtlSetBit(extension->VolumeBlockBitmap,
  2862. (ULONG) (tableEntry->VolumeOffset>>BLOCK_SHIFT));
  2863. tableEntry->IsComplete = TRUE;
  2864. KeReleaseSpinLock(&extension->SpinLock, irql);
  2865. while (!IsListEmpty(&tableEntry->WaitingQueueDpc)) {
  2866. l = RemoveHeadList(&tableEntry->WaitingQueueDpc);
  2867. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  2868. context = (PVSP_CONTEXT) workItem->Parameter;
  2869. if (context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT) {
  2870. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  2871. context->ReadSnapshot.IsCopyTarget = FALSE;
  2872. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  2873. }
  2874. workItem->WorkerRoutine(workItem->Parameter);
  2875. }
  2876. irp = tableEntry->WriteIrp;
  2877. tableEntry->WriteIrp = NULL;
  2878. status = VspIncrementVolumeRefCount(extension);
  2879. if (!NT_SUCCESS(status)) {
  2880. VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE);
  2881. VspDecrementIrpRefCount(irp);
  2882. return;
  2883. }
  2884. VspDecrementIrpRefCount(irp);
  2885. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase4,
  2886. tableEntry);
  2887. VspAcquirePagedResource(extension, &tableEntry->WorkItem);
  2888. }
  2889. VOID
  2890. VspKillTableUpdates(
  2891. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  2892. )
  2893. {
  2894. PVSP_DIFF_AREA_FILE diffAreaFile = DiffAreaFile;
  2895. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  2896. KIRQL irql;
  2897. LIST_ENTRY q;
  2898. PLIST_ENTRY l;
  2899. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  2900. ObReferenceObject(extension->DeviceObject);
  2901. for (;;) {
  2902. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2903. if (IsListEmpty(&diffAreaFile->TableUpdateQueue)) {
  2904. diffAreaFile->TableUpdateInProgress = FALSE;
  2905. KeReleaseSpinLock(&extension->SpinLock, irql);
  2906. break;
  2907. }
  2908. l = RemoveHeadList(&diffAreaFile->TableUpdateQueue);
  2909. tableEntry = CONTAINING_RECORD(l, TEMP_TRANSLATION_TABLE_ENTRY,
  2910. TableUpdateListEntry);
  2911. tableEntry->InTableUpdateQueue = FALSE;
  2912. KeReleaseSpinLock(&extension->SpinLock, irql);
  2913. VspDestroyAllSnapshots(extension->Filter, tableEntry, FALSE, FALSE);
  2914. }
  2915. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  2916. ObDereferenceObject(extension->DeviceObject);
  2917. }
  2918. NTSTATUS
  2919. VspReadNextDiffAreaBlockCompletion(
  2920. IN PDEVICE_OBJECT DeviceObject,
  2921. IN PIRP Irp,
  2922. IN PVOID DiffAreaFile
  2923. )
  2924. /*++
  2925. Routine Description:
  2926. This routine is the completion for a read of the next diff area file table
  2927. block.
  2928. Arguments:
  2929. DiffAreaFile - Supplies the diff area file.
  2930. Return Value:
  2931. STATUS_MORE_PROCESSING_REQUIRED
  2932. --*/
  2933. {
  2934. NTSTATUS status = Irp->IoStatus.Status;
  2935. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  2936. if (!NT_SUCCESS(status)) {
  2937. if (!diffAreaFile->Extension->Filter->DestroyAllSnapshotsPending) {
  2938. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  2939. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 8, FALSE);
  2940. }
  2941. VspKillTableUpdates(diffAreaFile);
  2942. return STATUS_MORE_PROCESSING_REQUIRED;
  2943. }
  2944. diffAreaFile->NextFreeTableEntryOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  2945. VspWriteTableUpdates(diffAreaFile);
  2946. return STATUS_MORE_PROCESSING_REQUIRED;
  2947. }
  2948. NTSTATUS
  2949. VspWriteTableUpdatesCompletion(
  2950. IN PDEVICE_OBJECT DeviceObject,
  2951. IN PIRP Irp,
  2952. IN PVOID DiffAreaFile
  2953. )
  2954. /*++
  2955. Routine Description:
  2956. This routine is the completion for a write to the diff area file table.
  2957. Arguments:
  2958. Context - Supplies the context.
  2959. Return Value:
  2960. STATUS_MORE_PROCESSING_REQUIRED
  2961. --*/
  2962. {
  2963. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  2964. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  2965. NTSTATUS status = Irp->IoStatus.Status;
  2966. PLIST_ENTRY l;
  2967. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  2968. if (!NT_SUCCESS(status)) {
  2969. if (!extension->Filter->DestroyAllSnapshotsPending) {
  2970. VspLogError(extension, diffAreaFile->Filter,
  2971. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 9, FALSE);
  2972. }
  2973. while (!IsListEmpty(&diffAreaFile->TableUpdatesInProgress)) {
  2974. l = RemoveHeadList(&diffAreaFile->TableUpdatesInProgress);
  2975. tableEntry = CONTAINING_RECORD(l, TEMP_TRANSLATION_TABLE_ENTRY,
  2976. TableUpdateListEntry);
  2977. VspDestroyAllSnapshots(extension->Filter, tableEntry, FALSE, FALSE);
  2978. }
  2979. VspKillTableUpdates(diffAreaFile);
  2980. return STATUS_MORE_PROCESSING_REQUIRED;
  2981. }
  2982. while (!IsListEmpty(&diffAreaFile->TableUpdatesInProgress)) {
  2983. l = RemoveHeadList(&diffAreaFile->TableUpdatesInProgress);
  2984. tableEntry = CONTAINING_RECORD(l, TEMP_TRANSLATION_TABLE_ENTRY,
  2985. TableUpdateListEntry);
  2986. if (tableEntry->IsMoveEntry) {
  2987. ASSERT(tableEntry->WaitEvent);
  2988. KeSetEvent(tableEntry->WaitEvent, IO_NO_INCREMENT, FALSE);
  2989. } else {
  2990. VspWriteVolumePhase35(tableEntry);
  2991. }
  2992. }
  2993. VspWriteTableUpdates(diffAreaFile);
  2994. return STATUS_MORE_PROCESSING_REQUIRED;
  2995. }
  2996. NTSTATUS
  2997. VspCreateNewDiffAreaBlockPhase5(
  2998. IN PDEVICE_OBJECT DeviceObject,
  2999. IN PIRP Irp,
  3000. IN PVOID DiffAreaFile
  3001. )
  3002. {
  3003. NTSTATUS status = Irp->IoStatus.Status;
  3004. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3005. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3006. PIRP irp;
  3007. PIO_STACK_LOCATION nextSp;
  3008. if (!NT_SUCCESS(status)) {
  3009. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3010. VspLogError(extension, diffAreaFile->Filter,
  3011. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 21, FALSE);
  3012. }
  3013. VspKillTableUpdates(diffAreaFile);
  3014. return STATUS_MORE_PROCESSING_REQUIRED;
  3015. }
  3016. VspWriteTableUpdates(diffAreaFile);
  3017. return STATUS_MORE_PROCESSING_REQUIRED;
  3018. }
  3019. NTSTATUS
  3020. VspCreateNewDiffAreaBlockPhase4(
  3021. IN PDEVICE_OBJECT DeviceObject,
  3022. IN PIRP Irp,
  3023. IN PVOID DiffAreaFile
  3024. )
  3025. {
  3026. NTSTATUS status = Irp->IoStatus.Status;
  3027. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3028. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3029. PIRP irp;
  3030. PIO_STACK_LOCATION nextSp;
  3031. if (!NT_SUCCESS(status)) {
  3032. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3033. VspLogError(extension, diffAreaFile->Filter,
  3034. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 20, FALSE);
  3035. }
  3036. VspKillTableUpdates(diffAreaFile);
  3037. return STATUS_MORE_PROCESSING_REQUIRED;
  3038. }
  3039. diffAreaFile->TableTargetOffset = diffAreaFile->NextTableTargetOffset;
  3040. diffAreaFile->NextFreeTableEntryOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  3041. irp = diffAreaFile->TableUpdateIrp;
  3042. nextSp = IoGetNextIrpStackLocation(irp);
  3043. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3044. nextSp->Parameters.Read.ByteOffset.QuadPart =
  3045. diffAreaFile->NextTableTargetOffset;
  3046. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  3047. nextSp->MajorFunction = IRP_MJ_READ;
  3048. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3049. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3050. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase5,
  3051. diffAreaFile, TRUE, TRUE, TRUE);
  3052. IoCallDriver(nextSp->DeviceObject, irp);
  3053. return STATUS_MORE_PROCESSING_REQUIRED;
  3054. }
  3055. NTSTATUS
  3056. VspCreateNewDiffAreaBlockPhase3(
  3057. IN PDEVICE_OBJECT DeviceObject,
  3058. IN PIRP Irp,
  3059. IN PVOID DiffAreaFile
  3060. )
  3061. {
  3062. NTSTATUS status = Irp->IoStatus.Status;
  3063. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3064. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3065. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  3066. PIRP irp;
  3067. PIO_STACK_LOCATION nextSp;
  3068. if (!NT_SUCCESS(status)) {
  3069. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3070. VspLogError(extension, diffAreaFile->Filter,
  3071. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 19, FALSE);
  3072. }
  3073. VspKillTableUpdates(diffAreaFile);
  3074. return STATUS_MORE_PROCESSING_REQUIRED;
  3075. }
  3076. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  3077. MmGetMdlVirtualAddress(diffAreaFile->TableUpdateIrp->MdlAddress);
  3078. diffAreaBlock->Header.NextVolumeOffset =
  3079. diffAreaFile->NextTableTargetOffset;
  3080. irp = diffAreaFile->TableUpdateIrp;
  3081. nextSp = IoGetNextIrpStackLocation(irp);
  3082. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3083. nextSp->Parameters.Write.ByteOffset.QuadPart =
  3084. diffAreaFile->TableTargetOffset;
  3085. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3086. nextSp->MajorFunction = IRP_MJ_WRITE;
  3087. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3088. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3089. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase4,
  3090. diffAreaFile, TRUE, TRUE, TRUE);
  3091. IoCallDriver(nextSp->DeviceObject, irp);
  3092. return STATUS_MORE_PROCESSING_REQUIRED;
  3093. }
  3094. NTSTATUS
  3095. VspCreateNewDiffAreaBlockPhase2(
  3096. IN PDEVICE_OBJECT DeviceObject,
  3097. IN PIRP Irp,
  3098. IN PVOID DiffAreaFile
  3099. )
  3100. {
  3101. NTSTATUS status = Irp->IoStatus.Status;
  3102. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3103. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3104. PIRP irp;
  3105. PIO_STACK_LOCATION nextSp;
  3106. if (!NT_SUCCESS(status)) {
  3107. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3108. VspLogError(extension, diffAreaFile->Filter,
  3109. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 18, FALSE);
  3110. }
  3111. VspKillTableUpdates(diffAreaFile);
  3112. return STATUS_MORE_PROCESSING_REQUIRED;
  3113. }
  3114. irp = diffAreaFile->TableUpdateIrp;
  3115. nextSp = IoGetNextIrpStackLocation(irp);
  3116. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3117. nextSp->Parameters.Read.ByteOffset.QuadPart =
  3118. diffAreaFile->TableTargetOffset;
  3119. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  3120. nextSp->MajorFunction = IRP_MJ_READ;
  3121. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3122. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3123. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase3,
  3124. diffAreaFile, TRUE, TRUE, TRUE);
  3125. IoCallDriver(nextSp->DeviceObject, irp);
  3126. return STATUS_MORE_PROCESSING_REQUIRED;
  3127. }
  3128. NTSTATUS
  3129. VspCreateNewDiffAreaBlockPhase15(
  3130. IN PDEVICE_OBJECT DeviceObject,
  3131. IN PIRP Irp,
  3132. IN PVOID DiffAreaFile
  3133. )
  3134. {
  3135. NTSTATUS status = Irp->IoStatus.Status;
  3136. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3137. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3138. PVOID buffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  3139. ULONG i;
  3140. PIRP irp;
  3141. PIO_STACK_LOCATION nextSp;
  3142. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  3143. if (!NT_SUCCESS(status)) {
  3144. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3145. VspLogError(extension, diffAreaFile->Filter,
  3146. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 100, FALSE);
  3147. }
  3148. VspKillTableUpdates(diffAreaFile);
  3149. return STATUS_MORE_PROCESSING_REQUIRED;
  3150. }
  3151. for (i = 0; i < BLOCK_SIZE; i += SMALLEST_NTFS_CLUSTER) {
  3152. if (RtlCompareMemory((PCHAR) buffer + i, &VSP_DIFF_AREA_FILE_GUID,
  3153. sizeof(GUID)) != sizeof(GUID)) {
  3154. break;
  3155. }
  3156. }
  3157. if (i < BLOCK_SIZE) {
  3158. VspWriteTableUpdates(diffAreaFile);
  3159. return STATUS_MORE_PROCESSING_REQUIRED;
  3160. }
  3161. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  3162. MmGetMdlVirtualAddress(diffAreaFile->TableUpdateIrp->MdlAddress);
  3163. RtlZeroMemory(diffAreaBlock, BLOCK_SIZE);
  3164. diffAreaBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  3165. diffAreaBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  3166. diffAreaBlock->Header.BlockType = VSP_BLOCK_TYPE_DIFF_AREA;
  3167. diffAreaBlock->Header.ThisFileOffset = diffAreaFile->NextTableFileOffset;
  3168. diffAreaBlock->Header.ThisVolumeOffset =
  3169. diffAreaFile->NextTableTargetOffset;
  3170. irp = diffAreaFile->TableUpdateIrp;
  3171. nextSp = IoGetNextIrpStackLocation(irp);
  3172. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3173. nextSp->Parameters.Write.ByteOffset.QuadPart =
  3174. diffAreaFile->NextTableTargetOffset;
  3175. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3176. nextSp->MajorFunction = IRP_MJ_WRITE;
  3177. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3178. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3179. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase2,
  3180. diffAreaFile, TRUE, TRUE, TRUE);
  3181. IoCallDriver(nextSp->DeviceObject, irp);
  3182. return STATUS_MORE_PROCESSING_REQUIRED;
  3183. }
  3184. VOID
  3185. VspCreateNewDiffAreaBlockPhase1(
  3186. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  3187. )
  3188. {
  3189. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3190. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3191. LONGLONG targetOffset = diffAreaFile->NextTableTargetOffset;
  3192. LONGLONG fileOffset = diffAreaFile->NextTableFileOffset;
  3193. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  3194. PIRP irp;
  3195. PIO_STACK_LOCATION nextSp;
  3196. ASSERT(targetOffset);
  3197. ASSERT(fileOffset);
  3198. if (extension->IsDetected && !extension->OkToGrowDiffArea &&
  3199. !extension->NoDiffAreaFill) {
  3200. irp = diffAreaFile->TableUpdateIrp;
  3201. nextSp = IoGetNextIrpStackLocation(irp);
  3202. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3203. nextSp->Parameters.Write.ByteOffset.QuadPart = targetOffset;
  3204. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3205. nextSp->MajorFunction = IRP_MJ_READ;
  3206. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3207. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3208. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase15,
  3209. diffAreaFile, TRUE, TRUE, TRUE);
  3210. IoCallDriver(nextSp->DeviceObject, irp);
  3211. return;
  3212. }
  3213. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  3214. MmGetMdlVirtualAddress(diffAreaFile->TableUpdateIrp->MdlAddress);
  3215. RtlZeroMemory(diffAreaBlock, BLOCK_SIZE);
  3216. diffAreaBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  3217. diffAreaBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  3218. diffAreaBlock->Header.BlockType = VSP_BLOCK_TYPE_DIFF_AREA;
  3219. diffAreaBlock->Header.ThisFileOffset = fileOffset;
  3220. diffAreaBlock->Header.ThisVolumeOffset = targetOffset;
  3221. irp = diffAreaFile->TableUpdateIrp;
  3222. nextSp = IoGetNextIrpStackLocation(irp);
  3223. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3224. nextSp->Parameters.Write.ByteOffset.QuadPart = targetOffset;
  3225. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3226. nextSp->MajorFunction = IRP_MJ_WRITE;
  3227. nextSp->DeviceObject = diffAreaFile->Filter->TargetObject;
  3228. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3229. IoSetCompletionRoutine(irp, VspCreateNewDiffAreaBlockPhase2,
  3230. diffAreaFile, TRUE, TRUE, TRUE);
  3231. IoCallDriver(nextSp->DeviceObject, irp);
  3232. }
  3233. VOID
  3234. VspCreateNewDiffAreaBlockAllocate(
  3235. IN PVOID DiffAreaFile
  3236. )
  3237. {
  3238. PVSP_DIFF_AREA_FILE diffAreaFile = (PVSP_DIFF_AREA_FILE) DiffAreaFile;
  3239. PVOLUME_EXTENSION extension = diffAreaFile->Extension;
  3240. PFILTER_EXTENSION filter;
  3241. KIRQL irql, irql2;
  3242. BOOLEAN dontNeedWrite;
  3243. diffAreaFile->StatusOfNextBlockAllocate =
  3244. VspAllocateDiffAreaSpace(extension,
  3245. &diffAreaFile->NextTableTargetOffset,
  3246. &diffAreaFile->NextTableFileOffset,
  3247. NULL, NULL);
  3248. VspReleaseNonPagedResource(extension);
  3249. if (!NT_SUCCESS(diffAreaFile->StatusOfNextBlockAllocate)) {
  3250. filter = extension->Filter;
  3251. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3252. if (extension->GrowDiffAreaFilePending) {
  3253. KeAcquireSpinLock(&filter->SpinLock, &irql2);
  3254. if ((IsListEmpty(&filter->DiffAreaFilesOnThisFilter) &&
  3255. !filter->FSRefCount &&
  3256. !diffAreaFile->Filter->SnapshotsPresent &&
  3257. !filter->UsedForPaging && extension->OkToGrowDiffArea) ||
  3258. extension->PastFileSystemOperations) {
  3259. InsertTailList(&extension->WaitingForDiffAreaSpace,
  3260. &diffAreaFile->WorkItem.List);
  3261. KeReleaseSpinLock(&filter->SpinLock, irql2);
  3262. KeReleaseSpinLock(&extension->SpinLock, irql);
  3263. return;
  3264. }
  3265. KeReleaseSpinLock(&filter->SpinLock, irql2);
  3266. }
  3267. KeReleaseSpinLock(&extension->SpinLock, irql);
  3268. }
  3269. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3270. dontNeedWrite = diffAreaFile->TableUpdateInProgress;
  3271. diffAreaFile->NextBlockAllocationComplete = TRUE;
  3272. diffAreaFile->TableUpdateInProgress = TRUE;
  3273. KeReleaseSpinLock(&extension->SpinLock, irql);
  3274. if (!dontNeedWrite) {
  3275. VspWriteTableUpdates(diffAreaFile);
  3276. }
  3277. }
  3278. VOID
  3279. VspWriteTableUpdates(
  3280. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  3281. )
  3282. /*++
  3283. Routine Description:
  3284. This routine adds the table entries into the diff area block and
  3285. writes them to disk. As needed this routine re-iterates and allocates
  3286. new diff area blocks.
  3287. Arguments:
  3288. DiffAreaFile - Supplies the diff area file.
  3289. Return Value:
  3290. None.
  3291. --*/
  3292. {
  3293. PVOLUME_EXTENSION extension = DiffAreaFile->Extension;
  3294. KIRQL irql;
  3295. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  3296. PLIST_ENTRY l;
  3297. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  3298. PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY diffAreaTableEntry;
  3299. PIRP irp;
  3300. PIO_STACK_LOCATION nextSp;
  3301. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3302. if (DiffAreaFile->IrpNeeded) {
  3303. DiffAreaFile->IrpNeeded = FALSE;
  3304. KeReleaseSpinLock(&extension->SpinLock, irql);
  3305. KeSetEvent(&DiffAreaFile->IrpReady, IO_NO_INCREMENT, FALSE);
  3306. return;
  3307. }
  3308. if (IsListEmpty(&DiffAreaFile->TableUpdateQueue)) {
  3309. DiffAreaFile->TableUpdateInProgress = FALSE;
  3310. KeReleaseSpinLock(&extension->SpinLock, irql);
  3311. return;
  3312. }
  3313. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  3314. MmGetMdlVirtualAddress(DiffAreaFile->TableUpdateIrp->MdlAddress);
  3315. if (DiffAreaFile->NextFreeTableEntryOffset +
  3316. sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY) > BLOCK_SIZE) {
  3317. if (DiffAreaFile->NextBlockAllocationComplete) {
  3318. DiffAreaFile->NextBlockAllocationComplete = FALSE;
  3319. ASSERT(DiffAreaFile->NextBlockAllocationInProgress);
  3320. DiffAreaFile->NextBlockAllocationInProgress = FALSE;
  3321. KeReleaseSpinLock(&extension->SpinLock, irql);
  3322. if (!NT_SUCCESS(DiffAreaFile->StatusOfNextBlockAllocate)) {
  3323. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3324. VspLogError(extension, NULL,
  3325. VS_ABORT_SNAPSHOTS_OUT_OF_DIFF_AREA,
  3326. STATUS_SUCCESS, 1, FALSE);
  3327. }
  3328. VspKillTableUpdates(DiffAreaFile);
  3329. return;
  3330. }
  3331. VspCreateNewDiffAreaBlockPhase1(DiffAreaFile);
  3332. return;
  3333. }
  3334. DiffAreaFile->TableUpdateInProgress = FALSE;
  3335. if (DiffAreaFile->NextBlockAllocationInProgress) {
  3336. KeReleaseSpinLock(&extension->SpinLock, irql);
  3337. return;
  3338. }
  3339. DiffAreaFile->NextBlockAllocationInProgress = TRUE;
  3340. KeReleaseSpinLock(&extension->SpinLock, irql);
  3341. ASSERT(!diffAreaBlock->Header.NextVolumeOffset);
  3342. ExInitializeWorkItem(&DiffAreaFile->WorkItem,
  3343. VspCreateNewDiffAreaBlockAllocate,
  3344. DiffAreaFile);
  3345. VspAcquireNonPagedResource(extension, &DiffAreaFile->WorkItem, TRUE);
  3346. return;
  3347. }
  3348. KeReleaseSpinLock(&extension->SpinLock, irql);
  3349. InitializeListHead(&DiffAreaFile->TableUpdatesInProgress);
  3350. for (;;) {
  3351. if (DiffAreaFile->NextFreeTableEntryOffset +
  3352. sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY) > BLOCK_SIZE) {
  3353. break;
  3354. }
  3355. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3356. if (IsListEmpty(&DiffAreaFile->TableUpdateQueue)) {
  3357. KeReleaseSpinLock(&extension->SpinLock, irql);
  3358. break;
  3359. }
  3360. l = RemoveHeadList(&DiffAreaFile->TableUpdateQueue);
  3361. tableEntry = CONTAINING_RECORD(l, TEMP_TRANSLATION_TABLE_ENTRY,
  3362. TableUpdateListEntry);
  3363. tableEntry->InTableUpdateQueue = FALSE;
  3364. KeReleaseSpinLock(&extension->SpinLock, irql);
  3365. InsertTailList(&DiffAreaFile->TableUpdatesInProgress, l);
  3366. diffAreaTableEntry = (PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY)
  3367. ((PCHAR) diffAreaBlock +
  3368. DiffAreaFile->NextFreeTableEntryOffset);
  3369. DiffAreaFile->NextFreeTableEntryOffset +=
  3370. sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY);
  3371. if (tableEntry->IsMoveEntry) {
  3372. diffAreaTableEntry->SnapshotVolumeOffset =
  3373. tableEntry->FileOffset;
  3374. diffAreaTableEntry->DiffAreaFileOffset =
  3375. tableEntry->VolumeOffset;
  3376. diffAreaTableEntry->Flags |=
  3377. VSP_DIFF_AREA_TABLE_ENTRY_FLAG_MOVE_ENTRY;
  3378. } else {
  3379. diffAreaTableEntry->SnapshotVolumeOffset =
  3380. tableEntry->VolumeOffset;
  3381. diffAreaTableEntry->DiffAreaFileOffset =
  3382. tableEntry->FileOffset;
  3383. diffAreaTableEntry->DiffAreaVolumeOffset =
  3384. tableEntry->TargetOffset;
  3385. }
  3386. }
  3387. irp = DiffAreaFile->TableUpdateIrp;
  3388. nextSp = IoGetNextIrpStackLocation(irp);
  3389. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3390. nextSp->Parameters.Write.ByteOffset.QuadPart =
  3391. diffAreaBlock->Header.ThisVolumeOffset;
  3392. ASSERT(diffAreaBlock->Header.ThisVolumeOffset ==
  3393. DiffAreaFile->TableTargetOffset);
  3394. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3395. nextSp->MajorFunction = IRP_MJ_WRITE;
  3396. nextSp->DeviceObject = DiffAreaFile->Filter->TargetObject;
  3397. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3398. IoSetCompletionRoutine(irp, VspWriteTableUpdatesCompletion, DiffAreaFile,
  3399. TRUE, TRUE, TRUE);
  3400. IoCallDriver(nextSp->DeviceObject, irp);
  3401. }
  3402. NTSTATUS
  3403. VspWriteVolumePhase3(
  3404. IN PDEVICE_OBJECT DeviceObject,
  3405. IN PIRP Irp,
  3406. IN PVOID TableEntry
  3407. )
  3408. /*++
  3409. Routine Description:
  3410. This routine is the completion for a write to the diff area file.
  3411. Arguments:
  3412. Context - Supplies the context.
  3413. Return Value:
  3414. STATUS_MORE_PROCESSING_REQUIRED
  3415. --*/
  3416. {
  3417. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3418. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3419. PFILTER_EXTENSION filter = extension->Filter;
  3420. NTSTATUS status = Irp->IoStatus.Status;
  3421. PVSP_DIFF_AREA_FILE diffAreaFile;
  3422. KIRQL irql;
  3423. BOOLEAN dontNeedWrite;
  3424. if (!NT_SUCCESS(status)) {
  3425. if (!filter->DestroyAllSnapshotsPending) {
  3426. VspLogError(extension, extension->DiffAreaFile->Filter,
  3427. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 10, FALSE);
  3428. }
  3429. VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE);
  3430. return STATUS_MORE_PROCESSING_REQUIRED;
  3431. }
  3432. VspFreeCopyIrp(extension, Irp);
  3433. tableEntry->CopyIrp = NULL;
  3434. if (extension->IsPersistent) {
  3435. diffAreaFile = extension->DiffAreaFile;
  3436. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3437. InsertTailList(&diffAreaFile->TableUpdateQueue,
  3438. &tableEntry->TableUpdateListEntry);
  3439. tableEntry->InTableUpdateQueue = TRUE;
  3440. dontNeedWrite = diffAreaFile->TableUpdateInProgress;
  3441. diffAreaFile->TableUpdateInProgress = TRUE;
  3442. KeReleaseSpinLock(&extension->SpinLock, irql);
  3443. if (!dontNeedWrite) {
  3444. VspWriteTableUpdates(diffAreaFile);
  3445. }
  3446. return STATUS_MORE_PROCESSING_REQUIRED;
  3447. }
  3448. VspWriteVolumePhase35(tableEntry);
  3449. return STATUS_MORE_PROCESSING_REQUIRED;
  3450. }
  3451. VOID
  3452. VspWriteVolumePhase25(
  3453. IN PVOID TableEntry
  3454. )
  3455. {
  3456. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3457. PIRP irp = tableEntry->CopyIrp;
  3458. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  3459. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3460. NTSTATUS status;
  3461. PFILTER_EXTENSION filter;
  3462. PVSP_DIFF_AREA_FILE diffAreaFile;
  3463. KIRQL irql, irql2;
  3464. status = VspAllocateDiffAreaSpace(extension, &tableEntry->TargetOffset,
  3465. &tableEntry->FileOffset, NULL, NULL);
  3466. VspReleaseNonPagedResource(extension);
  3467. if (!NT_SUCCESS(status)) {
  3468. diffAreaFile = extension->DiffAreaFile;
  3469. filter = extension->Filter;
  3470. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3471. if (extension->GrowDiffAreaFilePending) {
  3472. KeAcquireSpinLock(&filter->SpinLock, &irql2);
  3473. if ((IsListEmpty(&filter->DiffAreaFilesOnThisFilter) &&
  3474. !filter->FSRefCount &&
  3475. !diffAreaFile->Filter->SnapshotsPresent &&
  3476. !filter->UsedForPaging && extension->OkToGrowDiffArea) ||
  3477. extension->PastFileSystemOperations) {
  3478. ExInitializeWorkItem(&tableEntry->WorkItem,
  3479. VspWriteVolumePhase25,
  3480. tableEntry);
  3481. InsertTailList(&extension->WaitingForDiffAreaSpace,
  3482. &tableEntry->WorkItem.List);
  3483. KeReleaseSpinLock(&filter->SpinLock, irql2);
  3484. KeReleaseSpinLock(&extension->SpinLock, irql);
  3485. return;
  3486. }
  3487. KeReleaseSpinLock(&filter->SpinLock, irql2);
  3488. }
  3489. KeReleaseSpinLock(&extension->SpinLock, irql);
  3490. ObReferenceObject(extension->DeviceObject);
  3491. ObReferenceObject(filter->DeviceObject);
  3492. if (VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE)) {
  3493. if (extension->GrowFailed) {
  3494. if (extension->UserImposedLimit) {
  3495. VspLogError(extension, NULL,
  3496. VS_ABORT_NO_DIFF_AREA_SPACE_USER_IMPOSED,
  3497. STATUS_SUCCESS, 2, FALSE);
  3498. } else {
  3499. VspLogError(extension, NULL,
  3500. VS_ABORT_NO_DIFF_AREA_SPACE_GROW_FAILED,
  3501. STATUS_SUCCESS, 0, FALSE);
  3502. }
  3503. } else {
  3504. VspLogError(extension, NULL,
  3505. VS_ABORT_SNAPSHOTS_OUT_OF_DIFF_AREA,
  3506. STATUS_SUCCESS, 3, FALSE);
  3507. }
  3508. }
  3509. ObDereferenceObject(filter->DeviceObject);
  3510. ObDereferenceObject(extension->DeviceObject);
  3511. return;
  3512. }
  3513. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3514. nextSp->Parameters.Write.ByteOffset.QuadPart = tableEntry->TargetOffset;
  3515. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3516. nextSp->MajorFunction = IRP_MJ_WRITE;
  3517. nextSp->DeviceObject = tableEntry->TargetObject;
  3518. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3519. IoSetCompletionRoutine(irp, VspWriteVolumePhase3, tableEntry, TRUE, TRUE,
  3520. TRUE);
  3521. IoCallDriver(nextSp->DeviceObject, irp);
  3522. }
  3523. NTSTATUS
  3524. VspWriteVolumePhase2(
  3525. IN PDEVICE_OBJECT DeviceObject,
  3526. IN PIRP Irp,
  3527. IN PVOID TableEntry
  3528. )
  3529. /*++
  3530. Routine Description:
  3531. This routine is the completion for a read who's data will create
  3532. the table entry for the block that is being written to.
  3533. Arguments:
  3534. Context - Supplies the context.
  3535. Return Value:
  3536. STATUS_MORE_PROCESSING_REQUIRED
  3537. --*/
  3538. {
  3539. NTSTATUS status = Irp->IoStatus.Status;
  3540. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3541. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3542. PIRP irp;
  3543. PIO_STACK_LOCATION nextSp;
  3544. if (!NT_SUCCESS(status)) {
  3545. if (!extension->Filter->DestroyAllSnapshotsPending) {
  3546. VspLogError(extension, extension->Filter,
  3547. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 11, FALSE);
  3548. }
  3549. VspDestroyAllSnapshots(extension->Filter, tableEntry, FALSE, FALSE);
  3550. return STATUS_MORE_PROCESSING_REQUIRED;
  3551. }
  3552. if (tableEntry->TargetOffset) {
  3553. irp = tableEntry->CopyIrp;
  3554. nextSp = IoGetNextIrpStackLocation(irp);
  3555. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3556. nextSp->Parameters.Write.ByteOffset.QuadPart =
  3557. tableEntry->TargetOffset;
  3558. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  3559. nextSp->MajorFunction = IRP_MJ_WRITE;
  3560. nextSp->DeviceObject = tableEntry->TargetObject;
  3561. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3562. IoSetCompletionRoutine(irp, VspWriteVolumePhase3, tableEntry, TRUE,
  3563. TRUE, TRUE);
  3564. IoCallDriver(nextSp->DeviceObject, irp);
  3565. return STATUS_MORE_PROCESSING_REQUIRED;
  3566. }
  3567. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase25,
  3568. tableEntry);
  3569. VspAcquireNonPagedResource(extension, &tableEntry->WorkItem, FALSE);
  3570. return STATUS_MORE_PROCESSING_REQUIRED;
  3571. }
  3572. NTSTATUS
  3573. VspWriteVolumePhase15(
  3574. IN PDEVICE_OBJECT DeviceObject,
  3575. IN PIRP Irp,
  3576. IN PVOID TableEntry
  3577. )
  3578. {
  3579. NTSTATUS status = Irp->IoStatus.Status;
  3580. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
  3581. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3582. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3583. PFILTER_EXTENSION filter = extension->Filter;
  3584. PVOID buffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  3585. ULONG i;
  3586. if (!NT_SUCCESS(status)) {
  3587. if (!filter->DestroyAllSnapshotsPending) {
  3588. VspLogError(extension, extension->DiffAreaFile->Filter,
  3589. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 12, FALSE);
  3590. }
  3591. VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE);
  3592. return STATUS_MORE_PROCESSING_REQUIRED;
  3593. }
  3594. for (i = 0; i < BLOCK_SIZE; i += SMALLEST_NTFS_CLUSTER) {
  3595. if (RtlCompareMemory((PCHAR) buffer + i, &VSP_DIFF_AREA_FILE_GUID,
  3596. sizeof(GUID)) != sizeof(GUID)) {
  3597. break;
  3598. }
  3599. }
  3600. if (i < BLOCK_SIZE) {
  3601. tableEntry->TargetOffset = 0;
  3602. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase12,
  3603. tableEntry);
  3604. VspAcquireNonPagedResource(extension, &tableEntry->WorkItem, FALSE);
  3605. return STATUS_MORE_PROCESSING_REQUIRED;
  3606. }
  3607. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3608. nextSp = IoGetNextIrpStackLocation(Irp);
  3609. nextSp->Parameters.Read.ByteOffset.QuadPart = tableEntry->VolumeOffset;
  3610. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  3611. nextSp->MajorFunction = IRP_MJ_READ;
  3612. nextSp->DeviceObject = filter->TargetObject;
  3613. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3614. if (tableEntry->VolumeOffset + BLOCK_SIZE > extension->VolumeSize) {
  3615. if (extension->VolumeSize > tableEntry->VolumeOffset) {
  3616. nextSp->Parameters.Read.Length = (ULONG)
  3617. (extension->VolumeSize - tableEntry->VolumeOffset);
  3618. }
  3619. }
  3620. IoSetCompletionRoutine(Irp, VspWriteVolumePhase2, tableEntry, TRUE, TRUE,
  3621. TRUE);
  3622. IoCallDriver(nextSp->DeviceObject, Irp);
  3623. return STATUS_MORE_PROCESSING_REQUIRED;
  3624. }
  3625. VOID
  3626. VspWriteVolumePhase12(
  3627. IN PVOID TableEntry
  3628. )
  3629. {
  3630. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3631. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3632. PFILTER_EXTENSION filter = extension->Filter;
  3633. PIRP irp = tableEntry->CopyIrp;
  3634. NTSTATUS status;
  3635. PIO_STACK_LOCATION nextSp;
  3636. if (tableEntry->TargetOffset) {
  3637. status = STATUS_SUCCESS;
  3638. } else {
  3639. status = VspAllocateDiffAreaSpace(extension, &tableEntry->TargetOffset,
  3640. &tableEntry->FileOffset, NULL, NULL);
  3641. }
  3642. VspReleaseNonPagedResource(extension);
  3643. if (!NT_SUCCESS(status)) {
  3644. if (!filter->DestroyAllSnapshotsPending) {
  3645. VspLogError(extension, NULL, VS_ABORT_SNAPSHOTS_OUT_OF_DIFF_AREA,
  3646. status, 4, FALSE);
  3647. }
  3648. VspDestroyAllSnapshots(filter, tableEntry, FALSE, FALSE);
  3649. return;
  3650. }
  3651. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3652. nextSp = IoGetNextIrpStackLocation(irp);
  3653. nextSp->Parameters.Read.ByteOffset.QuadPart = tableEntry->TargetOffset;
  3654. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  3655. nextSp->MajorFunction = IRP_MJ_READ;
  3656. nextSp->DeviceObject = tableEntry->TargetObject;
  3657. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3658. IoSetCompletionRoutine(irp, VspWriteVolumePhase15, tableEntry, TRUE,
  3659. TRUE, TRUE);
  3660. IoCallDriver(nextSp->DeviceObject, irp);
  3661. }
  3662. VOID
  3663. VspWriteVolumePhase1(
  3664. IN PVOID TableEntry
  3665. )
  3666. /*++
  3667. Routine Description:
  3668. This routine is the first phase of copying volume data to the diff
  3669. area file. An irp and buffer are created for the initial read of
  3670. the block.
  3671. Arguments:
  3672. Context - Supplies the context.
  3673. Return Value:
  3674. None.
  3675. --*/
  3676. {
  3677. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  3678. PVOLUME_EXTENSION extension = tableEntry->Extension;
  3679. PFILTER_EXTENSION filter = extension->Filter;
  3680. PIRP irp = tableEntry->CopyIrp;
  3681. PIO_STACK_LOCATION nextSp;
  3682. irp->Flags &= ~(IRP_HIGH_PRIORITY_PAGING_IO | IRP_PAGING_IO);
  3683. irp->Flags |= (tableEntry->WriteIrp->Flags&
  3684. (IRP_HIGH_PRIORITY_PAGING_IO | IRP_PAGING_IO));
  3685. if (extension->IsDetected && !extension->OkToGrowDiffArea &&
  3686. !extension->NoDiffAreaFill) {
  3687. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase12,
  3688. tableEntry);
  3689. VspAcquireNonPagedResource(extension, &tableEntry->WorkItem, FALSE);
  3690. return;
  3691. }
  3692. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  3693. nextSp = IoGetNextIrpStackLocation(irp);
  3694. nextSp->Parameters.Read.ByteOffset.QuadPart = tableEntry->VolumeOffset;
  3695. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  3696. nextSp->MajorFunction = IRP_MJ_READ;
  3697. nextSp->DeviceObject = filter->TargetObject;
  3698. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  3699. if (tableEntry->VolumeOffset + BLOCK_SIZE > extension->VolumeSize) {
  3700. if (extension->VolumeSize > tableEntry->VolumeOffset) {
  3701. nextSp->Parameters.Read.Length = (ULONG)
  3702. (extension->VolumeSize - tableEntry->VolumeOffset);
  3703. }
  3704. }
  3705. IoSetCompletionRoutine(irp, VspWriteVolumePhase2, tableEntry, TRUE, TRUE,
  3706. TRUE);
  3707. IoCallDriver(nextSp->DeviceObject, irp);
  3708. }
  3709. VOID
  3710. VspUnmapNextDiffAreaFileMap(
  3711. IN PVOID Context
  3712. )
  3713. {
  3714. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  3715. PVOLUME_EXTENSION extension = context->Extension.Extension;
  3716. NTSTATUS status;
  3717. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  3718. VspFreeContext(extension->Root, context);
  3719. if (extension->NextDiffAreaFileMap) {
  3720. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  3721. extension->NextDiffAreaFileMap);
  3722. ASSERT(NT_SUCCESS(status));
  3723. extension->NextDiffAreaFileMap = NULL;
  3724. }
  3725. VspReleasePagedResource(extension);
  3726. ObDereferenceObject(extension->Filter->DeviceObject);
  3727. ObDereferenceObject(extension->DeviceObject);
  3728. }
  3729. NTSTATUS
  3730. VspTruncatePreviousDiffArea(
  3731. IN PVOLUME_EXTENSION Extension
  3732. )
  3733. /*++
  3734. Routine Description:
  3735. This routine takes the snapshot that occurred before this one and
  3736. truncates its diff area file to the current used size since diff
  3737. area files can't grow after a new snapshot is added on top.
  3738. Arguments:
  3739. Extension - Supplies the volume extension.
  3740. Return Value:
  3741. NTSTATUS
  3742. --*/
  3743. {
  3744. PFILTER_EXTENSION filter = Extension->Filter;
  3745. PLIST_ENTRY l, ll;
  3746. PVOLUME_EXTENSION extension;
  3747. PVSP_DIFF_AREA_FILE diffAreaFile;
  3748. NTSTATUS status;
  3749. LONGLONG diff;
  3750. KIRQL irql;
  3751. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  3752. PVSP_CONTEXT context;
  3753. l = Extension->ListEntry.Blink;
  3754. if (l == &filter->VolumeList) {
  3755. return STATUS_SUCCESS;
  3756. }
  3757. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  3758. diffAreaFile = extension->DiffAreaFile;
  3759. ASSERT(diffAreaFile);
  3760. status = VspSetFileSize(diffAreaFile->FileHandle,
  3761. diffAreaFile->NextAvailable);
  3762. VspAcquireNonPagedResource(extension, NULL, FALSE);
  3763. if (NT_SUCCESS(status)) {
  3764. diff = diffAreaFile->AllocatedFileSize - diffAreaFile->NextAvailable;
  3765. diffAreaFile->AllocatedFileSize -= diff;
  3766. KeAcquireSpinLock(&filter->SpinLock, &irql);
  3767. filter->AllocatedVolumeSpace -= diff;
  3768. KeReleaseSpinLock(&filter->SpinLock, irql);
  3769. }
  3770. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  3771. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  3772. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  3773. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  3774. ExFreePool(diffAreaFileAllocation);
  3775. }
  3776. if (diffAreaFile->TableUpdateIrp) {
  3777. ExFreePool(MmGetMdlVirtualAddress(
  3778. diffAreaFile->TableUpdateIrp->MdlAddress));
  3779. IoFreeMdl(diffAreaFile->TableUpdateIrp->MdlAddress);
  3780. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  3781. diffAreaFile->TableUpdateIrp = NULL;
  3782. }
  3783. VspReleaseNonPagedResource(extension);
  3784. if (extension->EmergencyCopyIrp) {
  3785. ExFreePool(MmGetMdlVirtualAddress(
  3786. extension->EmergencyCopyIrp->MdlAddress));
  3787. IoFreeMdl(extension->EmergencyCopyIrp->MdlAddress);
  3788. IoFreeIrp(extension->EmergencyCopyIrp);
  3789. extension->EmergencyCopyIrp = NULL;
  3790. }
  3791. context = VspAllocateContext(Extension->Root);
  3792. if (context) {
  3793. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  3794. context->Extension.Extension = extension;
  3795. ExInitializeWorkItem(&context->WorkItem, VspUnmapNextDiffAreaFileMap,
  3796. context);
  3797. ObReferenceObject(extension->DeviceObject);
  3798. ObReferenceObject(extension->Filter->DeviceObject);
  3799. VspAcquirePagedResource(extension, &context->WorkItem);
  3800. }
  3801. if (extension->IgnoreCopyDataReference) {
  3802. extension->IgnoreCopyDataReference = FALSE;
  3803. InterlockedDecrement(&filter->IgnoreCopyData);
  3804. }
  3805. return STATUS_SUCCESS;
  3806. }
  3807. VOID
  3808. VspOrBitmaps(
  3809. IN OUT PRTL_BITMAP BaseBitmap,
  3810. IN PRTL_BITMAP FactorBitmap
  3811. )
  3812. {
  3813. ULONG n, i;
  3814. PULONG p, q;
  3815. n = (BaseBitmap->SizeOfBitMap + 8*sizeof(ULONG) - 1)/(8*sizeof(ULONG));
  3816. p = BaseBitmap->Buffer;
  3817. q = FactorBitmap->Buffer;
  3818. for (i = 0; i < n; i++) {
  3819. *p++ |= *q++;
  3820. }
  3821. }
  3822. NTSTATUS
  3823. VspQueryFileOffset(
  3824. IN PLIST_ENTRY ExtentList,
  3825. IN LONGLONG VolumeOffset,
  3826. IN PDIFF_AREA_FILE_ALLOCATION StartFileAllocation,
  3827. IN LONGLONG StartFileAllocationFileOffset,
  3828. OUT PLONGLONG ResultFileOffset,
  3829. OUT PDIFF_AREA_FILE_ALLOCATION* ResultFileAllocation,
  3830. OUT PLONGLONG ResultFileAllocationFileOffset,
  3831. OUT PLONGLONG Length
  3832. )
  3833. {
  3834. PLIST_ENTRY l, start;
  3835. LONGLONG fileOffset, delta;
  3836. PDIFF_AREA_FILE_ALLOCATION diffAreaAllocation;
  3837. ASSERT(!IsListEmpty(ExtentList));
  3838. if (!StartFileAllocation) {
  3839. StartFileAllocation = CONTAINING_RECORD(ExtentList->Flink,
  3840. DIFF_AREA_FILE_ALLOCATION,
  3841. ListEntry);
  3842. StartFileAllocationFileOffset = 0;
  3843. }
  3844. ASSERT(&StartFileAllocation->ListEntry != ExtentList);
  3845. start = &StartFileAllocation->ListEntry;
  3846. l = start;
  3847. fileOffset = StartFileAllocationFileOffset;
  3848. for (;;) {
  3849. diffAreaAllocation = CONTAINING_RECORD(l, DIFF_AREA_FILE_ALLOCATION,
  3850. ListEntry);
  3851. if (diffAreaAllocation->NLength <= 0) {
  3852. fileOffset -= diffAreaAllocation->NLength;
  3853. } else {
  3854. if (diffAreaAllocation->Offset <= VolumeOffset &&
  3855. diffAreaAllocation->Offset + diffAreaAllocation->NLength >
  3856. VolumeOffset) {
  3857. delta = VolumeOffset - diffAreaAllocation->Offset;
  3858. *ResultFileOffset = fileOffset + delta;
  3859. *ResultFileAllocation = diffAreaAllocation;
  3860. *ResultFileAllocationFileOffset = fileOffset;
  3861. if (Length) {
  3862. *Length = diffAreaAllocation->NLength - delta;
  3863. }
  3864. return STATUS_SUCCESS;
  3865. }
  3866. fileOffset += diffAreaAllocation->NLength;
  3867. }
  3868. l = l->Flink;
  3869. if (l == ExtentList) {
  3870. fileOffset = 0;
  3871. l = l->Flink;
  3872. }
  3873. if (l == start) {
  3874. break;
  3875. }
  3876. }
  3877. return STATUS_INVALID_PARAMETER;
  3878. }
  3879. NTSTATUS
  3880. VspCheckBlockChainFileOffsets(
  3881. IN PFILTER_EXTENSION Filter,
  3882. IN LONGLONG StartingVolumeOffset,
  3883. IN PLIST_ENTRY ExtentList
  3884. )
  3885. {
  3886. PVSP_BLOCK_HEADER blockHeader;
  3887. LONGLONG volumeOffset, fileOffset;
  3888. NTSTATUS status;
  3889. PDIFF_AREA_FILE_ALLOCATION startFileAllocation, resultFileAllocation;
  3890. LONGLONG startFileAllocationFileOffset;
  3891. LONGLONG resultFileAllocationFileOffset;
  3892. if (IsListEmpty(ExtentList) || !StartingVolumeOffset) {
  3893. return STATUS_FILE_CORRUPT_ERROR;
  3894. }
  3895. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  3896. if (!Filter->SnapshotOnDiskIrp) {
  3897. VspReleaseNonPagedResource(Filter);
  3898. return STATUS_INVALID_PARAMETER;
  3899. }
  3900. blockHeader = (PVSP_BLOCK_HEADER) MmGetMdlVirtualAddress(
  3901. Filter->SnapshotOnDiskIrp->MdlAddress);
  3902. volumeOffset = StartingVolumeOffset;
  3903. startFileAllocation = NULL;
  3904. startFileAllocationFileOffset = 0;
  3905. while (volumeOffset) {
  3906. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  3907. Filter->TargetObject, IRP_MJ_READ,
  3908. volumeOffset, 0);
  3909. if (!NT_SUCCESS(status)) {
  3910. VspReleaseNonPagedResource(Filter);
  3911. return status;
  3912. }
  3913. status = VspQueryFileOffset(ExtentList, volumeOffset,
  3914. startFileAllocation,
  3915. startFileAllocationFileOffset,
  3916. &fileOffset, &resultFileAllocation,
  3917. &resultFileAllocationFileOffset, NULL);
  3918. if (!NT_SUCCESS(status)) {
  3919. VspReleaseNonPagedResource(Filter);
  3920. return status;
  3921. }
  3922. if (fileOffset != blockHeader->ThisFileOffset) {
  3923. ASSERT(FALSE);
  3924. VspReleaseNonPagedResource(Filter);
  3925. return STATUS_FILE_CORRUPT_ERROR;
  3926. }
  3927. volumeOffset = blockHeader->NextVolumeOffset;
  3928. startFileAllocation = resultFileAllocation;
  3929. startFileAllocationFileOffset = resultFileAllocationFileOffset;
  3930. }
  3931. VspReleaseNonPagedResource(Filter);
  3932. return status;
  3933. }
  3934. NTSTATUS
  3935. VspCheckControlBlockFileLocation(
  3936. IN PFILTER_EXTENSION Filter
  3937. )
  3938. {
  3939. HANDLE h = Filter->ControlBlockFileHandle;
  3940. NTSTATUS status;
  3941. LIST_ENTRY extentList;
  3942. PLIST_ENTRY l;
  3943. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  3944. if (!h) {
  3945. return STATUS_INVALID_PARAMETER;
  3946. }
  3947. status = VspQueryListOfExtents(h, 0, &extentList, NULL, FALSE);
  3948. if (!NT_SUCCESS(status)) {
  3949. return status;
  3950. }
  3951. status = VspCheckBlockChainFileOffsets(Filter,
  3952. Filter->FirstControlBlockVolumeOffset, &extentList);
  3953. while (!IsListEmpty(&extentList)) {
  3954. l = RemoveHeadList(&extentList);
  3955. diffAreaFileAllocation = CONTAINING_RECORD(l,
  3956. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  3957. ExFreePool(diffAreaFileAllocation);
  3958. }
  3959. return status;
  3960. }
  3961. VOID
  3962. VspWaitForVolumesSafeForWriteAccess(
  3963. IN PDO_EXTENSION RootExtension
  3964. )
  3965. {
  3966. UNICODE_STRING volumeSafeEventName;
  3967. OBJECT_ATTRIBUTES oa;
  3968. KEVENT event;
  3969. LARGE_INTEGER timeout;
  3970. ULONG i;
  3971. NTSTATUS status;
  3972. HANDLE volumeSafeEvent;
  3973. if (RootExtension->IsSetup || RootExtension->VolumesSafeForWriteAccess) {
  3974. return;
  3975. }
  3976. RtlInitUnicodeString(&volumeSafeEventName,
  3977. L"\\Device\\VolumesSafeForWriteAccess");
  3978. InitializeObjectAttributes(&oa, &volumeSafeEventName,
  3979. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL,
  3980. NULL);
  3981. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3982. timeout.QuadPart = -10*1000*1000; // 1 second
  3983. for (i = 0; i < 1000; i++) {
  3984. status = ZwOpenEvent(&volumeSafeEvent, EVENT_ALL_ACCESS, &oa);
  3985. if (NT_SUCCESS(status)) {
  3986. break;
  3987. }
  3988. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
  3989. if (RootExtension->VolumesSafeForWriteAccess) {
  3990. return;
  3991. }
  3992. }
  3993. if (i == 1000) {
  3994. return;
  3995. }
  3996. for (;;) {
  3997. status = ZwWaitForSingleObject(volumeSafeEvent, FALSE, &timeout);
  3998. if (status != STATUS_TIMEOUT) {
  3999. InterlockedExchange(&RootExtension->VolumesSafeForWriteAccess,
  4000. TRUE);
  4001. break;
  4002. }
  4003. if (RootExtension->VolumesSafeForWriteAccess) {
  4004. break;
  4005. }
  4006. }
  4007. ZwClose(volumeSafeEvent);
  4008. }
  4009. NTSTATUS
  4010. VspOpenControlBlockFile(
  4011. IN PFILTER_EXTENSION Filter
  4012. )
  4013. {
  4014. PFILTER_EXTENSION filter = Filter;
  4015. NTSTATUS status;
  4016. UNICODE_STRING fileName;
  4017. PWCHAR star;
  4018. OBJECT_ATTRIBUTES oa;
  4019. HANDLE h;
  4020. IO_STATUS_BLOCK ioStatus;
  4021. PLIST_ENTRY l;
  4022. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  4023. GUID snapshotGuid;
  4024. ULONG i;
  4025. LARGE_INTEGER timeout;
  4026. KEVENT event;
  4027. if (filter->ControlBlockFileHandle) {
  4028. return STATUS_SUCCESS;
  4029. }
  4030. VspWaitForVolumesSafeForWriteAccess(filter->Root);
  4031. KeWaitForSingleObject(&filter->ControlBlockFileHandleSemaphore,
  4032. Executive, KernelMode, FALSE, NULL);
  4033. if (filter->ControlBlockFileHandle) {
  4034. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4035. IO_NO_INCREMENT, 1, FALSE);
  4036. return STATUS_SUCCESS;
  4037. }
  4038. VspAcquireNonPagedResource(filter, NULL, FALSE);
  4039. VspCreateStartBlock(filter, filter->FirstControlBlockVolumeOffset,
  4040. filter->MaximumVolumeSpace);
  4041. VspReleaseNonPagedResource(filter);
  4042. status = VspCreateDiffAreaFileName(filter->TargetObject, NULL,
  4043. &fileName, FALSE, NULL);
  4044. if (!NT_SUCCESS(status)) {
  4045. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4046. IO_NO_INCREMENT, 1, FALSE);
  4047. return status;
  4048. }
  4049. star = fileName.Buffer + fileName.Length/sizeof(WCHAR) - 39;
  4050. RtlMoveMemory(star, star + 1, 38*sizeof(WCHAR));
  4051. fileName.Length -= sizeof(WCHAR);
  4052. fileName.Buffer[fileName.Length/sizeof(WCHAR)] = 0;
  4053. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  4054. OBJ_KERNEL_HANDLE, NULL, NULL);
  4055. KeInitializeEvent(&event, NotificationEvent, FALSE);
  4056. timeout.QuadPart = -10*1000; // 1 millisecond.
  4057. for (i = 0; i < 5000; i++) {
  4058. status = ZwOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &oa,
  4059. &ioStatus, 0, FILE_WRITE_THROUGH |
  4060. FILE_SYNCHRONOUS_IO_NONALERT |
  4061. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  4062. FILE_NO_COMPRESSION);
  4063. if (NT_SUCCESS(status)) {
  4064. break;
  4065. }
  4066. // Wait for RAW to DISMOUNT or for the DISMOUNT handle to close.
  4067. if (status != STATUS_INVALID_PARAMETER &&
  4068. status != STATUS_ACCESS_DENIED) {
  4069. break;
  4070. }
  4071. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  4072. &timeout);
  4073. }
  4074. ExFreePool(fileName.Buffer);
  4075. if (!NT_SUCCESS(status)) {
  4076. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4077. IO_NO_INCREMENT, 1, FALSE);
  4078. return status;
  4079. }
  4080. ASSERT(!filter->ControlBlockFileHandle);
  4081. InterlockedExchangePointer(&filter->ControlBlockFileHandle, h);
  4082. VspAcquire(filter->Root);
  4083. if (filter->IsRemoved) {
  4084. VspRelease(filter->Root);
  4085. h = InterlockedExchangePointer(&filter->ControlBlockFileHandle,
  4086. NULL);
  4087. if (h) {
  4088. ZwClose(h);
  4089. }
  4090. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4091. IO_NO_INCREMENT, 1, FALSE);
  4092. return STATUS_UNSUCCESSFUL;
  4093. }
  4094. VspRelease(filter->Root);
  4095. status = VspPinFile(filter->TargetObject, h);
  4096. if (!NT_SUCCESS(status)) {
  4097. h = InterlockedExchangePointer(&filter->ControlBlockFileHandle,
  4098. NULL);
  4099. if (h) {
  4100. ZwClose(h);
  4101. }
  4102. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4103. IO_NO_INCREMENT, 1, FALSE);
  4104. return status;
  4105. }
  4106. status = VspCheckControlBlockFileLocation(filter);
  4107. if (!NT_SUCCESS(status)) {
  4108. h = InterlockedExchangePointer(&filter->ControlBlockFileHandle,
  4109. NULL);
  4110. if (h) {
  4111. ZwClose(h);
  4112. }
  4113. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4114. IO_NO_INCREMENT, 1, FALSE);
  4115. return status;
  4116. }
  4117. VspAcquireNonPagedResource(filter, NULL, FALSE);
  4118. if (!filter->FirstControlBlockVolumeOffset) {
  4119. h = InterlockedExchangePointer(&filter->ControlBlockFileHandle,
  4120. NULL);
  4121. VspReleaseNonPagedResource(filter);
  4122. if (h) {
  4123. ZwClose(h);
  4124. }
  4125. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4126. IO_NO_INCREMENT, 1, FALSE);
  4127. return STATUS_UNSUCCESSFUL;
  4128. }
  4129. VspReleaseNonPagedResource(filter);
  4130. KeReleaseSemaphore(&filter->ControlBlockFileHandleSemaphore,
  4131. IO_NO_INCREMENT, 1, FALSE);
  4132. return STATUS_SUCCESS;
  4133. }
  4134. VOID
  4135. VspOpenControlBlockFileWorker(
  4136. IN PVOID Context
  4137. )
  4138. {
  4139. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4140. PFILTER_EXTENSION filter = context->Filter.Filter;
  4141. NTSTATUS status;
  4142. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  4143. KeWaitForSingleObject(&filter->Root->PastBootReinit, Executive,
  4144. KernelMode, FALSE, NULL);
  4145. status = VspOpenControlBlockFile(filter);
  4146. if (!NT_SUCCESS(status)) {
  4147. VspAcquireNonPagedResource(filter, NULL, FALSE);
  4148. VspCreateStartBlock(filter, 0, filter->MaximumVolumeSpace);
  4149. filter->FirstControlBlockVolumeOffset = 0;
  4150. VspReleaseNonPagedResource(filter);
  4151. }
  4152. VspFreeContext(filter->Root, context);
  4153. ObDereferenceObject(filter->TargetObject);
  4154. ObDereferenceObject(filter->DeviceObject);
  4155. }
  4156. NTSTATUS
  4157. VspCheckDiffAreaFileLocation(
  4158. IN PFILTER_EXTENSION Filter,
  4159. IN HANDLE FileHandle,
  4160. IN LONGLONG ApplicationInfoOffset,
  4161. IN LONGLONG FirstDiffAreaBlockOffset,
  4162. IN LONGLONG LocationOffset,
  4163. IN LONGLONG InitialBitmapOffset,
  4164. IN BOOLEAN CheckUnused
  4165. )
  4166. {
  4167. NTSTATUS status;
  4168. LIST_ENTRY extentList;
  4169. PLIST_ENTRY l;
  4170. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  4171. PVSP_BLOCK_HEADER blockHeader;
  4172. LONGLONG volumeOffset, fileOffset;
  4173. PDIFF_AREA_FILE_ALLOCATION startFileAllocation, resultFileAllocation;
  4174. LONGLONG startFileAllocationFileOffset;
  4175. LONGLONG resultFileAllocationFileOffset;
  4176. PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY diffAreaTableEntry;
  4177. ULONG blockOffset;
  4178. PVSP_DIFF_AREA_LOCATION_DESCRIPTOR locationDescriptor;
  4179. LONGLONG length;
  4180. if (!FileHandle) {
  4181. return STATUS_INVALID_PARAMETER;
  4182. }
  4183. status = VspQueryListOfExtents(FileHandle, 0, &extentList, NULL, FALSE);
  4184. if (!NT_SUCCESS(status)) {
  4185. ASSERT(FALSE);
  4186. return status;
  4187. }
  4188. status = VspCheckBlockChainFileOffsets(Filter, ApplicationInfoOffset,
  4189. &extentList);
  4190. if (!NT_SUCCESS(status)) {
  4191. goto Finish;
  4192. }
  4193. status = VspCheckBlockChainFileOffsets(Filter, FirstDiffAreaBlockOffset,
  4194. &extentList);
  4195. if (!NT_SUCCESS(status)) {
  4196. goto Finish;
  4197. }
  4198. status = VspCheckBlockChainFileOffsets(Filter, LocationOffset,
  4199. &extentList);
  4200. if (!NT_SUCCESS(status)) {
  4201. goto Finish;
  4202. }
  4203. if (InitialBitmapOffset) {
  4204. status = VspCheckBlockChainFileOffsets(Filter, InitialBitmapOffset,
  4205. &extentList);
  4206. if (!NT_SUCCESS(status)) {
  4207. goto Finish;
  4208. }
  4209. }
  4210. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  4211. if (!Filter->SnapshotOnDiskIrp) {
  4212. VspReleaseNonPagedResource(Filter);
  4213. status = STATUS_INVALID_PARAMETER;
  4214. goto Finish;
  4215. }
  4216. blockHeader = (PVSP_BLOCK_HEADER) MmGetMdlVirtualAddress(
  4217. Filter->SnapshotOnDiskIrp->MdlAddress);
  4218. volumeOffset = FirstDiffAreaBlockOffset;
  4219. startFileAllocation = NULL;
  4220. startFileAllocationFileOffset = 0;
  4221. while (volumeOffset) {
  4222. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  4223. Filter->TargetObject, IRP_MJ_READ,
  4224. volumeOffset, 0);
  4225. if (!NT_SUCCESS(status)) {
  4226. VspReleaseNonPagedResource(Filter);
  4227. goto Finish;
  4228. }
  4229. for (blockOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  4230. blockOffset + sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY) <=
  4231. BLOCK_SIZE;
  4232. blockOffset += sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY)) {
  4233. diffAreaTableEntry = (PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY)
  4234. ((PCHAR) blockHeader + blockOffset);
  4235. if (!diffAreaTableEntry->DiffAreaVolumeOffset) {
  4236. continue;
  4237. }
  4238. status = VspQueryFileOffset(
  4239. &extentList, diffAreaTableEntry->DiffAreaVolumeOffset,
  4240. startFileAllocation, startFileAllocationFileOffset,
  4241. &fileOffset, &resultFileAllocation,
  4242. &resultFileAllocationFileOffset, NULL);
  4243. if (!NT_SUCCESS(status)) {
  4244. VspReleaseNonPagedResource(Filter);
  4245. goto Finish;
  4246. }
  4247. if (fileOffset != diffAreaTableEntry->DiffAreaFileOffset) {
  4248. status = STATUS_FILE_CORRUPT_ERROR;
  4249. ASSERT(FALSE);
  4250. VspReleaseNonPagedResource(Filter);
  4251. goto Finish;
  4252. }
  4253. startFileAllocation = resultFileAllocation;
  4254. startFileAllocationFileOffset =
  4255. resultFileAllocationFileOffset;
  4256. }
  4257. volumeOffset = blockHeader->NextVolumeOffset;
  4258. }
  4259. if (!CheckUnused) {
  4260. VspReleaseNonPagedResource(Filter);
  4261. goto Finish;
  4262. }
  4263. blockHeader = (PVSP_BLOCK_HEADER) MmGetMdlVirtualAddress(
  4264. Filter->SnapshotOnDiskIrp->MdlAddress);
  4265. volumeOffset = LocationOffset;
  4266. startFileAllocation = NULL;
  4267. startFileAllocationFileOffset = 0;
  4268. while (volumeOffset) {
  4269. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  4270. Filter->TargetObject, IRP_MJ_READ,
  4271. volumeOffset, 0);
  4272. if (!NT_SUCCESS(status)) {
  4273. VspReleaseNonPagedResource(Filter);
  4274. goto Finish;
  4275. }
  4276. for (blockOffset = VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR;
  4277. blockOffset + sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR) <=
  4278. BLOCK_SIZE;
  4279. blockOffset += sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR)) {
  4280. locationDescriptor = (PVSP_DIFF_AREA_LOCATION_DESCRIPTOR)
  4281. ((PCHAR) blockHeader + blockOffset);
  4282. if (!locationDescriptor->VolumeOffset) {
  4283. continue;
  4284. }
  4285. status = VspQueryFileOffset(
  4286. &extentList, locationDescriptor->VolumeOffset,
  4287. startFileAllocation, startFileAllocationFileOffset,
  4288. &fileOffset, &resultFileAllocation,
  4289. &resultFileAllocationFileOffset, &length);
  4290. if (!NT_SUCCESS(status)) {
  4291. VspReleaseNonPagedResource(Filter);
  4292. goto Finish;
  4293. }
  4294. if (fileOffset != locationDescriptor->FileOffset ||
  4295. length < locationDescriptor->Length) {
  4296. status = STATUS_FILE_CORRUPT_ERROR;
  4297. ASSERT(FALSE);
  4298. VspReleaseNonPagedResource(Filter);
  4299. goto Finish;
  4300. }
  4301. startFileAllocation = resultFileAllocation;
  4302. startFileAllocationFileOffset =
  4303. resultFileAllocationFileOffset;
  4304. }
  4305. volumeOffset = blockHeader->NextVolumeOffset;
  4306. }
  4307. VspReleaseNonPagedResource(Filter);
  4308. Finish:
  4309. while (!IsListEmpty(&extentList)) {
  4310. l = RemoveHeadList(&extentList);
  4311. diffAreaFileAllocation = CONTAINING_RECORD(l,
  4312. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  4313. ExFreePool(diffAreaFileAllocation);
  4314. }
  4315. return status;
  4316. }
  4317. NTSTATUS
  4318. VspOpenFilesAndValidateSnapshots(
  4319. IN PFILTER_EXTENSION Filter
  4320. )
  4321. {
  4322. NTSTATUS status;
  4323. PLIST_ENTRY l;
  4324. UNICODE_STRING fileName;
  4325. OBJECT_ATTRIBUTES oa;
  4326. HANDLE h;
  4327. IO_STATUS_BLOCK ioStatus;
  4328. PVOLUME_EXTENSION extension;
  4329. PFILTER_EXTENSION diffAreaFilter;
  4330. LONGLONG appInfoOffset, firstDiffAreaBlockOffset, locationOffset, initialBitmapOffset;
  4331. BOOLEAN checkUnused;
  4332. ULONG i;
  4333. LARGE_INTEGER timeout;
  4334. KEVENT event;
  4335. status = VspOpenControlBlockFile(Filter);
  4336. if (!NT_SUCCESS(status)) {
  4337. VspLogError(NULL, Filter, VS_FAILURE_TO_OPEN_CRITICAL_FILE,
  4338. status, 1, FALSE);
  4339. return status;
  4340. }
  4341. status = STATUS_SUCCESS;
  4342. for (;;) {
  4343. VspAcquire(Filter->Root);
  4344. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  4345. l = l->Flink) {
  4346. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  4347. if (extension->DiffAreaFile &&
  4348. !extension->DiffAreaFile->FileHandle) {
  4349. break;
  4350. }
  4351. }
  4352. if (l == &Filter->VolumeList) {
  4353. VspRelease(Filter->Root);
  4354. break;
  4355. }
  4356. diffAreaFilter = extension->DiffAreaFile->Filter;
  4357. appInfoOffset = extension->DiffAreaFile->ApplicationInfoTargetOffset;
  4358. locationOffset =
  4359. extension->DiffAreaFile->DiffAreaLocationDescriptionTargetOffset;
  4360. firstDiffAreaBlockOffset =
  4361. extension->DiffAreaFile->FirstTableTargetOffset;
  4362. initialBitmapOffset =
  4363. extension->DiffAreaFile->InitialBitmapVolumeOffset;
  4364. ObReferenceObject(extension->DeviceObject);
  4365. ObReferenceObject(diffAreaFilter->DeviceObject);
  4366. ObReferenceObject(diffAreaFilter->TargetObject);
  4367. VspRelease(Filter->Root);
  4368. status = VspCreateDiffAreaFileName(
  4369. diffAreaFilter->TargetObject, extension, &fileName, FALSE,
  4370. NULL);
  4371. if (!NT_SUCCESS(status)) {
  4372. VspLogError(NULL, Filter, VS_FAILURE_TO_OPEN_CRITICAL_FILE,
  4373. status, 2, FALSE);
  4374. ObDereferenceObject(diffAreaFilter->TargetObject);
  4375. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4376. ObDereferenceObject(extension->DeviceObject);
  4377. break;
  4378. }
  4379. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  4380. OBJ_KERNEL_HANDLE, NULL, NULL);
  4381. KeInitializeEvent(&event, NotificationEvent, FALSE);
  4382. timeout.QuadPart = -10*1000; // 1 millisecond.
  4383. for (i = 0; i < 5000; i++) {
  4384. status = ZwOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &oa,
  4385. &ioStatus, 0, FILE_WRITE_THROUGH |
  4386. FILE_SYNCHRONOUS_IO_NONALERT |
  4387. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  4388. FILE_NO_COMPRESSION);
  4389. if (NT_SUCCESS(status)) {
  4390. break;
  4391. }
  4392. if (status != STATUS_ACCESS_DENIED &&
  4393. status != STATUS_INVALID_PARAMETER) {
  4394. break;
  4395. }
  4396. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  4397. &timeout);
  4398. }
  4399. ExFreePool(fileName.Buffer);
  4400. if (!NT_SUCCESS(status)) {
  4401. VspLogError(NULL, Filter, VS_FAILURE_TO_OPEN_CRITICAL_FILE,
  4402. status, 3, FALSE);
  4403. ObDereferenceObject(diffAreaFilter->TargetObject);
  4404. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4405. ObDereferenceObject(extension->DeviceObject);
  4406. break;
  4407. }
  4408. status = VspPinFile(diffAreaFilter->TargetObject, h);
  4409. if (!NT_SUCCESS(status)) {
  4410. VspLogError(NULL, Filter, VS_FAILURE_TO_OPEN_CRITICAL_FILE,
  4411. status, 4, FALSE);
  4412. ZwClose(h);
  4413. ObDereferenceObject(diffAreaFilter->TargetObject);
  4414. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4415. ObDereferenceObject(extension->DeviceObject);
  4416. break;
  4417. }
  4418. if (extension->ListEntry.Flink == &Filter->VolumeList) {
  4419. checkUnused = TRUE;
  4420. } else {
  4421. checkUnused = FALSE;
  4422. }
  4423. status = VspCheckDiffAreaFileLocation(diffAreaFilter, h,
  4424. appInfoOffset,
  4425. firstDiffAreaBlockOffset,
  4426. locationOffset,
  4427. initialBitmapOffset,
  4428. checkUnused);
  4429. if (!NT_SUCCESS(status)) {
  4430. VspLogError(NULL, Filter, VS_FAILURE_TO_OPEN_CRITICAL_FILE,
  4431. status, 5, FALSE);
  4432. ZwClose(h);
  4433. ObDereferenceObject(diffAreaFilter->TargetObject);
  4434. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4435. ObDereferenceObject(extension->DeviceObject);
  4436. break;
  4437. }
  4438. VspAcquire(Filter->Root);
  4439. if (extension->IsDead || !extension->DiffAreaFile) {
  4440. VspRelease(Filter->Root);
  4441. ZwClose(h);
  4442. ObDereferenceObject(diffAreaFilter->TargetObject);
  4443. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4444. ObDereferenceObject(extension->DeviceObject);
  4445. continue;
  4446. }
  4447. ASSERT(!extension->DiffAreaFile->FileHandle);
  4448. extension->DiffAreaFile->FileHandle = h;
  4449. VspRelease(Filter->Root);
  4450. ObDereferenceObject(diffAreaFilter->TargetObject);
  4451. ObDereferenceObject(diffAreaFilter->DeviceObject);
  4452. ObDereferenceObject(extension->DeviceObject);
  4453. }
  4454. return status;
  4455. }
  4456. VOID
  4457. VspCallDriver(
  4458. IN PVOID Context
  4459. )
  4460. {
  4461. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4462. ASSERT(context->Type == VSP_CONTEXT_TYPE_COPY_EXTENTS);
  4463. IoCallDriver(context->CopyExtents.Extension->Filter->DeviceObject,
  4464. context->CopyExtents.Irp);
  4465. }
  4466. DECLSPEC_NOINLINE
  4467. VOID
  4468. VspClearDirtyCrashdumpFlag(
  4469. IN PVSP_CONTROL_ITEM_SNAPSHOT SnapshotControlItem
  4470. )
  4471. {
  4472. SnapshotControlItem->SnapshotControlItemFlags &=
  4473. ~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_CRASHDUMP;
  4474. }
  4475. VOID
  4476. VspMarkCrashdumpClean(
  4477. IN PVOID Context
  4478. )
  4479. {
  4480. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4481. PVOLUME_EXTENSION extension = context->CopyExtents.Extension;
  4482. PFILTER_EXTENSION filter = extension->Filter;
  4483. BOOLEAN hiberfile = context->CopyExtents.HiberfileIncluded;
  4484. BOOLEAN pagefile = context->CopyExtents.PagefileIncluded;
  4485. UCHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  4486. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem;
  4487. NTSTATUS status;
  4488. LONG hibernate;
  4489. ASSERT(context->Type == VSP_CONTEXT_TYPE_COPY_EXTENTS);
  4490. VspFreeContext(filter->Root, context);
  4491. VspAcquire(filter->Root);
  4492. if (IsListEmpty(&filter->VolumeList)) {
  4493. VspRelease(filter->Root);
  4494. if (hiberfile) {
  4495. InterlockedExchange(&filter->HibernatePending, FALSE);
  4496. }
  4497. ObDereferenceObject(filter->DeviceObject);
  4498. ObDereferenceObject(extension->DeviceObject);
  4499. return;
  4500. }
  4501. if (!extension->IsPersistent) {
  4502. VspRelease(filter->Root);
  4503. ASSERT(!pagefile);
  4504. if (hiberfile) {
  4505. InterlockedExchange(&extension->HiberFileCopied, TRUE);
  4506. hibernate = InterlockedExchange(&filter->HibernatePending, FALSE);
  4507. if (hibernate) {
  4508. IoRaiseInformationalHardError(STATUS_VOLSNAP_HIBERNATE_READY,
  4509. NULL, NULL);
  4510. }
  4511. }
  4512. ObDereferenceObject(filter->DeviceObject);
  4513. ObDereferenceObject(extension->DeviceObject);
  4514. return;
  4515. }
  4516. VspAcquireNonPagedResource(filter, NULL, FALSE);
  4517. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  4518. &extension->SnapshotGuid, FALSE,
  4519. controlItemBuffer, FALSE);
  4520. if (!NT_SUCCESS(status)) {
  4521. if (!filter->DestroyAllSnapshotsPending) {
  4522. VspLogError(extension, filter, VS_ABORT_SNAPSHOTS_IO_FAILURE,
  4523. status, 14, FALSE);
  4524. }
  4525. VspReleaseNonPagedResource(filter);
  4526. VspRelease(filter->Root);
  4527. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  4528. if (hiberfile) {
  4529. InterlockedExchange(&filter->HibernatePending, FALSE);
  4530. }
  4531. ObDereferenceObject(filter->DeviceObject);
  4532. ObDereferenceObject(extension->DeviceObject);
  4533. return;
  4534. }
  4535. snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  4536. if (hiberfile) {
  4537. snapshotControlItem->SnapshotControlItemFlags |=
  4538. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_HIBERFIL_COPIED;
  4539. InterlockedExchange(&extension->HiberFileCopied, TRUE);
  4540. }
  4541. if (pagefile) {
  4542. VspClearDirtyCrashdumpFlag(snapshotControlItem);
  4543. snapshotControlItem->SnapshotControlItemFlags |=
  4544. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_PAGEFILE_COPIED;
  4545. InterlockedExchange(&extension->PageFileCopied, TRUE);
  4546. }
  4547. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  4548. &extension->SnapshotGuid, TRUE,
  4549. controlItemBuffer, FALSE);
  4550. if (!NT_SUCCESS(status)) {
  4551. if (!filter->DestroyAllSnapshotsPending) {
  4552. VspLogError(extension, filter, VS_ABORT_SNAPSHOTS_IO_FAILURE,
  4553. status, 15, FALSE);
  4554. }
  4555. VspReleaseNonPagedResource(filter);
  4556. VspRelease(filter->Root);
  4557. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  4558. if (hiberfile) {
  4559. InterlockedExchange(&filter->HibernatePending, FALSE);
  4560. }
  4561. ObDereferenceObject(filter->DeviceObject);
  4562. ObDereferenceObject(extension->DeviceObject);
  4563. return;
  4564. }
  4565. VspReleaseNonPagedResource(filter);
  4566. VspRelease(filter->Root);
  4567. if (hiberfile) {
  4568. hibernate = InterlockedExchange(&filter->HibernatePending, FALSE);
  4569. if (hibernate) {
  4570. IoRaiseInformationalHardError(STATUS_VOLSNAP_HIBERNATE_READY, NULL,
  4571. NULL);
  4572. }
  4573. }
  4574. ObDereferenceObject(filter->DeviceObject);
  4575. ObDereferenceObject(extension->DeviceObject);
  4576. }
  4577. NTSTATUS
  4578. VspCopyExtentsCompletionRoutine(
  4579. IN PDEVICE_OBJECT DeviceObject,
  4580. IN PIRP Irp,
  4581. IN PVOID Context
  4582. )
  4583. {
  4584. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4585. PVOLUME_EXTENSION extension = context->CopyExtents.Extension;
  4586. PFILTER_EXTENSION filter = extension->Filter;
  4587. PIO_STACK_LOCATION nextSp;
  4588. PDIFF_AREA_FILE_ALLOCATION fileExtent;
  4589. LONGLONG offset;
  4590. ULONG length;
  4591. ASSERT(context->Type == VSP_CONTEXT_TYPE_COPY_EXTENTS);
  4592. ASSERT(!IsListEmpty(&context->CopyExtents.ExtentList));
  4593. fileExtent = CONTAINING_RECORD(context->CopyExtents.ExtentList.Flink,
  4594. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  4595. ASSERT(fileExtent->NLength >= 0);
  4596. if (!fileExtent->NLength) {
  4597. RemoveEntryList(&fileExtent->ListEntry);
  4598. ExFreePool(fileExtent);
  4599. if (IsListEmpty(&context->CopyExtents.ExtentList)) {
  4600. ExInitializeWorkItem(&context->WorkItem, VspMarkCrashdumpClean,
  4601. context);
  4602. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  4603. IoFreeIrp(Irp);
  4604. return STATUS_MORE_PROCESSING_REQUIRED;
  4605. }
  4606. fileExtent = CONTAINING_RECORD(context->CopyExtents.ExtentList.Flink,
  4607. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  4608. ASSERT(fileExtent->NLength > 0);
  4609. }
  4610. length = 0x80000; // 512 KB
  4611. offset = fileExtent->Offset;
  4612. if (length > fileExtent->NLength) {
  4613. length = (ULONG) fileExtent->NLength;
  4614. }
  4615. fileExtent->Offset += length;
  4616. fileExtent->NLength -= length;
  4617. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  4618. nextSp = IoGetNextIrpStackLocation(Irp);
  4619. nextSp->Parameters.Write.ByteOffset.QuadPart = offset;
  4620. nextSp->Parameters.Write.Length = length;
  4621. nextSp->MajorFunction = IRP_MJ_WRITE;
  4622. nextSp->DeviceObject = filter->DeviceObject;
  4623. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  4624. IoSetCompletionRoutine(Irp, VspCopyExtentsCompletionRoutine, context,
  4625. TRUE, TRUE, TRUE);
  4626. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  4627. return STATUS_MORE_PROCESSING_REQUIRED;
  4628. }
  4629. NTSTATUS
  4630. VspCopyExtents(
  4631. IN PVOLUME_EXTENSION Extension,
  4632. IN PLIST_ENTRY ExtentList,
  4633. IN BOOLEAN HiberfileIncluded,
  4634. IN BOOLEAN PagefileIncluded
  4635. )
  4636. {
  4637. PVSP_CONTEXT context;
  4638. PIRP irp;
  4639. PIO_STACK_LOCATION nextSp;
  4640. if (IsListEmpty(ExtentList)) {
  4641. if (HiberfileIncluded) {
  4642. InterlockedExchange(&Extension->Filter->HibernatePending, FALSE);
  4643. }
  4644. return STATUS_SUCCESS;
  4645. }
  4646. context = VspAllocateContext(Extension->Root);
  4647. if (!context) {
  4648. if (HiberfileIncluded) {
  4649. InterlockedExchange(&Extension->Filter->HibernatePending, FALSE);
  4650. }
  4651. return STATUS_INSUFFICIENT_RESOURCES;
  4652. }
  4653. irp = IoAllocateIrp((CCHAR) Extension->Root->StackSize, FALSE);
  4654. if (!irp) {
  4655. if (HiberfileIncluded) {
  4656. InterlockedExchange(&Extension->Filter->HibernatePending, FALSE);
  4657. }
  4658. VspFreeContext(Extension->Root, context);
  4659. return STATUS_INSUFFICIENT_RESOURCES;
  4660. }
  4661. irp->MdlAddress = NULL;
  4662. context->Type = VSP_CONTEXT_TYPE_COPY_EXTENTS;
  4663. ExInitializeWorkItem(&context->WorkItem, VspCallDriver, context);
  4664. context->CopyExtents.Extension = Extension;
  4665. context->CopyExtents.Irp = irp;
  4666. context->CopyExtents.ExtentList = *ExtentList;
  4667. context->CopyExtents.ExtentList.Flink->Blink =
  4668. &context->CopyExtents.ExtentList;
  4669. context->CopyExtents.ExtentList.Blink->Flink =
  4670. &context->CopyExtents.ExtentList;
  4671. context->CopyExtents.HiberfileIncluded = HiberfileIncluded;
  4672. context->CopyExtents.PagefileIncluded = PagefileIncluded;
  4673. ObReferenceObject(Extension->DeviceObject);
  4674. ObReferenceObject(Extension->Filter->DeviceObject);
  4675. VspCopyExtentsCompletionRoutine(NULL, irp, context);
  4676. return STATUS_SUCCESS;
  4677. }
  4678. VOID
  4679. VspSystemSid(
  4680. IN OUT SID* Sid
  4681. )
  4682. {
  4683. Sid->Revision = SID_REVISION;
  4684. Sid->SubAuthorityCount = 1;
  4685. Sid->IdentifierAuthority = ntAuthority;
  4686. Sid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
  4687. }
  4688. VOID
  4689. VspAdminSid(
  4690. IN OUT SID* Sid
  4691. )
  4692. {
  4693. Sid->Revision = SID_REVISION;
  4694. Sid->SubAuthorityCount = 2;
  4695. Sid->IdentifierAuthority = ntAuthority;
  4696. Sid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
  4697. Sid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
  4698. }
  4699. BOOLEAN
  4700. VspHasStrongAcl(
  4701. IN HANDLE Handle,
  4702. OUT PNTSTATUS Status
  4703. )
  4704. {
  4705. NTSTATUS status;
  4706. ULONG sdLength;
  4707. PSECURITY_DESCRIPTOR sd;
  4708. PSID sid;
  4709. BOOLEAN ownerDefaulted, daclPresent, daclDefaulted;
  4710. PACL acl;
  4711. ULONG i;
  4712. PACCESS_ALLOWED_ACE ace;
  4713. PSID systemSid;
  4714. UCHAR sidBuffer[2*sizeof(SID)];
  4715. PSID adminSid;
  4716. UCHAR sidBuffer2[2*sizeof(SID)];
  4717. ULONG priviledgedBits;
  4718. status = ZwQuerySecurityObject(Handle, OWNER_SECURITY_INFORMATION |
  4719. DACL_SECURITY_INFORMATION, NULL, 0,
  4720. &sdLength);
  4721. if (status != STATUS_BUFFER_TOO_SMALL) {
  4722. // The file system does not support security.
  4723. return TRUE;
  4724. }
  4725. sd = ExAllocatePoolWithTag(PagedPool, sdLength, VOLSNAP_TAG_SHORT_TERM);
  4726. if (!sd) {
  4727. *Status = STATUS_INSUFFICIENT_RESOURCES;
  4728. return FALSE;
  4729. }
  4730. status = ZwQuerySecurityObject(Handle, OWNER_SECURITY_INFORMATION |
  4731. DACL_SECURITY_INFORMATION, sd, sdLength,
  4732. &sdLength);
  4733. if (!NT_SUCCESS(status)) {
  4734. ExFreePool(sd);
  4735. *Status = status;
  4736. return FALSE;
  4737. }
  4738. status = RtlGetDaclSecurityDescriptor(sd, &daclPresent, &acl,
  4739. &daclDefaulted);
  4740. if (!NT_SUCCESS(status)) {
  4741. ExFreePool(sd);
  4742. *Status = status;
  4743. return FALSE;
  4744. }
  4745. status = RtlGetOwnerSecurityDescriptor(sd, &sid, &ownerDefaulted);
  4746. if (!NT_SUCCESS(status)) {
  4747. ExFreePool(sd);
  4748. *Status = status;
  4749. return FALSE;
  4750. }
  4751. systemSid = (PSID) sidBuffer;
  4752. adminSid = (PSID) sidBuffer2;
  4753. VspSystemSid((SID*) systemSid);
  4754. VspAdminSid((SID*) adminSid);
  4755. if (!sid) {
  4756. ExFreePool(sd);
  4757. *Status = STATUS_NO_SECURITY_ON_OBJECT;
  4758. return FALSE;
  4759. }
  4760. if (!RtlEqualSid(sid, adminSid) && !RtlEqualSid(sid, systemSid)) {
  4761. ExFreePool(sd);
  4762. *Status = STATUS_NO_SECURITY_ON_OBJECT;
  4763. return FALSE;
  4764. }
  4765. if (!daclPresent || (daclPresent && !acl)) {
  4766. ExFreePool(sd);
  4767. *Status = STATUS_NO_SECURITY_ON_OBJECT;
  4768. return FALSE;
  4769. }
  4770. priviledgedBits = FILE_READ_DATA | WRITE_DAC | WRITE_OWNER |
  4771. ACCESS_SYSTEM_SECURITY | GENERIC_ALL | GENERIC_READ;
  4772. for (i = 0; ; i++) {
  4773. status = RtlGetAce(acl, i, (PVOID*) &ace);
  4774. if (!NT_SUCCESS(status)) {
  4775. ace = NULL;
  4776. }
  4777. if (!ace) {
  4778. break;
  4779. }
  4780. if (ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
  4781. continue;
  4782. }
  4783. sid = (PSID) &ace->SidStart;
  4784. if (RtlEqualSid(sid, systemSid) || RtlEqualSid(sid, adminSid)) {
  4785. continue;
  4786. }
  4787. if (ace->Mask&priviledgedBits) {
  4788. ExFreePool(sd);
  4789. *Status = STATUS_NO_SECURITY_ON_OBJECT;
  4790. return FALSE;
  4791. }
  4792. }
  4793. ExFreePool(sd);
  4794. return TRUE;
  4795. }
  4796. VOID
  4797. VspAdjustBitmap(
  4798. IN PVOID Context
  4799. )
  4800. {
  4801. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4802. PVOLUME_EXTENSION extension = context->Extension.Extension;
  4803. NTSTATUS status;
  4804. LIST_ENTRY extentList;
  4805. WCHAR nameBuffer[100];
  4806. UNICODE_STRING name;
  4807. OBJECT_ATTRIBUTES oa;
  4808. HANDLE h;
  4809. IO_STATUS_BLOCK ioStatus;
  4810. KIRQL irql;
  4811. PLIST_ENTRY l;
  4812. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  4813. BOOLEAN isNtfs;
  4814. PWORK_QUEUE_ITEM workItem;
  4815. PWORKER_THREAD_ROUTINE workerRoutine;
  4816. PVOID parameter;
  4817. PVSP_DIFF_AREA_FILE diffAreaFile;
  4818. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  4819. VspFreeContext(extension->Root, context);
  4820. KeWaitForSingleObject(&extension->Root->PastBootReinit, Executive,
  4821. KernelMode, FALSE, NULL);
  4822. if (extension->IsDetected) {
  4823. status = VspOpenFilesAndValidateSnapshots(extension->Filter);
  4824. if (!NT_SUCCESS(status)) {
  4825. if (!extension->Filter->ControlBlockFileHandle) {
  4826. VspAcquireNonPagedResource(extension, NULL, FALSE);
  4827. VspCreateStartBlock(extension->Filter, 0,
  4828. extension->Filter->MaximumVolumeSpace);
  4829. extension->Filter->FirstControlBlockVolumeOffset = 0;
  4830. VspReleaseNonPagedResource(extension);
  4831. }
  4832. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, TRUE);
  4833. goto Finish;
  4834. }
  4835. } else {
  4836. if (extension->IsPersistent) {
  4837. VspComputeIgnorableBitmap(extension, NULL);
  4838. }
  4839. KeSetEvent(&extension->Filter->EndCommitProcessCompleted,
  4840. IO_NO_INCREMENT, FALSE);
  4841. swprintf(nameBuffer,
  4842. L"\\Device\\HarddiskVolumeShadowCopy%d\\pagefile.sys",
  4843. extension->VolumeNumber);
  4844. RtlInitUnicodeString(&name, nameBuffer);
  4845. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  4846. OBJ_KERNEL_HANDLE, NULL, NULL);
  4847. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  4848. FILE_SHARE_READ | FILE_SHARE_WRITE |
  4849. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  4850. if (NT_SUCCESS(status)) {
  4851. if (!VspHasStrongAcl(h, &status)) {
  4852. ZwClose(h);
  4853. }
  4854. }
  4855. if (NT_SUCCESS(status)) {
  4856. VspMarkFileAllocationInBitmap(extension, h, NULL, NULL);
  4857. if (extension->ContainsCrashdumpFile) {
  4858. ASSERT(extension->IsPersistent);
  4859. status = VspQueryListOfExtents(h, 0, &extentList, NULL, TRUE);
  4860. if (NT_SUCCESS(status)) {
  4861. status = VspCopyExtents(extension, &extentList, FALSE,
  4862. TRUE);
  4863. if (!NT_SUCCESS(status)) {
  4864. while (!IsListEmpty(&extentList)) {
  4865. l = RemoveHeadList(&extentList);
  4866. diffAreaFileAllocation = CONTAINING_RECORD(l,
  4867. DIFF_AREA_FILE_ALLOCATION,
  4868. ListEntry);
  4869. ExFreePool(diffAreaFileAllocation);
  4870. }
  4871. VspLogError(NULL, extension->Filter,
  4872. VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES,
  4873. status, 4, FALSE);
  4874. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  4875. }
  4876. } else {
  4877. VspLogError(NULL, extension->Filter,
  4878. VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES, status,
  4879. 1, FALSE);
  4880. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  4881. }
  4882. }
  4883. ZwClose(h);
  4884. } else if (extension->ContainsCrashdumpFile) {
  4885. VspLogError(NULL, extension->Filter,
  4886. VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES, status, 2,
  4887. FALSE);
  4888. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  4889. }
  4890. swprintf(nameBuffer,
  4891. L"\\Device\\HarddiskVolumeShadowCopy%d\\hiberfil.sys",
  4892. extension->VolumeNumber);
  4893. RtlInitUnicodeString(&name, nameBuffer);
  4894. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  4895. OBJ_KERNEL_HANDLE, NULL, NULL);
  4896. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  4897. FILE_SHARE_READ | FILE_SHARE_WRITE |
  4898. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  4899. if (NT_SUCCESS(status)) {
  4900. if (!VspHasStrongAcl(h, &status)) {
  4901. ZwClose(h);
  4902. }
  4903. }
  4904. if (NT_SUCCESS(status)) {
  4905. VspMarkFileAllocationInBitmap(extension, h, NULL, NULL);
  4906. if (extension->IsPersistent) {
  4907. status = STATUS_SUCCESS;
  4908. isNtfs = TRUE;
  4909. } else {
  4910. status = VspIsNtfs(h, &isNtfs);
  4911. }
  4912. if (NT_SUCCESS(status) && isNtfs) {
  4913. status = VspQueryListOfExtents(h, 0, &extentList, NULL, TRUE);
  4914. if (NT_SUCCESS(status)) {
  4915. status = VspCopyExtents(extension, &extentList, TRUE,
  4916. FALSE);
  4917. if (!NT_SUCCESS(status)) {
  4918. while (!IsListEmpty(&extentList)) {
  4919. l = RemoveHeadList(&extentList);
  4920. diffAreaFileAllocation = CONTAINING_RECORD(l,
  4921. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  4922. ExFreePool(diffAreaFileAllocation);
  4923. }
  4924. VspLogError(NULL, extension->Filter,
  4925. VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES,
  4926. status, 14, FALSE);
  4927. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  4928. }
  4929. } else {
  4930. VspLogError(NULL, extension->Filter,
  4931. VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES, status,
  4932. 3, FALSE);
  4933. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  4934. }
  4935. }
  4936. ZwClose(h);
  4937. }
  4938. }
  4939. status = VspComputeIgnorableProduct(extension);
  4940. KeAcquireSpinLock(&extension->SpinLock, &irql);
  4941. if (extension->IgnorableProduct) {
  4942. if (NT_SUCCESS(status) && extension->VolumeBlockBitmap) {
  4943. VspOrBitmaps(extension->VolumeBlockBitmap,
  4944. extension->IgnorableProduct);
  4945. } else if (extension->VolumeBlockBitmap && extension->IsDetected) {
  4946. KeReleaseSpinLock(&extension->SpinLock, irql);
  4947. if (!extension->Filter->DestroyAllSnapshotsPending) {
  4948. VspLogError(extension, NULL,
  4949. VS_ABORT_SNAPSHOTS_FAILED_FREE_SPACE_DETECTION,
  4950. status, 1, FALSE);
  4951. }
  4952. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, TRUE);
  4953. goto Finish;
  4954. }
  4955. ExFreePool(extension->IgnorableProduct->Buffer);
  4956. ExFreePool(extension->IgnorableProduct);
  4957. extension->IgnorableProduct = NULL;
  4958. }
  4959. KeReleaseSpinLock(&extension->SpinLock, irql);
  4960. if (extension->IsDetected) {
  4961. InterlockedExchange(&extension->OkToGrowDiffArea, TRUE);
  4962. if (extension->DetectedNeedForGrow) {
  4963. context = VspAllocateContext(extension->Root);
  4964. if (context) {
  4965. KeAcquireSpinLock(&extension->SpinLock, &irql);
  4966. ASSERT(!extension->GrowDiffAreaFilePending);
  4967. ASSERT(IsListEmpty(&extension->WaitingForDiffAreaSpace));
  4968. extension->PastFileSystemOperations = FALSE;
  4969. extension->GrowDiffAreaFilePending = TRUE;
  4970. KeReleaseSpinLock(&extension->SpinLock, irql);
  4971. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  4972. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea,
  4973. context);
  4974. context->GrowDiffArea.Extension = extension;
  4975. ObReferenceObject(extension->DeviceObject);
  4976. VspQueueWorkItem(extension->Root, &context->WorkItem, 0);
  4977. }
  4978. }
  4979. }
  4980. Finish:
  4981. if (extension->IsDetected) {
  4982. KeSetEvent(&extension->Filter->EndCommitProcessCompleted,
  4983. IO_NO_INCREMENT, FALSE);
  4984. }
  4985. VspAcquire(extension->Root);
  4986. if (extension->IgnoreCopyDataReference) {
  4987. extension->IgnoreCopyDataReference = FALSE;
  4988. InterlockedDecrement(&extension->Filter->IgnoreCopyData);
  4989. }
  4990. VspRelease(extension->Root);
  4991. KeAcquireSpinLock(&extension->Root->ESpinLock, &irql);
  4992. ASSERT(extension->Root->AdjustBitmapInProgress);
  4993. if (IsListEmpty(&extension->Root->AdjustBitmapQueue)) {
  4994. extension->Root->AdjustBitmapInProgress = FALSE;
  4995. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  4996. } else {
  4997. l = RemoveHeadList(&extension->Root->AdjustBitmapQueue);
  4998. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  4999. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  5000. workerRoutine = workItem->WorkerRoutine;
  5001. parameter = workItem->Parameter;
  5002. ExInitializeWorkItem(workItem, workerRoutine, parameter);
  5003. ExQueueWorkItem(workItem, DelayedWorkQueue);
  5004. }
  5005. ObDereferenceObject(extension->Filter->TargetObject);
  5006. ObDereferenceObject(extension->Filter->DeviceObject);
  5007. ObDereferenceObject(extension->DeviceObject);
  5008. }
  5009. VOID
  5010. VspSetIgnorableBlocksInBitmapWorker(
  5011. IN PVOID Context
  5012. )
  5013. {
  5014. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5015. PVOLUME_EXTENSION extension = context->Extension.Extension;
  5016. NTSTATUS status;
  5017. KIRQL irql;
  5018. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  5019. if (!extension->IsDetected) {
  5020. status = VspMarkFreeSpaceInBitmap(extension, NULL, NULL);
  5021. if (NT_SUCCESS(status)) {
  5022. InterlockedExchange(&extension->OkToGrowDiffArea, TRUE);
  5023. } else {
  5024. if (!extension->Filter->DestroyAllSnapshotsPending) {
  5025. VspLogError(extension, NULL,
  5026. VS_ABORT_SNAPSHOTS_FAILED_FREE_SPACE_DETECTION,
  5027. status, 2, FALSE);
  5028. }
  5029. VspDestroyAllSnapshots(extension->Filter, NULL, FALSE, FALSE);
  5030. }
  5031. }
  5032. ExInitializeWorkItem(&context->WorkItem, VspAdjustBitmap, context);
  5033. KeAcquireSpinLock(&extension->Root->ESpinLock, &irql);
  5034. if (extension->Root->AdjustBitmapInProgress) {
  5035. InsertTailList(&extension->Root->AdjustBitmapQueue,
  5036. &context->WorkItem.List);
  5037. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  5038. } else {
  5039. extension->Root->AdjustBitmapInProgress = TRUE;
  5040. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  5041. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  5042. }
  5043. }
  5044. VOID
  5045. VspFreeCopyIrp(
  5046. IN PVOLUME_EXTENSION Extension,
  5047. IN PIRP CopyIrp
  5048. )
  5049. {
  5050. KIRQL irql;
  5051. PLIST_ENTRY l;
  5052. PWORK_QUEUE_ITEM workItem;
  5053. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  5054. if (Extension->EmergencyCopyIrp == CopyIrp) {
  5055. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  5056. if (IsListEmpty(&Extension->EmergencyCopyIrpQueue)) {
  5057. Extension->EmergencyCopyIrpInUse = FALSE;
  5058. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5059. return;
  5060. }
  5061. l = RemoveHeadList(&Extension->EmergencyCopyIrpQueue);
  5062. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5063. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  5064. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) workItem->Parameter;
  5065. tableEntry->CopyIrp = CopyIrp;
  5066. workItem->WorkerRoutine(workItem->Parameter);
  5067. return;
  5068. }
  5069. if (!Extension->EmergencyCopyIrpInUse) {
  5070. ExFreePool(MmGetMdlVirtualAddress(CopyIrp->MdlAddress));
  5071. IoFreeMdl(CopyIrp->MdlAddress);
  5072. IoFreeIrp(CopyIrp);
  5073. return;
  5074. }
  5075. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  5076. if (IsListEmpty(&Extension->EmergencyCopyIrpQueue)) {
  5077. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5078. ExFreePool(MmGetMdlVirtualAddress(CopyIrp->MdlAddress));
  5079. IoFreeMdl(CopyIrp->MdlAddress);
  5080. IoFreeIrp(CopyIrp);
  5081. return;
  5082. }
  5083. l = RemoveHeadList(&Extension->EmergencyCopyIrpQueue);
  5084. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5085. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  5086. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) workItem->Parameter;
  5087. tableEntry->CopyIrp = CopyIrp;
  5088. workItem->WorkerRoutine(workItem->Parameter);
  5089. }
  5090. VOID
  5091. VspApplyThresholdDelta(
  5092. IN PVOLUME_EXTENSION Extension,
  5093. IN ULONG IncreaseDelta
  5094. )
  5095. {
  5096. PVSP_DIFF_AREA_FILE diffAreaFile;
  5097. PVSP_CONTEXT context;
  5098. KIRQL irql;
  5099. ASSERT(Extension->DiffAreaFile);
  5100. diffAreaFile = Extension->DiffAreaFile;
  5101. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease <=
  5102. diffAreaFile->AllocatedFileSize) {
  5103. return;
  5104. }
  5105. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease -
  5106. IncreaseDelta > diffAreaFile->AllocatedFileSize) {
  5107. return;
  5108. }
  5109. context = VspAllocateContext(Extension->Root);
  5110. if (!context) {
  5111. if (!Extension->OkToGrowDiffArea) {
  5112. VspLogError(Extension, diffAreaFile->Filter,
  5113. VS_GROW_BEFORE_FREE_SPACE, STATUS_SUCCESS, 3, FALSE);
  5114. }
  5115. return;
  5116. }
  5117. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  5118. ASSERT(!Extension->GrowDiffAreaFilePending);
  5119. ASSERT(IsListEmpty(&Extension->WaitingForDiffAreaSpace));
  5120. Extension->PastFileSystemOperations = FALSE;
  5121. Extension->GrowDiffAreaFilePending = TRUE;
  5122. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5123. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  5124. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea, context);
  5125. context->GrowDiffArea.Extension = Extension;
  5126. ObReferenceObject(Extension->DeviceObject);
  5127. if (!Extension->OkToGrowDiffArea) {
  5128. ObReferenceObject(Extension->Filter->DeviceObject);
  5129. ExInitializeWorkItem(&context->WorkItem, VspWaitForInstall, context);
  5130. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  5131. return;
  5132. }
  5133. VspQueueWorkItem(Extension->Root, &context->WorkItem, 0);
  5134. }
  5135. NTSTATUS
  5136. VspCheckOnDiskNotCommitted(
  5137. IN PVOLUME_EXTENSION Extension
  5138. )
  5139. {
  5140. PFILTER_EXTENSION filter = Extension->Filter;
  5141. NTSTATUS status;
  5142. UCHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  5143. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem;
  5144. if (!Extension->OnDiskNotCommitted) {
  5145. return STATUS_SUCCESS;
  5146. }
  5147. Extension->OnDiskNotCommitted = FALSE;
  5148. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  5149. &Extension->SnapshotGuid, FALSE,
  5150. controlItemBuffer, FALSE);
  5151. if (!NT_SUCCESS(status)) {
  5152. if (!filter->DestroyAllSnapshotsPending) {
  5153. VspLogError(Extension, filter, VS_ABORT_SNAPSHOTS_IO_FAILURE,
  5154. status, 16, FALSE);
  5155. }
  5156. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  5157. return status;
  5158. }
  5159. snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  5160. snapshotControlItem->SnapshotOrderNumber =
  5161. Extension->SnapshotOrderNumber;
  5162. snapshotControlItem->SnapshotTime = Extension->CommitTimeStamp;
  5163. if (Extension->ContainsCrashdumpFile) {
  5164. snapshotControlItem->SnapshotControlItemFlags =
  5165. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_CRASHDUMP;
  5166. }
  5167. if (Extension->NoDiffAreaFill) {
  5168. snapshotControlItem->SnapshotControlItemFlags |=
  5169. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_NO_DIFF_AREA_FILL;
  5170. }
  5171. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  5172. &Extension->SnapshotGuid, TRUE,
  5173. controlItemBuffer, FALSE);
  5174. if (!NT_SUCCESS(status)) {
  5175. if (!filter->DestroyAllSnapshotsPending) {
  5176. VspLogError(Extension, filter, VS_ABORT_SNAPSHOTS_IO_FAILURE,
  5177. status, 17, FALSE);
  5178. }
  5179. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  5180. return status;
  5181. }
  5182. return STATUS_SUCCESS;
  5183. }
  5184. VOID
  5185. VspWriteVolume(
  5186. IN PVOID Context
  5187. )
  5188. /*++
  5189. Routine Description:
  5190. This routine performs a volume write, making sure that all of the
  5191. parts of the volume write have an old version of the data placed
  5192. in the diff area for the snapshot.
  5193. Arguments:
  5194. Irp - Supplies the I/O request packet.
  5195. Return Value:
  5196. None.
  5197. --*/
  5198. {
  5199. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5200. PVOLUME_EXTENSION extension = context->WriteVolume.Extension;
  5201. PIRP irp = (PIRP) context->WriteVolume.Irp;
  5202. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  5203. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  5204. PFILTER_EXTENSION filter = extension->Filter;
  5205. NTSTATUS status;
  5206. PLIST_ENTRY l;
  5207. LONGLONG start, end, roundedStart, roundedEnd;
  5208. ULONG irpLength, increase, increaseDelta;
  5209. TEMP_TRANSLATION_TABLE_ENTRY keyTableEntry;
  5210. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  5211. PVOID nodeOrParent;
  5212. TABLE_SEARCH_RESULT searchResult;
  5213. KIRQL irql;
  5214. CCHAR stackSize;
  5215. PVSP_DIFF_AREA_FILE diffAreaFile;
  5216. PDO_EXTENSION rootExtension;
  5217. PVOID buffer;
  5218. PMDL mdl;
  5219. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  5220. if (extension->OnDiskNotCommitted) {
  5221. status = VspCheckOnDiskNotCommitted(extension);
  5222. if (!NT_SUCCESS(status)) {
  5223. VspFreeContext(filter->Root, context);
  5224. VspReleaseNonPagedResource(extension);
  5225. VspDecrementIrpRefCount(irp);
  5226. return;
  5227. }
  5228. }
  5229. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  5230. irpLength = irpSp->Parameters.Read.Length;
  5231. end = start + irpLength;
  5232. if (context->WriteVolume.RoundedStart) {
  5233. roundedStart = context->WriteVolume.RoundedStart;
  5234. } else {
  5235. roundedStart = start&(~(BLOCK_SIZE - 1));
  5236. }
  5237. roundedEnd = end&(~(BLOCK_SIZE - 1));
  5238. if (roundedEnd != end) {
  5239. roundedEnd += BLOCK_SIZE;
  5240. }
  5241. ASSERT(extension->VolumeBlockBitmap);
  5242. for (; roundedStart < roundedEnd; roundedStart += BLOCK_SIZE) {
  5243. if (roundedStart < 0 ||
  5244. roundedStart >= extension->VolumeSize) {
  5245. continue;
  5246. }
  5247. KeAcquireSpinLock(&extension->SpinLock, &irql);
  5248. if (RtlCheckBit(extension->VolumeBlockBitmap,
  5249. (ULONG) (roundedStart>>BLOCK_SHIFT))) {
  5250. KeReleaseSpinLock(&extension->SpinLock, irql);
  5251. continue;
  5252. }
  5253. KeReleaseSpinLock(&extension->SpinLock, irql);
  5254. keyTableEntry.VolumeOffset = roundedStart;
  5255. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  5256. RtlLookupElementGenericTableFull(
  5257. &extension->TempVolumeBlockTable, &keyTableEntry,
  5258. &nodeOrParent, &searchResult);
  5259. if (tableEntry) {
  5260. context = VspAllocateContext(extension->Root);
  5261. if (context) {
  5262. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  5263. context->Extension.Extension = extension;
  5264. context->Extension.Irp = irp;
  5265. } else {
  5266. context = (PVSP_CONTEXT) Context;
  5267. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  5268. context->WriteVolume.RoundedStart = roundedStart;
  5269. }
  5270. ExInitializeWorkItem(&context->WorkItem,
  5271. VspDecrementIrpRefCountWorker, context);
  5272. KeAcquireSpinLock(&extension->SpinLock, &irql);
  5273. if (tableEntry->IsComplete) {
  5274. KeReleaseSpinLock(&extension->SpinLock, irql);
  5275. if (context->Type == VSP_CONTEXT_TYPE_EXTENSION) {
  5276. VspFreeContext(extension->Root, context);
  5277. }
  5278. continue;
  5279. }
  5280. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  5281. InsertTailList(&tableEntry->WaitingQueueDpc,
  5282. &context->WorkItem.List);
  5283. KeReleaseSpinLock(&extension->SpinLock, irql);
  5284. if (context == Context) {
  5285. VspReleaseNonPagedResource(extension);
  5286. return;
  5287. }
  5288. continue;
  5289. }
  5290. RtlZeroMemory(&keyTableEntry, sizeof(TEMP_TRANSLATION_TABLE_ENTRY));
  5291. keyTableEntry.VolumeOffset = roundedStart;
  5292. ASSERT(!extension->TempTableEntry);
  5293. extension->TempTableEntry =
  5294. VspAllocateTempTableEntry(extension->Root);
  5295. if (!extension->TempTableEntry) {
  5296. rootExtension = extension->Root;
  5297. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  5298. if (rootExtension->EmergencyTableEntryInUse) {
  5299. context = (PVSP_CONTEXT) Context;
  5300. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  5301. context->WriteVolume.RoundedStart = roundedStart;
  5302. InsertTailList(&rootExtension->WorkItemWaitingList,
  5303. &context->WorkItem.List);
  5304. if (!rootExtension->WorkItemWaitingListNeedsChecking) {
  5305. InterlockedExchange(
  5306. &rootExtension->WorkItemWaitingListNeedsChecking,
  5307. TRUE);
  5308. }
  5309. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  5310. VspReleaseNonPagedResource(extension);
  5311. return;
  5312. }
  5313. rootExtension->EmergencyTableEntryInUse = TRUE;
  5314. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  5315. extension->TempTableEntry = rootExtension->EmergencyTableEntry;
  5316. }
  5317. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  5318. RtlInsertElementGenericTableFull(
  5319. &extension->TempVolumeBlockTable, &keyTableEntry,
  5320. sizeof(TEMP_TRANSLATION_TABLE_ENTRY), NULL,
  5321. nodeOrParent, searchResult);
  5322. ASSERT(tableEntry);
  5323. if (extension->TempVolumeBlockTable.NumberGenericTableElements >
  5324. extension->MaximumNumberOfTempEntries) {
  5325. extension->MaximumNumberOfTempEntries =
  5326. extension->TempVolumeBlockTable.NumberGenericTableElements;
  5327. VspQueryDiffAreaFileIncrease(extension, &increase);
  5328. ASSERT(increase >= extension->DiffAreaFileIncrease);
  5329. increaseDelta = increase - extension->DiffAreaFileIncrease;
  5330. if (increaseDelta) {
  5331. InterlockedExchange((PLONG) &extension->DiffAreaFileIncrease,
  5332. (LONG) increase);
  5333. VspApplyThresholdDelta(extension, increaseDelta);
  5334. }
  5335. }
  5336. tableEntry->Extension = extension;
  5337. tableEntry->WriteIrp = irp;
  5338. diffAreaFile = extension->DiffAreaFile;
  5339. ASSERT(diffAreaFile);
  5340. tableEntry->TargetObject = diffAreaFile->Filter->TargetObject;
  5341. tableEntry->IsComplete = FALSE;
  5342. InitializeListHead(&tableEntry->WaitingQueueDpc);
  5343. tableEntry->CopyIrp = IoAllocateIrp(
  5344. (CCHAR) extension->Root->StackSize, FALSE);
  5345. buffer = ExAllocatePoolWithTagPriority(NonPagedPool, BLOCK_SIZE,
  5346. VOLSNAP_TAG_BUFFER,
  5347. LowPoolPriority);
  5348. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  5349. if (!tableEntry->CopyIrp || !buffer || !mdl) {
  5350. if (tableEntry->CopyIrp) {
  5351. IoFreeIrp(tableEntry->CopyIrp);
  5352. tableEntry->CopyIrp = NULL;
  5353. }
  5354. if (buffer) {
  5355. ExFreePool(buffer);
  5356. }
  5357. if (mdl) {
  5358. IoFreeMdl(mdl);
  5359. }
  5360. KeAcquireSpinLock(&extension->SpinLock, &irql);
  5361. if (extension->EmergencyCopyIrpInUse) {
  5362. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  5363. ExInitializeWorkItem(&tableEntry->WorkItem,
  5364. VspWriteVolumePhase1, tableEntry);
  5365. InsertTailList(&extension->EmergencyCopyIrpQueue,
  5366. &tableEntry->WorkItem.List);
  5367. KeReleaseSpinLock(&extension->SpinLock, irql);
  5368. continue;
  5369. }
  5370. extension->EmergencyCopyIrpInUse = TRUE;
  5371. KeReleaseSpinLock(&extension->SpinLock, irql);
  5372. tableEntry->CopyIrp = extension->EmergencyCopyIrp;
  5373. } else {
  5374. MmBuildMdlForNonPagedPool(mdl);
  5375. tableEntry->CopyIrp->MdlAddress = mdl;
  5376. }
  5377. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  5378. VspAllocateDiffAreaSpace(extension, &tableEntry->TargetOffset,
  5379. &tableEntry->FileOffset, NULL, NULL);
  5380. VspWriteVolumePhase1(tableEntry);
  5381. }
  5382. context = (PVSP_CONTEXT) Context;
  5383. VspFreeContext(filter->Root, context);
  5384. VspReleaseNonPagedResource(extension);
  5385. VspDecrementIrpRefCount(irp);
  5386. }
  5387. VOID
  5388. VspIrpsTimerDpc(
  5389. IN PKDPC TimerDpc,
  5390. IN PVOID Context,
  5391. IN PVOID SystemArgument1,
  5392. IN PVOID SystemArgument2
  5393. )
  5394. {
  5395. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Context;
  5396. KIRQL irql;
  5397. LIST_ENTRY q;
  5398. PLIST_ENTRY l;
  5399. BOOLEAN emptyQueue;
  5400. if (TimerDpc) {
  5401. VspLogError(NULL, filter, VS_FLUSH_AND_HOLD_IRP_TIMEOUT,
  5402. STATUS_SUCCESS, 0, FALSE);
  5403. }
  5404. IoStopTimer(filter->DeviceObject);
  5405. KeAcquireSpinLock(&filter->SpinLock, &irql);
  5406. ASSERT(filter->ExternalWaiter);
  5407. filter->ExternalWaiter = FALSE;
  5408. InterlockedIncrement(&filter->RefCount);
  5409. InterlockedDecrement(&filter->HoldIncomingWrites);
  5410. if (filter->HoldIncomingWrites) {
  5411. KeReleaseSpinLock(&filter->SpinLock, irql);
  5412. VspDecrementRefCount(filter);
  5413. return;
  5414. }
  5415. KeResetEvent(&filter->ZeroRefEvent);
  5416. if (IsListEmpty(&filter->HoldQueue)) {
  5417. emptyQueue = FALSE;
  5418. } else {
  5419. emptyQueue = TRUE;
  5420. q = filter->HoldQueue;
  5421. InitializeListHead(&filter->HoldQueue);
  5422. }
  5423. KeReleaseSpinLock(&filter->SpinLock, irql);
  5424. if (emptyQueue) {
  5425. q.Blink->Flink = &q;
  5426. q.Flink->Blink = &q;
  5427. VspEmptyIrpQueue(filter->Root->DriverObject, &q);
  5428. }
  5429. }
  5430. VOID
  5431. VspEndCommitDpc(
  5432. IN PKDPC TimerDpc,
  5433. IN PVOID Context,
  5434. IN PVOID SystemArgument1,
  5435. IN PVOID SystemArgument2
  5436. )
  5437. {
  5438. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Context;
  5439. VspLogError(NULL, filter, VS_END_COMMIT_TIMEOUT, STATUS_CANCELLED, 0,
  5440. FALSE);
  5441. InterlockedExchange(&filter->HibernatePending, FALSE);
  5442. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT, FALSE);
  5443. ObDereferenceObject(filter->DeviceObject);
  5444. }
  5445. NTSTATUS
  5446. VspCheckForMemoryPressure(
  5447. IN PFILTER_EXTENSION Filter
  5448. )
  5449. /*++
  5450. Routine Description:
  5451. This routine will allocate 256 K of paged and non paged pool. If these
  5452. allocs succeed, it indicates that the system is not under memory pressure
  5453. and so it is ok to hold write irps for the next second.
  5454. Arguments:
  5455. Filter - Supplies the filter extension.
  5456. Return Value:
  5457. NTSTATUS
  5458. --*/
  5459. {
  5460. PVOID p, np;
  5461. p = ExAllocatePoolWithTagPriority(PagedPool,
  5462. MEMORY_PRESSURE_CHECK_ALLOC_SIZE, VOLSNAP_TAG_SHORT_TERM,
  5463. LowPoolPriority);
  5464. if (!p) {
  5465. VspLogError(NULL, Filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  5466. STATUS_INSUFFICIENT_RESOURCES, 1, FALSE);
  5467. return STATUS_INSUFFICIENT_RESOURCES;
  5468. }
  5469. np = ExAllocatePoolWithTagPriority(NonPagedPool,
  5470. MEMORY_PRESSURE_CHECK_ALLOC_SIZE, VOLSNAP_TAG_SHORT_TERM,
  5471. LowPoolPriority);
  5472. if (!np) {
  5473. ExFreePool(p);
  5474. VspLogError(NULL, Filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  5475. STATUS_INSUFFICIENT_RESOURCES, 2, FALSE);
  5476. return STATUS_INSUFFICIENT_RESOURCES;
  5477. }
  5478. ExFreePool(np);
  5479. ExFreePool(p);
  5480. return STATUS_SUCCESS;
  5481. }
  5482. VOID
  5483. VspOneSecondTimerWorker(
  5484. IN PDEVICE_OBJECT DeviceObject,
  5485. IN PVOID WorkItem
  5486. )
  5487. {
  5488. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  5489. PIO_WORKITEM workItem = (PIO_WORKITEM) WorkItem;
  5490. NTSTATUS status;
  5491. status = VspCheckForMemoryPressure(filter);
  5492. if (!NT_SUCCESS(status)) {
  5493. InterlockedExchange(&filter->LastReleaseDueToMemoryPressure, TRUE);
  5494. VspReleaseWrites(filter);
  5495. }
  5496. IoFreeWorkItem(workItem);
  5497. }
  5498. VOID
  5499. VspOneSecondTimer(
  5500. IN PDEVICE_OBJECT DeviceObject,
  5501. IN PVOID Filter
  5502. )
  5503. /*++
  5504. Routine Description:
  5505. This routine will get called once every second after an IoStartTimer.
  5506. This routine checks for memory pressure and aborts the lovelace operation
  5507. if any memory pressure is detected.
  5508. Arguments:
  5509. DeviceObject - Supplies the device object.
  5510. Filter - Supplies the filter extension.
  5511. Return Value:
  5512. None.
  5513. --*/
  5514. {
  5515. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  5516. PIO_WORKITEM workItem;
  5517. workItem = IoAllocateWorkItem(filter->DeviceObject);
  5518. if (!workItem) {
  5519. VspLogError(NULL, filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  5520. STATUS_INSUFFICIENT_RESOURCES, 3, FALSE);
  5521. VspReleaseWrites(filter);
  5522. return;
  5523. }
  5524. IoQueueWorkItem(workItem, VspOneSecondTimerWorker, CriticalWorkQueue,
  5525. workItem);
  5526. }
  5527. NTSTATUS
  5528. VolSnapAddDevice(
  5529. IN PDRIVER_OBJECT DriverObject,
  5530. IN PDEVICE_OBJECT PhysicalDeviceObject
  5531. )
  5532. /*++
  5533. Routine Description:
  5534. This routine creates and initializes a new FILTER for the corresponding
  5535. volume PDO.
  5536. Arguments:
  5537. DriverObject - Supplies the VOLSNAP driver object.
  5538. PhysicalDeviceObject - Supplies the volume PDO.
  5539. Return Value:
  5540. NTSTATUS
  5541. --*/
  5542. {
  5543. NTSTATUS status;
  5544. PDEVICE_OBJECT deviceObject;
  5545. PDO_EXTENSION rootExtension;
  5546. PFILTER_EXTENSION filter;
  5547. status = IoCreateDevice(DriverObject, sizeof(FILTER_EXTENSION),
  5548. NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject);
  5549. if (!NT_SUCCESS(status)) {
  5550. return status;
  5551. }
  5552. rootExtension = (PDO_EXTENSION)
  5553. IoGetDriverObjectExtension(DriverObject, VolSnapAddDevice);
  5554. if (!rootExtension) {
  5555. IoDeleteDevice(deviceObject);
  5556. return STATUS_NO_SUCH_DEVICE;
  5557. }
  5558. filter = (PFILTER_EXTENSION) deviceObject->DeviceExtension;
  5559. RtlZeroMemory(filter, sizeof(FILTER_EXTENSION));
  5560. filter->DeviceObject = deviceObject;
  5561. filter->Root = rootExtension;
  5562. filter->DeviceExtensionType = DEVICE_EXTENSION_FILTER;
  5563. KeInitializeSpinLock(&filter->SpinLock);
  5564. filter->TargetObject =
  5565. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  5566. if (!filter->TargetObject) {
  5567. IoDeleteDevice(deviceObject);
  5568. return STATUS_NO_SUCH_DEVICE;
  5569. }
  5570. filter->Pdo = PhysicalDeviceObject;
  5571. KeInitializeSemaphore(&filter->ControlBlockFileHandleSemaphore, 1, 1);
  5572. InitializeListHead(&filter->SnapshotLookupTableEntries);
  5573. InitializeListHead(&filter->DiffAreaLookupTableEntries);
  5574. KeInitializeEvent(&filter->ControlBlockFileHandleReady, NotificationEvent,
  5575. TRUE);
  5576. filter->RefCount = 1;
  5577. InitializeListHead(&filter->HoldQueue);
  5578. KeInitializeEvent(&filter->ZeroRefEvent, NotificationEvent, FALSE);
  5579. KeInitializeSemaphore(&filter->ZeroRefSemaphore, 1, 1);
  5580. KeInitializeTimer(&filter->HoldWritesTimer);
  5581. KeInitializeDpc(&filter->HoldWritesTimerDpc, VspIrpsTimerDpc, filter);
  5582. KeInitializeEvent(&filter->EndCommitProcessCompleted, NotificationEvent,
  5583. TRUE);
  5584. InitializeListHead(&filter->VolumeList);
  5585. KeInitializeSemaphore(&filter->CriticalOperationSemaphore, 1, 1);
  5586. InitializeListHead(&filter->DeadVolumeList);
  5587. InitializeListHead(&filter->DiffAreaFilesOnThisFilter);
  5588. InitializeListHead(&filter->CopyOnWriteList);
  5589. filter->DiffAreaVolume = filter;
  5590. KeInitializeTimer(&filter->EndCommitTimer);
  5591. KeInitializeDpc(&filter->EndCommitTimerDpc, VspEndCommitDpc, filter);
  5592. InitializeListHead(&filter->NonPagedResourceList);
  5593. InitializeListHead(&filter->PagedResourceList);
  5594. filter->EpicNumber = 1;
  5595. status = IoInitializeTimer(deviceObject, VspOneSecondTimer, filter);
  5596. if (!NT_SUCCESS(status)) {
  5597. IoDetachDevice(filter->TargetObject);
  5598. IoDeleteDevice(deviceObject);
  5599. return status;
  5600. }
  5601. deviceObject->DeviceType = filter->TargetObject->DeviceType;
  5602. deviceObject->Flags |= DO_DIRECT_IO;
  5603. if (filter->TargetObject->Flags & DO_POWER_PAGABLE) {
  5604. deviceObject->Flags |= DO_POWER_PAGABLE;
  5605. }
  5606. if (filter->TargetObject->Flags & DO_POWER_INRUSH) {
  5607. deviceObject->Flags |= DO_POWER_INRUSH;
  5608. }
  5609. deviceObject->Characteristics |=
  5610. (filter->Pdo->Characteristics&FILE_CHARACTERISTICS_PROPAGATED);
  5611. VspAcquire(filter->Root);
  5612. if (filter->TargetObject->StackSize > filter->Root->StackSize) {
  5613. InterlockedExchange(&filter->Root->StackSize,
  5614. (LONG) filter->TargetObject->StackSize);
  5615. }
  5616. InsertTailList(&filter->Root->FilterList, &filter->ListEntry);
  5617. VspRelease(filter->Root);
  5618. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  5619. return STATUS_SUCCESS;
  5620. }
  5621. NTSTATUS
  5622. VolSnapCreate(
  5623. IN PDEVICE_OBJECT DeviceObject,
  5624. IN PIRP Irp
  5625. )
  5626. /*++
  5627. Routine Description:
  5628. This routine is the dispatch for IRP_MJ_CREATE.
  5629. Arguments:
  5630. DeviceObject - Supplies the device object.
  5631. Irp - Supplies the IO request block.
  5632. Return Value:
  5633. NTSTATUS
  5634. --*/
  5635. {
  5636. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  5637. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  5638. IoSkipCurrentIrpStackLocation(Irp);
  5639. return IoCallDriver(filter->TargetObject, Irp);
  5640. }
  5641. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  5642. Irp->IoStatus.Status = STATUS_SUCCESS;
  5643. Irp->IoStatus.Information = 0;
  5644. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5645. return STATUS_SUCCESS;
  5646. }
  5647. VOID
  5648. VspReadSnapshotPhase3(
  5649. IN PVOID Context
  5650. )
  5651. {
  5652. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5653. PVOLUME_EXTENSION extension = context->ReadSnapshot.Extension;
  5654. PIRP irp = context->ReadSnapshot.OriginalReadIrp;
  5655. PFILTER_EXTENSION filter = extension->Filter;
  5656. KIRQL irql;
  5657. PVOLUME_EXTENSION e;
  5658. TRANSLATION_TABLE_ENTRY keyTableEntry;
  5659. NTSTATUS status;
  5660. PTRANSLATION_TABLE_ENTRY tableEntry;
  5661. TEMP_TRANSLATION_TABLE_ENTRY keyTempTableEntry;
  5662. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  5663. ASSERT(context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT);
  5664. KeAcquireSpinLock(&filter->SpinLock, &irql);
  5665. e = CONTAINING_RECORD(filter->VolumeList.Blink, VOLUME_EXTENSION,
  5666. ListEntry);
  5667. KeReleaseSpinLock(&filter->SpinLock, irql);
  5668. keyTableEntry.VolumeOffset = context->ReadSnapshot.OriginalVolumeOffset;
  5669. status = STATUS_SUCCESS;
  5670. _try {
  5671. tableEntry = (PTRANSLATION_TABLE_ENTRY)
  5672. RtlLookupElementGenericTable(&e->VolumeBlockTable,
  5673. &keyTableEntry);
  5674. } _except (EXCEPTION_EXECUTE_HANDLER) {
  5675. status = GetExceptionCode();
  5676. tableEntry = NULL;
  5677. }
  5678. if (!NT_SUCCESS(status)) {
  5679. irp->IoStatus.Status = status;
  5680. irp->IoStatus.Information = 0;
  5681. VspReleasePagedResource(extension);
  5682. VspFreeContext(extension->Root, context);
  5683. VspDecrementVolumeIrpRefCount(irp);
  5684. return;
  5685. }
  5686. if (tableEntry &&
  5687. tableEntry->TargetObject != context->ReadSnapshot.TargetObject) {
  5688. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  5689. if (tableEntry->Flags&VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY) {
  5690. context->ReadSnapshot.IsCopyTarget = TRUE;
  5691. } else {
  5692. context->ReadSnapshot.IsCopyTarget = FALSE;
  5693. }
  5694. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  5695. VspReleasePagedResource(extension);
  5696. VspReadSnapshotPhase1(context);
  5697. return;
  5698. }
  5699. VspAcquireNonPagedResource(e, NULL, FALSE);
  5700. keyTempTableEntry.VolumeOffset = context->ReadSnapshot.TargetOffset;
  5701. tempTableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  5702. RtlLookupElementGenericTable(
  5703. &e->TempVolumeBlockTable, &keyTempTableEntry);
  5704. if (tempTableEntry) {
  5705. KeAcquireSpinLock(&e->SpinLock, &irql);
  5706. if (!tempTableEntry->IsComplete) {
  5707. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshotPhase1,
  5708. context);
  5709. InsertTailList(&tempTableEntry->WaitingQueueDpc,
  5710. &context->WorkItem.List);
  5711. KeReleaseSpinLock(&e->SpinLock, irql);
  5712. VspReleaseNonPagedResource(e);
  5713. VspReleasePagedResource(extension);
  5714. return;
  5715. }
  5716. KeReleaseSpinLock(&e->SpinLock, irql);
  5717. context->ReadSnapshot.TargetObject = tempTableEntry->TargetObject;
  5718. context->ReadSnapshot.IsCopyTarget = FALSE;
  5719. context->ReadSnapshot.TargetOffset = tempTableEntry->TargetOffset;
  5720. VspReleaseNonPagedResource(e);
  5721. VspReleasePagedResource(e);
  5722. VspReadSnapshotPhase1(context);
  5723. return;
  5724. }
  5725. VspReleaseNonPagedResource(e);
  5726. VspReleasePagedResource(extension);
  5727. VspFreeContext(extension->Root, context);
  5728. VspDecrementVolumeIrpRefCount(irp);
  5729. }
  5730. NTSTATUS
  5731. VspReadSnapshotPhase2(
  5732. IN PDEVICE_OBJECT DeviceObject,
  5733. IN PIRP Irp,
  5734. IN PVOID Context
  5735. )
  5736. {
  5737. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5738. PVOLUME_EXTENSION extension = context->ReadSnapshot.Extension;
  5739. PIRP irp = context->ReadSnapshot.OriginalReadIrp;
  5740. ASSERT(context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT);
  5741. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  5742. irp->IoStatus = Irp->IoStatus;
  5743. }
  5744. IoFreeMdl(Irp->MdlAddress);
  5745. IoFreeIrp(Irp);
  5746. if (context->ReadSnapshot.IsCopyTarget) {
  5747. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshotPhase3,
  5748. context);
  5749. VspAcquirePagedResource(extension, &context->WorkItem);
  5750. return STATUS_MORE_PROCESSING_REQUIRED;
  5751. }
  5752. VspFreeContext(extension->Root, context);
  5753. VspDecrementVolumeIrpRefCount(irp);
  5754. return STATUS_MORE_PROCESSING_REQUIRED;
  5755. }
  5756. VOID
  5757. VspReadSnapshotPhase1(
  5758. IN PVOID Context
  5759. )
  5760. /*++
  5761. Routine Description:
  5762. This routine is called when a read snapshot routine is waiting for
  5763. somebody else to finish updating the public area of a table entry.
  5764. When this routine is called, the public area of the table entry is
  5765. valid.
  5766. Arguments:
  5767. Context - Supplies the context.
  5768. Return Value:
  5769. None.
  5770. --*/
  5771. {
  5772. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5773. PVOLUME_EXTENSION extension = context->ReadSnapshot.Extension;
  5774. TEMP_TRANSLATION_TABLE_ENTRY keyTempTableEntry;
  5775. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  5776. TRANSLATION_TABLE_ENTRY keyTableEntry;
  5777. PTRANSLATION_TABLE_ENTRY tableEntry;
  5778. NTSTATUS status;
  5779. PIRP irp;
  5780. PIO_STACK_LOCATION nextSp;
  5781. PCHAR vp;
  5782. PMDL mdl;
  5783. ASSERT(context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT);
  5784. if (!context->ReadSnapshot.TargetObject || !extension->IsStarted) {
  5785. irp = context->ReadSnapshot.OriginalReadIrp;
  5786. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  5787. irp->IoStatus.Information = 0;
  5788. VspFreeContext(extension->Root, context);
  5789. VspDecrementVolumeIrpRefCount(irp);
  5790. return;
  5791. }
  5792. irp = IoAllocateIrp(context->ReadSnapshot.TargetObject->StackSize, FALSE);
  5793. if (!irp) {
  5794. irp = context->ReadSnapshot.OriginalReadIrp;
  5795. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5796. irp->IoStatus.Information = 0;
  5797. VspFreeContext(extension->Root, context);
  5798. VspDecrementVolumeIrpRefCount(irp);
  5799. return;
  5800. }
  5801. vp = (PCHAR) MmGetMdlVirtualAddress(
  5802. context->ReadSnapshot.OriginalReadIrp->MdlAddress) +
  5803. context->ReadSnapshot.OriginalReadIrpOffset;
  5804. mdl = IoAllocateMdl(vp, context->ReadSnapshot.Length, FALSE, FALSE, NULL);
  5805. if (!mdl) {
  5806. IoFreeIrp(irp);
  5807. irp = context->ReadSnapshot.OriginalReadIrp;
  5808. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5809. irp->IoStatus.Information = 0;
  5810. VspFreeContext(extension->Root, context);
  5811. VspDecrementVolumeIrpRefCount(irp);
  5812. return;
  5813. }
  5814. IoBuildPartialMdl(context->ReadSnapshot.OriginalReadIrp->MdlAddress, mdl,
  5815. vp, context->ReadSnapshot.Length);
  5816. irp->MdlAddress = mdl;
  5817. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  5818. nextSp = IoGetNextIrpStackLocation(irp);
  5819. nextSp->Parameters.Read.ByteOffset.QuadPart =
  5820. context->ReadSnapshot.TargetOffset +
  5821. context->ReadSnapshot.BlockOffset;
  5822. nextSp->Parameters.Read.Length = context->ReadSnapshot.Length;
  5823. nextSp->MajorFunction = IRP_MJ_READ;
  5824. nextSp->DeviceObject = context->ReadSnapshot.TargetObject;
  5825. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  5826. IoSetCompletionRoutine(irp, VspReadSnapshotPhase2, context, TRUE, TRUE,
  5827. TRUE);
  5828. IoCallDriver(nextSp->DeviceObject, irp);
  5829. }
  5830. VOID
  5831. VspReadSnapshot(
  5832. IN PVOID Context
  5833. )
  5834. /*++
  5835. Routine Description:
  5836. This routine kicks off a read snapshot. First the table is searched
  5837. to see if any of the data for this IRP resides in the diff area. If not,
  5838. then the Irp is sent directly to the original volume and then the diff
  5839. area is checked again when it returns to fill in any gaps that may
  5840. have been written while the IRP was in transit.
  5841. Arguments:
  5842. Irp - Supplies the I/O request packet.
  5843. Return Value:
  5844. None.
  5845. --*/
  5846. {
  5847. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5848. PVOLUME_EXTENSION extension = context->Extension.Extension;
  5849. PIRP irp = context->Extension.Irp;
  5850. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  5851. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  5852. PFILTER_EXTENSION filter = extension->Filter;
  5853. LONGLONG start, end, roundedStart, roundedEnd;
  5854. ULONG irpOffset, irpLength, length, blockOffset;
  5855. TRANSLATION_TABLE_ENTRY keyTableEntry;
  5856. TEMP_TRANSLATION_TABLE_ENTRY keyTempTableEntry;
  5857. PVOLUME_EXTENSION e;
  5858. PTRANSLATION_TABLE_ENTRY tableEntry;
  5859. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  5860. KIRQL irql;
  5861. NTSTATUS status;
  5862. LONGLONG copyTarget;
  5863. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  5864. VspFreeContext(extension->Root, context);
  5865. if (!extension->IsStarted) {
  5866. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  5867. irp->IoStatus.Information = 0;
  5868. VspReleasePagedResource(extension);
  5869. VspDecrementVolumeIrpRefCount(irp);
  5870. return;
  5871. }
  5872. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  5873. irpLength = irpSp->Parameters.Read.Length;
  5874. end = start + irpLength;
  5875. roundedStart = start&(~(BLOCK_SIZE - 1));
  5876. roundedEnd = end&(~(BLOCK_SIZE - 1));
  5877. if (roundedEnd != end) {
  5878. roundedEnd += BLOCK_SIZE;
  5879. }
  5880. irpOffset = 0;
  5881. RtlZeroMemory(&keyTableEntry, sizeof(keyTableEntry));
  5882. for (; roundedStart < roundedEnd; roundedStart += BLOCK_SIZE) {
  5883. if (roundedStart < start) {
  5884. blockOffset = (ULONG) (start - roundedStart);
  5885. } else {
  5886. blockOffset = 0;
  5887. }
  5888. copyTarget = 0;
  5889. length = BLOCK_SIZE - blockOffset;
  5890. if (irpLength < length) {
  5891. length = irpLength;
  5892. }
  5893. keyTableEntry.VolumeOffset = roundedStart;
  5894. e = extension;
  5895. status = STATUS_SUCCESS;
  5896. for (;;) {
  5897. _try {
  5898. tableEntry = (PTRANSLATION_TABLE_ENTRY)
  5899. RtlLookupElementGenericTable(&e->VolumeBlockTable,
  5900. &keyTableEntry);
  5901. } _except (EXCEPTION_EXECUTE_HANDLER) {
  5902. status = GetExceptionCode();
  5903. tableEntry = NULL;
  5904. }
  5905. if (tableEntry) {
  5906. if (!(tableEntry->Flags&
  5907. VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY)) {
  5908. break;
  5909. }
  5910. copyTarget = tableEntry->TargetOffset;
  5911. keyTableEntry.VolumeOffset = copyTarget;
  5912. tableEntry = NULL;
  5913. }
  5914. if (!NT_SUCCESS(status)) {
  5915. irp->IoStatus.Status = status;
  5916. irp->IoStatus.Information = 0;
  5917. break;
  5918. }
  5919. KeAcquireSpinLock(&filter->SpinLock, &irql);
  5920. if (e->ListEntry.Flink == &filter->VolumeList) {
  5921. KeReleaseSpinLock(&filter->SpinLock, irql);
  5922. break;
  5923. }
  5924. e = CONTAINING_RECORD(e->ListEntry.Flink,
  5925. VOLUME_EXTENSION, ListEntry);
  5926. KeReleaseSpinLock(&filter->SpinLock, irql);
  5927. }
  5928. if (!tableEntry) {
  5929. if (!NT_SUCCESS(status)) {
  5930. break;
  5931. }
  5932. if (copyTarget) {
  5933. keyTempTableEntry.VolumeOffset = copyTarget;
  5934. } else {
  5935. keyTempTableEntry.VolumeOffset = roundedStart;
  5936. }
  5937. VspAcquireNonPagedResource(e, NULL, FALSE);
  5938. tempTableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  5939. RtlLookupElementGenericTable(
  5940. &e->TempVolumeBlockTable, &keyTempTableEntry);
  5941. if (!tempTableEntry && !copyTarget) {
  5942. VspReleaseNonPagedResource(e);
  5943. irpOffset += length;
  5944. irpLength -= length;
  5945. continue;
  5946. }
  5947. }
  5948. context = VspAllocateContext(extension->Root);
  5949. if (!context) {
  5950. if (!tableEntry) {
  5951. VspReleaseNonPagedResource(e);
  5952. }
  5953. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5954. irp->IoStatus.Information = 0;
  5955. break;
  5956. }
  5957. context->Type = VSP_CONTEXT_TYPE_READ_SNAPSHOT;
  5958. context->ReadSnapshot.Extension = extension;
  5959. context->ReadSnapshot.OriginalReadIrp = irp;
  5960. context->ReadSnapshot.OriginalReadIrpOffset = irpOffset;
  5961. context->ReadSnapshot.OriginalVolumeOffset = roundedStart;
  5962. context->ReadSnapshot.BlockOffset = blockOffset;
  5963. context->ReadSnapshot.Length = length;
  5964. context->ReadSnapshot.TargetObject = NULL;
  5965. context->ReadSnapshot.IsCopyTarget = FALSE;
  5966. context->ReadSnapshot.TargetOffset = 0;
  5967. if (!tableEntry) {
  5968. if (copyTarget) {
  5969. VspReleaseNonPagedResource(e);
  5970. context->ReadSnapshot.TargetObject = filter->TargetObject;
  5971. context->ReadSnapshot.IsCopyTarget = TRUE;
  5972. context->ReadSnapshot.TargetOffset = copyTarget;
  5973. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  5974. VspReadSnapshotPhase1(context);
  5975. irpOffset += length;
  5976. irpLength -= length;
  5977. continue;
  5978. }
  5979. KeAcquireSpinLock(&e->SpinLock, &irql);
  5980. if (!tempTableEntry->IsComplete) {
  5981. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  5982. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshotPhase1,
  5983. context);
  5984. InsertTailList(&tempTableEntry->WaitingQueueDpc,
  5985. &context->WorkItem.List);
  5986. KeReleaseSpinLock(&e->SpinLock, irql);
  5987. VspReleaseNonPagedResource(e);
  5988. irpOffset += length;
  5989. irpLength -= length;
  5990. continue;
  5991. }
  5992. KeReleaseSpinLock(&e->SpinLock, irql);
  5993. context->ReadSnapshot.TargetObject = tempTableEntry->TargetObject;
  5994. context->ReadSnapshot.IsCopyTarget = FALSE;
  5995. context->ReadSnapshot.TargetOffset = tempTableEntry->TargetOffset;
  5996. VspReleaseNonPagedResource(e);
  5997. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  5998. VspReadSnapshotPhase1(context);
  5999. irpOffset += length;
  6000. irpLength -= length;
  6001. continue;
  6002. }
  6003. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  6004. context->ReadSnapshot.IsCopyTarget = FALSE;
  6005. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  6006. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  6007. VspReadSnapshotPhase1(context);
  6008. irpOffset += length;
  6009. irpLength -= length;
  6010. }
  6011. VspReleasePagedResource(extension);
  6012. VspDecrementVolumeIrpRefCount(irp);
  6013. }
  6014. NTSTATUS
  6015. VspReadCompletionForReadSnapshot(
  6016. IN PDEVICE_OBJECT DeviceObject,
  6017. IN PIRP Irp,
  6018. IN PVOID Extension
  6019. )
  6020. /*++
  6021. Routine Description:
  6022. This routine is the completion to a read of the filter in
  6023. response to a snapshot read. This completion routine queues
  6024. a worker routine to look at the diff area table and fill in
  6025. any parts of the original that have been invalidated.
  6026. Arguments:
  6027. DeviceObject - Supplies the device object.
  6028. Irp - Supplies the I/O request packet.
  6029. Extension - Supplies the volume extension.
  6030. Return Value:
  6031. NTSTATUS
  6032. --*/
  6033. {
  6034. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  6035. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
  6036. PVSP_CONTEXT context;
  6037. nextSp->Parameters.Read.Length = 1; // Use this for a ref count.
  6038. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  6039. VspDecrementVolumeIrpRefCount(Irp);
  6040. return STATUS_MORE_PROCESSING_REQUIRED;
  6041. }
  6042. context = VspAllocateContext(extension->Root);
  6043. if (!context) {
  6044. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  6045. Irp->IoStatus.Information = 0;
  6046. VspDecrementVolumeIrpRefCount(Irp);
  6047. return STATUS_MORE_PROCESSING_REQUIRED;
  6048. }
  6049. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  6050. context->Extension.Extension = extension;
  6051. context->Extension.Irp = Irp;
  6052. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshot, context);
  6053. VspAcquirePagedResource(extension, &context->WorkItem);
  6054. return STATUS_MORE_PROCESSING_REQUIRED;
  6055. }
  6056. RTL_GENERIC_COMPARE_RESULTS
  6057. VspTableCompareRoutine(
  6058. IN PRTL_GENERIC_TABLE Table,
  6059. IN PVOID First,
  6060. IN PVOID Second
  6061. )
  6062. {
  6063. PTRANSLATION_TABLE_ENTRY first = (PTRANSLATION_TABLE_ENTRY) First;
  6064. PTRANSLATION_TABLE_ENTRY second = (PTRANSLATION_TABLE_ENTRY) Second;
  6065. if (first->VolumeOffset < second->VolumeOffset) {
  6066. return GenericLessThan;
  6067. } else if (first->VolumeOffset > second->VolumeOffset) {
  6068. return GenericGreaterThan;
  6069. }
  6070. return GenericEqual;
  6071. }
  6072. VOID
  6073. VspCreateHeap(
  6074. IN PVOID Context
  6075. )
  6076. {
  6077. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  6078. PVOLUME_EXTENSION extension = context->Extension.Extension;
  6079. PIRP irp = context->Extension.Irp;
  6080. ULONG increase;
  6081. OBJECT_ATTRIBUTES oa;
  6082. NTSTATUS status;
  6083. SIZE_T size;
  6084. LARGE_INTEGER sectionSize, sectionOffset;
  6085. HANDLE h;
  6086. PVOID mapPointer;
  6087. KIRQL irql;
  6088. BOOLEAN emptyQueue;
  6089. LIST_ENTRY q;
  6090. PLIST_ENTRY l;
  6091. PWORK_QUEUE_ITEM workItem;
  6092. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  6093. VspFreeContext(extension->Root, context);
  6094. // First check that there is 5 MB of space available. This driver
  6095. // should not consume all available page file space.
  6096. InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
  6097. size = 5*1024*1024;
  6098. sectionSize.QuadPart = size;
  6099. status = ZwCreateSection(&h, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
  6100. SECTION_MAP_READ | SECTION_MAP_WRITE, &oa,
  6101. &sectionSize, PAGE_READWRITE, SEC_COMMIT,
  6102. NULL);
  6103. if (!NT_SUCCESS(status)) {
  6104. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 1, FALSE);
  6105. goto Finish;
  6106. }
  6107. sectionOffset.QuadPart = 0;
  6108. mapPointer = NULL;
  6109. status = ZwMapViewOfSection(h, NtCurrentProcess(), &mapPointer, 0, 0,
  6110. &sectionOffset, &size, ViewShare, 0,
  6111. PAGE_READWRITE);
  6112. ZwClose(h);
  6113. if (!NT_SUCCESS(status)) {
  6114. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 2, FALSE);
  6115. goto Finish;
  6116. }
  6117. status = ZwUnmapViewOfSection(NtCurrentProcess(), mapPointer);
  6118. ASSERT(NT_SUCCESS(status));
  6119. // Now we have 5 MB, so go ahead and make the alloc.
  6120. increase = extension->DiffAreaFileIncrease;
  6121. increase >>= BLOCK_SHIFT;
  6122. size = increase*(sizeof(TRANSLATION_TABLE_ENTRY) +
  6123. sizeof(RTL_BALANCED_LINKS));
  6124. size = (size + 0xFFFF)&(~0xFFFF);
  6125. ASSERT(size >= MINIMUM_TABLE_HEAP_SIZE);
  6126. if (extension->RootSemaphoreHeld) {
  6127. irp = (PIRP) 1;
  6128. }
  6129. DoOver:
  6130. sectionSize.QuadPart = size;
  6131. status = ZwCreateSection(&h, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
  6132. SECTION_MAP_READ | SECTION_MAP_WRITE, &oa,
  6133. &sectionSize, PAGE_READWRITE, SEC_COMMIT,
  6134. NULL);
  6135. if (!NT_SUCCESS(status)) {
  6136. if (size > MINIMUM_TABLE_HEAP_SIZE) {
  6137. size = MINIMUM_TABLE_HEAP_SIZE;
  6138. goto DoOver;
  6139. }
  6140. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 3, FALSE);
  6141. goto Finish;
  6142. }
  6143. sectionOffset.QuadPart = 0;
  6144. mapPointer = NULL;
  6145. status = ZwMapViewOfSection(h, NtCurrentProcess(), &mapPointer, 0, 0,
  6146. &sectionOffset, &size, ViewShare, 0,
  6147. PAGE_READWRITE);
  6148. ZwClose(h);
  6149. if (!NT_SUCCESS(status)) {
  6150. if (size > MINIMUM_TABLE_HEAP_SIZE) {
  6151. size = MINIMUM_TABLE_HEAP_SIZE;
  6152. goto DoOver;
  6153. }
  6154. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 4, FALSE);
  6155. goto Finish;
  6156. }
  6157. status = VspIncrementVolumeRefCount(extension);
  6158. if (!NT_SUCCESS(status)) {
  6159. status = ZwUnmapViewOfSection(NtCurrentProcess(), mapPointer);
  6160. ASSERT(NT_SUCCESS(status));
  6161. goto Finish;
  6162. }
  6163. VspAcquirePagedResource(extension, NULL);
  6164. extension->NextDiffAreaFileMap = mapPointer;
  6165. extension->NextDiffAreaFileMapSize = (ULONG) size;
  6166. extension->DiffAreaFileMapProcess = NtCurrentProcess();
  6167. VspReleasePagedResource(extension);
  6168. VspDecrementVolumeRefCount(extension);
  6169. Finish:
  6170. KeAcquireSpinLock(&extension->SpinLock, &irql);
  6171. if (extension->PageFileSpaceCreatePending) {
  6172. extension->PageFileSpaceCreatePending = FALSE;
  6173. if (IsListEmpty(&extension->WaitingForPageFileSpace)) {
  6174. emptyQueue = FALSE;
  6175. } else {
  6176. emptyQueue = TRUE;
  6177. q = extension->WaitingForPageFileSpace;
  6178. InitializeListHead(&extension->WaitingForPageFileSpace);
  6179. }
  6180. } else {
  6181. emptyQueue = FALSE;
  6182. }
  6183. KeReleaseSpinLock(&extension->SpinLock, irql);
  6184. if (emptyQueue) {
  6185. q.Flink->Blink = &q;
  6186. q.Blink->Flink = &q;
  6187. while (!IsListEmpty(&q)) {
  6188. l = RemoveHeadList(&q);
  6189. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  6190. VspAcquirePagedResource(extension, workItem);
  6191. }
  6192. }
  6193. ObDereferenceObject(extension->DeviceObject);
  6194. }
  6195. PVOID
  6196. VspTableAllocateRoutine(
  6197. IN PRTL_GENERIC_TABLE Table,
  6198. IN CLONG Size
  6199. )
  6200. {
  6201. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  6202. PVOID p;
  6203. POLD_HEAP_ENTRY oldHeap;
  6204. PVSP_CONTEXT context;
  6205. KIRQL irql;
  6206. if (extension->NextAvailable + Size <= extension->DiffAreaFileMapSize) {
  6207. p = (PCHAR) extension->DiffAreaFileMap + extension->NextAvailable;
  6208. extension->NextAvailable += Size;
  6209. return p;
  6210. }
  6211. if (!extension->NextDiffAreaFileMap) {
  6212. return NULL;
  6213. }
  6214. oldHeap = (POLD_HEAP_ENTRY)
  6215. ExAllocatePoolWithTag(PagedPool, sizeof(OLD_HEAP_ENTRY),
  6216. VOLSNAP_TAG_OLD_HEAP);
  6217. if (!oldHeap) {
  6218. return NULL;
  6219. }
  6220. context = VspAllocateContext(extension->Root);
  6221. if (!context) {
  6222. ExFreePool(oldHeap);
  6223. return NULL;
  6224. }
  6225. KeAcquireSpinLock(&extension->SpinLock, &irql);
  6226. ASSERT(!extension->PageFileSpaceCreatePending);
  6227. ASSERT(IsListEmpty(&extension->WaitingForPageFileSpace));
  6228. extension->PageFileSpaceCreatePending = TRUE;
  6229. KeReleaseSpinLock(&extension->SpinLock, irql);
  6230. oldHeap->DiffAreaFileMap = extension->DiffAreaFileMap;
  6231. InsertTailList(&extension->OldHeaps, &oldHeap->ListEntry);
  6232. extension->DiffAreaFileMap = extension->NextDiffAreaFileMap;
  6233. extension->DiffAreaFileMapSize = extension->NextDiffAreaFileMapSize;
  6234. extension->NextAvailable = 0;
  6235. extension->NextDiffAreaFileMap = NULL;
  6236. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  6237. context->Extension.Extension = extension;
  6238. context->Extension.Irp = NULL;
  6239. ObReferenceObject(extension->DeviceObject);
  6240. ExInitializeWorkItem(&context->WorkItem, VspCreateHeap, context);
  6241. if (extension->RootSemaphoreHeld) {
  6242. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  6243. } else {
  6244. VspQueueWorkItem(extension->Root, &context->WorkItem, 0);
  6245. }
  6246. p = extension->DiffAreaFileMap;
  6247. extension->NextAvailable += Size;
  6248. return p;
  6249. }
  6250. VOID
  6251. VspTableFreeRoutine(
  6252. IN PRTL_GENERIC_TABLE Table,
  6253. IN PVOID Buffer
  6254. )
  6255. {
  6256. }
  6257. PVOID
  6258. VspTempTableAllocateRoutine(
  6259. IN PRTL_GENERIC_TABLE Table,
  6260. IN CLONG Size
  6261. )
  6262. {
  6263. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  6264. PVOID r;
  6265. ASSERT(Size <= sizeof(RTL_BALANCED_LINKS) +
  6266. sizeof(TEMP_TRANSLATION_TABLE_ENTRY));
  6267. r = extension->TempTableEntry;
  6268. extension->TempTableEntry = NULL;
  6269. return r;
  6270. }
  6271. VOID
  6272. VspTempTableFreeRoutine(
  6273. IN PRTL_GENERIC_TABLE Table,
  6274. IN PVOID Buffer
  6275. )
  6276. {
  6277. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  6278. VspFreeTempTableEntry(extension->Root, Buffer);
  6279. }
  6280. PFILTER_EXTENSION
  6281. VspFindFilter(
  6282. IN PDO_EXTENSION RootExtension,
  6283. IN PFILTER_EXTENSION Filter,
  6284. IN PUNICODE_STRING VolumeName,
  6285. IN PFILE_OBJECT FileObject
  6286. )
  6287. {
  6288. NTSTATUS status;
  6289. PDEVICE_OBJECT deviceObject, d;
  6290. PLIST_ENTRY l;
  6291. PFILTER_EXTENSION filter;
  6292. if (VolumeName) {
  6293. status = IoGetDeviceObjectPointer(VolumeName, FILE_READ_ATTRIBUTES,
  6294. &FileObject, &deviceObject);
  6295. if (!NT_SUCCESS(status)) {
  6296. if (Filter) {
  6297. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  6298. status, 1, FALSE);
  6299. }
  6300. return NULL;
  6301. }
  6302. }
  6303. deviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
  6304. for (l = RootExtension->FilterList.Flink;
  6305. l != &RootExtension->FilterList; l = l->Flink) {
  6306. filter = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  6307. d = IoGetAttachedDeviceReference(filter->DeviceObject);
  6308. ObDereferenceObject(d);
  6309. if (d == deviceObject) {
  6310. break;
  6311. }
  6312. }
  6313. ObDereferenceObject(deviceObject);
  6314. if (VolumeName) {
  6315. ObDereferenceObject(FileObject);
  6316. }
  6317. if (l != &RootExtension->FilterList) {
  6318. return filter;
  6319. }
  6320. if (Filter) {
  6321. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  6322. STATUS_NOT_FOUND, 2, FALSE);
  6323. }
  6324. return NULL;
  6325. }
  6326. NTSTATUS
  6327. VspIsNtfs(
  6328. IN HANDLE FileHandle,
  6329. OUT PBOOLEAN IsNtfs
  6330. )
  6331. {
  6332. ULONG size;
  6333. PFILE_FS_ATTRIBUTE_INFORMATION fsAttributeInfo;
  6334. NTSTATUS status;
  6335. IO_STATUS_BLOCK ioStatus;
  6336. size = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  6337. 4*sizeof(WCHAR);
  6338. fsAttributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)
  6339. ExAllocatePoolWithTag(PagedPool, size,
  6340. VOLSNAP_TAG_SHORT_TERM);
  6341. if (!fsAttributeInfo) {
  6342. return STATUS_INSUFFICIENT_RESOURCES;
  6343. }
  6344. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  6345. fsAttributeInfo, size,
  6346. FileFsAttributeInformation);
  6347. if (status == STATUS_BUFFER_OVERFLOW) {
  6348. *IsNtfs = FALSE;
  6349. ExFreePool(fsAttributeInfo);
  6350. return STATUS_SUCCESS;
  6351. }
  6352. if (!NT_SUCCESS(status)) {
  6353. ExFreePool(fsAttributeInfo);
  6354. return status;
  6355. }
  6356. if (fsAttributeInfo->FileSystemNameLength == 8 &&
  6357. fsAttributeInfo->FileSystemName[0] == 'N' &&
  6358. fsAttributeInfo->FileSystemName[1] == 'T' &&
  6359. fsAttributeInfo->FileSystemName[2] == 'F' &&
  6360. fsAttributeInfo->FileSystemName[3] == 'S') {
  6361. ExFreePool(fsAttributeInfo);
  6362. *IsNtfs = TRUE;
  6363. return STATUS_SUCCESS;
  6364. }
  6365. ExFreePool(fsAttributeInfo);
  6366. *IsNtfs = FALSE;
  6367. return STATUS_SUCCESS;
  6368. }
  6369. LONGLONG
  6370. VspQueryVolumeSize(
  6371. IN PFILTER_EXTENSION Filter
  6372. )
  6373. {
  6374. PDEVICE_OBJECT targetObject;
  6375. KEVENT event;
  6376. PIRP irp;
  6377. GET_LENGTH_INFORMATION lengthInfo;
  6378. IO_STATUS_BLOCK ioStatus;
  6379. NTSTATUS status;
  6380. targetObject = Filter->TargetObject;
  6381. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6382. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_LENGTH_INFO,
  6383. targetObject, NULL, 0, &lengthInfo,
  6384. sizeof(lengthInfo), FALSE, &event,
  6385. &ioStatus);
  6386. if (!irp) {
  6387. return 0;
  6388. }
  6389. status = IoCallDriver(targetObject, irp);
  6390. if (status == STATUS_PENDING) {
  6391. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6392. status = ioStatus.Status;
  6393. }
  6394. if (!NT_SUCCESS(status)) {
  6395. return 0;
  6396. }
  6397. return lengthInfo.Length.QuadPart;
  6398. }
  6399. VOID
  6400. VspCancelRoutine(
  6401. IN OUT PDEVICE_OBJECT DeviceObject,
  6402. IN OUT PIRP Irp
  6403. )
  6404. /*++
  6405. Routine Description:
  6406. This routine is called on when the given IRP is cancelled. It
  6407. will dequeue this IRP off the work queue and complete the
  6408. request as CANCELLED.
  6409. Arguments:
  6410. DeviceObject - Supplies the device object.
  6411. Irp - Supplies the IRP.
  6412. Return Value:
  6413. None.
  6414. --*/
  6415. {
  6416. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  6417. ASSERT(Irp == filter->FlushAndHoldIrp);
  6418. filter->FlushAndHoldIrp = NULL;
  6419. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  6420. IoReleaseCancelSpinLock(Irp->CancelIrql);
  6421. Irp->IoStatus.Status = STATUS_CANCELLED;
  6422. Irp->IoStatus.Information = 0;
  6423. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6424. }
  6425. VOID
  6426. VspFsTimerDpc(
  6427. IN PKDPC TimerDpc,
  6428. IN PVOID Context,
  6429. IN PVOID SystemArgument1,
  6430. IN PVOID SystemArgument2
  6431. )
  6432. {
  6433. PDO_EXTENSION rootExtension = (PDO_EXTENSION) Context;
  6434. KIRQL irql;
  6435. PIRP irp;
  6436. PFILTER_EXTENSION filter;
  6437. IoAcquireCancelSpinLock(&irql);
  6438. while (!IsListEmpty(&rootExtension->HoldIrps)) {
  6439. irp = CONTAINING_RECORD(rootExtension->HoldIrps.Flink, IRP,
  6440. Tail.Overlay.ListEntry);
  6441. irp->CancelIrql = irql;
  6442. IoSetCancelRoutine(irp, NULL);
  6443. filter = (PFILTER_EXTENSION) IoGetCurrentIrpStackLocation(irp)->
  6444. DeviceObject->DeviceExtension;
  6445. ObReferenceObject(filter->DeviceObject);
  6446. VspCancelRoutine(filter->DeviceObject, irp);
  6447. VspLogError(NULL, filter, VS_FLUSH_AND_HOLD_FS_TIMEOUT,
  6448. STATUS_CANCELLED, 0, FALSE);
  6449. ObDereferenceObject(filter->DeviceObject);
  6450. IoAcquireCancelSpinLock(&irql);
  6451. }
  6452. rootExtension->HoldRefCount = 0;
  6453. IoReleaseCancelSpinLock(irql);
  6454. }
  6455. VOID
  6456. VspZeroRefCallback(
  6457. IN PFILTER_EXTENSION Filter
  6458. )
  6459. {
  6460. PIRP irp = (PIRP) Filter->ZeroRefContext;
  6461. LARGE_INTEGER timeout;
  6462. timeout.QuadPart = -10*1000*1000*((LONGLONG) Filter->HoldWritesTimeout);
  6463. KeSetTimer(&Filter->HoldWritesTimer, timeout, &Filter->HoldWritesTimerDpc);
  6464. irp->IoStatus.Status = STATUS_SUCCESS;
  6465. irp->IoStatus.Information = 0;
  6466. IoCompleteRequest(irp, IO_SOUND_INCREMENT);
  6467. }
  6468. VOID
  6469. VspFlushAndHoldWriteIrps(
  6470. IN PIRP Irp,
  6471. IN ULONG HoldWritesTimeout
  6472. )
  6473. /*++
  6474. Routine Description:
  6475. This routine waits for outstanding write requests to complete while
  6476. holding incoming write requests. This IRP will complete when all
  6477. outstanding IRPs have completed. A timer will be set for the given
  6478. timeout value and held writes irps will be released after that point or
  6479. when IOCTL_VOLSNAP_RELEASE_WRITES comes in, whichever is sooner.
  6480. Arguments:
  6481. Irp - Supplies the I/O request packet.
  6482. HoldWritesTimeout - Supplies the maximum length of time in seconds that a
  6483. write IRP will be held up.
  6484. Return Value:
  6485. None.
  6486. --*/
  6487. {
  6488. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6489. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  6490. KIRQL irql;
  6491. NTSTATUS status;
  6492. KeAcquireSpinLock(&filter->SpinLock, &irql);
  6493. if (filter->ExternalWaiter) {
  6494. KeReleaseSpinLock(&filter->SpinLock, irql);
  6495. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  6496. Irp->IoStatus.Information = 0;
  6497. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6498. return;
  6499. }
  6500. filter->ExternalWaiter = TRUE;
  6501. filter->ZeroRefCallback = VspZeroRefCallback;
  6502. filter->ZeroRefContext = Irp;
  6503. filter->HoldWritesTimeout = HoldWritesTimeout;
  6504. if (filter->HoldIncomingWrites) {
  6505. InterlockedIncrement(&filter->HoldIncomingWrites);
  6506. InterlockedIncrement(&filter->RefCount);
  6507. } else {
  6508. InterlockedIncrement(&filter->HoldIncomingWrites);
  6509. }
  6510. KeReleaseSpinLock(&filter->SpinLock, irql);
  6511. VspDecrementRefCount(filter);
  6512. IoStartTimer(filter->DeviceObject);
  6513. status = VspCheckForMemoryPressure(filter);
  6514. if (!NT_SUCCESS(status)) {
  6515. InterlockedExchange(&filter->LastReleaseDueToMemoryPressure, TRUE);
  6516. VspReleaseWrites(filter);
  6517. }
  6518. }
  6519. NTSTATUS
  6520. VspFlushAndHoldWrites(
  6521. IN PFILTER_EXTENSION Filter,
  6522. IN PIRP Irp
  6523. )
  6524. /*++
  6525. Routine Description:
  6526. This routine is called for multiple volumes at once. On the first
  6527. call the GUID is checked and if it is different than the current one
  6528. then the current set is aborted. If the GUID is new then subsequent
  6529. calls are compared to the GUID passed in here until the required
  6530. number of calls is completed. A timer is used to wait until all
  6531. of the IRPs have reached this driver and then another time out is used
  6532. after all of these calls complete to wait for IOCTL_VOLSNAP_RELEASE_WRITES
  6533. to be sent to all of the volumes involved.
  6534. Arguments:
  6535. Filter - Supplies the filter device extension.
  6536. Irp - Supplies the I/O request packet.
  6537. Return Value:
  6538. NTSTATUS
  6539. --*/
  6540. {
  6541. PDO_EXTENSION rootExtension = Filter->Root;
  6542. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6543. PVOLSNAP_FLUSH_AND_HOLD_INPUT input;
  6544. KIRQL irql;
  6545. LARGE_INTEGER timeout;
  6546. LIST_ENTRY q;
  6547. PLIST_ENTRY l;
  6548. PIRP irp;
  6549. PFILTER_EXTENSION filter;
  6550. ULONG irpTimeout;
  6551. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6552. sizeof(VOLSNAP_FLUSH_AND_HOLD_INPUT)) {
  6553. return STATUS_INVALID_PARAMETER;
  6554. }
  6555. input = (PVOLSNAP_FLUSH_AND_HOLD_INPUT) Irp->AssociatedIrp.SystemBuffer;
  6556. if (!input->NumberOfVolumesToFlush ||
  6557. !input->SecondsToHoldFileSystemsTimeout ||
  6558. !input->SecondsToHoldIrpsTimeout) {
  6559. return STATUS_INVALID_PARAMETER;
  6560. }
  6561. IoAcquireCancelSpinLock(&irql);
  6562. if (Filter->FlushAndHoldIrp) {
  6563. IoReleaseCancelSpinLock(irql);
  6564. VspLogError(NULL, Filter, VS_TWO_FLUSH_AND_HOLDS,
  6565. STATUS_INVALID_PARAMETER, 1, FALSE);
  6566. return STATUS_INVALID_PARAMETER;
  6567. }
  6568. if (rootExtension->HoldRefCount) {
  6569. if (!IsEqualGUID(rootExtension->HoldInstanceGuid, input->InstanceId)) {
  6570. IoReleaseCancelSpinLock(irql);
  6571. VspLogError(NULL, Filter, VS_TWO_FLUSH_AND_HOLDS,
  6572. STATUS_INVALID_PARAMETER, 2, FALSE);
  6573. return STATUS_INVALID_PARAMETER;
  6574. }
  6575. } else {
  6576. if (IsEqualGUID(rootExtension->HoldInstanceGuid, input->InstanceId)) {
  6577. IoReleaseCancelSpinLock(irql);
  6578. return STATUS_INVALID_PARAMETER;
  6579. }
  6580. rootExtension->HoldRefCount = input->NumberOfVolumesToFlush + 1;
  6581. rootExtension->HoldInstanceGuid = input->InstanceId;
  6582. rootExtension->SecondsToHoldFsTimeout =
  6583. input->SecondsToHoldFileSystemsTimeout;
  6584. rootExtension->SecondsToHoldIrpTimeout =
  6585. input->SecondsToHoldIrpsTimeout;
  6586. timeout.QuadPart = -10*1000*1000*
  6587. ((LONGLONG) rootExtension->SecondsToHoldFsTimeout);
  6588. KeSetTimer(&rootExtension->HoldTimer, timeout,
  6589. &rootExtension->HoldTimerDpc);
  6590. }
  6591. Filter->FlushAndHoldIrp = Irp;
  6592. InsertTailList(&rootExtension->HoldIrps, &Irp->Tail.Overlay.ListEntry);
  6593. IoSetCancelRoutine(Irp, VspCancelRoutine);
  6594. IoMarkIrpPending(Irp);
  6595. rootExtension->HoldRefCount--;
  6596. if (rootExtension->HoldRefCount != 1) {
  6597. IoReleaseCancelSpinLock(irql);
  6598. return STATUS_PENDING;
  6599. }
  6600. InitializeListHead(&q);
  6601. while (!IsListEmpty(&rootExtension->HoldIrps)) {
  6602. l = RemoveHeadList(&rootExtension->HoldIrps);
  6603. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  6604. filter = (PFILTER_EXTENSION)
  6605. IoGetCurrentIrpStackLocation(irp)->DeviceObject->
  6606. DeviceExtension;
  6607. InsertTailList(&q, l);
  6608. filter->FlushAndHoldIrp = NULL;
  6609. IoSetCancelRoutine(irp, NULL);
  6610. }
  6611. irpTimeout = rootExtension->SecondsToHoldIrpTimeout;
  6612. if (KeCancelTimer(&rootExtension->HoldTimer)) {
  6613. IoReleaseCancelSpinLock(irql);
  6614. VspFsTimerDpc(&rootExtension->HoldTimerDpc,
  6615. rootExtension->HoldTimerDpc.DeferredContext,
  6616. rootExtension->HoldTimerDpc.SystemArgument1,
  6617. rootExtension->HoldTimerDpc.SystemArgument2);
  6618. } else {
  6619. IoReleaseCancelSpinLock(irql);
  6620. }
  6621. while (!IsListEmpty(&q)) {
  6622. l = RemoveHeadList(&q);
  6623. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  6624. VspFlushAndHoldWriteIrps(irp, irpTimeout);
  6625. }
  6626. return STATUS_PENDING;
  6627. }
  6628. NTSTATUS
  6629. VspCreateDiffAreaFileName(
  6630. IN PDEVICE_OBJECT DeviceObject,
  6631. IN PVOLUME_EXTENSION Extension,
  6632. OUT PUNICODE_STRING DiffAreaFileName,
  6633. IN BOOLEAN ValidateSystemVolumeInformationFolder,
  6634. IN GUID* SnapshotGuid
  6635. )
  6636. /*++
  6637. Routine Description:
  6638. This routine builds the diff area file name for the given diff area
  6639. volume and the given volume snapshot number. The name formed will
  6640. look like <Diff Area Volume Name>\<Volume Snapshot Number><GUID>.
  6641. Arguments:
  6642. Filter - Supplies the filter extension.
  6643. VolumeSnapshotNumber - Supplies the volume snapshot number.
  6644. DiffAreaFileName - Returns the name of the diff area file.
  6645. Return Value:
  6646. NTSTATUS
  6647. --*/
  6648. {
  6649. PDEVICE_OBJECT targetObject = DeviceObject;
  6650. KEVENT event;
  6651. PMOUNTDEV_NAME name;
  6652. UCHAR buffer[512];
  6653. PIRP irp;
  6654. IO_STATUS_BLOCK ioStatus;
  6655. NTSTATUS status;
  6656. UNICODE_STRING sysvol, guidString, numberString, string;
  6657. WCHAR numberBuffer[80];
  6658. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6659. name = (PMOUNTDEV_NAME) buffer;
  6660. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  6661. targetObject, NULL, 0, name,
  6662. 500, FALSE, &event, &ioStatus);
  6663. if (!irp) {
  6664. return STATUS_INSUFFICIENT_RESOURCES;
  6665. }
  6666. status = IoCallDriver(targetObject, irp);
  6667. if (status == STATUS_PENDING) {
  6668. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6669. status = ioStatus.Status;
  6670. }
  6671. if (!NT_SUCCESS(status)) {
  6672. return status;
  6673. }
  6674. RtlInitUnicodeString(&sysvol, RTL_SYSTEM_VOLUME_INFORMATION_FOLDER);
  6675. if (SnapshotGuid) {
  6676. status = RtlStringFromGUID(*SnapshotGuid, &guidString);
  6677. if (!NT_SUCCESS(status)) {
  6678. return status;
  6679. }
  6680. swprintf(numberBuffer, L"\\%s", guidString.Buffer);
  6681. ExFreePool(guidString.Buffer);
  6682. } else if (Extension) {
  6683. if (Extension->IsPersistent) {
  6684. status = RtlStringFromGUID(Extension->SnapshotGuid, &guidString);
  6685. if (!NT_SUCCESS(status)) {
  6686. return status;
  6687. }
  6688. swprintf(numberBuffer, L"\\%s", guidString.Buffer);
  6689. ExFreePool(guidString.Buffer);
  6690. } else {
  6691. swprintf(numberBuffer, L"\\%d", Extension->VolumeNumber);
  6692. }
  6693. } else {
  6694. swprintf(numberBuffer, L"\\*");
  6695. }
  6696. RtlInitUnicodeString(&numberString, numberBuffer);
  6697. status = RtlStringFromGUID(VSP_DIFF_AREA_FILE_GUID, &guidString);
  6698. if (!NT_SUCCESS(status)) {
  6699. return status;
  6700. }
  6701. string.MaximumLength = name->NameLength + sizeof(WCHAR) + sysvol.Length +
  6702. numberString.Length + guidString.Length +
  6703. sizeof(WCHAR);
  6704. string.Length = 0;
  6705. string.Buffer = (PWCHAR)
  6706. ExAllocatePoolWithTag(PagedPool, string.MaximumLength,
  6707. VOLSNAP_TAG_SHORT_TERM);
  6708. if (!string.Buffer) {
  6709. ExFreePool(guidString.Buffer);
  6710. return STATUS_INSUFFICIENT_RESOURCES;
  6711. }
  6712. string.Length = name->NameLength;
  6713. RtlCopyMemory(string.Buffer, name->Name, string.Length);
  6714. string.Buffer[string.Length/sizeof(WCHAR)] = '\\';
  6715. string.Length += sizeof(WCHAR);
  6716. if (ValidateSystemVolumeInformationFolder) {
  6717. RtlCreateSystemVolumeInformationFolder(&string);
  6718. }
  6719. RtlAppendUnicodeStringToString(&string, &sysvol);
  6720. RtlAppendUnicodeStringToString(&string, &numberString);
  6721. RtlAppendUnicodeStringToString(&string, &guidString);
  6722. ExFreePool(guidString.Buffer);
  6723. string.Buffer[string.Length/sizeof(WCHAR)] = 0;
  6724. *DiffAreaFileName = string;
  6725. return STATUS_SUCCESS;
  6726. }
  6727. NTSTATUS
  6728. VspCreateSecurityDescriptor(
  6729. OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
  6730. OUT PACL* Acl
  6731. )
  6732. {
  6733. PSECURITY_DESCRIPTOR sd;
  6734. NTSTATUS status;
  6735. ULONG aclLength;
  6736. PACL acl;
  6737. sd = (PSECURITY_DESCRIPTOR)
  6738. ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_DESCRIPTOR),
  6739. VOLSNAP_TAG_SHORT_TERM);
  6740. if (!sd) {
  6741. return STATUS_INSUFFICIENT_RESOURCES;
  6742. }
  6743. status = RtlCreateSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
  6744. if (!NT_SUCCESS(status)) {
  6745. ExFreePool(sd);
  6746. return status;
  6747. }
  6748. aclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
  6749. RtlLengthSid(SeExports->SeAliasAdminsSid) - sizeof(ULONG);
  6750. acl = (PACL) ExAllocatePoolWithTag(PagedPool, aclLength,
  6751. VOLSNAP_TAG_SHORT_TERM);
  6752. if (!acl) {
  6753. ExFreePool(sd);
  6754. return STATUS_INSUFFICIENT_RESOURCES;
  6755. }
  6756. status = RtlCreateAcl(acl, aclLength, ACL_REVISION);
  6757. if (!NT_SUCCESS(status)) {
  6758. ExFreePool(acl);
  6759. ExFreePool(sd);
  6760. return status;
  6761. }
  6762. status = RtlAddAccessAllowedAce(acl, ACL_REVISION, DELETE,
  6763. SeExports->SeAliasAdminsSid);
  6764. if (!NT_SUCCESS(status)) {
  6765. ExFreePool(acl);
  6766. ExFreePool(sd);
  6767. return status;
  6768. }
  6769. status = RtlSetDaclSecurityDescriptor(sd, TRUE, acl, FALSE);
  6770. if (!NT_SUCCESS(status)) {
  6771. ExFreePool(acl);
  6772. ExFreePool(sd);
  6773. return status;
  6774. }
  6775. *SecurityDescriptor = sd;
  6776. *Acl = acl;
  6777. return STATUS_SUCCESS;
  6778. }
  6779. NTSTATUS
  6780. VspPinFile(
  6781. IN PDEVICE_OBJECT TargetObject,
  6782. IN HANDLE FileHandle
  6783. )
  6784. /*++
  6785. Routine Description:
  6786. This routine pins down the extents of the given diff area file so that
  6787. defrag operations are disabled.
  6788. Arguments:
  6789. DiffAreaFile - Supplies the diff area file.
  6790. Return Value:
  6791. NTSTATUS
  6792. --*/
  6793. {
  6794. NTSTATUS status;
  6795. UNICODE_STRING volumeName;
  6796. OBJECT_ATTRIBUTES oa;
  6797. HANDLE h;
  6798. IO_STATUS_BLOCK ioStatus;
  6799. MARK_HANDLE_INFO markHandleInfo;
  6800. status = VspCreateDiffAreaFileName(TargetObject, NULL, &volumeName,
  6801. FALSE, NULL);
  6802. if (!NT_SUCCESS(status)) {
  6803. return status;
  6804. }
  6805. // 66 characters back to take of \System Volume Information\*{guid}
  6806. // resulting in the name of the volume.
  6807. volumeName.Length -= 66*sizeof(WCHAR);
  6808. volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0;
  6809. InitializeObjectAttributes(&oa, &volumeName, OBJ_CASE_INSENSITIVE |
  6810. OBJ_KERNEL_HANDLE, NULL, NULL);
  6811. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  6812. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  6813. FILE_SYNCHRONOUS_IO_NONALERT);
  6814. ExFreePool(volumeName.Buffer);
  6815. if (!NT_SUCCESS(status)) {
  6816. return status;
  6817. }
  6818. RtlZeroMemory(&markHandleInfo, sizeof(MARK_HANDLE_INFO));
  6819. markHandleInfo.VolumeHandle = h;
  6820. markHandleInfo.HandleInfo = MARK_HANDLE_PROTECT_CLUSTERS;
  6821. status = ZwFsControlFile(FileHandle, NULL, NULL, NULL,
  6822. &ioStatus, FSCTL_MARK_HANDLE, &markHandleInfo,
  6823. sizeof(markHandleInfo), NULL, 0);
  6824. ZwClose(h);
  6825. return status;
  6826. }
  6827. NTSTATUS
  6828. VspOptimizeDiffAreaFileLocation(
  6829. IN PFILTER_EXTENSION Filter,
  6830. IN HANDLE FileHandle,
  6831. IN PVOLUME_EXTENSION BitmapExtension,
  6832. IN LONGLONG StartingOffset,
  6833. IN LONGLONG FileSize
  6834. )
  6835. /*++
  6836. Routine Description:
  6837. This routine optimizes the location of the diff area file so that more
  6838. of it can be used.
  6839. Arguments:
  6840. Filter - Supplies the filter extension where the diff area resides.
  6841. FileHandle - Provides a handle to the diff area.
  6842. BitmapExtension - Supplies the extension of the active snapshot on the
  6843. given filter, if any.
  6844. StartingOffset - Supplies the starting point of where to optimize
  6845. the file.
  6846. FileSize - Supplies the allocated size of the file.
  6847. Return Value:
  6848. NTSTATUS
  6849. --*/
  6850. {
  6851. NTSTATUS status;
  6852. IO_STATUS_BLOCK ioStatus;
  6853. FILE_FS_SIZE_INFORMATION fsSize;
  6854. ULONG bitmapSize;
  6855. PVOID bitmapBuffer;
  6856. RTL_BITMAP bitmap;
  6857. PMOUNTDEV_NAME mountdevName;
  6858. UCHAR buffer[512];
  6859. KEVENT event;
  6860. PIRP irp;
  6861. UNICODE_STRING fileName;
  6862. OBJECT_ATTRIBUTES oa;
  6863. HANDLE h;
  6864. KIRQL irql;
  6865. ULONG numBitsToFind, bitIndex, bpc, bitsFound, chunk;
  6866. MOVE_FILE_DATA moveFileData;
  6867. // Align the given file and if 'BitmapExtension' is available, try to
  6868. // confine the file to the bits already set in the bitmap in
  6869. // 'BitmapExtension'.
  6870. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus, &fsSize,
  6871. sizeof(fsSize),
  6872. FileFsSizeInformation);
  6873. if (!NT_SUCCESS(status)) {
  6874. return status;
  6875. }
  6876. bitmapSize = (ULONG) (fsSize.TotalAllocationUnits.QuadPart*
  6877. fsSize.SectorsPerAllocationUnit*
  6878. fsSize.BytesPerSector/BLOCK_SIZE);
  6879. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  6880. (bitmapSize + 8*sizeof(ULONG) - 1)/
  6881. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  6882. if (!bitmapBuffer) {
  6883. return STATUS_INSUFFICIENT_RESOURCES;
  6884. }
  6885. RtlInitializeBitMap(&bitmap, (PULONG) bitmapBuffer, bitmapSize);
  6886. RtlClearAllBits(&bitmap);
  6887. mountdevName = (PMOUNTDEV_NAME) buffer;
  6888. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6889. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  6890. Filter->TargetObject, NULL, 0,
  6891. mountdevName, 500, FALSE, &event,
  6892. &ioStatus);
  6893. if (!irp) {
  6894. ExFreePool(bitmapBuffer);
  6895. return STATUS_INSUFFICIENT_RESOURCES;
  6896. }
  6897. status = IoCallDriver(Filter->TargetObject, irp);
  6898. if (status == STATUS_PENDING) {
  6899. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6900. status = ioStatus.Status;
  6901. }
  6902. if (!NT_SUCCESS(status)) {
  6903. ExFreePool(bitmapBuffer);
  6904. return status;
  6905. }
  6906. mountdevName->Name[mountdevName->NameLength/sizeof(WCHAR)] = 0;
  6907. RtlInitUnicodeString(&fileName, mountdevName->Name);
  6908. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  6909. OBJ_KERNEL_HANDLE, NULL, NULL);
  6910. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  6911. FILE_SHARE_READ | FILE_SHARE_WRITE |
  6912. FILE_SHARE_DELETE,
  6913. FILE_SYNCHRONOUS_IO_NONALERT);
  6914. if (!NT_SUCCESS(status)) {
  6915. ExFreePool(bitmapBuffer);
  6916. return status;
  6917. }
  6918. status = VspMarkFreeSpaceInBitmap(NULL, h, &bitmap);
  6919. if (!NT_SUCCESS(status)) {
  6920. ZwClose(h);
  6921. ExFreePool(bitmapBuffer);
  6922. return status;
  6923. }
  6924. if (BitmapExtension) {
  6925. status = VspIncrementVolumeRefCount(BitmapExtension);
  6926. if (NT_SUCCESS(status)) {
  6927. KeAcquireSpinLock(&BitmapExtension->SpinLock, &irql);
  6928. if (BitmapExtension->VolumeBlockBitmap) {
  6929. if (BitmapExtension->VolumeBlockBitmap->SizeOfBitMap <
  6930. bitmap.SizeOfBitMap) {
  6931. bitmap.SizeOfBitMap =
  6932. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap;
  6933. }
  6934. VspAndBitmaps(&bitmap, BitmapExtension->VolumeBlockBitmap);
  6935. if (bitmap.SizeOfBitMap < bitmapSize) {
  6936. bitmap.SizeOfBitMap = bitmapSize;
  6937. RtlClearBits(&bitmap,
  6938. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap,
  6939. bitmapSize -
  6940. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap);
  6941. }
  6942. }
  6943. KeReleaseSpinLock(&BitmapExtension->SpinLock, irql);
  6944. VspDecrementVolumeRefCount(BitmapExtension);
  6945. }
  6946. }
  6947. numBitsToFind = (ULONG) ((FileSize - StartingOffset)/BLOCK_SIZE);
  6948. bpc = fsSize.SectorsPerAllocationUnit*fsSize.BytesPerSector;
  6949. chunk = 64;
  6950. while (numBitsToFind) {
  6951. bitsFound = numBitsToFind;
  6952. if (bitsFound > chunk) {
  6953. bitsFound = chunk;
  6954. }
  6955. bitIndex = RtlFindSetBits(&bitmap, bitsFound, 0);
  6956. if (bitIndex == (ULONG) -1) {
  6957. if (chunk == 1) {
  6958. ZwClose(h);
  6959. ExFreePool(bitmapBuffer);
  6960. return STATUS_DISK_FULL;
  6961. }
  6962. chunk /= 2;
  6963. continue;
  6964. }
  6965. moveFileData.FileHandle = FileHandle;
  6966. moveFileData.StartingVcn.QuadPart = StartingOffset/bpc;
  6967. moveFileData.StartingLcn.QuadPart =
  6968. (((LONGLONG) bitIndex)<<BLOCK_SHIFT)/bpc;
  6969. moveFileData.ClusterCount = (ULONG) ((((LONGLONG) bitsFound)<<
  6970. BLOCK_SHIFT)/bpc);
  6971. InterlockedIncrement(&Filter->IgnoreCopyData);
  6972. status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
  6973. FSCTL_MOVE_FILE, &moveFileData,
  6974. sizeof(moveFileData), NULL, 0);
  6975. InterlockedDecrement(&Filter->IgnoreCopyData);
  6976. RtlClearBits(&bitmap, bitIndex, bitsFound);
  6977. if (!NT_SUCCESS(status)) {
  6978. continue;
  6979. }
  6980. numBitsToFind -= bitsFound;
  6981. StartingOffset += ((LONGLONG) bitsFound)<<BLOCK_SHIFT;
  6982. }
  6983. ZwClose(h);
  6984. ExFreePool(bitmapBuffer);
  6985. return STATUS_SUCCESS;
  6986. }
  6987. NTSTATUS
  6988. VspOpenDiffAreaFile(
  6989. IN OUT PVSP_DIFF_AREA_FILE DiffAreaFile,
  6990. IN BOOLEAN NoErrorLogOnDiskFull
  6991. )
  6992. {
  6993. LARGE_INTEGER diffAreaFileSize;
  6994. NTSTATUS status;
  6995. UNICODE_STRING diffAreaFileName;
  6996. PSECURITY_DESCRIPTOR securityDescriptor;
  6997. PACL acl;
  6998. OBJECT_ATTRIBUTES oa;
  6999. IO_STATUS_BLOCK ioStatus;
  7000. BOOLEAN isNtfs;
  7001. PVOLUME_EXTENSION bitmapExtension;
  7002. diffAreaFileSize.QuadPart = DiffAreaFile->AllocatedFileSize;
  7003. status = VspCreateDiffAreaFileName(DiffAreaFile->Filter->TargetObject,
  7004. DiffAreaFile->Extension,
  7005. &diffAreaFileName, TRUE, NULL);
  7006. if (!NT_SUCCESS(status)) {
  7007. return status;
  7008. }
  7009. status = VspCreateSecurityDescriptor(&securityDescriptor, &acl);
  7010. if (!NT_SUCCESS(status)) {
  7011. ExFreePool(diffAreaFileName.Buffer);
  7012. return status;
  7013. }
  7014. InitializeObjectAttributes(&oa, &diffAreaFileName,
  7015. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  7016. NULL, securityDescriptor);
  7017. status = ZwCreateFile(&DiffAreaFile->FileHandle, FILE_GENERIC_READ |
  7018. FILE_GENERIC_WRITE, &oa, &ioStatus,
  7019. &diffAreaFileSize, FILE_ATTRIBUTE_HIDDEN |
  7020. FILE_ATTRIBUTE_SYSTEM, 0, FILE_OVERWRITE_IF,
  7021. FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT |
  7022. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  7023. FILE_NO_COMPRESSION, NULL, 0);
  7024. ExFreePool(acl);
  7025. ExFreePool(securityDescriptor);
  7026. ExFreePool(diffAreaFileName.Buffer);
  7027. if (NT_SUCCESS(status)) {
  7028. status = VspSetFileSize(DiffAreaFile->FileHandle,
  7029. diffAreaFileSize.QuadPart);
  7030. if (!NT_SUCCESS(status)) {
  7031. ZwClose(DiffAreaFile->FileHandle);
  7032. DiffAreaFile->FileHandle = NULL;
  7033. }
  7034. }
  7035. if (!NT_SUCCESS(status)) {
  7036. if (status == STATUS_DISK_FULL) {
  7037. if (!NoErrorLogOnDiskFull) {
  7038. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  7039. VS_DIFF_AREA_CREATE_FAILED_LOW_DISK_SPACE, status,
  7040. 0, FALSE);
  7041. }
  7042. } else {
  7043. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  7044. VS_DIFF_AREA_CREATE_FAILED, status, 0, FALSE);
  7045. }
  7046. return status;
  7047. }
  7048. status = VspIsNtfs(DiffAreaFile->FileHandle, &isNtfs);
  7049. if (!NT_SUCCESS(status) || !isNtfs) {
  7050. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  7051. VS_NOT_NTFS, status, 0, FALSE);
  7052. ZwClose(DiffAreaFile->FileHandle);
  7053. DiffAreaFile->FileHandle = NULL;
  7054. return STATUS_INVALID_PARAMETER;
  7055. }
  7056. VspAcquire(DiffAreaFile->Filter->Root);
  7057. if (IsListEmpty(&DiffAreaFile->Filter->VolumeList)) {
  7058. bitmapExtension = NULL;
  7059. } else {
  7060. bitmapExtension = CONTAINING_RECORD(
  7061. DiffAreaFile->Filter->VolumeList.Blink,
  7062. VOLUME_EXTENSION, ListEntry);
  7063. if (bitmapExtension->IsDead) {
  7064. bitmapExtension = NULL;
  7065. } else {
  7066. ObReferenceObject(bitmapExtension->DeviceObject);
  7067. }
  7068. }
  7069. VspRelease(DiffAreaFile->Filter->Root);
  7070. status = VspOptimizeDiffAreaFileLocation(DiffAreaFile->Filter,
  7071. DiffAreaFile->FileHandle,
  7072. bitmapExtension, 0,
  7073. DiffAreaFile->AllocatedFileSize);
  7074. if (!NT_SUCCESS(status)) {
  7075. if (status != STATUS_DISK_FULL || !NoErrorLogOnDiskFull) {
  7076. if (status == STATUS_DISK_FULL) {
  7077. if (bitmapExtension) {
  7078. if (bitmapExtension->IgnoreCopyDataReference) {
  7079. VspLogError(DiffAreaFile->Extension,
  7080. DiffAreaFile->Filter,
  7081. VS_INITIAL_DEFRAG_FAILED_BITMAP_ADJUSTMENT_IN_PROGRESS,
  7082. status, 0, FALSE);
  7083. } else {
  7084. VspLogError(DiffAreaFile->Extension,
  7085. DiffAreaFile->Filter,
  7086. VS_INITIAL_DEFRAG_FAILED, status, 0,
  7087. FALSE);
  7088. }
  7089. } else {
  7090. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  7091. VS_INITIAL_DEFRAG_FAILED_STRICT_FRAGMENTATION,
  7092. status, 0, FALSE);
  7093. }
  7094. } else {
  7095. VspLogError(DiffAreaFile->Extension, NULL,
  7096. VS_CANT_ALLOCATE_BITMAP, status, 5, FALSE);
  7097. }
  7098. }
  7099. ZwClose(DiffAreaFile->FileHandle);
  7100. DiffAreaFile->FileHandle = NULL;
  7101. if (bitmapExtension) {
  7102. ObDereferenceObject(bitmapExtension->DeviceObject);
  7103. }
  7104. return status;
  7105. }
  7106. if (bitmapExtension) {
  7107. ObDereferenceObject(bitmapExtension->DeviceObject);
  7108. }
  7109. status = VspPinFile(DiffAreaFile->Filter->TargetObject,
  7110. DiffAreaFile->FileHandle);
  7111. if (!NT_SUCCESS(status)) {
  7112. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  7113. VS_PIN_DIFF_AREA_FAILED, status, 0, FALSE);
  7114. ZwClose(DiffAreaFile->FileHandle);
  7115. DiffAreaFile->FileHandle = NULL;
  7116. return status;
  7117. }
  7118. return STATUS_SUCCESS;
  7119. }
  7120. NTSTATUS
  7121. VspTrimOlderSnapshotBeforeCreate(
  7122. IN PFILTER_EXTENSION Filter,
  7123. IN OUT PLONGLONG DiffAreaSpaceDeleted
  7124. )
  7125. {
  7126. LIST_ENTRY listOfDiffAreaFilesToClose;
  7127. LIST_ENTRY listOfDeviceObjectToDelete;
  7128. PVOLUME_EXTENSION extension;
  7129. InitializeListHead(&listOfDiffAreaFilesToClose);
  7130. InitializeListHead(&listOfDeviceObjectToDelete);
  7131. VspAcquire(Filter->Root);
  7132. if (IsListEmpty(&Filter->VolumeList)) {
  7133. VspRelease(Filter->Root);
  7134. return STATUS_UNSUCCESSFUL;
  7135. }
  7136. extension = CONTAINING_RECORD(Filter->VolumeList.Flink,
  7137. VOLUME_EXTENSION, ListEntry);
  7138. VspAcquireNonPagedResource(extension, NULL, FALSE);
  7139. *DiffAreaSpaceDeleted += extension->DiffAreaFile->AllocatedFileSize;
  7140. VspReleaseNonPagedResource(extension);
  7141. VspLogError(extension, NULL, VS_DELETE_TO_TRIM_SPACE, STATUS_SUCCESS,
  7142. 3, TRUE);
  7143. VspDeleteOldestSnapshot(Filter, &listOfDiffAreaFilesToClose,
  7144. &listOfDeviceObjectToDelete, FALSE, FALSE);
  7145. VspRelease(Filter->Root);
  7146. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  7147. &listOfDeviceObjectToDelete);
  7148. return STATUS_SUCCESS;
  7149. }
  7150. NTSTATUS
  7151. VspCreateInitialDiffAreaFile(
  7152. IN PVOLUME_EXTENSION Extension,
  7153. IN LONGLONG InitialDiffAreaAllocation
  7154. )
  7155. /*++
  7156. Routine Description:
  7157. This routine creates the initial diff area file entries for the
  7158. given device extension.
  7159. Arguments:
  7160. Extension - Supplies the volume extension.
  7161. Return Value:
  7162. NTSTATUS
  7163. --*/
  7164. {
  7165. PFILTER_EXTENSION filter = Extension->Filter;
  7166. NTSTATUS status;
  7167. PVSP_DIFF_AREA_FILE diffAreaFile;
  7168. KIRQL irql;
  7169. PVOID buf;
  7170. PMDL mdl;
  7171. LONGLONG diffAreaSpaceDeleted;
  7172. VspAcquire(Extension->Root);
  7173. if (!filter->DiffAreaVolume) {
  7174. VspRelease(Extension->Root);
  7175. return STATUS_INVALID_PARAMETER;
  7176. }
  7177. status = STATUS_SUCCESS;
  7178. diffAreaFile = (PVSP_DIFF_AREA_FILE)
  7179. ExAllocatePoolWithTag(NonPagedPool,
  7180. sizeof(VSP_DIFF_AREA_FILE), VOLSNAP_TAG_DIFF_FILE);
  7181. if (!diffAreaFile) {
  7182. VspRelease(Extension->Root);
  7183. status = STATUS_INSUFFICIENT_RESOURCES;
  7184. goto Cleanup;
  7185. }
  7186. RtlZeroMemory(diffAreaFile, sizeof(VSP_DIFF_AREA_FILE));
  7187. diffAreaFile->Extension = Extension;
  7188. diffAreaFile->Filter = filter->DiffAreaVolume;
  7189. diffAreaFile->AllocatedFileSize = InitialDiffAreaAllocation;
  7190. Extension->DiffAreaFile = diffAreaFile;
  7191. InitializeListHead(&diffAreaFile->UnusedAllocationList);
  7192. if (Extension->IsPersistent) {
  7193. diffAreaFile->TableUpdateIrp =
  7194. IoAllocateIrp((CCHAR) Extension->Root->StackSize, FALSE);
  7195. if (!diffAreaFile->TableUpdateIrp) {
  7196. Extension->DiffAreaFile = NULL;
  7197. ExFreePool(diffAreaFile);
  7198. VspRelease(Extension->Root);
  7199. status = STATUS_INSUFFICIENT_RESOURCES;
  7200. goto Cleanup;
  7201. }
  7202. buf = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  7203. VOLSNAP_TAG_BUFFER);
  7204. if (!buf) {
  7205. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  7206. Extension->DiffAreaFile = NULL;
  7207. ExFreePool(diffAreaFile);
  7208. VspRelease(Extension->Root);
  7209. status = STATUS_INSUFFICIENT_RESOURCES;
  7210. goto Cleanup;
  7211. }
  7212. RtlZeroMemory(buf, BLOCK_SIZE);
  7213. mdl = IoAllocateMdl(buf, BLOCK_SIZE, FALSE, FALSE, NULL);
  7214. if (!mdl) {
  7215. ExFreePool(buf);
  7216. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  7217. Extension->DiffAreaFile = NULL;
  7218. ExFreePool(diffAreaFile);
  7219. VspRelease(Extension->Root);
  7220. status = STATUS_INSUFFICIENT_RESOURCES;
  7221. goto Cleanup;
  7222. }
  7223. MmBuildMdlForNonPagedPool(mdl);
  7224. diffAreaFile->TableUpdateIrp->MdlAddress = mdl;
  7225. InitializeListHead(&diffAreaFile->TableUpdateQueue);
  7226. }
  7227. VspRelease(Extension->Root);
  7228. KeAcquireSpinLock(&filter->SpinLock, &irql);
  7229. filter->AllocatedVolumeSpace += diffAreaFile->AllocatedFileSize;
  7230. KeReleaseSpinLock(&filter->SpinLock, irql);
  7231. diffAreaSpaceDeleted = 0;
  7232. for (;;) {
  7233. status = VspOpenDiffAreaFile(diffAreaFile, TRUE);
  7234. if (status != STATUS_DISK_FULL) {
  7235. break;
  7236. }
  7237. if (diffAreaSpaceDeleted >= 2*InitialDiffAreaAllocation) {
  7238. status = VspOpenDiffAreaFile(diffAreaFile, FALSE);
  7239. break;
  7240. }
  7241. status = VspTrimOlderSnapshotBeforeCreate(filter,
  7242. &diffAreaSpaceDeleted);
  7243. if (!NT_SUCCESS(status)) {
  7244. status = VspOpenDiffAreaFile(diffAreaFile, FALSE);
  7245. break;
  7246. }
  7247. }
  7248. if (!NT_SUCCESS(status)) {
  7249. goto Cleanup;
  7250. }
  7251. return status;
  7252. Cleanup:
  7253. if (Extension->DiffAreaFile) {
  7254. diffAreaFile = Extension->DiffAreaFile;
  7255. Extension->DiffAreaFile = NULL;
  7256. if (diffAreaFile->FileHandle) {
  7257. ZwClose(diffAreaFile->FileHandle);
  7258. }
  7259. KeAcquireSpinLock(&filter->SpinLock, &irql);
  7260. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  7261. KeReleaseSpinLock(&filter->SpinLock, irql);
  7262. if (diffAreaFile->TableUpdateIrp) {
  7263. ExFreePool(MmGetMdlVirtualAddress(
  7264. diffAreaFile->TableUpdateIrp->MdlAddress));
  7265. IoFreeMdl(diffAreaFile->TableUpdateIrp->MdlAddress);
  7266. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  7267. }
  7268. ASSERT(!diffAreaFile->FilterListEntryBeingUsed);
  7269. ExFreePool(diffAreaFile);
  7270. }
  7271. return status;
  7272. }
  7273. VOID
  7274. VspDeleteInitialDiffAreaFile(
  7275. IN PVOLUME_EXTENSION Extension
  7276. )
  7277. {
  7278. PFILTER_EXTENSION filter = Extension->Filter;
  7279. PLIST_ENTRY l, ll;
  7280. PVSP_DIFF_AREA_FILE diffAreaFile;
  7281. KIRQL irql;
  7282. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  7283. diffAreaFile = Extension->DiffAreaFile;
  7284. Extension->DiffAreaFile = NULL;
  7285. ASSERT(diffAreaFile);
  7286. if (diffAreaFile->FileHandle) {
  7287. ZwClose(diffAreaFile->FileHandle);
  7288. }
  7289. KeAcquireSpinLock(&filter->SpinLock, &irql);
  7290. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  7291. filter->UsedVolumeSpace -= diffAreaFile->NextAvailable;
  7292. KeReleaseSpinLock(&filter->SpinLock, irql);
  7293. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  7294. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  7295. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  7296. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  7297. ExFreePool(diffAreaFileAllocation);
  7298. }
  7299. KeAcquireSpinLock(&diffAreaFile->Filter->SpinLock, &irql);
  7300. if (diffAreaFile->FilterListEntryBeingUsed) {
  7301. RemoveEntryList(&diffAreaFile->FilterListEntry);
  7302. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  7303. }
  7304. KeReleaseSpinLock(&diffAreaFile->Filter->SpinLock, irql);
  7305. if (diffAreaFile->TableUpdateIrp) {
  7306. ExFreePool(MmGetMdlVirtualAddress(
  7307. diffAreaFile->TableUpdateIrp->MdlAddress));
  7308. IoFreeMdl(diffAreaFile->TableUpdateIrp->MdlAddress);
  7309. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  7310. diffAreaFile->TableUpdateIrp = NULL;
  7311. }
  7312. ExFreePool(diffAreaFile);
  7313. }
  7314. VOID
  7315. VspDiffAreaFillCompletion(
  7316. IN PVOID Context
  7317. )
  7318. {
  7319. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  7320. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  7321. KeSetEvent(&context->GrowDiffArea.Event, IO_NO_INCREMENT, FALSE);
  7322. }
  7323. NTSTATUS
  7324. VspMarkFileAllocationInBitmap(
  7325. IN PVOLUME_EXTENSION Extension,
  7326. IN HANDLE FileHandle,
  7327. IN PVSP_DIFF_AREA_FILE DiffAreaFile,
  7328. IN PRTL_BITMAP BitmapToSet
  7329. )
  7330. {
  7331. NTSTATUS status;
  7332. BOOLEAN isNtfs;
  7333. IO_STATUS_BLOCK ioStatus;
  7334. FILE_FS_SIZE_INFORMATION fsSize;
  7335. ULONG bpc;
  7336. STARTING_VCN_INPUT_BUFFER input;
  7337. RETRIEVAL_POINTERS_BUFFER output;
  7338. LONGLONG start, length, end, roundedStart, roundedEnd, s;
  7339. ULONG startBit, numBits, i;
  7340. KIRQL irql;
  7341. PVOLUME_EXTENSION bitmapExtension;
  7342. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  7343. BOOLEAN isNegative;
  7344. PVSP_CONTEXT context;
  7345. status = VspIsNtfs(FileHandle, &isNtfs);
  7346. if (!NT_SUCCESS(status) || !isNtfs) {
  7347. return status;
  7348. }
  7349. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  7350. &fsSize, sizeof(fsSize),
  7351. FileFsSizeInformation);
  7352. if (!NT_SUCCESS(status)) {
  7353. return status;
  7354. }
  7355. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  7356. input.StartingVcn.QuadPart = 0;
  7357. for (;;) {
  7358. status = ZwFsControlFile(FileHandle, NULL, NULL, NULL, &ioStatus,
  7359. FSCTL_GET_RETRIEVAL_POINTERS, &input,
  7360. sizeof(input), &output, sizeof(output));
  7361. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
  7362. if (status == STATUS_END_OF_FILE) {
  7363. status = STATUS_SUCCESS;
  7364. }
  7365. break;
  7366. }
  7367. if (!output.ExtentCount) {
  7368. if (DiffAreaFile) {
  7369. status = STATUS_INVALID_PARAMETER;
  7370. } else {
  7371. status = STATUS_SUCCESS;
  7372. }
  7373. break;
  7374. }
  7375. if (output.Extents[0].Lcn.QuadPart == -1) {
  7376. ASSERT(!DiffAreaFile);
  7377. if (status != STATUS_BUFFER_OVERFLOW) {
  7378. break;
  7379. }
  7380. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  7381. continue;
  7382. }
  7383. start = output.Extents[0].Lcn.QuadPart*bpc;
  7384. length = output.Extents[0].NextVcn.QuadPart -
  7385. output.StartingVcn.QuadPart;
  7386. length *= bpc;
  7387. end = start + length;
  7388. roundedStart = start&(~(BLOCK_SIZE - 1));
  7389. roundedEnd = end&(~(BLOCK_SIZE - 1));
  7390. if (start != roundedStart) {
  7391. roundedStart += BLOCK_SIZE;
  7392. }
  7393. if (DiffAreaFile) {
  7394. if (IsListEmpty(&DiffAreaFile->Filter->VolumeList)) {
  7395. bitmapExtension = NULL;
  7396. } else {
  7397. bitmapExtension = CONTAINING_RECORD(
  7398. DiffAreaFile->Filter->VolumeList.Blink,
  7399. VOLUME_EXTENSION, ListEntry);
  7400. if (bitmapExtension->IsDead) {
  7401. bitmapExtension = NULL;
  7402. }
  7403. }
  7404. if (roundedStart > start) {
  7405. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  7406. ExAllocatePoolWithTag(NonPagedPool,
  7407. sizeof(DIFF_AREA_FILE_ALLOCATION),
  7408. VOLSNAP_TAG_BIT_HISTORY);
  7409. if (!diffAreaFileAllocation) {
  7410. status = STATUS_INSUFFICIENT_RESOURCES;
  7411. break;
  7412. }
  7413. diffAreaFileAllocation->Offset = start;
  7414. diffAreaFileAllocation->NLength = -(roundedStart - start);
  7415. if (roundedStart > end) {
  7416. diffAreaFileAllocation->NLength += roundedStart - end;
  7417. }
  7418. ASSERT(diffAreaFileAllocation->NLength);
  7419. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  7420. &diffAreaFileAllocation->ListEntry);
  7421. }
  7422. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  7423. ExAllocatePoolWithTag(NonPagedPool,
  7424. sizeof(DIFF_AREA_FILE_ALLOCATION),
  7425. VOLSNAP_TAG_BIT_HISTORY);
  7426. if (!diffAreaFileAllocation) {
  7427. status = STATUS_INSUFFICIENT_RESOURCES;
  7428. break;
  7429. }
  7430. diffAreaFileAllocation->Offset = roundedStart;
  7431. diffAreaFileAllocation->NLength = 0;
  7432. for (s = roundedStart; s < roundedEnd; s += BLOCK_SIZE) {
  7433. isNegative = FALSE;
  7434. if (bitmapExtension) {
  7435. KeAcquireSpinLock(&bitmapExtension->SpinLock, &irql);
  7436. if (bitmapExtension->VolumeBlockBitmap &&
  7437. !RtlCheckBit(bitmapExtension->VolumeBlockBitmap,
  7438. s>>BLOCK_SHIFT)) {
  7439. isNegative = TRUE;
  7440. }
  7441. KeReleaseSpinLock(&bitmapExtension->SpinLock, irql);
  7442. }
  7443. if (isNegative) {
  7444. if (diffAreaFileAllocation->NLength <= 0) {
  7445. diffAreaFileAllocation->NLength -= BLOCK_SIZE;
  7446. } else {
  7447. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  7448. &diffAreaFileAllocation->ListEntry);
  7449. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  7450. ExAllocatePoolWithTag(NonPagedPool,
  7451. sizeof(DIFF_AREA_FILE_ALLOCATION),
  7452. VOLSNAP_TAG_BIT_HISTORY);
  7453. if (!diffAreaFileAllocation) {
  7454. return STATUS_INSUFFICIENT_RESOURCES;
  7455. }
  7456. diffAreaFileAllocation->Offset = s;
  7457. diffAreaFileAllocation->NLength = -BLOCK_SIZE;
  7458. }
  7459. } else {
  7460. if (diffAreaFileAllocation->NLength >= 0) {
  7461. diffAreaFileAllocation->NLength += BLOCK_SIZE;
  7462. } else {
  7463. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  7464. &diffAreaFileAllocation->ListEntry);
  7465. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  7466. ExAllocatePoolWithTag(NonPagedPool,
  7467. sizeof(DIFF_AREA_FILE_ALLOCATION),
  7468. VOLSNAP_TAG_BIT_HISTORY);
  7469. if (!diffAreaFileAllocation) {
  7470. return STATUS_INSUFFICIENT_RESOURCES;
  7471. }
  7472. diffAreaFileAllocation->Offset = s;
  7473. diffAreaFileAllocation->NLength = BLOCK_SIZE;
  7474. }
  7475. }
  7476. }
  7477. if (diffAreaFileAllocation->NLength) {
  7478. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  7479. &diffAreaFileAllocation->ListEntry);
  7480. } else {
  7481. ExFreePool(diffAreaFileAllocation);
  7482. }
  7483. if (end > roundedEnd && roundedEnd >= roundedStart) {
  7484. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  7485. ExAllocatePoolWithTag(NonPagedPool,
  7486. sizeof(DIFF_AREA_FILE_ALLOCATION),
  7487. VOLSNAP_TAG_BIT_HISTORY);
  7488. if (!diffAreaFileAllocation) {
  7489. status = STATUS_INSUFFICIENT_RESOURCES;
  7490. break;
  7491. }
  7492. diffAreaFileAllocation->Offset = roundedEnd;
  7493. diffAreaFileAllocation->NLength = -(end - roundedEnd);
  7494. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  7495. &diffAreaFileAllocation->ListEntry);
  7496. }
  7497. if (status != STATUS_BUFFER_OVERFLOW) {
  7498. break;
  7499. }
  7500. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  7501. continue;
  7502. }
  7503. if (roundedStart >= roundedEnd) {
  7504. if (status != STATUS_BUFFER_OVERFLOW) {
  7505. break;
  7506. }
  7507. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  7508. continue;
  7509. }
  7510. startBit = (ULONG) (roundedStart>>BLOCK_SHIFT);
  7511. numBits = (ULONG) ((roundedEnd - roundedStart)>>BLOCK_SHIFT);
  7512. if (BitmapToSet) {
  7513. RtlSetBits(BitmapToSet, startBit, numBits);
  7514. } else {
  7515. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  7516. if (Extension->VolumeBlockBitmap) {
  7517. if (Extension->IgnorableProduct) {
  7518. for (i = 0; i < numBits; i++) {
  7519. if (RtlCheckBit(Extension->IgnorableProduct,
  7520. i + startBit)) {
  7521. RtlSetBit(Extension->VolumeBlockBitmap,
  7522. i + startBit);
  7523. }
  7524. }
  7525. } else {
  7526. RtlSetBits(Extension->VolumeBlockBitmap, startBit,
  7527. numBits);
  7528. }
  7529. }
  7530. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7531. }
  7532. if (status != STATUS_BUFFER_OVERFLOW) {
  7533. break;
  7534. }
  7535. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  7536. }
  7537. if (DiffAreaFile && Extension->IsPersistent &&
  7538. !Extension->NoDiffAreaFill) {
  7539. context = VspAllocateContext(Extension->Root);
  7540. if (!context) {
  7541. return STATUS_INSUFFICIENT_RESOURCES;
  7542. }
  7543. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  7544. ExInitializeWorkItem(&context->WorkItem, VspDiffAreaFillCompletion,
  7545. context);
  7546. context->GrowDiffArea.Extension = Extension;
  7547. context->GrowDiffArea.ExtentList = DiffAreaFile->UnusedAllocationList;
  7548. ASSERT(!IsListEmpty(&DiffAreaFile->UnusedAllocationList));
  7549. context->GrowDiffArea.ExtentList.Flink->Blink =
  7550. &context->GrowDiffArea.ExtentList;
  7551. context->GrowDiffArea.ExtentList.Blink->Flink =
  7552. &context->GrowDiffArea.ExtentList;
  7553. KeInitializeSpinLock(&context->GrowDiffArea.SpinLock);
  7554. context->GrowDiffArea.CurrentEntry =
  7555. context->GrowDiffArea.ExtentList.Flink;
  7556. context->GrowDiffArea.CurrentEntryOffset = 0;
  7557. context->GrowDiffArea.TargetObject =
  7558. DiffAreaFile->Filter->TargetObject;
  7559. ObReferenceObject(context->GrowDiffArea.TargetObject);
  7560. KeInitializeEvent(&context->GrowDiffArea.Event, NotificationEvent,
  7561. FALSE);
  7562. VspLaunchDiffAreaFill(context);
  7563. KeWaitForSingleObject(&context->GrowDiffArea.Event, Executive,
  7564. KernelMode, FALSE, NULL);
  7565. DiffAreaFile->UnusedAllocationList.Blink->Flink =
  7566. &DiffAreaFile->UnusedAllocationList;
  7567. DiffAreaFile->UnusedAllocationList.Flink->Blink =
  7568. &DiffAreaFile->UnusedAllocationList;
  7569. VspReleaseNonPagedResource(Extension);
  7570. status = context->GrowDiffArea.ResultStatus;
  7571. VspFreeContext(Extension->Root, context);
  7572. }
  7573. return status;
  7574. }
  7575. NTSTATUS
  7576. VspSetDiffAreaBlocksInBitmap(
  7577. IN PVOLUME_EXTENSION Extension
  7578. )
  7579. {
  7580. PVSP_DIFF_AREA_FILE diffAreaFile;
  7581. PFILTER_EXTENSION diffAreaFilter;
  7582. KIRQL irql;
  7583. NTSTATUS status, status2;
  7584. PLIST_ENTRY l;
  7585. diffAreaFile = Extension->DiffAreaFile;
  7586. ASSERT(diffAreaFile);
  7587. diffAreaFilter = diffAreaFile->Filter;
  7588. KeAcquireSpinLock(&diffAreaFilter->SpinLock, &irql);
  7589. ASSERT(!diffAreaFile->FilterListEntryBeingUsed);
  7590. InsertTailList(&diffAreaFilter->DiffAreaFilesOnThisFilter,
  7591. &diffAreaFile->FilterListEntry);
  7592. diffAreaFile->FilterListEntryBeingUsed = TRUE;
  7593. KeReleaseSpinLock(&diffAreaFilter->SpinLock, irql);
  7594. status = VspMarkFileAllocationInBitmap(Extension,
  7595. diffAreaFile->FileHandle,
  7596. diffAreaFile, NULL);
  7597. if (!NT_SUCCESS(status)) {
  7598. VspLogError(Extension, diffAreaFilter, VS_CANT_MAP_DIFF_AREA_FILE,
  7599. status, 0, FALSE);
  7600. KeAcquireSpinLock(&diffAreaFilter->SpinLock, &irql);
  7601. RemoveEntryList(&diffAreaFile->FilterListEntry);
  7602. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  7603. KeReleaseSpinLock(&diffAreaFilter->SpinLock, irql);
  7604. return status;
  7605. }
  7606. return STATUS_SUCCESS;
  7607. }
  7608. NTSTATUS
  7609. VspCreateInitialHeap(
  7610. IN PVOLUME_EXTENSION Extension,
  7611. IN BOOLEAN CallerHoldingSemaphore
  7612. )
  7613. {
  7614. PVSP_CONTEXT context;
  7615. NTSTATUS status;
  7616. context = VspAllocateContext(Extension->Root);
  7617. if (!context) {
  7618. return STATUS_INSUFFICIENT_RESOURCES;
  7619. }
  7620. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  7621. context->Extension.Extension = Extension;
  7622. if (CallerHoldingSemaphore) {
  7623. context->Extension.Irp = (PIRP) 1;
  7624. } else {
  7625. context->Extension.Irp = NULL;
  7626. }
  7627. ObReferenceObject(Extension->DeviceObject);
  7628. VspCreateHeap(context);
  7629. if (!Extension->NextDiffAreaFileMap) {
  7630. return STATUS_INSUFFICIENT_RESOURCES;
  7631. }
  7632. ASSERT(!Extension->DiffAreaFileMap);
  7633. Extension->DiffAreaFileMap = Extension->NextDiffAreaFileMap;
  7634. Extension->DiffAreaFileMapSize = Extension->NextDiffAreaFileMapSize;
  7635. Extension->NextAvailable = 0;
  7636. Extension->NextDiffAreaFileMap = NULL;
  7637. context = VspAllocateContext(Extension->Root);
  7638. if (!context) {
  7639. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  7640. Extension->DiffAreaFileMap);
  7641. ASSERT(NT_SUCCESS(status));
  7642. Extension->DiffAreaFileMap = NULL;
  7643. return STATUS_INSUFFICIENT_RESOURCES;
  7644. }
  7645. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  7646. context->Extension.Extension = Extension;
  7647. if (CallerHoldingSemaphore) {
  7648. context->Extension.Irp = (PIRP) 1;
  7649. } else {
  7650. context->Extension.Irp = NULL;
  7651. }
  7652. ObReferenceObject(Extension->DeviceObject);
  7653. VspCreateHeap(context);
  7654. if (!Extension->NextDiffAreaFileMap) {
  7655. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  7656. Extension->DiffAreaFileMap);
  7657. ASSERT(NT_SUCCESS(status));
  7658. Extension->DiffAreaFileMap = NULL;
  7659. return STATUS_INSUFFICIENT_RESOURCES;
  7660. }
  7661. return STATUS_SUCCESS;
  7662. }
  7663. NTSTATUS
  7664. VspReadInitialBitmap(
  7665. IN PVOLUME_EXTENSION Extension,
  7666. IN OUT PRTL_BITMAP Bitmap
  7667. )
  7668. {
  7669. PVOID buffer;
  7670. PMDL mdl;
  7671. PIRP irp;
  7672. LONGLONG offset;
  7673. PDEVICE_OBJECT targetObject;
  7674. NTSTATUS status;
  7675. PVSP_BLOCK_INITIAL_BITMAP initialBitmap;
  7676. LONGLONG bytesCopied, bytesToCopy, totalBytesToCopy;
  7677. buffer = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  7678. VOLSNAP_TAG_BUFFER);
  7679. if (!buffer) {
  7680. return STATUS_INSUFFICIENT_RESOURCES;
  7681. }
  7682. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  7683. if (!mdl) {
  7684. ExFreePool(buffer);
  7685. return STATUS_INSUFFICIENT_RESOURCES;
  7686. }
  7687. irp = IoAllocateIrp((CCHAR) Extension->Root->StackSize, FALSE);
  7688. if (!irp) {
  7689. IoFreeMdl(mdl);
  7690. ExFreePool(buffer);
  7691. return STATUS_INSUFFICIENT_RESOURCES;
  7692. }
  7693. irp->MdlAddress = mdl;
  7694. MmBuildMdlForNonPagedPool(mdl);
  7695. offset = Extension->DiffAreaFile->InitialBitmapVolumeOffset;
  7696. targetObject = Extension->DiffAreaFile->Filter->TargetObject;
  7697. status = STATUS_UNSUCCESSFUL;
  7698. initialBitmap = (PVSP_BLOCK_INITIAL_BITMAP) buffer;
  7699. bytesCopied = 0;
  7700. totalBytesToCopy = (Bitmap->SizeOfBitMap + 7)/8;
  7701. while (offset) {
  7702. status = VspSynchronousIo(irp, targetObject, IRP_MJ_READ, offset, 0);
  7703. if (!NT_SUCCESS(status)) {
  7704. break;
  7705. }
  7706. if (!IsEqualGUID(initialBitmap->Header.Signature,
  7707. VSP_DIFF_AREA_FILE_GUID) ||
  7708. initialBitmap->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  7709. initialBitmap->Header.BlockType != VSP_BLOCK_TYPE_INITIAL_BITMAP ||
  7710. initialBitmap->Header.ThisVolumeOffset != offset ||
  7711. initialBitmap->Header.NextVolumeOffset == offset) {
  7712. status = STATUS_INVALID_PARAMETER;
  7713. break;
  7714. }
  7715. bytesToCopy = (BLOCK_SIZE - VSP_OFFSET_TO_START_OF_BITMAP);
  7716. if (bytesToCopy + bytesCopied > totalBytesToCopy) {
  7717. bytesToCopy = totalBytesToCopy - bytesCopied;
  7718. }
  7719. RtlCopyMemory((PCHAR) Bitmap->Buffer + bytesCopied,
  7720. (PCHAR) initialBitmap + VSP_OFFSET_TO_START_OF_BITMAP,
  7721. (ULONG) bytesToCopy);
  7722. bytesCopied += bytesToCopy;
  7723. offset = initialBitmap->Header.NextVolumeOffset;
  7724. }
  7725. ExFreePool(buffer);
  7726. IoFreeMdl(mdl);
  7727. IoFreeIrp(irp);
  7728. return status;
  7729. }
  7730. VOID
  7731. VspWriteInitialBitmap(
  7732. IN PVOLUME_EXTENSION Extension,
  7733. IN OUT PRTL_BITMAP Bitmap
  7734. )
  7735. {
  7736. ULONG numBytesPerBlock, bitmapBytes, numBlocks, i;
  7737. PLONGLONG volumeOffset, fileOffset;
  7738. PVOID buffer;
  7739. PMDL mdl;
  7740. PIRP irp;
  7741. NTSTATUS status;
  7742. PVSP_BLOCK_INITIAL_BITMAP initialBitmap;
  7743. ULONG bytesCopied, bytesToCopy;
  7744. PDEVICE_OBJECT targetObject;
  7745. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  7746. PVSP_CONTROL_ITEM_DIFF_AREA diffAreaControlItem;
  7747. numBytesPerBlock = BLOCK_SIZE - VSP_OFFSET_TO_START_OF_BITMAP;
  7748. bitmapBytes = (Bitmap->SizeOfBitMap + 7)/8;
  7749. numBlocks = (bitmapBytes + numBytesPerBlock - 1)/numBytesPerBlock;
  7750. ASSERT(numBlocks);
  7751. volumeOffset = (PLONGLONG)
  7752. ExAllocatePoolWithTag(NonPagedPool,
  7753. numBlocks*sizeof(LONGLONG),
  7754. VOLSNAP_TAG_SHORT_TERM);
  7755. if (!volumeOffset) {
  7756. return;
  7757. }
  7758. fileOffset = (PLONGLONG)
  7759. ExAllocatePoolWithTag(NonPagedPool,
  7760. numBlocks*sizeof(LONGLONG),
  7761. VOLSNAP_TAG_SHORT_TERM);
  7762. if (!fileOffset) {
  7763. ExFreePool(volumeOffset);
  7764. return;
  7765. }
  7766. buffer = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  7767. VOLSNAP_TAG_BUFFER);
  7768. if (!buffer) {
  7769. ExFreePool(fileOffset);
  7770. ExFreePool(volumeOffset);
  7771. return;
  7772. }
  7773. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  7774. if (!mdl) {
  7775. ExFreePool(buffer);
  7776. ExFreePool(fileOffset);
  7777. ExFreePool(volumeOffset);
  7778. return;
  7779. }
  7780. irp = IoAllocateIrp((CCHAR) Extension->Root->StackSize, FALSE);
  7781. if (!irp) {
  7782. IoFreeMdl(mdl);
  7783. ExFreePool(buffer);
  7784. ExFreePool(fileOffset);
  7785. ExFreePool(volumeOffset);
  7786. return;
  7787. }
  7788. irp->MdlAddress = mdl;
  7789. MmBuildMdlForNonPagedPool(mdl);
  7790. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  7791. for (i = 0; i < numBlocks; i++) {
  7792. status = VspAllocateDiffAreaSpace(Extension, &volumeOffset[i],
  7793. &fileOffset[i], NULL, NULL);
  7794. if (!NT_SUCCESS(status)) {
  7795. break;
  7796. }
  7797. }
  7798. if (i < numBlocks) {
  7799. goto Cleanup;
  7800. }
  7801. initialBitmap = (PVSP_BLOCK_INITIAL_BITMAP) buffer;
  7802. bytesCopied = 0;
  7803. targetObject = Extension->DiffAreaFile->Filter->TargetObject;
  7804. for (i = 0; i < numBlocks; i++) {
  7805. RtlZeroMemory(initialBitmap, BLOCK_SIZE);
  7806. initialBitmap->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  7807. initialBitmap->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  7808. initialBitmap->Header.BlockType = VSP_BLOCK_TYPE_INITIAL_BITMAP;
  7809. initialBitmap->Header.ThisFileOffset = fileOffset[i];
  7810. initialBitmap->Header.ThisVolumeOffset = volumeOffset[i];
  7811. if (i + 1 < numBlocks) {
  7812. initialBitmap->Header.NextVolumeOffset = volumeOffset[i + 1];
  7813. } else {
  7814. initialBitmap->Header.NextVolumeOffset = 0;
  7815. }
  7816. bytesToCopy = (BLOCK_SIZE - VSP_OFFSET_TO_START_OF_BITMAP);
  7817. if (bytesToCopy + bytesCopied > bitmapBytes) {
  7818. bytesToCopy = bitmapBytes - bytesCopied;
  7819. }
  7820. RtlCopyMemory((PCHAR) initialBitmap + VSP_OFFSET_TO_START_OF_BITMAP,
  7821. (PCHAR) Bitmap->Buffer + bytesCopied,
  7822. (ULONG) bytesToCopy);
  7823. bytesCopied += bytesToCopy;
  7824. status = VspSynchronousIo(irp, targetObject, IRP_MJ_WRITE,
  7825. volumeOffset[i], 0);
  7826. if (!NT_SUCCESS(status)) {
  7827. goto Cleanup;
  7828. }
  7829. }
  7830. status = VspIoControlItem(Extension->DiffAreaFile->Filter,
  7831. VSP_CONTROL_ITEM_TYPE_DIFF_AREA,
  7832. &Extension->SnapshotGuid, FALSE,
  7833. controlItemBuffer, FALSE);
  7834. if (!NT_SUCCESS(status)) {
  7835. goto Cleanup;
  7836. }
  7837. diffAreaControlItem = (PVSP_CONTROL_ITEM_DIFF_AREA) controlItemBuffer;
  7838. diffAreaControlItem->InitialBitmapVolumeOffset = volumeOffset[0];
  7839. status = VspIoControlItem(Extension->DiffAreaFile->Filter,
  7840. VSP_CONTROL_ITEM_TYPE_DIFF_AREA,
  7841. &Extension->SnapshotGuid, TRUE,
  7842. controlItemBuffer, FALSE);
  7843. if (!NT_SUCCESS(status)) {
  7844. goto Cleanup;
  7845. }
  7846. Extension->DiffAreaFile->InitialBitmapVolumeOffset = volumeOffset[0];
  7847. Cleanup:
  7848. VspReleaseNonPagedResource(Extension);
  7849. IoFreeIrp(irp);
  7850. IoFreeMdl(mdl);
  7851. ExFreePool(buffer);
  7852. ExFreePool(fileOffset);
  7853. ExFreePool(volumeOffset);
  7854. }
  7855. VOID
  7856. VspSetOfflineBit(
  7857. IN PVOLUME_EXTENSION Extension,
  7858. IN BOOLEAN BitState
  7859. )
  7860. {
  7861. NTSTATUS status;
  7862. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  7863. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  7864. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  7865. if (Extension->IsOffline) {
  7866. if (BitState) {
  7867. VspReleaseNonPagedResource(Extension);
  7868. return;
  7869. }
  7870. InterlockedExchange(&Extension->IsOffline, FALSE);
  7871. } else {
  7872. if (!BitState) {
  7873. VspReleaseNonPagedResource(Extension);
  7874. return;
  7875. }
  7876. InterlockedExchange(&Extension->IsOffline, TRUE);
  7877. }
  7878. if (!Extension->IsPersistent) {
  7879. VspReleaseNonPagedResource(Extension);
  7880. return;
  7881. }
  7882. status = VspIoControlItem(Extension->Filter,
  7883. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  7884. &Extension->SnapshotGuid, FALSE,
  7885. controlItemBuffer, FALSE);
  7886. if (!NT_SUCCESS(status)) {
  7887. ASSERT(FALSE);
  7888. VspReleaseNonPagedResource(Extension);
  7889. return;
  7890. }
  7891. if (BitState) {
  7892. snapshotControlItem->SnapshotControlItemFlags |=
  7893. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_OFFLINE;
  7894. } else {
  7895. snapshotControlItem->SnapshotControlItemFlags &=
  7896. ~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_OFFLINE;
  7897. }
  7898. status = VspIoControlItem(Extension->Filter,
  7899. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  7900. &Extension->SnapshotGuid, TRUE,
  7901. controlItemBuffer, FALSE);
  7902. ASSERT(NT_SUCCESS(status));
  7903. VspReleaseNonPagedResource(Extension);
  7904. }
  7905. NTSTATUS
  7906. VspComputeIgnorableBitmap(
  7907. IN PVOLUME_EXTENSION Extension,
  7908. IN OUT PRTL_BITMAP Bitmap
  7909. )
  7910. {
  7911. PFILTER_EXTENSION filter = Extension->Filter;
  7912. KIRQL irql;
  7913. ULONG bitmapSize;
  7914. PVOID bitmapBuffer;
  7915. RTL_BITMAP bitmap;
  7916. WCHAR nameBuffer[150];
  7917. UNICODE_STRING name, guidString;
  7918. OBJECT_ATTRIBUTES oa;
  7919. NTSTATUS status;
  7920. HANDLE h, fileHandle;
  7921. IO_STATUS_BLOCK ioStatus;
  7922. CHAR buffer[200];
  7923. PFILE_NAMES_INFORMATION fileNamesInfo;
  7924. BOOLEAN restartScan, moveEntries;
  7925. PLIST_ENTRY l;
  7926. PVOLUME_EXTENSION e;
  7927. PTRANSLATION_TABLE_ENTRY p;
  7928. VspAcquire(Extension->Root);
  7929. if (Extension->IsDead) {
  7930. VspRelease(Extension->Root);
  7931. return STATUS_UNSUCCESSFUL;
  7932. }
  7933. if (Bitmap) {
  7934. bitmapBuffer = NULL;
  7935. } else {
  7936. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  7937. if (!Extension->VolumeBlockBitmap) {
  7938. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7939. VspRelease(Extension->Root);
  7940. return STATUS_INVALID_PARAMETER;
  7941. }
  7942. bitmapSize = Extension->VolumeBlockBitmap->SizeOfBitMap;
  7943. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7944. bitmapBuffer = ExAllocatePoolWithTag(
  7945. NonPagedPool, (bitmapSize + 8*sizeof(ULONG) - 1)/
  7946. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  7947. if (!bitmapBuffer) {
  7948. VspRelease(Extension->Root);
  7949. return STATUS_INSUFFICIENT_RESOURCES;
  7950. }
  7951. RtlInitializeBitMap(&bitmap, (PULONG) bitmapBuffer, bitmapSize);
  7952. RtlClearAllBits(&bitmap);
  7953. Bitmap = &bitmap;
  7954. }
  7955. if (Extension->DiffAreaFile->InitialBitmapVolumeOffset) {
  7956. status = VspReadInitialBitmap(Extension, Bitmap);
  7957. if (NT_SUCCESS(status)) {
  7958. goto AddInTable;
  7959. }
  7960. RtlClearAllBits(Bitmap);
  7961. }
  7962. VspRelease(Extension->Root);
  7963. if (Extension->IsOffline) {
  7964. VspSetOfflineBit(Extension, FALSE);
  7965. }
  7966. swprintf(nameBuffer,
  7967. L"\\Device\\HarddiskVolumeShadowCopy%d\\pagefile.sys",
  7968. Extension->VolumeNumber);
  7969. RtlInitUnicodeString(&name, nameBuffer);
  7970. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  7971. OBJ_KERNEL_HANDLE, NULL, NULL);
  7972. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  7973. FILE_SHARE_READ | FILE_SHARE_WRITE |
  7974. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  7975. if (NT_SUCCESS(status)) {
  7976. if (!VspHasStrongAcl(h, &status)) {
  7977. ZwClose(h);
  7978. }
  7979. }
  7980. if (NT_SUCCESS(status)) {
  7981. VspMarkFileAllocationInBitmap(NULL, h, NULL, Bitmap);
  7982. ZwClose(h);
  7983. }
  7984. swprintf(nameBuffer,
  7985. L"\\Device\\HarddiskVolumeShadowCopy%d\\hiberfil.sys",
  7986. Extension->VolumeNumber);
  7987. RtlInitUnicodeString(&name, nameBuffer);
  7988. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  7989. OBJ_KERNEL_HANDLE, NULL, NULL);
  7990. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  7991. FILE_SHARE_READ | FILE_SHARE_WRITE |
  7992. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  7993. if (NT_SUCCESS(status)) {
  7994. if (!VspHasStrongAcl(h, &status)) {
  7995. ZwClose(h);
  7996. }
  7997. }
  7998. if (NT_SUCCESS(status)) {
  7999. VspMarkFileAllocationInBitmap(NULL, h, NULL, Bitmap);
  8000. ZwClose(h);
  8001. }
  8002. swprintf(nameBuffer,
  8003. L"\\Device\\HarddiskVolumeShadowCopy%d\\System Volume Information\\",
  8004. Extension->VolumeNumber);
  8005. RtlInitUnicodeString(&name, nameBuffer);
  8006. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  8007. OBJ_KERNEL_HANDLE, NULL, NULL);
  8008. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa,
  8009. &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  8010. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  8011. if (!NT_SUCCESS(status)) {
  8012. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  8013. status = STATUS_SUCCESS;
  8014. }
  8015. if (bitmapBuffer) {
  8016. ExFreePool(bitmapBuffer);
  8017. }
  8018. return status;
  8019. }
  8020. status = RtlStringFromGUID(VSP_DIFF_AREA_FILE_GUID, &guidString);
  8021. if (!NT_SUCCESS(status)) {
  8022. ZwClose(h);
  8023. if (bitmapBuffer) {
  8024. ExFreePool(bitmapBuffer);
  8025. }
  8026. return status;
  8027. }
  8028. name.Buffer = nameBuffer;
  8029. name.Length = sizeof(WCHAR) + guidString.Length;
  8030. name.MaximumLength = name.Length + sizeof(WCHAR);
  8031. name.Buffer[0] = '*';
  8032. RtlCopyMemory(&name.Buffer[1], guidString.Buffer, guidString.Length);
  8033. name.Buffer[name.Length/sizeof(WCHAR)] = 0;
  8034. ExFreePool(guidString.Buffer);
  8035. fileNamesInfo = (PFILE_NAMES_INFORMATION) buffer;
  8036. restartScan = TRUE;
  8037. for (;;) {
  8038. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  8039. fileNamesInfo, 200,
  8040. FileNamesInformation, TRUE,
  8041. restartScan ? &name : NULL,
  8042. restartScan);
  8043. restartScan = FALSE;
  8044. if (!NT_SUCCESS(status)) {
  8045. break;
  8046. }
  8047. name.Length = name.MaximumLength =
  8048. (USHORT) fileNamesInfo->FileNameLength;
  8049. name.Buffer = fileNamesInfo->FileName;
  8050. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  8051. OBJ_KERNEL_HANDLE, h, NULL);
  8052. status = ZwOpenFile(&fileHandle, FILE_GENERIC_READ, &oa, &ioStatus,
  8053. FILE_SHARE_DELETE | FILE_SHARE_READ |
  8054. FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
  8055. if (!NT_SUCCESS(status)) {
  8056. continue;
  8057. }
  8058. VspMarkFileAllocationInBitmap(NULL, fileHandle, NULL, Bitmap);
  8059. ZwClose(fileHandle);
  8060. }
  8061. ZwClose(h);
  8062. status = VspMarkFreeSpaceInBitmap(Extension, NULL, Bitmap);
  8063. if (!NT_SUCCESS(status)) {
  8064. if (bitmapBuffer) {
  8065. ExFreePool(bitmapBuffer);
  8066. }
  8067. return status;
  8068. }
  8069. VspAcquire(Extension->Root);
  8070. if (Extension->IsDead) {
  8071. VspRelease(Extension->Root);
  8072. if (bitmapBuffer) {
  8073. ExFreePool(bitmapBuffer);
  8074. }
  8075. return STATUS_UNSUCCESSFUL;
  8076. }
  8077. if (Extension->IsPersistent) {
  8078. VspWriteInitialBitmap(Extension, Bitmap);
  8079. }
  8080. AddInTable:
  8081. for (l = &Extension->ListEntry; l != &filter->VolumeList; l = l->Flink) {
  8082. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  8083. VspAcquirePagedResource(e, NULL);
  8084. moveEntries = FALSE;
  8085. _try {
  8086. p = (PTRANSLATION_TABLE_ENTRY)
  8087. RtlEnumerateGenericTable(&e->VolumeBlockTable, TRUE);
  8088. while (p) {
  8089. RtlSetBit(Bitmap, (ULONG) (p->VolumeOffset>>BLOCK_SHIFT));
  8090. if (p->Flags&VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY) {
  8091. moveEntries = TRUE;
  8092. }
  8093. p = (PTRANSLATION_TABLE_ENTRY)
  8094. RtlEnumerateGenericTable(&e->VolumeBlockTable, FALSE);
  8095. }
  8096. if (moveEntries) {
  8097. p = (PTRANSLATION_TABLE_ENTRY)
  8098. RtlEnumerateGenericTable(&e->VolumeBlockTable, TRUE);
  8099. while (p) {
  8100. if (p->Flags&VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY) {
  8101. RtlClearBit(Bitmap,
  8102. (ULONG) (p->TargetOffset>>BLOCK_SHIFT));
  8103. }
  8104. p = (PTRANSLATION_TABLE_ENTRY)
  8105. RtlEnumerateGenericTable(&e->VolumeBlockTable, FALSE);
  8106. }
  8107. }
  8108. } _except (EXCEPTION_EXECUTE_HANDLER) {
  8109. status = GetExceptionCode();
  8110. }
  8111. VspReleasePagedResource(e);
  8112. if (!NT_SUCCESS(status)) {
  8113. break;
  8114. }
  8115. }
  8116. VspRelease(Extension->Root);
  8117. if (bitmapBuffer) {
  8118. ExFreePool(bitmapBuffer);
  8119. }
  8120. return status;
  8121. }
  8122. VOID
  8123. VspAndBitmaps(
  8124. IN OUT PRTL_BITMAP BaseBitmap,
  8125. IN PRTL_BITMAP FactorBitmap
  8126. )
  8127. {
  8128. ULONG n, i;
  8129. PULONG p, q;
  8130. n = (BaseBitmap->SizeOfBitMap + 8*sizeof(ULONG) - 1)/(8*sizeof(ULONG));
  8131. p = BaseBitmap->Buffer;
  8132. q = FactorBitmap->Buffer;
  8133. for (i = 0; i < n; i++) {
  8134. *p++ &= *q++;
  8135. }
  8136. }
  8137. NTSTATUS
  8138. VspComputeIgnorableProduct(
  8139. IN PVOLUME_EXTENSION Extension
  8140. )
  8141. {
  8142. PFILTER_EXTENSION filter = Extension->Filter;
  8143. ULONG bitmapSize;
  8144. PVOID bitmapBuffer;
  8145. RTL_BITMAP bitmap;
  8146. ULONG i, j;
  8147. PLIST_ENTRY l;
  8148. PVOLUME_EXTENSION e;
  8149. NTSTATUS status;
  8150. KIRQL irql;
  8151. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8152. if (!Extension->IgnorableProduct) {
  8153. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8154. return STATUS_INVALID_PARAMETER;
  8155. }
  8156. bitmapSize = Extension->IgnorableProduct->SizeOfBitMap;
  8157. RtlSetAllBits(Extension->IgnorableProduct);
  8158. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8159. bitmapBuffer = ExAllocatePoolWithTag(
  8160. NonPagedPool, (bitmapSize + 8*sizeof(ULONG) - 1)/
  8161. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  8162. if (!bitmapBuffer) {
  8163. return STATUS_INSUFFICIENT_RESOURCES;
  8164. }
  8165. RtlInitializeBitMap(&bitmap, (PULONG) bitmapBuffer, bitmapSize);
  8166. for (i = 1; ; i++) {
  8167. RtlClearAllBits(&bitmap);
  8168. VspAcquire(Extension->Root);
  8169. l = filter->VolumeList.Blink;
  8170. if (l != &Extension->ListEntry) {
  8171. VspRelease(Extension->Root);
  8172. ExFreePool(bitmapBuffer);
  8173. return STATUS_INVALID_PARAMETER;
  8174. }
  8175. j = 0;
  8176. for (;;) {
  8177. if (l == &filter->VolumeList) {
  8178. break;
  8179. }
  8180. j++;
  8181. if (j == i) {
  8182. break;
  8183. }
  8184. l = l->Blink;
  8185. }
  8186. if (j < i) {
  8187. VspRelease(Extension->Root);
  8188. break;
  8189. }
  8190. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  8191. ObReferenceObject(e->DeviceObject);
  8192. VspRelease(Extension->Root);
  8193. status = VspComputeIgnorableBitmap(e, &bitmap);
  8194. if (!NT_SUCCESS(status)) {
  8195. VspAcquire(Extension->Root);
  8196. if (e->IsDead) {
  8197. VspRelease(Extension->Root);
  8198. ObDereferenceObject(e->DeviceObject);
  8199. ExFreePool(bitmapBuffer);
  8200. return STATUS_SUCCESS;
  8201. }
  8202. VspRelease(Extension->Root);
  8203. ObDereferenceObject(e->DeviceObject);
  8204. ExFreePool(bitmapBuffer);
  8205. return status;
  8206. }
  8207. ObDereferenceObject(e->DeviceObject);
  8208. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8209. if (Extension->IgnorableProduct) {
  8210. VspAndBitmaps(Extension->IgnorableProduct, &bitmap);
  8211. }
  8212. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8213. }
  8214. ExFreePool(bitmapBuffer);
  8215. return STATUS_SUCCESS;
  8216. }
  8217. VOID
  8218. VspQueryMinimumDiffAreaFileSize(
  8219. IN PDO_EXTENSION RootExtension,
  8220. OUT PLONGLONG MinDiffAreaFileSize
  8221. )
  8222. {
  8223. ULONG zero, size;
  8224. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  8225. NTSTATUS status;
  8226. zero = 0;
  8227. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  8228. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  8229. queryTable[0].Name = L"MinDiffAreaFileSize";
  8230. queryTable[0].EntryContext = &size;
  8231. queryTable[0].DefaultType = REG_DWORD;
  8232. queryTable[0].DefaultData = &zero;
  8233. queryTable[0].DefaultLength = sizeof(ULONG);
  8234. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  8235. RootExtension->RegistryPath.Buffer,
  8236. queryTable, NULL, NULL);
  8237. if (!NT_SUCCESS(status)) {
  8238. size = zero;
  8239. }
  8240. *MinDiffAreaFileSize = ((LONGLONG) size)*1024*1024;
  8241. }
  8242. NTSTATUS
  8243. VspCreateStartBlock(
  8244. IN PFILTER_EXTENSION Filter,
  8245. IN LONGLONG ControlBlockOffset,
  8246. IN LONGLONG MaximumDiffAreaSpace
  8247. )
  8248. /*++
  8249. Routine Description:
  8250. This routine creates the start block in the NTFS boot code.
  8251. Arguments:
  8252. Filter - Supplies the filter extension.
  8253. Return Value:
  8254. NTSTATUS
  8255. --*/
  8256. {
  8257. PVOID buffer;
  8258. KEVENT event;
  8259. LARGE_INTEGER byteOffset;
  8260. PIRP irp;
  8261. IO_STATUS_BLOCK ioStatus;
  8262. NTSTATUS status;
  8263. PVSP_BLOCK_START startBlock;
  8264. buffer = ExAllocatePoolWithTag(NonPagedPool, BYTES_IN_BOOT_AREA >
  8265. PAGE_SIZE ? BYTES_IN_BOOT_AREA :
  8266. PAGE_SIZE, VOLSNAP_TAG_BUFFER);
  8267. if (!buffer) {
  8268. return STATUS_INSUFFICIENT_RESOURCES;
  8269. }
  8270. KeInitializeEvent(&event, NotificationEvent, FALSE);
  8271. byteOffset.QuadPart = 0;
  8272. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, Filter->TargetObject,
  8273. buffer, BYTES_IN_BOOT_AREA,
  8274. &byteOffset, &event, &ioStatus);
  8275. if (!irp) {
  8276. ExFreePool(buffer);
  8277. return STATUS_INSUFFICIENT_RESOURCES;
  8278. }
  8279. status = IoCallDriver(Filter->TargetObject, irp);
  8280. if (status == STATUS_PENDING) {
  8281. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  8282. status = ioStatus.Status;
  8283. }
  8284. if (!NT_SUCCESS(status)) {
  8285. ExFreePool(buffer);
  8286. return status;
  8287. }
  8288. if (!VspIsNtfsBootSector(Filter, buffer)) {
  8289. ExFreePool(buffer);
  8290. return STATUS_SUCCESS;
  8291. }
  8292. startBlock = (PVSP_BLOCK_START) ((PCHAR) buffer +
  8293. VSP_START_BLOCK_OFFSET);
  8294. if (ControlBlockOffset || MaximumDiffAreaSpace) {
  8295. startBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  8296. startBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  8297. startBlock->Header.BlockType = VSP_BLOCK_TYPE_START;
  8298. startBlock->Header.ThisFileOffset = VSP_START_BLOCK_OFFSET;
  8299. startBlock->Header.ThisVolumeOffset = VSP_START_BLOCK_OFFSET;
  8300. startBlock->Header.NextVolumeOffset = 0;
  8301. startBlock->FirstControlBlockVolumeOffset = ControlBlockOffset;
  8302. startBlock->MaximumDiffAreaSpace = MaximumDiffAreaSpace;
  8303. } else {
  8304. RtlZeroMemory(startBlock, sizeof(VSP_BLOCK_START));
  8305. }
  8306. KeInitializeEvent(&event, NotificationEvent, FALSE);
  8307. byteOffset.QuadPart = 0;
  8308. irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, Filter->TargetObject,
  8309. buffer, BYTES_IN_BOOT_AREA,
  8310. &byteOffset, &event, &ioStatus);
  8311. if (!irp) {
  8312. ExFreePool(buffer);
  8313. return STATUS_INSUFFICIENT_RESOURCES;
  8314. }
  8315. status = IoCallDriver(Filter->TargetObject, irp);
  8316. if (status == STATUS_PENDING) {
  8317. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  8318. status = ioStatus.Status;
  8319. }
  8320. ExFreePool(buffer);
  8321. return status;
  8322. }
  8323. VOID
  8324. VspCreateSnapshotOnDiskIrp(
  8325. IN PFILTER_EXTENSION Filter
  8326. )
  8327. {
  8328. PVOID buffer;
  8329. PMDL mdl;
  8330. ASSERT(!Filter->SnapshotOnDiskIrp);
  8331. buffer = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  8332. VOLSNAP_TAG_BUFFER);
  8333. if (!buffer) {
  8334. return;
  8335. }
  8336. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  8337. if (!mdl) {
  8338. ExFreePool(buffer);
  8339. return;
  8340. }
  8341. MmBuildMdlForNonPagedPool(mdl);
  8342. Filter->SnapshotOnDiskIrp = IoAllocateIrp(
  8343. (CCHAR) Filter->Root->StackSize, FALSE);
  8344. if (!Filter->SnapshotOnDiskIrp) {
  8345. IoFreeMdl(mdl);
  8346. ExFreePool(buffer);
  8347. return;
  8348. }
  8349. Filter->SnapshotOnDiskIrp->MdlAddress = mdl;
  8350. }
  8351. NTSTATUS
  8352. VspCreateInitialControlBlockFile(
  8353. IN PFILTER_EXTENSION Filter
  8354. )
  8355. /*++
  8356. Routine Description:
  8357. This routine creates the initial control block file on the given filter.
  8358. Arguments:
  8359. Filter - Supplies the filter extension.
  8360. Return Value:
  8361. NTSTATUS
  8362. --*/
  8363. {
  8364. NTSTATUS status;
  8365. UNICODE_STRING fileName;
  8366. PWCHAR star;
  8367. OBJECT_ATTRIBUTES oa;
  8368. LARGE_INTEGER fileSize;
  8369. HANDLE h;
  8370. IO_STATUS_BLOCK ioStatus;
  8371. LIST_ENTRY extentList;
  8372. PLIST_ENTRY l;
  8373. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  8374. PVSP_BLOCK_CONTROL controlBlock;
  8375. PVOLUME_EXTENSION bitmapExtension;
  8376. LONGLONG lastVolumeOffset;
  8377. BOOLEAN isNtfs;
  8378. PSECURITY_DESCRIPTOR securityDescriptor;
  8379. PACL acl;
  8380. status = VspCreateDiffAreaFileName(Filter->TargetObject, NULL, &fileName,
  8381. TRUE, NULL);
  8382. if (!NT_SUCCESS(status)) {
  8383. return status;
  8384. }
  8385. star = fileName.Buffer + fileName.Length/sizeof(WCHAR) - 39;
  8386. RtlMoveMemory(star, star + 1, 38*sizeof(WCHAR));
  8387. fileName.Length -= sizeof(WCHAR);
  8388. fileName.Buffer[fileName.Length/sizeof(WCHAR)] = 0;
  8389. status = VspCreateSecurityDescriptor(&securityDescriptor, &acl);
  8390. if (!NT_SUCCESS(status)) {
  8391. ExFreePool(fileName.Buffer);
  8392. return status;
  8393. }
  8394. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  8395. OBJ_KERNEL_HANDLE, NULL, securityDescriptor);
  8396. fileSize.QuadPart = LARGEST_NTFS_CLUSTER;
  8397. ASSERT(LARGEST_NTFS_CLUSTER >= BLOCK_SIZE);
  8398. KeWaitForSingleObject(&Filter->ControlBlockFileHandleReady, Executive,
  8399. KernelMode, FALSE, NULL);
  8400. status = ZwCreateFile(&h, FILE_GENERIC_READ |
  8401. FILE_GENERIC_WRITE, &oa, &ioStatus,
  8402. &fileSize, FILE_ATTRIBUTE_HIDDEN |
  8403. FILE_ATTRIBUTE_SYSTEM, 0, FILE_OVERWRITE_IF,
  8404. FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT |
  8405. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  8406. FILE_NO_COMPRESSION, NULL, 0);
  8407. ExFreePool(fileName.Buffer);
  8408. if (!NT_SUCCESS(status)) {
  8409. return status;
  8410. }
  8411. status = VspSetFileSize(h, fileSize.QuadPart);
  8412. if (!NT_SUCCESS(status)) {
  8413. ZwClose(h);
  8414. return status;
  8415. }
  8416. status = VspIsNtfs(h, &isNtfs);
  8417. if (!NT_SUCCESS(status) || !isNtfs) {
  8418. ZwClose(h);
  8419. return STATUS_INVALID_PARAMETER;
  8420. }
  8421. VspAcquire(Filter->Root);
  8422. if (!IsListEmpty(&Filter->VolumeList)) {
  8423. bitmapExtension = CONTAINING_RECORD(Filter->VolumeList.Blink,
  8424. VOLUME_EXTENSION, ListEntry);
  8425. ObReferenceObject(bitmapExtension->DeviceObject);
  8426. } else {
  8427. bitmapExtension = NULL;
  8428. }
  8429. VspRelease(Filter->Root);
  8430. status = VspOptimizeDiffAreaFileLocation(Filter, h, bitmapExtension, 0,
  8431. LARGEST_NTFS_CLUSTER);
  8432. if (!NT_SUCCESS(status)) {
  8433. if (bitmapExtension) {
  8434. ObDereferenceObject(bitmapExtension->DeviceObject);
  8435. }
  8436. ZwClose(h);
  8437. return status;
  8438. }
  8439. status = VspPinFile(Filter->TargetObject, h);
  8440. if (!NT_SUCCESS(status)) {
  8441. if (bitmapExtension) {
  8442. ObDereferenceObject(bitmapExtension->DeviceObject);
  8443. }
  8444. ZwClose(h);
  8445. return status;
  8446. }
  8447. status = VspQueryListOfExtents(h, 0, &extentList, bitmapExtension, FALSE);
  8448. if (bitmapExtension) {
  8449. ObDereferenceObject(bitmapExtension->DeviceObject);
  8450. }
  8451. if (!NT_SUCCESS(status)) {
  8452. ZwClose(h);
  8453. return status;
  8454. }
  8455. for (l = extentList.Flink; l != &extentList; l = l->Flink) {
  8456. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8457. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8458. if (diffAreaFileAllocation->NLength < 0) {
  8459. ZwClose(h);
  8460. return STATUS_INSUFFICIENT_RESOURCES;
  8461. }
  8462. }
  8463. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  8464. if (!Filter->SnapshotOnDiskIrp) {
  8465. VspCreateSnapshotOnDiskIrp(Filter);
  8466. if (!Filter->SnapshotOnDiskIrp) {
  8467. VspReleaseNonPagedResource(Filter);
  8468. while (!IsListEmpty(&extentList)) {
  8469. l = RemoveHeadList(&extentList);
  8470. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8471. DIFF_AREA_FILE_ALLOCATION,
  8472. ListEntry);
  8473. ExFreePool(diffAreaFileAllocation);
  8474. }
  8475. ZwClose(h);
  8476. return STATUS_INSUFFICIENT_RESOURCES;
  8477. }
  8478. }
  8479. controlBlock = (PVSP_BLOCK_CONTROL) MmGetMdlVirtualAddress(
  8480. Filter->SnapshotOnDiskIrp->MdlAddress);
  8481. RtlZeroMemory(controlBlock, BLOCK_SIZE);
  8482. controlBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  8483. controlBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  8484. controlBlock->Header.BlockType = VSP_BLOCK_TYPE_CONTROL;
  8485. controlBlock->Header.ThisFileOffset = LARGEST_NTFS_CLUSTER;
  8486. lastVolumeOffset = 0;
  8487. l = extentList.Blink;
  8488. while (l != &extentList) {
  8489. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8490. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8491. if (!diffAreaFileAllocation->NLength) {
  8492. l = l->Blink;
  8493. continue;
  8494. }
  8495. diffAreaFileAllocation->NLength -= BLOCK_SIZE;
  8496. controlBlock->Header.ThisFileOffset -= BLOCK_SIZE;
  8497. controlBlock->Header.ThisVolumeOffset =
  8498. diffAreaFileAllocation->Offset + diffAreaFileAllocation->NLength;
  8499. controlBlock->Header.NextVolumeOffset = lastVolumeOffset;
  8500. lastVolumeOffset = controlBlock->Header.ThisVolumeOffset;
  8501. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8502. Filter->TargetObject, IRP_MJ_WRITE,
  8503. controlBlock->Header.ThisVolumeOffset, 0);
  8504. if (!NT_SUCCESS(status)) {
  8505. VspReleaseNonPagedResource(Filter);
  8506. while (!IsListEmpty(&extentList)) {
  8507. l = RemoveHeadList(&extentList);
  8508. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8509. DIFF_AREA_FILE_ALLOCATION,
  8510. ListEntry);
  8511. ExFreePool(diffAreaFileAllocation);
  8512. }
  8513. ZwClose(h);
  8514. return status;
  8515. }
  8516. }
  8517. VspReleaseNonPagedResource(Filter);
  8518. diffAreaFileAllocation = CONTAINING_RECORD(extentList.Flink,
  8519. DIFF_AREA_FILE_ALLOCATION,
  8520. ListEntry);
  8521. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  8522. status = VspCreateStartBlock(Filter, diffAreaFileAllocation->Offset,
  8523. Filter->MaximumVolumeSpace);
  8524. if (!NT_SUCCESS(status)) {
  8525. VspReleaseNonPagedResource(Filter);
  8526. while (!IsListEmpty(&extentList)) {
  8527. l = RemoveHeadList(&extentList);
  8528. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8529. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8530. ExFreePool(diffAreaFileAllocation);
  8531. }
  8532. ZwClose(h);
  8533. return status;
  8534. }
  8535. ASSERT(!Filter->ControlBlockFileHandle);
  8536. Filter->FirstControlBlockVolumeOffset = diffAreaFileAllocation->Offset;
  8537. VspReleaseNonPagedResource(Filter);
  8538. InterlockedExchangePointer(&Filter->ControlBlockFileHandle, h);
  8539. VspAcquire(Filter->Root);
  8540. if (Filter->IsRemoved) {
  8541. VspRelease(Filter->Root);
  8542. h = InterlockedExchangePointer(&Filter->ControlBlockFileHandle,
  8543. NULL);
  8544. if (h) {
  8545. ZwClose(h);
  8546. }
  8547. }
  8548. VspRelease(Filter->Root);
  8549. while (!IsListEmpty(&extentList)) {
  8550. l = RemoveHeadList(&extentList);
  8551. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8552. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8553. ExFreePool(diffAreaFileAllocation);
  8554. }
  8555. return STATUS_SUCCESS;
  8556. }
  8557. NTSTATUS
  8558. VspAddControlBlocks(
  8559. IN PFILTER_EXTENSION Filter,
  8560. IN LONGLONG OffsetOfLastControlBlock
  8561. )
  8562. /*++
  8563. Routine Description:
  8564. This routine adds new control blocks to the control block list.
  8565. Arguments:
  8566. Filter - Supplies the filter extension.
  8567. OffsetOfLastControlBlock - Supplies the offset of the last control
  8568. block.
  8569. Return Value:
  8570. NTSTATUS
  8571. --*/
  8572. {
  8573. HANDLE handle;
  8574. NTSTATUS status;
  8575. LONGLONG fileSize;
  8576. PVOLUME_EXTENSION extension;
  8577. LIST_ENTRY extentList;
  8578. PLIST_ENTRY l;
  8579. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  8580. PVSP_BLOCK_CONTROL controlBlock;
  8581. handle = Filter->ControlBlockFileHandle;
  8582. if (!handle) {
  8583. return STATUS_INVALID_PARAMETER;
  8584. }
  8585. status = VspQueryFileSize(handle, &fileSize);
  8586. if (!NT_SUCCESS(status)) {
  8587. return status;
  8588. }
  8589. ASSERT(fileSize);
  8590. for (;;) {
  8591. status = VspSetFileSize(handle, fileSize + LARGEST_NTFS_CLUSTER);
  8592. if (!NT_SUCCESS(status)) {
  8593. return status;
  8594. }
  8595. VspAcquire(Filter->Root);
  8596. if (IsListEmpty(&Filter->VolumeList)) {
  8597. extension = NULL;
  8598. } else {
  8599. extension = CONTAINING_RECORD(Filter->VolumeList.Blink,
  8600. VOLUME_EXTENSION, ListEntry);
  8601. if (extension->IsDead) {
  8602. extension = NULL;
  8603. } else {
  8604. ObReferenceObject(extension->DeviceObject);
  8605. }
  8606. }
  8607. VspRelease(Filter->Root);
  8608. VspOptimizeDiffAreaFileLocation(Filter, handle, extension, fileSize,
  8609. fileSize + LARGEST_NTFS_CLUSTER);
  8610. status = VspQueryListOfExtents(handle, fileSize, &extentList,
  8611. extension, FALSE);
  8612. if (extension) {
  8613. ObDereferenceObject(extension->DeviceObject);
  8614. }
  8615. if (!NT_SUCCESS(status)) {
  8616. return status;
  8617. }
  8618. for (l = extentList.Flink; l != &extentList; l = l->Flink) {
  8619. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8620. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8621. if (diffAreaFileAllocation->NLength > 0) {
  8622. break;
  8623. }
  8624. }
  8625. if (l != &extentList) {
  8626. break;
  8627. }
  8628. while (!IsListEmpty(&extentList)) {
  8629. l = RemoveHeadList(&extentList);
  8630. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8631. DIFF_AREA_FILE_ALLOCATION,
  8632. ListEntry);
  8633. ExFreePool(diffAreaFileAllocation);
  8634. }
  8635. fileSize += LARGEST_NTFS_CLUSTER;
  8636. }
  8637. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  8638. if (!Filter->SnapshotOnDiskIrp) {
  8639. VspReleaseNonPagedResource(Filter);
  8640. return STATUS_INVALID_PARAMETER;
  8641. }
  8642. controlBlock = (PVSP_BLOCK_CONTROL) MmGetMdlVirtualAddress(
  8643. Filter->SnapshotOnDiskIrp->MdlAddress);
  8644. l = extentList.Flink;
  8645. while (l != &extentList) {
  8646. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8647. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  8648. if (diffAreaFileAllocation->NLength <= 0) {
  8649. l = l->Flink;
  8650. fileSize -= diffAreaFileAllocation->NLength;
  8651. continue;
  8652. }
  8653. RtlZeroMemory(controlBlock, BLOCK_SIZE);
  8654. controlBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  8655. controlBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  8656. controlBlock->Header.BlockType = VSP_BLOCK_TYPE_CONTROL;
  8657. controlBlock->Header.ThisFileOffset = fileSize;
  8658. controlBlock->Header.ThisVolumeOffset =
  8659. diffAreaFileAllocation->Offset;
  8660. controlBlock->Header.NextVolumeOffset = 0;
  8661. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8662. Filter->TargetObject, IRP_MJ_WRITE,
  8663. controlBlock->Header.ThisVolumeOffset, 0);
  8664. if (!NT_SUCCESS(status)) {
  8665. break;
  8666. }
  8667. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8668. Filter->TargetObject, IRP_MJ_READ,
  8669. OffsetOfLastControlBlock, 0);
  8670. if (!NT_SUCCESS(status)) {
  8671. break;
  8672. }
  8673. controlBlock->Header.NextVolumeOffset =
  8674. diffAreaFileAllocation->Offset;
  8675. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8676. Filter->TargetObject, IRP_MJ_WRITE,
  8677. controlBlock->Header.ThisVolumeOffset, 0);
  8678. if (!NT_SUCCESS(status)) {
  8679. break;
  8680. }
  8681. OffsetOfLastControlBlock = diffAreaFileAllocation->Offset;
  8682. diffAreaFileAllocation->NLength -= BLOCK_SIZE;
  8683. diffAreaFileAllocation->Offset += BLOCK_SIZE;
  8684. fileSize += BLOCK_SIZE;
  8685. }
  8686. VspReleaseNonPagedResource(Filter);
  8687. while (!IsListEmpty(&extentList)) {
  8688. l = RemoveHeadList(&extentList);
  8689. diffAreaFileAllocation = CONTAINING_RECORD(l,
  8690. DIFF_AREA_FILE_ALLOCATION,
  8691. ListEntry);
  8692. ExFreePool(diffAreaFileAllocation);
  8693. }
  8694. return status;
  8695. }
  8696. NTSTATUS
  8697. VspAddControlItemInfoToLookupTable(
  8698. IN PFILTER_EXTENSION Filter,
  8699. IN PVSP_CONTROL_ITEM_SNAPSHOT ControlItem,
  8700. IN PBOOLEAN IsComplete
  8701. )
  8702. {
  8703. PVSP_CONTROL_ITEM_DIFF_AREA diffAreaControlItem;
  8704. VSP_LOOKUP_TABLE_ENTRY lookupEntryBuffer;
  8705. PVSP_LOOKUP_TABLE_ENTRY lookupEntry, le;
  8706. PLIST_ENTRY l;
  8707. if (IsComplete) {
  8708. *IsComplete = FALSE;
  8709. }
  8710. if (ControlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  8711. if (ControlItem->Reserved || ControlItem->VolumeSnapshotSize <= 0 ||
  8712. ControlItem->SnapshotOrderNumber < 0 ||
  8713. (ControlItem->SnapshotControlItemFlags&
  8714. (~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_ALL))) {
  8715. return STATUS_INVALID_PARAMETER;
  8716. }
  8717. } else if (ControlItem->ControlItemType ==
  8718. VSP_CONTROL_ITEM_TYPE_DIFF_AREA) {
  8719. diffAreaControlItem = (PVSP_CONTROL_ITEM_DIFF_AREA) ControlItem;
  8720. if (diffAreaControlItem->Reserved ||
  8721. diffAreaControlItem->DiffAreaStartingVolumeOffset <= 0 ||
  8722. (diffAreaControlItem->DiffAreaStartingVolumeOffset&
  8723. (BLOCK_SIZE - 1)) ||
  8724. diffAreaControlItem->ApplicationInfoStartingVolumeOffset <= 0 ||
  8725. (diffAreaControlItem->ApplicationInfoStartingVolumeOffset&
  8726. (BLOCK_SIZE - 1)) ||
  8727. diffAreaControlItem->DiffAreaLocationDescriptionVolumeOffset <= 0 ||
  8728. (diffAreaControlItem->DiffAreaLocationDescriptionVolumeOffset&
  8729. (BLOCK_SIZE - 1)) ||
  8730. diffAreaControlItem->InitialBitmapVolumeOffset < 0 ||
  8731. (diffAreaControlItem->InitialBitmapVolumeOffset&(BLOCK_SIZE - 1))) {
  8732. return STATUS_INVALID_PARAMETER;
  8733. }
  8734. } else {
  8735. return STATUS_INVALID_PARAMETER;
  8736. }
  8737. RtlZeroMemory(&lookupEntryBuffer, sizeof(lookupEntryBuffer));
  8738. lookupEntryBuffer.SnapshotGuid = ControlItem->SnapshotGuid;
  8739. KeWaitForSingleObject(&Filter->Root->LookupTableMutex, Executive,
  8740. KernelMode, FALSE, NULL);
  8741. lookupEntry = (PVSP_LOOKUP_TABLE_ENTRY)
  8742. RtlLookupElementGenericTable(
  8743. &Filter->Root->PersistentSnapshotLookupTable,
  8744. &lookupEntryBuffer);
  8745. if (!lookupEntry) {
  8746. lookupEntry = (PVSP_LOOKUP_TABLE_ENTRY)
  8747. RtlInsertElementGenericTable(
  8748. &Filter->Root->PersistentSnapshotLookupTable,
  8749. &lookupEntryBuffer, sizeof(lookupEntryBuffer),
  8750. NULL);
  8751. if (!lookupEntry) {
  8752. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8753. return STATUS_INSUFFICIENT_RESOURCES;
  8754. }
  8755. }
  8756. if (ControlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  8757. if (lookupEntry->SnapshotFilter) {
  8758. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8759. return STATUS_UNSUCCESSFUL;
  8760. }
  8761. lookupEntry->SnapshotFilter = Filter;
  8762. lookupEntry->VolumeSnapshotSize = ControlItem->VolumeSnapshotSize;
  8763. lookupEntry->SnapshotOrderNumber = ControlItem->SnapshotOrderNumber;
  8764. lookupEntry->SnapshotControlItemFlags =
  8765. ControlItem->SnapshotControlItemFlags;
  8766. lookupEntry->SnapshotTime = ControlItem->SnapshotTime;
  8767. for (l = Filter->SnapshotLookupTableEntries.Flink;
  8768. l != &Filter->SnapshotLookupTableEntries; l = l->Flink) {
  8769. le = CONTAINING_RECORD(l, VSP_LOOKUP_TABLE_ENTRY,
  8770. SnapshotFilterListEntry);
  8771. if (le->SnapshotOrderNumber > lookupEntry->SnapshotOrderNumber) {
  8772. break;
  8773. }
  8774. }
  8775. InsertTailList(l, &lookupEntry->SnapshotFilterListEntry);
  8776. if (lookupEntry->DiffAreaFilter && IsComplete) {
  8777. *IsComplete = TRUE;
  8778. }
  8779. } else {
  8780. ASSERT(ControlItem->ControlItemType ==
  8781. VSP_CONTROL_ITEM_TYPE_DIFF_AREA);
  8782. if (lookupEntry->DiffAreaFilter) {
  8783. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8784. return STATUS_UNSUCCESSFUL;
  8785. }
  8786. lookupEntry->DiffAreaFilter = Filter;
  8787. lookupEntry->DiffAreaStartingVolumeOffset =
  8788. ((PVSP_CONTROL_ITEM_DIFF_AREA) ControlItem)->
  8789. DiffAreaStartingVolumeOffset;
  8790. lookupEntry->ApplicationInfoStartingVolumeOffset =
  8791. ((PVSP_CONTROL_ITEM_DIFF_AREA) ControlItem)->
  8792. ApplicationInfoStartingVolumeOffset;
  8793. lookupEntry->DiffAreaLocationDescriptionVolumeOffset =
  8794. ((PVSP_CONTROL_ITEM_DIFF_AREA) ControlItem)->
  8795. DiffAreaLocationDescriptionVolumeOffset;
  8796. lookupEntry->InitialBitmapVolumeOffset =
  8797. ((PVSP_CONTROL_ITEM_DIFF_AREA) ControlItem)->
  8798. InitialBitmapVolumeOffset;
  8799. InsertTailList(&Filter->DiffAreaLookupTableEntries,
  8800. &lookupEntry->DiffAreaFilterListEntry);
  8801. if (lookupEntry->SnapshotFilter && IsComplete) {
  8802. *IsComplete = TRUE;
  8803. }
  8804. }
  8805. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8806. return STATUS_SUCCESS;
  8807. }
  8808. VOID
  8809. VspRemoveControlItemInfoFromLookupTable(
  8810. IN PFILTER_EXTENSION Filter,
  8811. IN PVSP_CONTROL_ITEM_SNAPSHOT ControlItem
  8812. )
  8813. {
  8814. VSP_LOOKUP_TABLE_ENTRY lookupEntryBuffer;
  8815. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  8816. lookupEntryBuffer.SnapshotGuid = ControlItem->SnapshotGuid;
  8817. KeWaitForSingleObject(&Filter->Root->LookupTableMutex, Executive,
  8818. KernelMode, FALSE, NULL);
  8819. lookupEntry = (PVSP_LOOKUP_TABLE_ENTRY)
  8820. RtlLookupElementGenericTable(
  8821. &Filter->Root->PersistentSnapshotLookupTable,
  8822. &lookupEntryBuffer);
  8823. if (!lookupEntry) {
  8824. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8825. return;
  8826. }
  8827. if (ControlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  8828. ASSERT(lookupEntry->SnapshotFilter == Filter);
  8829. lookupEntry->SnapshotFilter = NULL;
  8830. RemoveEntryList(&lookupEntry->SnapshotFilterListEntry);
  8831. } else {
  8832. ASSERT(ControlItem->ControlItemType ==
  8833. VSP_CONTROL_ITEM_TYPE_DIFF_AREA);
  8834. ASSERT(lookupEntry->DiffAreaFilter == Filter);
  8835. lookupEntry->DiffAreaFilter = NULL;
  8836. RemoveEntryList(&lookupEntry->DiffAreaFilterListEntry);
  8837. if (lookupEntry->DiffAreaHandle) {
  8838. ZwClose(lookupEntry->DiffAreaHandle);
  8839. lookupEntry->DiffAreaHandle = NULL;
  8840. }
  8841. }
  8842. if (!lookupEntry->SnapshotFilter && !lookupEntry->DiffAreaFilter) {
  8843. ASSERT(!lookupEntry->DiffAreaHandle);
  8844. RtlDeleteElementGenericTable(
  8845. &Filter->Root->PersistentSnapshotLookupTable, lookupEntry);
  8846. }
  8847. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  8848. }
  8849. PVSP_LOOKUP_TABLE_ENTRY
  8850. VspFindLookupTableItem(
  8851. IN PDO_EXTENSION RootExtension,
  8852. IN GUID* SnapshotGuid
  8853. )
  8854. {
  8855. VSP_LOOKUP_TABLE_ENTRY lookupEntryBuffer;
  8856. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  8857. lookupEntryBuffer.SnapshotGuid = *SnapshotGuid;
  8858. KeWaitForSingleObject(&RootExtension->LookupTableMutex, Executive,
  8859. KernelMode, FALSE, NULL);
  8860. lookupEntry = (PVSP_LOOKUP_TABLE_ENTRY)
  8861. RtlLookupElementGenericTable(
  8862. &RootExtension->PersistentSnapshotLookupTable,
  8863. &lookupEntryBuffer);
  8864. KeReleaseMutex(&RootExtension->LookupTableMutex, FALSE);
  8865. return lookupEntry;
  8866. }
  8867. VOID
  8868. VspCloseHandlesWorker(
  8869. IN PVOID Context
  8870. )
  8871. {
  8872. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  8873. PFILTER_EXTENSION filter = context->CloseHandles.Filter;
  8874. ASSERT(context->Type == VSP_CONTEXT_TYPE_CLOSE_HANDLES);
  8875. if (context->CloseHandles.Handle1) {
  8876. ZwClose(context->CloseHandles.Handle1);
  8877. }
  8878. if (context->CloseHandles.Handle2) {
  8879. ZwClose(context->CloseHandles.Handle2);
  8880. }
  8881. KeSetEvent(&filter->ControlBlockFileHandleReady, IO_NO_INCREMENT, FALSE);
  8882. VspFreeContext(filter->Root, context);
  8883. ObDereferenceObject(filter->DeviceObject);
  8884. }
  8885. NTSTATUS
  8886. VspDeleteControlItemsWithGuid(
  8887. IN PFILTER_EXTENSION Filter,
  8888. IN GUID* SnapshotGuid,
  8889. IN BOOLEAN NonPagedResourceHeld
  8890. )
  8891. /*++
  8892. Routine Description:
  8893. This routine adds a control item to the given master control block on
  8894. the given filter.
  8895. Arguments:
  8896. Filter - Supplies the filter extension.
  8897. ControlItem - Supplies the control item.
  8898. Return Value:
  8899. NTSTATUS
  8900. --*/
  8901. {
  8902. PVSP_BLOCK_CONTROL controlBlock;
  8903. LONGLONG byteOffset;
  8904. NTSTATUS status;
  8905. BOOLEAN needWrite, itemsLeft;
  8906. ULONG offset;
  8907. PVSP_CONTROL_ITEM_SNAPSHOT controlItem;
  8908. HANDLE h, hh;
  8909. PVSP_CONTEXT context;
  8910. if (!NonPagedResourceHeld) {
  8911. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  8912. }
  8913. if (!Filter->FirstControlBlockVolumeOffset) {
  8914. if (!NonPagedResourceHeld) {
  8915. VspReleaseNonPagedResource(Filter);
  8916. }
  8917. return STATUS_SUCCESS;
  8918. }
  8919. ASSERT(Filter->SnapshotOnDiskIrp);
  8920. controlBlock = (PVSP_BLOCK_CONTROL) MmGetMdlVirtualAddress(
  8921. Filter->SnapshotOnDiskIrp->MdlAddress);
  8922. byteOffset = Filter->FirstControlBlockVolumeOffset;
  8923. itemsLeft = FALSE;
  8924. for (;;) {
  8925. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8926. Filter->TargetObject, IRP_MJ_READ,
  8927. byteOffset, 0);
  8928. if (!NT_SUCCESS(status)) {
  8929. if (!NonPagedResourceHeld) {
  8930. VspReleaseNonPagedResource(Filter);
  8931. }
  8932. return status;
  8933. }
  8934. needWrite = FALSE;
  8935. for (offset = VSP_BYTES_PER_CONTROL_ITEM; offset < BLOCK_SIZE;
  8936. offset += VSP_BYTES_PER_CONTROL_ITEM) {
  8937. controlItem = (PVSP_CONTROL_ITEM_SNAPSHOT)
  8938. ((PCHAR) controlBlock + offset);
  8939. if (controlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_END) {
  8940. break;
  8941. }
  8942. if (controlItem->ControlItemType > VSP_CONTROL_ITEM_TYPE_FREE) {
  8943. if (SnapshotGuid) {
  8944. if (IsEqualGUID(controlItem->SnapshotGuid,
  8945. *SnapshotGuid)) {
  8946. VspRemoveControlItemInfoFromLookupTable(
  8947. Filter, controlItem);
  8948. RtlZeroMemory(controlItem,
  8949. VSP_BYTES_PER_CONTROL_ITEM);
  8950. controlItem->ControlItemType =
  8951. VSP_CONTROL_ITEM_TYPE_FREE;
  8952. needWrite = TRUE;
  8953. } else {
  8954. itemsLeft = TRUE;
  8955. }
  8956. } else {
  8957. if (controlItem->ControlItemType ==
  8958. VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  8959. VspRemoveControlItemInfoFromLookupTable(
  8960. Filter, controlItem);
  8961. RtlZeroMemory(controlItem,
  8962. VSP_BYTES_PER_CONTROL_ITEM);
  8963. controlItem->ControlItemType =
  8964. VSP_CONTROL_ITEM_TYPE_FREE;
  8965. needWrite = TRUE;
  8966. } else {
  8967. itemsLeft = TRUE;
  8968. }
  8969. }
  8970. }
  8971. }
  8972. if (needWrite) {
  8973. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  8974. Filter->TargetObject, IRP_MJ_WRITE,
  8975. byteOffset, 0);
  8976. if (!NT_SUCCESS(status)) {
  8977. if (!NonPagedResourceHeld) {
  8978. VspReleaseNonPagedResource(Filter);
  8979. }
  8980. return status;
  8981. }
  8982. }
  8983. if (!controlBlock->Header.NextVolumeOffset) {
  8984. break;
  8985. }
  8986. byteOffset = controlBlock->Header.NextVolumeOffset;
  8987. }
  8988. if (!itemsLeft) {
  8989. if (NonPagedResourceHeld) {
  8990. context = VspAllocateContext(Filter->Root);
  8991. if (context) {
  8992. h = InterlockedExchangePointer(&Filter->ControlBlockFileHandle,
  8993. NULL);
  8994. Filter->FirstControlBlockVolumeOffset = 0;
  8995. VspCreateStartBlock(Filter, 0, Filter->MaximumVolumeSpace);
  8996. hh = InterlockedExchangePointer(&Filter->BootStatHandle, NULL);
  8997. if (!h && !hh) {
  8998. VspFreeContext(Filter->Root, context);
  8999. }
  9000. } else {
  9001. h = NULL;
  9002. hh = NULL;
  9003. }
  9004. } else {
  9005. h = InterlockedExchangePointer(&Filter->ControlBlockFileHandle,
  9006. NULL);
  9007. Filter->FirstControlBlockVolumeOffset = 0;
  9008. VspCreateStartBlock(Filter, 0, Filter->MaximumVolumeSpace);
  9009. hh = InterlockedExchangePointer(&Filter->BootStatHandle, NULL);
  9010. }
  9011. } else {
  9012. h = NULL;
  9013. hh = NULL;
  9014. }
  9015. if (NonPagedResourceHeld) {
  9016. if (h || hh) {
  9017. ASSERT(context);
  9018. context->Type = VSP_CONTEXT_TYPE_CLOSE_HANDLES;
  9019. ExInitializeWorkItem(&context->WorkItem, VspCloseHandlesWorker,
  9020. context);
  9021. context->CloseHandles.Filter = Filter;
  9022. context->CloseHandles.Handle1 = h;
  9023. context->CloseHandles.Handle2 = hh;
  9024. ObReferenceObject(Filter->DeviceObject);
  9025. KeResetEvent(&Filter->ControlBlockFileHandleReady);
  9026. ExQueueWorkItem(&context->WorkItem, CriticalWorkQueue);
  9027. }
  9028. } else {
  9029. VspReleaseNonPagedResource(Filter);
  9030. if (h) {
  9031. ZwClose(h);
  9032. }
  9033. if (hh) {
  9034. ZwClose(hh);
  9035. }
  9036. }
  9037. return STATUS_SUCCESS;
  9038. }
  9039. NTSTATUS
  9040. VspIoControlItem(
  9041. IN PFILTER_EXTENSION Filter,
  9042. IN ULONG ControlItemType,
  9043. IN GUID* SnapshotGuid,
  9044. IN BOOLEAN IsSet,
  9045. IN OUT PVOID ControlItem,
  9046. IN BOOLEAN AcquireLock
  9047. )
  9048. /*++
  9049. Routine Description:
  9050. This routine returns the control item with the given control item type
  9051. and snapshot guid.
  9052. Arguments:
  9053. Filter - Supplies the filter.
  9054. ControlItemType - Supplies the control item type.
  9055. SnapshotGuid - Supplies the snapshot guid.
  9056. ControlItem - Returns the control item.
  9057. Return Value:
  9058. NTSTATUS
  9059. --*/
  9060. {
  9061. PVSP_BLOCK_CONTROL controlBlock;
  9062. LONGLONG byteOffset;
  9063. NTSTATUS status;
  9064. ULONG offset;
  9065. PVSP_CONTROL_ITEM_SNAPSHOT controlItem;
  9066. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  9067. PVSP_CONTROL_ITEM_DIFF_AREA daControlItem;
  9068. if (AcquireLock) {
  9069. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  9070. }
  9071. if (!Filter->FirstControlBlockVolumeOffset) {
  9072. if (AcquireLock) {
  9073. VspReleaseNonPagedResource(Filter);
  9074. }
  9075. if (!IsSet) {
  9076. return STATUS_UNSUCCESSFUL;
  9077. }
  9078. status = VspCreateInitialControlBlockFile(Filter);
  9079. if (AcquireLock) {
  9080. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  9081. }
  9082. if (!Filter->FirstControlBlockVolumeOffset) {
  9083. if (AcquireLock) {
  9084. VspReleaseNonPagedResource(Filter);
  9085. }
  9086. if (NT_SUCCESS(status)) {
  9087. status = STATUS_UNSUCCESSFUL;
  9088. }
  9089. return status;
  9090. }
  9091. }
  9092. ASSERT(Filter->SnapshotOnDiskIrp);
  9093. controlBlock = (PVSP_BLOCK_CONTROL) MmGetMdlVirtualAddress(
  9094. Filter->SnapshotOnDiskIrp->MdlAddress);
  9095. byteOffset = Filter->FirstControlBlockVolumeOffset;
  9096. for (;;) {
  9097. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  9098. Filter->TargetObject, IRP_MJ_READ,
  9099. byteOffset, 0);
  9100. if (!NT_SUCCESS(status)) {
  9101. if (AcquireLock) {
  9102. VspReleaseNonPagedResource(Filter);
  9103. }
  9104. return status;
  9105. }
  9106. for (offset = VSP_BYTES_PER_CONTROL_ITEM; offset < BLOCK_SIZE;
  9107. offset += VSP_BYTES_PER_CONTROL_ITEM) {
  9108. controlItem = (PVSP_CONTROL_ITEM_SNAPSHOT)
  9109. ((PCHAR) controlBlock + offset);
  9110. if (ControlItemType == VSP_CONTROL_ITEM_TYPE_FREE) {
  9111. if (controlItem->ControlItemType >
  9112. VSP_CONTROL_ITEM_TYPE_FREE) {
  9113. continue;
  9114. }
  9115. } else {
  9116. if (controlItem->ControlItemType ==
  9117. VSP_CONTROL_ITEM_TYPE_END) {
  9118. break;
  9119. }
  9120. if (controlItem->ControlItemType != ControlItemType ||
  9121. !IsEqualGUID(controlItem->SnapshotGuid, *SnapshotGuid)) {
  9122. continue;
  9123. }
  9124. }
  9125. if (!IsSet) {
  9126. RtlCopyMemory(ControlItem, controlItem,
  9127. VSP_BYTES_PER_CONTROL_ITEM);
  9128. if (AcquireLock) {
  9129. VspReleaseNonPagedResource(Filter);
  9130. }
  9131. return STATUS_SUCCESS;
  9132. }
  9133. RtlCopyMemory(controlItem, ControlItem,
  9134. VSP_BYTES_PER_CONTROL_ITEM);
  9135. if (ControlItemType == VSP_CONTROL_ITEM_TYPE_FREE) {
  9136. status = VspAddControlItemInfoToLookupTable(Filter,
  9137. controlItem,
  9138. NULL);
  9139. if (!NT_SUCCESS(status)) {
  9140. if (AcquireLock) {
  9141. VspReleaseNonPagedResource(Filter);
  9142. }
  9143. return status;
  9144. }
  9145. } else if (ControlItemType == VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  9146. ASSERT(controlItem->ControlItemType == ControlItemType);
  9147. lookupEntry = VspFindLookupTableItem(
  9148. Filter->Root, &controlItem->SnapshotGuid);
  9149. ASSERT(lookupEntry);
  9150. lookupEntry->VolumeSnapshotSize =
  9151. controlItem->VolumeSnapshotSize;
  9152. lookupEntry->SnapshotOrderNumber =
  9153. controlItem->SnapshotOrderNumber;
  9154. lookupEntry->SnapshotControlItemFlags =
  9155. controlItem->SnapshotControlItemFlags;
  9156. lookupEntry->SnapshotTime = controlItem->SnapshotTime;
  9157. } else {
  9158. ASSERT(controlItem->ControlItemType == ControlItemType);
  9159. lookupEntry = VspFindLookupTableItem(
  9160. Filter->Root, &controlItem->SnapshotGuid);
  9161. ASSERT(lookupEntry);
  9162. daControlItem = (PVSP_CONTROL_ITEM_DIFF_AREA) controlItem;
  9163. lookupEntry->DiffAreaStartingVolumeOffset =
  9164. daControlItem->DiffAreaStartingVolumeOffset;
  9165. lookupEntry->ApplicationInfoStartingVolumeOffset =
  9166. daControlItem->ApplicationInfoStartingVolumeOffset;
  9167. lookupEntry->DiffAreaLocationDescriptionVolumeOffset =
  9168. daControlItem->DiffAreaLocationDescriptionVolumeOffset;
  9169. lookupEntry->InitialBitmapVolumeOffset =
  9170. daControlItem->InitialBitmapVolumeOffset;
  9171. }
  9172. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  9173. Filter->TargetObject, IRP_MJ_WRITE,
  9174. byteOffset, 0);
  9175. if (!NT_SUCCESS(status)) {
  9176. VspRemoveControlItemInfoFromLookupTable(Filter, controlItem);
  9177. if (AcquireLock) {
  9178. VspReleaseNonPagedResource(Filter);
  9179. }
  9180. return status;
  9181. }
  9182. if (AcquireLock) {
  9183. VspReleaseNonPagedResource(Filter);
  9184. }
  9185. return STATUS_SUCCESS;
  9186. }
  9187. if (!controlBlock->Header.NextVolumeOffset) {
  9188. if (ControlItemType == VSP_CONTROL_ITEM_TYPE_FREE) {
  9189. if (AcquireLock) {
  9190. VspReleaseNonPagedResource(Filter);
  9191. }
  9192. status = VspAddControlBlocks(Filter, byteOffset);
  9193. if (!NT_SUCCESS(status)) {
  9194. return status;
  9195. }
  9196. byteOffset = Filter->FirstControlBlockVolumeOffset;
  9197. if (AcquireLock) {
  9198. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  9199. }
  9200. continue;
  9201. }
  9202. break;
  9203. }
  9204. byteOffset = controlBlock->Header.NextVolumeOffset;
  9205. }
  9206. if (AcquireLock) {
  9207. VspReleaseNonPagedResource(Filter);
  9208. }
  9209. return STATUS_UNSUCCESSFUL;
  9210. }
  9211. NTSTATUS
  9212. VspAddControlItem(
  9213. IN PFILTER_EXTENSION Filter,
  9214. IN PVOID ControlItem,
  9215. IN BOOLEAN AcquireLock
  9216. )
  9217. /*++
  9218. Routine Description:
  9219. This routine adds a control item to the given master control block on
  9220. the given filter.
  9221. Arguments:
  9222. Filter - Supplies the filter extension.
  9223. ControlItem - Supplies the control item.
  9224. Return Value:
  9225. NTSTATUS
  9226. --*/
  9227. {
  9228. GUID zeroGuid;
  9229. RtlZeroMemory(&zeroGuid, sizeof(zeroGuid));
  9230. return VspIoControlItem(Filter, VSP_CONTROL_ITEM_TYPE_FREE, &zeroGuid,
  9231. TRUE, ControlItem, AcquireLock);
  9232. }
  9233. NTSTATUS
  9234. VspCleanupControlItemsForSnapshot(
  9235. IN PVOLUME_EXTENSION Extension
  9236. )
  9237. /*++
  9238. Routine Description:
  9239. This routine cleans up all of the control items associated with the
  9240. given snapshot.
  9241. Arguments:
  9242. Extension - Supplies the volume extension.
  9243. Return Value:
  9244. NTSTATUS
  9245. --*/
  9246. {
  9247. NTSTATUS status;
  9248. PLIST_ENTRY l;
  9249. PVSP_DIFF_AREA_FILE diffAreaFile;
  9250. status = VspDeleteControlItemsWithGuid(Extension->Filter,
  9251. &Extension->SnapshotGuid, FALSE);
  9252. if (!NT_SUCCESS(status)) {
  9253. return status;
  9254. }
  9255. if (Extension->DiffAreaFile) {
  9256. diffAreaFile = Extension->DiffAreaFile;
  9257. status = VspDeleteControlItemsWithGuid(diffAreaFile->Filter,
  9258. &Extension->SnapshotGuid,
  9259. FALSE);
  9260. if (!NT_SUCCESS(status)) {
  9261. return status;
  9262. }
  9263. }
  9264. return STATUS_SUCCESS;
  9265. }
  9266. NTSTATUS
  9267. VspLayDownOnDiskForSnapshot(
  9268. IN PVOLUME_EXTENSION Extension
  9269. )
  9270. /*++
  9271. Routine Description:
  9272. This routine lays down the on disk structure for the given snapshot,
  9273. including the snapshot control item, diff area control items, and
  9274. the initial diff area file blocks.
  9275. Arguments:
  9276. Extension - Supplies the volume extension.
  9277. Return Value:
  9278. NTSTATUS
  9279. --*/
  9280. {
  9281. UCHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  9282. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  9283. PVSP_CONTROL_ITEM_DIFF_AREA diffAreaControlItem = (PVSP_CONTROL_ITEM_DIFF_AREA) controlItemBuffer;
  9284. NTSTATUS status;
  9285. PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION locationBlock;
  9286. ULONG totalNumEntries, numEntriesPerBlock, numBlocks, j;
  9287. PLIST_ENTRY l, ll;
  9288. PVSP_DIFF_AREA_FILE diffAreaFile;
  9289. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  9290. IO_STATUS_BLOCK ioStatus;
  9291. KIRQL irql;
  9292. LONGLONG targetOffset, fileOffset, fo;
  9293. PLONGLONG targetOffsetArray, fileOffsetArray;
  9294. ULONG blockOffset;
  9295. PVSP_DIFF_AREA_LOCATION_DESCRIPTOR locationDescriptor;
  9296. PVSP_BLOCK_APP_INFO appInfoBlock;
  9297. RtlZeroMemory(controlItemBuffer, VSP_BYTES_PER_CONTROL_ITEM);
  9298. snapshotControlItem->ControlItemType = VSP_CONTROL_ITEM_TYPE_SNAPSHOT;
  9299. snapshotControlItem->VolumeSnapshotSize = Extension->VolumeSize;
  9300. snapshotControlItem->SnapshotGuid = Extension->SnapshotGuid;
  9301. status = VspAddControlItem(Extension->Filter, snapshotControlItem, TRUE);
  9302. if (!NT_SUCCESS(status)) {
  9303. return status;
  9304. }
  9305. RtlZeroMemory(controlItemBuffer, VSP_BYTES_PER_CONTROL_ITEM);
  9306. diffAreaControlItem->ControlItemType = VSP_CONTROL_ITEM_TYPE_DIFF_AREA;
  9307. diffAreaControlItem->SnapshotGuid = Extension->SnapshotGuid;
  9308. diffAreaFile = Extension->DiffAreaFile;
  9309. ASSERT(diffAreaFile);
  9310. totalNumEntries = 0;
  9311. for (ll = diffAreaFile->UnusedAllocationList.Flink;
  9312. ll != &diffAreaFile->UnusedAllocationList; ll = ll->Flink) {
  9313. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  9314. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  9315. if (diffAreaFileAllocation->NLength > 0) {
  9316. totalNumEntries++;
  9317. }
  9318. }
  9319. numEntriesPerBlock = (BLOCK_SIZE -
  9320. VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR)/
  9321. sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR);
  9322. numBlocks = (totalNumEntries + numEntriesPerBlock - 1)/
  9323. numEntriesPerBlock;
  9324. numBlocks += 2;
  9325. locationBlock = (PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION)
  9326. MmGetMdlVirtualAddress(diffAreaFile->TableUpdateIrp->MdlAddress);
  9327. targetOffsetArray = (PLONGLONG)
  9328. ExAllocatePoolWithTag(PagedPool,
  9329. sizeof(LONGLONG)*numBlocks,
  9330. VOLSNAP_TAG_SHORT_TERM);
  9331. fileOffsetArray = (PLONGLONG)
  9332. ExAllocatePoolWithTag(PagedPool,
  9333. sizeof(LONGLONG)*numBlocks,
  9334. VOLSNAP_TAG_SHORT_TERM);
  9335. if (!targetOffsetArray || !fileOffsetArray) {
  9336. if (targetOffsetArray) {
  9337. ExFreePool(targetOffsetArray);
  9338. }
  9339. if (fileOffsetArray) {
  9340. ExFreePool(fileOffsetArray);
  9341. }
  9342. VspCleanupControlItemsForSnapshot(Extension);
  9343. return STATUS_INSUFFICIENT_RESOURCES;
  9344. }
  9345. for (j = 0; j < numBlocks; j++) {
  9346. status = VspAllocateDiffAreaSpace(Extension, &targetOffset,
  9347. &fileOffset, NULL, NULL);
  9348. if (!NT_SUCCESS(status)) {
  9349. ExFreePool(targetOffsetArray);
  9350. ExFreePool(fileOffsetArray);
  9351. VspCleanupControlItemsForSnapshot(Extension);
  9352. return STATUS_INSUFFICIENT_RESOURCES;
  9353. }
  9354. targetOffsetArray[j] = targetOffset;
  9355. fileOffsetArray[j] = fileOffset;
  9356. }
  9357. diffAreaFile->NextFreeTableEntryOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  9358. diffAreaFile->ApplicationInfoTargetOffset = targetOffsetArray[0];
  9359. diffAreaFile->FirstTableTargetOffset = targetOffsetArray[1];
  9360. diffAreaFile->TableTargetOffset = targetOffsetArray[1];
  9361. diffAreaFile->DiffAreaLocationDescriptionTargetOffset =
  9362. targetOffsetArray[2];
  9363. ll = diffAreaFile->UnusedAllocationList.Flink;
  9364. fo = diffAreaFile->NextAvailable;
  9365. for (j = 0; j < numBlocks; j++) {
  9366. RtlZeroMemory(locationBlock, BLOCK_SIZE);
  9367. locationBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  9368. locationBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  9369. locationBlock->Header.ThisFileOffset = fileOffsetArray[j];
  9370. locationBlock->Header.ThisVolumeOffset = targetOffsetArray[j];
  9371. if (j == 0) {
  9372. locationBlock->Header.BlockType = VSP_BLOCK_TYPE_APP_INFO;
  9373. if (Extension->ApplicationInformationSize) {
  9374. appInfoBlock = (PVSP_BLOCK_APP_INFO) locationBlock;
  9375. appInfoBlock->AppInfoSize =
  9376. Extension->ApplicationInformationSize;
  9377. RtlCopyMemory((PCHAR) locationBlock + VSP_OFFSET_TO_APP_INFO,
  9378. Extension->ApplicationInformation,
  9379. Extension->ApplicationInformationSize);
  9380. }
  9381. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  9382. diffAreaFile->Filter->TargetObject,
  9383. IRP_MJ_WRITE,
  9384. locationBlock->Header.ThisVolumeOffset,
  9385. 0);
  9386. if (!NT_SUCCESS(status)) {
  9387. ExFreePool(targetOffsetArray);
  9388. ExFreePool(fileOffsetArray);
  9389. VspCleanupControlItemsForSnapshot(Extension);
  9390. return status;
  9391. }
  9392. continue;
  9393. }
  9394. if (j == 1) {
  9395. locationBlock->Header.BlockType = VSP_BLOCK_TYPE_DIFF_AREA;
  9396. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  9397. diffAreaFile->Filter->TargetObject,
  9398. IRP_MJ_WRITE,
  9399. locationBlock->Header.ThisVolumeOffset,
  9400. 0);
  9401. if (!NT_SUCCESS(status)) {
  9402. ExFreePool(targetOffsetArray);
  9403. ExFreePool(fileOffsetArray);
  9404. VspCleanupControlItemsForSnapshot(Extension);
  9405. return status;
  9406. }
  9407. continue;
  9408. }
  9409. locationBlock->Header.BlockType =
  9410. VSP_BLOCK_TYPE_DIFF_AREA_LOCATION_DESCRIPTION;
  9411. if (j + 1 < numBlocks) {
  9412. locationBlock->Header.NextVolumeOffset =
  9413. targetOffsetArray[j + 1];
  9414. }
  9415. blockOffset = VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR;
  9416. locationDescriptor = (PVSP_DIFF_AREA_LOCATION_DESCRIPTOR)
  9417. ((PCHAR) locationBlock + blockOffset);
  9418. for (; ll != &diffAreaFile->UnusedAllocationList; ll = ll->Flink) {
  9419. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  9420. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  9421. if (diffAreaFileAllocation->NLength <= 0) {
  9422. fo -= diffAreaFileAllocation->NLength;
  9423. continue;
  9424. }
  9425. locationDescriptor->VolumeOffset = diffAreaFileAllocation->Offset;
  9426. locationDescriptor->FileOffset = fo;
  9427. locationDescriptor->Length = diffAreaFileAllocation->NLength;
  9428. fo += locationDescriptor->Length;
  9429. blockOffset += sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR);
  9430. if (blockOffset + sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR) >
  9431. BLOCK_SIZE) {
  9432. ll = ll->Flink;
  9433. break;
  9434. }
  9435. locationDescriptor = (PVSP_DIFF_AREA_LOCATION_DESCRIPTOR)
  9436. ((PCHAR) locationBlock + blockOffset);
  9437. }
  9438. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  9439. diffAreaFile->Filter->TargetObject,
  9440. IRP_MJ_WRITE,
  9441. locationBlock->Header.ThisVolumeOffset,
  9442. 0);
  9443. if (!NT_SUCCESS(status)) {
  9444. ExFreePool(targetOffsetArray);
  9445. ExFreePool(fileOffsetArray);
  9446. VspCleanupControlItemsForSnapshot(Extension);
  9447. return status;
  9448. }
  9449. }
  9450. ExFreePool(targetOffsetArray);
  9451. ExFreePool(fileOffsetArray);
  9452. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  9453. diffAreaFile->Filter->TargetObject,
  9454. IRP_MJ_READ,
  9455. diffAreaFile->TableTargetOffset, 0);
  9456. if (!NT_SUCCESS(status)) {
  9457. VspCleanupControlItemsForSnapshot(Extension);
  9458. return status;
  9459. }
  9460. diffAreaControlItem->DiffAreaStartingVolumeOffset =
  9461. diffAreaFile->TableTargetOffset;
  9462. diffAreaControlItem->ApplicationInfoStartingVolumeOffset =
  9463. diffAreaFile->ApplicationInfoTargetOffset;
  9464. diffAreaControlItem->DiffAreaLocationDescriptionVolumeOffset =
  9465. diffAreaFile->DiffAreaLocationDescriptionTargetOffset;
  9466. diffAreaControlItem->InitialBitmapVolumeOffset =
  9467. diffAreaFile->InitialBitmapVolumeOffset;
  9468. status = VspAddControlItem(diffAreaFile->Filter, diffAreaControlItem,
  9469. TRUE);
  9470. if (!NT_SUCCESS(status)) {
  9471. VspCleanupControlItemsForSnapshot(Extension);
  9472. return status;
  9473. }
  9474. return STATUS_SUCCESS;
  9475. }
  9476. HANDLE
  9477. VspPinBootStat(
  9478. IN PFILTER_EXTENSION Filter
  9479. )
  9480. {
  9481. UNICODE_STRING name;
  9482. OBJECT_ATTRIBUTES oa;
  9483. NTSTATUS status;
  9484. HANDLE h;
  9485. IO_STATUS_BLOCK ioStatus;
  9486. RtlInitUnicodeString(&name, L"\\SystemRoot\\bootstat.dat");
  9487. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  9488. OBJ_KERNEL_HANDLE, NULL, NULL);
  9489. status = ZwOpenFile(&h, SYNCHRONIZE, &oa, &ioStatus,
  9490. FILE_SHARE_READ | FILE_SHARE_WRITE |
  9491. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  9492. if (!NT_SUCCESS(status)) {
  9493. return NULL;
  9494. }
  9495. status = VspPinFile(Filter->TargetObject, h);
  9496. if (!NT_SUCCESS(status)) {
  9497. ZwClose(h);
  9498. return NULL;
  9499. }
  9500. return h;
  9501. }
  9502. BOOLEAN
  9503. VspQueryNoDiffAreaFill(
  9504. IN PDO_EXTENSION RootExtension
  9505. )
  9506. {
  9507. ULONG zero, result;
  9508. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  9509. NTSTATUS status;
  9510. zero = 0;
  9511. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  9512. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  9513. queryTable[0].Name = L"NoDiffAreaFill";
  9514. queryTable[0].EntryContext = &result;
  9515. queryTable[0].DefaultType = REG_DWORD;
  9516. queryTable[0].DefaultData = &zero;
  9517. queryTable[0].DefaultLength = sizeof(ULONG);
  9518. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  9519. RootExtension->RegistryPath.Buffer,
  9520. queryTable, NULL, NULL);
  9521. if (!NT_SUCCESS(status)) {
  9522. result = zero;
  9523. }
  9524. return result ? TRUE : FALSE;
  9525. }
  9526. VOID
  9527. VspPerformPreExposure(
  9528. IN PVOLUME_EXTENSION Extension
  9529. )
  9530. {
  9531. NTSTATUS status;
  9532. LARGE_INTEGER timeout;
  9533. VspAcquire(Extension->Root);
  9534. if (Extension->Filter->IsRemoved) {
  9535. VspRelease(Extension->Root);
  9536. return;
  9537. }
  9538. IoInvalidateDeviceRelations(Extension->Filter->Pdo, BusRelations);
  9539. VspRelease(Extension->Root);
  9540. timeout.QuadPart = (LONGLONG) -10*1000*1000*120*10; // 20 minutes.
  9541. status = KeWaitForSingleObject(&Extension->PreExposureEvent, Executive,
  9542. KernelMode, FALSE, &timeout);
  9543. if (status == STATUS_TIMEOUT) {
  9544. VspAcquire(Extension->Root);
  9545. if (Extension->IsStarted) {
  9546. Extension->IsInstalled = TRUE;
  9547. }
  9548. VspRelease(Extension->Root);
  9549. }
  9550. }
  9551. ULONG
  9552. VspClaimNextDevnodeNumber(
  9553. IN PDO_EXTENSION RootExtension
  9554. )
  9555. {
  9556. PULONG p, c;
  9557. ULONG r;
  9558. p = NULL;
  9559. c = (PULONG)
  9560. RtlEnumerateGenericTable(&RootExtension->UsedDevnodeNumbers, TRUE);
  9561. while (c) {
  9562. if (p) {
  9563. if (*p + 1 < *c) {
  9564. r = *p + 1;
  9565. goto Finish;
  9566. }
  9567. } else {
  9568. if (1 < *c) {
  9569. r = 1;
  9570. goto Finish;
  9571. }
  9572. }
  9573. p = c;
  9574. c = (PULONG)
  9575. RtlEnumerateGenericTable(&RootExtension->UsedDevnodeNumbers, FALSE);
  9576. }
  9577. if (p) {
  9578. r = *p + 1;
  9579. } else {
  9580. r = 1;
  9581. }
  9582. Finish:
  9583. if (!RtlInsertElementGenericTable(&RootExtension->UsedDevnodeNumbers, &r,
  9584. sizeof(r), NULL)) {
  9585. return 0;
  9586. }
  9587. return r;
  9588. }
  9589. VOID
  9590. VspPrepareForSnapshotWorker(
  9591. IN PDEVICE_OBJECT DeviceObject,
  9592. IN PVOID Context
  9593. )
  9594. {
  9595. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  9596. PFILTER_EXTENSION Filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  9597. PIRP Irp = context->Dispatch.Irp;
  9598. PDO_EXTENSION rootExtension = Filter->Root;
  9599. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  9600. PVOLSNAP_PREPARE_INFO input = (PVOLSNAP_PREPARE_INFO) Irp->AssociatedIrp.SystemBuffer;
  9601. BOOLEAN fallThrough = FALSE;
  9602. BOOLEAN isInternal, isPersistent;
  9603. PULONG pu;
  9604. LONGLONG minDiffAreaFileSize;
  9605. KIRQL irql;
  9606. ULONG volumeNumber;
  9607. WCHAR buffer[100];
  9608. UNICODE_STRING volumeName;
  9609. NTSTATUS status;
  9610. PDEVICE_OBJECT deviceObject;
  9611. PVOLUME_EXTENSION extension, e;
  9612. ULONG bitmapSize, n;
  9613. PVOID bitmapBuffer, p;
  9614. PVOID buf;
  9615. PMDL mdl;
  9616. HANDLE h, hh;
  9617. PLIST_ENTRY l;
  9618. PSECURITY_DESCRIPTOR sd;
  9619. BOOLEAN ma;
  9620. ASSERT(context->Type == VSP_CONTEXT_TYPE_DISPATCH);
  9621. InterlockedExchange(&rootExtension->VolumesSafeForWriteAccess, TRUE);
  9622. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  9623. KernelMode, FALSE, NULL);
  9624. VspAcquireCritical(Filter);
  9625. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  9626. sizeof(VOLSNAP_PREPARE_INFO)) {
  9627. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  9628. goto Finish;
  9629. }
  9630. if (irpSp->Parameters.DeviceIoControl.InputBufferLength >=
  9631. sizeof(VOLSNAP_PREPARE_INFO) + sizeof(ULONG)) {
  9632. pu = (PULONG) (input + 1);
  9633. if (*pu == 'NPK ') {
  9634. isInternal = TRUE;
  9635. } else {
  9636. isInternal = FALSE;
  9637. }
  9638. } else {
  9639. isInternal = FALSE;
  9640. }
  9641. if (input->Attributes&(~VOLSNAP_ALL_ATTRIBUTES)) {
  9642. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  9643. goto Finish;
  9644. }
  9645. if (input->Attributes&VOLSNAP_ATTRIBUTE_PERSISTENT) {
  9646. isPersistent = TRUE;
  9647. } else {
  9648. isPersistent = FALSE;
  9649. }
  9650. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  9651. KernelMode, FALSE, NULL);
  9652. VspAcquire(Filter->Root);
  9653. if (!Filter->DiffAreaVolume) {
  9654. VspRelease(Filter->Root);
  9655. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  9656. goto Finish;
  9657. }
  9658. if ((isPersistent && Filter->ProtectedBlocksBitmap) ||
  9659. Filter->DiffAreaVolume->ProtectedBlocksBitmap) {
  9660. VspRelease(Filter->Root);
  9661. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  9662. goto Finish;
  9663. }
  9664. if (Filter->SnapshotsPresent) {
  9665. if (Filter->PersistentSnapshots) {
  9666. isPersistent = TRUE;
  9667. }
  9668. }
  9669. if (isPersistent && Filter->Pdo->Flags&DO_SYSTEM_BOOT_PARTITION &&
  9670. !Filter->BootStatHandle) {
  9671. VspRelease(Filter->Root);
  9672. h = VspPinBootStat(Filter);
  9673. VspAcquire(Filter->Root);
  9674. if (h) {
  9675. hh = InterlockedExchangePointer(&Filter->BootStatHandle, h);
  9676. if (hh) {
  9677. ZwClose(hh);
  9678. }
  9679. }
  9680. }
  9681. VspRelease(Filter->Root);
  9682. VspQueryMinimumDiffAreaFileSize(Filter->Root, &minDiffAreaFileSize);
  9683. if (input->InitialDiffAreaAllocation < 2*NOMINAL_DIFF_AREA_FILE_GROWTH) {
  9684. input->InitialDiffAreaAllocation = 2*NOMINAL_DIFF_AREA_FILE_GROWTH;
  9685. }
  9686. if (input->InitialDiffAreaAllocation < minDiffAreaFileSize) {
  9687. input->InitialDiffAreaAllocation = minDiffAreaFileSize;
  9688. }
  9689. volumeNumber = (ULONG)
  9690. InterlockedIncrement(&Filter->Root->NextVolumeNumber);
  9691. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d", volumeNumber);
  9692. RtlInitUnicodeString(&volumeName, buffer);
  9693. status = IoCreateDevice(rootExtension->DriverObject,
  9694. sizeof(VOLUME_EXTENSION), &volumeName,
  9695. FILE_DEVICE_VIRTUAL_DISK, 0, FALSE,
  9696. &deviceObject);
  9697. if (!NT_SUCCESS(status)) {
  9698. Irp->IoStatus.Status = status;
  9699. goto Finish;
  9700. }
  9701. extension = (PVOLUME_EXTENSION) deviceObject->DeviceExtension;
  9702. RtlZeroMemory(extension, sizeof(VOLUME_EXTENSION));
  9703. extension->DeviceObject = deviceObject;
  9704. extension->Root = Filter->Root;
  9705. extension->DeviceExtensionType = DEVICE_EXTENSION_VOLUME;
  9706. KeInitializeSpinLock(&extension->SpinLock);
  9707. extension->Filter = Filter;
  9708. extension->RefCount = 1;
  9709. InitializeListHead(&extension->WriteContextList);
  9710. KeInitializeEvent(&extension->ZeroRefEvent, NotificationEvent, FALSE);
  9711. extension->IsPersistent = isPersistent;
  9712. extension->NoDiffAreaFill = VspQueryNoDiffAreaFill(extension->Root);
  9713. if (isPersistent) {
  9714. extension->OnDiskNotCommitted = TRUE;
  9715. }
  9716. extension->VolumeNumber = volumeNumber;
  9717. status = ExUuidCreate(&extension->SnapshotGuid);
  9718. if (!NT_SUCCESS(status)) {
  9719. IoDeleteDevice(deviceObject);
  9720. Irp->IoStatus.Status = status;
  9721. goto Finish;
  9722. }
  9723. RtlInitializeGenericTable(&extension->VolumeBlockTable,
  9724. VspTableCompareRoutine,
  9725. VspTableAllocateRoutine,
  9726. VspTableFreeRoutine, extension);
  9727. RtlInitializeGenericTable(&extension->CopyBackPointerTable,
  9728. VspTableCompareRoutine,
  9729. VspTableAllocateRoutine,
  9730. VspTableFreeRoutine, extension);
  9731. RtlInitializeGenericTable(&extension->TempVolumeBlockTable,
  9732. VspTableCompareRoutine,
  9733. VspTempTableAllocateRoutine,
  9734. VspTempTableFreeRoutine, extension);
  9735. extension->DiffAreaFileIncrease = NOMINAL_DIFF_AREA_FILE_GROWTH;
  9736. status = VspCreateInitialDiffAreaFile(extension,
  9737. input->InitialDiffAreaAllocation);
  9738. if (!NT_SUCCESS(status)) {
  9739. IoDeleteDevice(deviceObject);
  9740. Irp->IoStatus.Status = status;
  9741. goto Finish;
  9742. }
  9743. status = VspCreateWorkerThread(rootExtension);
  9744. if (!NT_SUCCESS(status)) {
  9745. VspLogError(extension, NULL, VS_CREATE_WORKER_THREADS_FAILED, status,
  9746. 0, FALSE);
  9747. VspDeleteInitialDiffAreaFile(extension);
  9748. IoDeleteDevice(deviceObject);
  9749. Irp->IoStatus.Status = status;
  9750. goto Finish;
  9751. }
  9752. extension->VolumeBlockBitmap = (PRTL_BITMAP)
  9753. ExAllocatePoolWithTag(
  9754. NonPagedPool, sizeof(RTL_BITMAP),
  9755. VOLSNAP_TAG_BITMAP);
  9756. if (!extension->VolumeBlockBitmap) {
  9757. VspDeleteWorkerThread(rootExtension);
  9758. VspDeleteInitialDiffAreaFile(extension);
  9759. IoDeleteDevice(deviceObject);
  9760. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9761. goto Finish;
  9762. }
  9763. extension->ApplicationInformationSize = 68;
  9764. extension->ApplicationInformation =
  9765. ExAllocatePoolWithTag(PagedPool,
  9766. extension->ApplicationInformationSize,
  9767. VOLSNAP_TAG_APP_INFO);
  9768. if (!extension->ApplicationInformation) {
  9769. ExFreePool(extension->VolumeBlockBitmap);
  9770. extension->VolumeBlockBitmap = NULL;
  9771. VspDeleteWorkerThread(rootExtension);
  9772. VspDeleteInitialDiffAreaFile(extension);
  9773. IoDeleteDevice(deviceObject);
  9774. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9775. goto Finish;
  9776. }
  9777. RtlZeroMemory(extension->ApplicationInformation,
  9778. extension->ApplicationInformationSize);
  9779. RtlCopyMemory(extension->ApplicationInformation,
  9780. &VOLSNAP_APPINFO_GUID_SYSTEM_HIDDEN, sizeof(GUID));
  9781. extension->VolumeSize = VspQueryVolumeSize(Filter);
  9782. if (!extension->VolumeSize) {
  9783. ExFreePool(extension->VolumeBlockBitmap);
  9784. extension->VolumeBlockBitmap = NULL;
  9785. VspDeleteWorkerThread(rootExtension);
  9786. VspDeleteInitialDiffAreaFile(extension);
  9787. IoDeleteDevice(deviceObject);
  9788. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9789. goto Finish;
  9790. }
  9791. bitmapSize = (ULONG) ((extension->VolumeSize + BLOCK_SIZE - 1)>>
  9792. BLOCK_SHIFT);
  9793. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  9794. (bitmapSize + 8*sizeof(ULONG) - 1)/
  9795. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  9796. if (!bitmapBuffer) {
  9797. VspLogError(extension, NULL, VS_CANT_ALLOCATE_BITMAP,
  9798. STATUS_INSUFFICIENT_RESOURCES, 1, FALSE);
  9799. ExFreePool(extension->VolumeBlockBitmap);
  9800. extension->VolumeBlockBitmap = NULL;
  9801. VspDeleteWorkerThread(rootExtension);
  9802. VspDeleteInitialDiffAreaFile(extension);
  9803. IoDeleteDevice(deviceObject);
  9804. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9805. goto Finish;
  9806. }
  9807. RtlInitializeBitMap(extension->VolumeBlockBitmap, (PULONG) bitmapBuffer,
  9808. bitmapSize);
  9809. RtlClearAllBits(extension->VolumeBlockBitmap);
  9810. status = VspCreateInitialHeap(extension, FALSE);
  9811. if (!NT_SUCCESS(status)) {
  9812. ExFreePool(bitmapBuffer);
  9813. ExFreePool(extension->VolumeBlockBitmap);
  9814. extension->VolumeBlockBitmap = NULL;
  9815. VspDeleteWorkerThread(rootExtension);
  9816. VspDeleteInitialDiffAreaFile(extension);
  9817. IoDeleteDevice(deviceObject);
  9818. Irp->IoStatus.Status = status;
  9819. goto Finish;
  9820. }
  9821. InitializeListHead(&extension->OldHeaps);
  9822. extension->EmergencyCopyIrp =
  9823. IoAllocateIrp((CCHAR) extension->Root->StackSize, FALSE);
  9824. if (!extension->EmergencyCopyIrp) {
  9825. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9826. extension->DiffAreaFileMap);
  9827. ASSERT(NT_SUCCESS(status));
  9828. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9829. extension->NextDiffAreaFileMap);
  9830. ASSERT(NT_SUCCESS(status));
  9831. ExFreePool(bitmapBuffer);
  9832. ExFreePool(extension->VolumeBlockBitmap);
  9833. extension->VolumeBlockBitmap = NULL;
  9834. VspDeleteWorkerThread(rootExtension);
  9835. VspDeleteInitialDiffAreaFile(extension);
  9836. IoDeleteDevice(deviceObject);
  9837. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9838. goto Finish;
  9839. }
  9840. buf = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE, VOLSNAP_TAG_BUFFER);
  9841. if (!buf) {
  9842. IoFreeIrp(extension->EmergencyCopyIrp);
  9843. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9844. extension->DiffAreaFileMap);
  9845. ASSERT(NT_SUCCESS(status));
  9846. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9847. extension->NextDiffAreaFileMap);
  9848. ASSERT(NT_SUCCESS(status));
  9849. ExFreePool(bitmapBuffer);
  9850. ExFreePool(extension->VolumeBlockBitmap);
  9851. extension->VolumeBlockBitmap = NULL;
  9852. VspDeleteWorkerThread(rootExtension);
  9853. VspDeleteInitialDiffAreaFile(extension);
  9854. IoDeleteDevice(deviceObject);
  9855. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9856. goto Finish;
  9857. }
  9858. mdl = IoAllocateMdl(buf, BLOCK_SIZE, FALSE, FALSE, NULL);
  9859. if (!mdl) {
  9860. ExFreePool(buf);
  9861. IoFreeIrp(extension->EmergencyCopyIrp);
  9862. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9863. extension->DiffAreaFileMap);
  9864. ASSERT(NT_SUCCESS(status));
  9865. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9866. extension->NextDiffAreaFileMap);
  9867. ASSERT(NT_SUCCESS(status));
  9868. ExFreePool(bitmapBuffer);
  9869. ExFreePool(extension->VolumeBlockBitmap);
  9870. extension->VolumeBlockBitmap = NULL;
  9871. VspDeleteWorkerThread(rootExtension);
  9872. VspDeleteInitialDiffAreaFile(extension);
  9873. IoDeleteDevice(deviceObject);
  9874. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9875. goto Finish;
  9876. }
  9877. MmBuildMdlForNonPagedPool(mdl);
  9878. extension->EmergencyCopyIrp->MdlAddress = mdl;
  9879. InitializeListHead(&extension->EmergencyCopyIrpQueue);
  9880. InitializeListHead(&extension->WaitingForPageFileSpace);
  9881. InitializeListHead(&extension->WaitingForDiffAreaSpace);
  9882. VspAcquire(rootExtension);
  9883. if (!IsListEmpty(&Filter->VolumeList)) {
  9884. extension->IgnorableProduct = (PRTL_BITMAP)
  9885. ExAllocatePoolWithTag(NonPagedPool, sizeof(RTL_BITMAP),
  9886. VOLSNAP_TAG_BITMAP);
  9887. if (!extension->IgnorableProduct) {
  9888. VspRelease(rootExtension);
  9889. ExFreePool(buf);
  9890. IoFreeIrp(extension->EmergencyCopyIrp);
  9891. IoFreeMdl(mdl);
  9892. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9893. extension->DiffAreaFileMap);
  9894. ASSERT(NT_SUCCESS(status));
  9895. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9896. extension->NextDiffAreaFileMap);
  9897. ASSERT(NT_SUCCESS(status));
  9898. ExFreePool(bitmapBuffer);
  9899. ExFreePool(extension->VolumeBlockBitmap);
  9900. extension->VolumeBlockBitmap = NULL;
  9901. VspDeleteWorkerThread(rootExtension);
  9902. VspDeleteInitialDiffAreaFile(extension);
  9903. IoDeleteDevice(deviceObject);
  9904. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9905. goto Finish;
  9906. }
  9907. p = ExAllocatePoolWithTag(NonPagedPool,
  9908. (bitmapSize + 8*sizeof(ULONG) - 1)/
  9909. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  9910. if (!p) {
  9911. VspLogError(extension, NULL, VS_CANT_ALLOCATE_BITMAP,
  9912. STATUS_INSUFFICIENT_RESOURCES, 2, FALSE);
  9913. ExFreePool(extension->IgnorableProduct);
  9914. extension->IgnorableProduct = NULL;
  9915. VspRelease(rootExtension);
  9916. ExFreePool(buf);
  9917. IoFreeMdl(mdl);
  9918. IoFreeIrp(extension->EmergencyCopyIrp);
  9919. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9920. extension->DiffAreaFileMap);
  9921. ASSERT(NT_SUCCESS(status));
  9922. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9923. extension->NextDiffAreaFileMap);
  9924. ASSERT(NT_SUCCESS(status));
  9925. ExFreePool(bitmapBuffer);
  9926. ExFreePool(extension->VolumeBlockBitmap);
  9927. extension->VolumeBlockBitmap = NULL;
  9928. VspDeleteWorkerThread(rootExtension);
  9929. VspDeleteInitialDiffAreaFile(extension);
  9930. IoDeleteDevice(deviceObject);
  9931. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  9932. goto Finish;
  9933. }
  9934. RtlInitializeBitMap(extension->IgnorableProduct, (PULONG) p,
  9935. bitmapSize);
  9936. RtlSetAllBits(extension->IgnorableProduct);
  9937. e = CONTAINING_RECORD(Filter->VolumeList.Blink, VOLUME_EXTENSION,
  9938. ListEntry);
  9939. KeAcquireSpinLock(&e->SpinLock, &irql);
  9940. if (e->VolumeBlockBitmap) {
  9941. n = extension->IgnorableProduct->SizeOfBitMap;
  9942. extension->IgnorableProduct->SizeOfBitMap =
  9943. e->VolumeBlockBitmap->SizeOfBitMap;
  9944. VspAndBitmaps(extension->IgnorableProduct, e->VolumeBlockBitmap);
  9945. extension->IgnorableProduct->SizeOfBitMap = n;
  9946. }
  9947. KeReleaseSpinLock(&e->SpinLock, irql);
  9948. }
  9949. status = VspSetDiffAreaBlocksInBitmap(extension);
  9950. if (!NT_SUCCESS(status)) {
  9951. if (extension->IgnorableProduct) {
  9952. ExFreePool(extension->IgnorableProduct->Buffer);
  9953. ExFreePool(extension->IgnorableProduct);
  9954. extension->IgnorableProduct = NULL;
  9955. }
  9956. VspRelease(rootExtension);
  9957. ExFreePool(buf);
  9958. IoFreeMdl(mdl);
  9959. IoFreeIrp(extension->EmergencyCopyIrp);
  9960. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9961. extension->DiffAreaFileMap);
  9962. ASSERT(NT_SUCCESS(status));
  9963. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  9964. extension->NextDiffAreaFileMap);
  9965. ASSERT(NT_SUCCESS(status));
  9966. ExFreePool(bitmapBuffer);
  9967. ExFreePool(extension->VolumeBlockBitmap);
  9968. extension->VolumeBlockBitmap = NULL;
  9969. VspDeleteWorkerThread(rootExtension);
  9970. VspDeleteInitialDiffAreaFile(extension);
  9971. IoDeleteDevice(deviceObject);
  9972. Irp->IoStatus.Status = status;
  9973. goto Finish;
  9974. }
  9975. status = ObGetObjectSecurity(Filter->Pdo, &sd, &ma);
  9976. if (NT_SUCCESS(status)) {
  9977. status = ObSetSecurityObjectByPointer(deviceObject,
  9978. DACL_SECURITY_INFORMATION, sd);
  9979. ObReleaseObjectSecurity(sd, ma);
  9980. }
  9981. if (NT_SUCCESS(status)) {
  9982. extension->DevnodeNumber =
  9983. VspClaimNextDevnodeNumber(extension->Root);
  9984. if (!extension->DevnodeNumber) {
  9985. status = STATUS_INSUFFICIENT_RESOURCES;
  9986. }
  9987. }
  9988. if (!NT_SUCCESS(status)) {
  9989. if (extension->DiffAreaFile) {
  9990. KeAcquireSpinLock(&extension->DiffAreaFile->Filter->SpinLock,
  9991. &irql);
  9992. if (extension->DiffAreaFile->FilterListEntryBeingUsed) {
  9993. RemoveEntryList(&extension->DiffAreaFile->FilterListEntry);
  9994. extension->DiffAreaFile->FilterListEntryBeingUsed = FALSE;
  9995. }
  9996. KeReleaseSpinLock(&extension->DiffAreaFile->Filter->SpinLock,
  9997. irql);
  9998. }
  9999. if (extension->IgnorableProduct) {
  10000. ExFreePool(extension->IgnorableProduct->Buffer);
  10001. ExFreePool(extension->IgnorableProduct);
  10002. extension->IgnorableProduct = NULL;
  10003. }
  10004. VspRelease(rootExtension);
  10005. ExFreePool(buf);
  10006. IoFreeMdl(mdl);
  10007. IoFreeIrp(extension->EmergencyCopyIrp);
  10008. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10009. extension->DiffAreaFileMap);
  10010. ASSERT(NT_SUCCESS(status));
  10011. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10012. extension->NextDiffAreaFileMap);
  10013. ASSERT(NT_SUCCESS(status));
  10014. ExFreePool(bitmapBuffer);
  10015. ExFreePool(extension->VolumeBlockBitmap);
  10016. extension->VolumeBlockBitmap = NULL;
  10017. VspDeleteWorkerThread(rootExtension);
  10018. VspDeleteInitialDiffAreaFile(extension);
  10019. RtlDeleteElementGenericTable(&rootExtension->UsedDevnodeNumbers,
  10020. &extension->DevnodeNumber);
  10021. IoDeleteDevice(deviceObject);
  10022. Irp->IoStatus.Status = status;
  10023. goto Finish;
  10024. }
  10025. if (extension->IsPersistent) {
  10026. VspRelease(rootExtension);
  10027. status = VspLayDownOnDiskForSnapshot(extension);
  10028. if (!NT_SUCCESS(status)) {
  10029. VspLogError(NULL, Filter, VS_CANT_LAY_DOWN_ON_DISK, status, 0,
  10030. FALSE);
  10031. VspAcquire(rootExtension);
  10032. if (extension->DiffAreaFile) {
  10033. KeAcquireSpinLock(&extension->DiffAreaFile->Filter->SpinLock,
  10034. &irql);
  10035. if (extension->DiffAreaFile->FilterListEntryBeingUsed) {
  10036. RemoveEntryList(&extension->DiffAreaFile->FilterListEntry);
  10037. extension->DiffAreaFile->FilterListEntryBeingUsed = FALSE;
  10038. }
  10039. KeReleaseSpinLock(&extension->DiffAreaFile->Filter->SpinLock,
  10040. irql);
  10041. }
  10042. VspRelease(rootExtension);
  10043. if (extension->IgnorableProduct) {
  10044. ExFreePool(extension->IgnorableProduct->Buffer);
  10045. ExFreePool(extension->IgnorableProduct);
  10046. extension->IgnorableProduct = NULL;
  10047. }
  10048. ExFreePool(buf);
  10049. IoFreeIrp(extension->EmergencyCopyIrp);
  10050. ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10051. extension->DiffAreaFileMap);
  10052. ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10053. extension->NextDiffAreaFileMap);
  10054. ExFreePool(bitmapBuffer);
  10055. ExFreePool(extension->VolumeBlockBitmap);
  10056. extension->VolumeBlockBitmap = NULL;
  10057. VspDeleteWorkerThread(rootExtension);
  10058. VspDeleteInitialDiffAreaFile(extension);
  10059. RtlDeleteElementGenericTable(&rootExtension->UsedDevnodeNumbers,
  10060. &extension->DevnodeNumber);
  10061. IoDeleteDevice(deviceObject);
  10062. Irp->IoStatus.Status = status;
  10063. goto Finish;
  10064. }
  10065. VspAcquire(rootExtension);
  10066. }
  10067. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  10068. e = Filter->PreparedSnapshot;
  10069. Filter->PreparedSnapshot = extension;
  10070. KeReleaseSpinLock(&Filter->SpinLock, irql);
  10071. if (!isInternal) {
  10072. ObReferenceObject(extension->DeviceObject);
  10073. extension->IsPreExposure = TRUE;
  10074. KeInitializeEvent(&extension->PreExposureEvent, NotificationEvent,
  10075. FALSE);
  10076. }
  10077. deviceObject->Flags |= DO_DIRECT_IO;
  10078. deviceObject->StackSize = (CCHAR) Filter->Root->StackSize + 1;
  10079. deviceObject->AlignmentRequirement =
  10080. extension->Filter->Pdo->AlignmentRequirement |
  10081. extension->DiffAreaFile->Filter->Pdo->AlignmentRequirement;
  10082. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  10083. VspRelease(rootExtension);
  10084. if (e) {
  10085. VspCleanupInitialSnapshot(e, TRUE, FALSE);
  10086. }
  10087. fallThrough = TRUE;
  10088. Finish:
  10089. VspReleaseCritical(Filter);
  10090. if (fallThrough && !isInternal) {
  10091. VspPerformPreExposure(extension);
  10092. ObDereferenceObject(extension->DeviceObject);
  10093. }
  10094. IoFreeWorkItem(context->Dispatch.IoWorkItem);
  10095. VspFreeContext(rootExtension, context);
  10096. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  10097. }
  10098. NTSTATUS
  10099. VspPrepareForSnapshot(
  10100. IN PFILTER_EXTENSION Filter,
  10101. IN PIRP Irp
  10102. )
  10103. /*++
  10104. Routine Description:
  10105. This routine prepares a snapshot device object to be used later
  10106. for a snapshot. This phase is distict from commit snapshot because
  10107. it can be called before IRPs are held.
  10108. Besides creating the device object, this routine will also pre
  10109. allocate some of the diff area.
  10110. Arguments:
  10111. Filter - Supplies the filter extension.
  10112. Irp - Supplies the I/O request packet.
  10113. Return Value:
  10114. NTSTATUS
  10115. --*/
  10116. {
  10117. PVSP_CONTEXT context;
  10118. Irp->IoStatus.Status = STATUS_SUCCESS;
  10119. Irp->IoStatus.Information = 0;
  10120. context = VspAllocateContext(Filter->Root);
  10121. if (!context) {
  10122. return STATUS_INSUFFICIENT_RESOURCES;
  10123. }
  10124. context->Type = VSP_CONTEXT_TYPE_DISPATCH;
  10125. context->Dispatch.IoWorkItem = IoAllocateWorkItem(Filter->DeviceObject);
  10126. if (!context->Dispatch.IoWorkItem) {
  10127. VspFreeContext(Filter->Root, context);
  10128. return STATUS_INSUFFICIENT_RESOURCES;
  10129. }
  10130. IoMarkIrpPending(Irp);
  10131. context->Dispatch.Irp = Irp;
  10132. IoQueueWorkItem(context->Dispatch.IoWorkItem,
  10133. VspPrepareForSnapshotWorker, DelayedWorkQueue, context);
  10134. return STATUS_PENDING;
  10135. }
  10136. VOID
  10137. VspCleanupInitialMaps(
  10138. IN PVOID Context
  10139. )
  10140. {
  10141. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  10142. PVOLUME_EXTENSION extension = context->Extension.Extension;
  10143. NTSTATUS status;
  10144. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  10145. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10146. extension->DiffAreaFileMap);
  10147. ASSERT(NT_SUCCESS(status));
  10148. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  10149. extension->NextDiffAreaFileMap);
  10150. ASSERT(NT_SUCCESS(status));
  10151. VspFreeContext(extension->Root, context);
  10152. VspReleasePagedResource(extension);
  10153. ObDereferenceObject(extension->DeviceObject);
  10154. }
  10155. VOID
  10156. VspCleanupInitialSnapshot(
  10157. IN PVOLUME_EXTENSION Extension,
  10158. IN BOOLEAN NeedLock,
  10159. IN BOOLEAN IsFinalRemove
  10160. )
  10161. {
  10162. PVSP_CONTEXT context;
  10163. NTSTATUS status;
  10164. KIRQL irql;
  10165. if (Extension->IsPersistent) {
  10166. VspCleanupControlItemsForSnapshot(Extension);
  10167. }
  10168. context = VspAllocateContext(Extension->Root);
  10169. if (context) {
  10170. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  10171. context->Extension.Extension = Extension;
  10172. context->Extension.Irp = NULL;
  10173. ExInitializeWorkItem(&context->WorkItem, VspCleanupInitialMaps,
  10174. context);
  10175. ObReferenceObject(Extension->DeviceObject);
  10176. VspAcquirePagedResource(Extension, &context->WorkItem);
  10177. } else {
  10178. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  10179. Extension->DiffAreaFileMap);
  10180. ASSERT(NT_SUCCESS(status));
  10181. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  10182. Extension->NextDiffAreaFileMap);
  10183. ASSERT(NT_SUCCESS(status));
  10184. }
  10185. if (NeedLock) {
  10186. VspAcquire(Extension->Root);
  10187. }
  10188. VspDeleteWorkerThread(Extension->Root);
  10189. if (Extension->DiffAreaFile) {
  10190. KeAcquireSpinLock(&Extension->DiffAreaFile->Filter->SpinLock, &irql);
  10191. if (Extension->DiffAreaFile->FilterListEntryBeingUsed) {
  10192. RemoveEntryList(&Extension->DiffAreaFile->FilterListEntry);
  10193. Extension->DiffAreaFile->FilterListEntryBeingUsed = FALSE;
  10194. }
  10195. KeReleaseSpinLock(&Extension->DiffAreaFile->Filter->SpinLock, irql);
  10196. }
  10197. VspDeleteInitialDiffAreaFile(Extension);
  10198. if (Extension->IsPreExposure) {
  10199. KeSetEvent(&Extension->PreExposureEvent, IO_NO_INCREMENT, FALSE);
  10200. }
  10201. if (NeedLock) {
  10202. VspRelease(Extension->Root);
  10203. }
  10204. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  10205. ExFreePool(Extension->VolumeBlockBitmap->Buffer);
  10206. ExFreePool(Extension->VolumeBlockBitmap);
  10207. Extension->VolumeBlockBitmap = NULL;
  10208. if (Extension->IgnorableProduct) {
  10209. ExFreePool(Extension->IgnorableProduct->Buffer);
  10210. ExFreePool(Extension->IgnorableProduct);
  10211. Extension->IgnorableProduct = NULL;
  10212. }
  10213. KeReleaseSpinLock(&Extension->SpinLock, irql);
  10214. ExFreePool(MmGetMdlVirtualAddress(
  10215. Extension->EmergencyCopyIrp->MdlAddress));
  10216. IoFreeMdl(Extension->EmergencyCopyIrp->MdlAddress);
  10217. IoFreeIrp(Extension->EmergencyCopyIrp);
  10218. if (Extension->AliveToPnp) {
  10219. InsertTailList(&Extension->Filter->DeadVolumeList,
  10220. &Extension->ListEntry);
  10221. if (!IsFinalRemove) {
  10222. IoInvalidateDeviceRelations(Extension->Filter->Pdo, BusRelations);
  10223. }
  10224. } else {
  10225. if (NeedLock) {
  10226. VspAcquire(Extension->Root);
  10227. }
  10228. RtlDeleteElementGenericTable(&Extension->Root->UsedDevnodeNumbers,
  10229. &Extension->DevnodeNumber);
  10230. if (NeedLock) {
  10231. VspRelease(Extension->Root);
  10232. }
  10233. IoDeleteDevice(Extension->DeviceObject);
  10234. }
  10235. }
  10236. NTSTATUS
  10237. VspMarkFreeSpaceInBitmap(
  10238. IN PVOLUME_EXTENSION Extension,
  10239. IN HANDLE UseThisHandle,
  10240. IN PRTL_BITMAP BitmapToSet
  10241. )
  10242. /*++
  10243. Routine Description:
  10244. This routine opens the snapshot volume and marks off the free
  10245. space in the NTFS bitmap as 'ignorable'.
  10246. Arguments:
  10247. Extension - Supplies the volume extension.
  10248. Return Value:
  10249. NTSTATUS
  10250. --*/
  10251. {
  10252. WCHAR buffer[100];
  10253. KEVENT event;
  10254. IO_STATUS_BLOCK ioStatus;
  10255. UNICODE_STRING fileName;
  10256. OBJECT_ATTRIBUTES oa;
  10257. NTSTATUS status;
  10258. HANDLE h;
  10259. LARGE_INTEGER timeout;
  10260. BOOLEAN isNtfs;
  10261. FILE_FS_SIZE_INFORMATION fsSize;
  10262. ULONG bitmapSize;
  10263. STARTING_LCN_INPUT_BUFFER input;
  10264. PVOLUME_BITMAP_BUFFER output;
  10265. RTL_BITMAP freeSpaceBitmap;
  10266. ULONG bpc, f, numBits, startBit, s, n, i;
  10267. KIRQL irql;
  10268. ULONG r;
  10269. if (UseThisHandle) {
  10270. h = UseThisHandle;
  10271. } else {
  10272. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  10273. Extension->VolumeNumber);
  10274. RtlInitUnicodeString(&fileName, buffer);
  10275. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  10276. OBJ_KERNEL_HANDLE, NULL, NULL);
  10277. KeInitializeEvent(&event, NotificationEvent, FALSE);
  10278. timeout.QuadPart = -10*1000; // 1 millisecond.
  10279. for (i = 0; i < 5000; i++) {
  10280. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  10281. FILE_SHARE_READ | FILE_SHARE_WRITE |
  10282. FILE_SHARE_DELETE,
  10283. FILE_SYNCHRONOUS_IO_NONALERT);
  10284. if (NT_SUCCESS(status)) {
  10285. break;
  10286. }
  10287. if (status != STATUS_NO_SUCH_DEVICE) {
  10288. return status;
  10289. }
  10290. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  10291. &timeout);
  10292. }
  10293. if (!NT_SUCCESS(status)) {
  10294. return status;
  10295. }
  10296. }
  10297. status = VspIsNtfs(h, &isNtfs);
  10298. if (!NT_SUCCESS(status) || !isNtfs) {
  10299. if (!UseThisHandle) {
  10300. ZwClose(h);
  10301. }
  10302. return status;
  10303. }
  10304. status = ZwQueryVolumeInformationFile(h, &ioStatus, &fsSize,
  10305. sizeof(fsSize),
  10306. FileFsSizeInformation);
  10307. if (!NT_SUCCESS(status)) {
  10308. if (!UseThisHandle) {
  10309. ZwClose(h);
  10310. }
  10311. return status;
  10312. }
  10313. bitmapSize = (ULONG) ((fsSize.TotalAllocationUnits.QuadPart+7)/8 +
  10314. FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + 3);
  10315. input.StartingLcn.QuadPart = 0;
  10316. output = (PVOLUME_BITMAP_BUFFER)
  10317. ExAllocatePoolWithTag(PagedPool, bitmapSize, VOLSNAP_TAG_BITMAP);
  10318. if (!output) {
  10319. if (!UseThisHandle) {
  10320. ZwClose(h);
  10321. }
  10322. return STATUS_INSUFFICIENT_RESOURCES;
  10323. }
  10324. status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
  10325. FSCTL_GET_VOLUME_BITMAP, &input,
  10326. sizeof(input), output, bitmapSize);
  10327. if (!UseThisHandle) {
  10328. ZwClose(h);
  10329. }
  10330. if (!NT_SUCCESS(status)) {
  10331. ExFreePool(output);
  10332. return status;
  10333. }
  10334. ASSERT(output->BitmapSize.HighPart == 0);
  10335. RtlInitializeBitMap(&freeSpaceBitmap, (PULONG) output->Buffer,
  10336. output->BitmapSize.LowPart);
  10337. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  10338. if (bpc < BLOCK_SIZE) {
  10339. f = BLOCK_SIZE/bpc;
  10340. } else {
  10341. f = bpc/BLOCK_SIZE;
  10342. }
  10343. startBit = 0;
  10344. for (;;) {
  10345. if (startBit < freeSpaceBitmap.SizeOfBitMap) {
  10346. numBits = RtlFindNextForwardRunClear(&freeSpaceBitmap, startBit,
  10347. &startBit);
  10348. } else {
  10349. numBits = 0;
  10350. }
  10351. if (!numBits) {
  10352. break;
  10353. }
  10354. if (bpc == BLOCK_SIZE) {
  10355. s = startBit;
  10356. n = numBits;
  10357. } else if (bpc < BLOCK_SIZE) {
  10358. s = (startBit + f - 1)/f;
  10359. r = startBit%f;
  10360. if (r) {
  10361. if (numBits > f - r) {
  10362. n = numBits - (f - r);
  10363. } else {
  10364. n = 0;
  10365. }
  10366. } else {
  10367. n = numBits;
  10368. }
  10369. n /= f;
  10370. } else {
  10371. s = startBit*f;
  10372. n = numBits*f;
  10373. }
  10374. if (n) {
  10375. if (BitmapToSet) {
  10376. RtlSetBits(BitmapToSet, s, n);
  10377. } else {
  10378. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  10379. if (Extension->VolumeBlockBitmap) {
  10380. if (Extension->IgnorableProduct) {
  10381. for (i = 0; i < n; i++) {
  10382. if (RtlCheckBit(Extension->IgnorableProduct, i + s)) {
  10383. RtlSetBit(Extension->VolumeBlockBitmap, i + s);
  10384. }
  10385. }
  10386. } else {
  10387. RtlSetBits(Extension->VolumeBlockBitmap, s, n);
  10388. }
  10389. }
  10390. KeReleaseSpinLock(&Extension->SpinLock, irql);
  10391. }
  10392. }
  10393. startBit += numBits;
  10394. }
  10395. ExFreePool(output);
  10396. return STATUS_SUCCESS;
  10397. }
  10398. NTSTATUS
  10399. VspCommitSnapshot(
  10400. IN PFILTER_EXTENSION Filter,
  10401. IN PIRP Irp
  10402. )
  10403. /*++
  10404. Routine Description:
  10405. This routine commits the prepared snapshot.
  10406. Arguments:
  10407. Filter - Supplies the filter extension.
  10408. Irp - Supplies the I/O request packet.
  10409. Return Value:
  10410. NTSTATUS
  10411. --*/
  10412. {
  10413. KIRQL irql;
  10414. PVOLUME_EXTENSION extension, previousExtension;
  10415. PLIST_ENTRY l;
  10416. PVSP_DIFF_AREA_FILE diffAreaFile;
  10417. InterlockedIncrement(&Filter->IgnoreCopyData);
  10418. VspAcquire(Filter->Root);
  10419. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  10420. extension = Filter->PreparedSnapshot;
  10421. Filter->PreparedSnapshot = NULL;
  10422. KeReleaseSpinLock(&Filter->SpinLock, irql);
  10423. if (!extension) {
  10424. VspRelease(Filter->Root);
  10425. InterlockedDecrement(&Filter->IgnoreCopyData);
  10426. return STATUS_INVALID_PARAMETER;
  10427. }
  10428. if (extension->DiffAreaFile->Filter->ProtectedBlocksBitmap) {
  10429. VspRelease(Filter->Root);
  10430. VspCleanupInitialSnapshot(extension, TRUE, FALSE);
  10431. InterlockedDecrement(&Filter->IgnoreCopyData);
  10432. return STATUS_INVALID_PARAMETER;
  10433. }
  10434. if (extension->IsPersistent &&
  10435. extension->Filter->ProtectedBlocksBitmap) {
  10436. VspRelease(Filter->Root);
  10437. VspCleanupInitialSnapshot(extension, TRUE, FALSE);
  10438. InterlockedDecrement(&Filter->IgnoreCopyData);
  10439. return STATUS_INVALID_PARAMETER;
  10440. }
  10441. if (!Filter->HoldIncomingWrites) {
  10442. VspRelease(Filter->Root);
  10443. VspCleanupInitialSnapshot(extension, TRUE, FALSE);
  10444. InterlockedDecrement(&Filter->IgnoreCopyData);
  10445. return Filter->LastReleaseDueToMemoryPressure ?
  10446. STATUS_INSUFFICIENT_RESOURCES : STATUS_INVALID_PARAMETER;
  10447. }
  10448. extension->IgnoreCopyDataReference = TRUE;
  10449. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  10450. InterlockedExchange(&Filter->SnapshotsPresent, TRUE);
  10451. if (extension->IsPersistent) {
  10452. InterlockedExchange(&Filter->PersistentSnapshots, TRUE);
  10453. } else {
  10454. InterlockedExchange(&Filter->PersistentSnapshots, FALSE);
  10455. }
  10456. InsertTailList(&Filter->VolumeList, &extension->ListEntry);
  10457. InterlockedIncrement(&Filter->EpicNumber);
  10458. extension->IsPreExposure = FALSE;
  10459. KeReleaseSpinLock(&Filter->SpinLock, irql);
  10460. l = extension->ListEntry.Blink;
  10461. if (l != &Filter->VolumeList) {
  10462. previousExtension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  10463. KeAcquireSpinLock(&previousExtension->SpinLock, &irql);
  10464. ExFreePool(previousExtension->VolumeBlockBitmap->Buffer);
  10465. ExFreePool(previousExtension->VolumeBlockBitmap);
  10466. previousExtension->VolumeBlockBitmap = NULL;
  10467. KeReleaseSpinLock(&previousExtension->SpinLock, irql);
  10468. extension->SnapshotOrderNumber =
  10469. previousExtension->SnapshotOrderNumber + 1;
  10470. } else {
  10471. extension->SnapshotOrderNumber = 1;
  10472. }
  10473. KeQuerySystemTime(&extension->CommitTimeStamp);
  10474. if (Filter->UsedForCrashdump && extension->IsPersistent) {
  10475. extension->ContainsCrashdumpFile = TRUE;
  10476. }
  10477. VspRelease(Filter->Root);
  10478. return STATUS_SUCCESS;
  10479. }
  10480. VOID
  10481. VspCheckMaxSizeWorker(
  10482. IN PVOID Context
  10483. )
  10484. {
  10485. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  10486. PFILTER_EXTENSION filter = context->Filter.Filter;
  10487. ULONG i, n;
  10488. PLIST_ENTRY l;
  10489. KIRQL irql;
  10490. LIST_ENTRY closeList, deleteList;
  10491. PVOLUME_EXTENSION extension;
  10492. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  10493. VspFreeContext(filter->Root, context);
  10494. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  10495. KernelMode, FALSE, NULL);
  10496. VspAcquire(filter->Root);
  10497. if (filter->IsRemoved) {
  10498. VspRelease(filter->Root);
  10499. ObDereferenceObject(filter->DeviceObject);
  10500. return;
  10501. }
  10502. i = 0;
  10503. for (l = filter->VolumeList.Flink; l != &filter->VolumeList;
  10504. l = l->Flink) {
  10505. i++;
  10506. }
  10507. if (i > VSP_MAX_SNAPSHOTS) {
  10508. n = i - VSP_MAX_SNAPSHOTS;
  10509. } else {
  10510. n = 0;
  10511. }
  10512. InitializeListHead(&closeList);
  10513. InitializeListHead(&deleteList);
  10514. for (i = 0; i < n; i++) {
  10515. extension = CONTAINING_RECORD(filter->VolumeList.Flink,
  10516. VOLUME_EXTENSION, ListEntry);
  10517. VspLogError(extension, NULL, VS_DELETE_TO_MAX_NUMBER, STATUS_SUCCESS,
  10518. 0, TRUE);
  10519. VspDeleteOldestSnapshot(filter, &closeList, &deleteList, FALSE, FALSE);
  10520. }
  10521. KeAcquireSpinLock(&filter->SpinLock, &irql);
  10522. if (!filter->MaximumVolumeSpace) {
  10523. KeReleaseSpinLock(&filter->SpinLock, irql);
  10524. VspRelease(filter->Root);
  10525. VspCloseDiffAreaFiles(&closeList, &deleteList);
  10526. ObDereferenceObject(filter->DeviceObject);
  10527. return;
  10528. }
  10529. while (filter->AllocatedVolumeSpace > filter->MaximumVolumeSpace) {
  10530. KeReleaseSpinLock(&filter->SpinLock, irql);
  10531. extension = CONTAINING_RECORD(filter->VolumeList.Flink,
  10532. VOLUME_EXTENSION, ListEntry);
  10533. VspLogError(extension, NULL, VS_DELETE_TO_TRIM_SPACE, STATUS_SUCCESS,
  10534. 2, TRUE);
  10535. VspDeleteOldestSnapshot(filter, &closeList, &deleteList, FALSE, FALSE);
  10536. KeAcquireSpinLock(&filter->SpinLock, &irql);
  10537. if (!filter->MaximumVolumeSpace) {
  10538. break;
  10539. }
  10540. }
  10541. KeReleaseSpinLock(&filter->SpinLock, irql);
  10542. VspRelease(filter->Root);
  10543. VspCloseDiffAreaFiles(&closeList, &deleteList);
  10544. ObDereferenceObject(filter->DeviceObject);
  10545. }
  10546. VOID
  10547. VspCheckMaxSize(
  10548. IN PFILTER_EXTENSION Filter
  10549. )
  10550. {
  10551. PVSP_CONTEXT context;
  10552. context = VspAllocateContext(Filter->Root);
  10553. if (!context) {
  10554. return;
  10555. }
  10556. ObReferenceObject(Filter->DeviceObject);
  10557. context->Type = VSP_CONTEXT_TYPE_FILTER;
  10558. context->Filter.Filter = Filter;
  10559. ExInitializeWorkItem(&context->WorkItem, VspCheckMaxSizeWorker,
  10560. context);
  10561. VspQueueLowPriorityWorkItem(Filter->Root, &context->WorkItem);
  10562. }
  10563. NTSTATUS
  10564. VspEndCommitSnapshot(
  10565. IN PFILTER_EXTENSION Filter,
  10566. IN PIRP Irp
  10567. )
  10568. /*++
  10569. Routine Description:
  10570. This routine commits the prepared snapshot.
  10571. Arguments:
  10572. Filter - Supplies the filter extension.
  10573. Irp - Supplies the I/O request packet.
  10574. Return Value:
  10575. NTSTATUS
  10576. --*/
  10577. {
  10578. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  10579. PLIST_ENTRY l;
  10580. PVOLUME_EXTENSION extension;
  10581. WCHAR buffer[100];
  10582. UNICODE_STRING volumeName;
  10583. PVOLSNAP_NAME output;
  10584. NTSTATUS status;
  10585. LARGE_INTEGER timeout;
  10586. PVSP_CONTEXT context;
  10587. VspAcquire(Filter->Root);
  10588. l = Filter->VolumeList.Blink;
  10589. if (l == &Filter->VolumeList) {
  10590. VspRelease(Filter->Root);
  10591. return STATUS_INVALID_PARAMETER;
  10592. }
  10593. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  10594. if (extension->HasEndCommit) {
  10595. VspRelease(Filter->Root);
  10596. return STATUS_INVALID_PARAMETER;
  10597. }
  10598. if (irpSp->Parameters.DeviceIoControl.InputBufferLength) {
  10599. status = VspSetApplicationInfo(extension, Irp);
  10600. if (!NT_SUCCESS(status)) {
  10601. if (extension->IgnoreCopyDataReference) {
  10602. extension->IgnoreCopyDataReference = FALSE;
  10603. InterlockedDecrement(&Filter->IgnoreCopyData);
  10604. }
  10605. VspRelease(Filter->Root);
  10606. return status;
  10607. }
  10608. }
  10609. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  10610. extension->VolumeNumber);
  10611. RtlInitUnicodeString(&volumeName, buffer);
  10612. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAME, Name) +
  10613. volumeName.Length + sizeof(WCHAR);
  10614. if (Irp->IoStatus.Information >
  10615. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  10616. if (extension->IgnoreCopyDataReference) {
  10617. extension->IgnoreCopyDataReference = FALSE;
  10618. InterlockedDecrement(&Filter->IgnoreCopyData);
  10619. }
  10620. VspRelease(Filter->Root);
  10621. Irp->IoStatus.Information = 0;
  10622. return STATUS_INVALID_PARAMETER;
  10623. }
  10624. output = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  10625. output->NameLength = volumeName.Length;
  10626. RtlCopyMemory(output->Name, volumeName.Buffer,
  10627. output->NameLength + sizeof(WCHAR));
  10628. extension->HasEndCommit = TRUE;
  10629. if (extension->IsPersistent) {
  10630. VspAcquireNonPagedResource(extension, NULL, FALSE);
  10631. status = VspCheckOnDiskNotCommitted(extension);
  10632. VspReleaseNonPagedResource(extension);
  10633. } else {
  10634. status = STATUS_SUCCESS;
  10635. }
  10636. if (NT_SUCCESS(status)) {
  10637. VspTruncatePreviousDiffArea(extension);
  10638. }
  10639. if (!KeCancelTimer(&Filter->EndCommitTimer)) {
  10640. ObReferenceObject(Filter->DeviceObject);
  10641. }
  10642. KeResetEvent(&Filter->EndCommitProcessCompleted);
  10643. if (extension->IsInstalled) {
  10644. context = VspAllocateContext(Filter->Root);
  10645. if (!context) {
  10646. InterlockedExchange(&Filter->HibernatePending, FALSE);
  10647. KeSetEvent(&Filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  10648. FALSE);
  10649. VspRelease(Filter->Root);
  10650. ObDereferenceObject(Filter->DeviceObject);
  10651. return STATUS_INSUFFICIENT_RESOURCES;
  10652. }
  10653. ObReferenceObject(extension->DeviceObject);
  10654. ObReferenceObject(Filter->TargetObject);
  10655. VspRelease(Filter->Root);
  10656. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  10657. context->Extension.Extension = extension;
  10658. context->Extension.Irp = NULL;
  10659. ExInitializeWorkItem(&context->WorkItem,
  10660. VspSetIgnorableBlocksInBitmapWorker, context);
  10661. VspQueueWorkItem(Filter->Root, &context->WorkItem, 0);
  10662. } else {
  10663. timeout.QuadPart = (LONGLONG) -10*1000*1000*120*10; // 20 minutes.
  10664. KeSetTimer(&Filter->EndCommitTimer, timeout,
  10665. &Filter->EndCommitTimerDpc);
  10666. VspRelease(Filter->Root);
  10667. IoInvalidateDeviceRelations(Filter->Pdo, BusRelations);
  10668. }
  10669. VspCheckMaxSize(Filter);
  10670. return STATUS_SUCCESS;
  10671. }
  10672. NTSTATUS
  10673. VspVolumeRefCountCompletionRoutine(
  10674. IN PDEVICE_OBJECT DeviceObject,
  10675. IN PIRP Irp,
  10676. IN PVOID Extension
  10677. )
  10678. {
  10679. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  10680. VspDecrementVolumeRefCount(extension);
  10681. return STATUS_SUCCESS;
  10682. }
  10683. NTSTATUS
  10684. VspQueryNamesOfSnapshots(
  10685. IN PFILTER_EXTENSION Filter,
  10686. IN PIRP Irp
  10687. )
  10688. /*++
  10689. Routine Description:
  10690. This routine returns the names of all of the snapshots for this filter.
  10691. Arguments:
  10692. Filter - Supplies the filter extension.
  10693. Irp - Supplies the I/O request packet.
  10694. Return Value:
  10695. NTSTATUS
  10696. --*/
  10697. {
  10698. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  10699. PVOLSNAP_NAMES output;
  10700. PLIST_ENTRY l;
  10701. PVOLUME_EXTENSION extension;
  10702. WCHAR buffer[100];
  10703. UNICODE_STRING name;
  10704. PWCHAR buf;
  10705. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAMES, Names);
  10706. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  10707. Irp->IoStatus.Information) {
  10708. Irp->IoStatus.Information = 0;
  10709. return STATUS_INVALID_PARAMETER;
  10710. }
  10711. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  10712. KernelMode, FALSE, NULL);
  10713. output = (PVOLSNAP_NAMES) Irp->AssociatedIrp.SystemBuffer;
  10714. VspAcquire(Filter->Root);
  10715. output->MultiSzLength = sizeof(WCHAR);
  10716. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  10717. l = l->Flink) {
  10718. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  10719. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  10720. extension->VolumeNumber);
  10721. RtlInitUnicodeString(&name, buffer);
  10722. output->MultiSzLength += name.Length + sizeof(WCHAR);
  10723. }
  10724. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  10725. Irp->IoStatus.Information + output->MultiSzLength) {
  10726. VspRelease(Filter->Root);
  10727. return STATUS_BUFFER_OVERFLOW;
  10728. }
  10729. Irp->IoStatus.Information += output->MultiSzLength;
  10730. buf = output->Names;
  10731. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  10732. l = l->Flink) {
  10733. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  10734. swprintf(buf, L"\\Device\\HarddiskVolumeShadowCopy%d",
  10735. extension->VolumeNumber);
  10736. RtlInitUnicodeString(&name, buf);
  10737. buf += name.Length/sizeof(WCHAR) + 1;
  10738. }
  10739. *buf = 0;
  10740. VspRelease(Filter->Root);
  10741. return STATUS_SUCCESS;
  10742. }
  10743. NTSTATUS
  10744. VspClearDiffArea(
  10745. IN PFILTER_EXTENSION Filter,
  10746. IN PIRP Irp
  10747. )
  10748. /*++
  10749. Routine Description:
  10750. This routine clears the list of diff areas used by this filter. This
  10751. call will fail if there are any snapshots in flight.
  10752. Arguments:
  10753. Filter - Supplies the filter extension.
  10754. Irp - Supplies the I/O request packet.
  10755. Return Value:
  10756. NTSTATUS
  10757. --*/
  10758. {
  10759. VspAcquire(Filter->Root);
  10760. Filter->DiffAreaVolume = NULL;
  10761. VspRelease(Filter->Root);
  10762. return STATUS_SUCCESS;
  10763. }
  10764. NTSTATUS
  10765. VspAddVolumeToDiffArea(
  10766. IN PFILTER_EXTENSION Filter,
  10767. IN PIRP Irp
  10768. )
  10769. /*++
  10770. Routine Description:
  10771. This routine adds the given volume to the diff area for this volume.
  10772. All snapshots get a new diff area file.
  10773. Arguments:
  10774. Filter - Supplies the filter extension.
  10775. Irp - Supplies the I/O request packet.
  10776. Return Value:
  10777. NTSTATUS
  10778. --*/
  10779. {
  10780. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  10781. PVOLSNAP_NAME input;
  10782. UNICODE_STRING volumeName;
  10783. PFILTER_EXTENSION filter;
  10784. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  10785. sizeof(VOLSNAP_NAME)) {
  10786. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  10787. STATUS_INVALID_PARAMETER, 3, FALSE);
  10788. return STATUS_INVALID_PARAMETER;
  10789. }
  10790. input = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  10791. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  10792. (ULONG) FIELD_OFFSET(VOLSNAP_NAME, Name) + input->NameLength) {
  10793. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  10794. STATUS_INVALID_PARAMETER, 4, FALSE);
  10795. return STATUS_INVALID_PARAMETER;
  10796. }
  10797. volumeName.Length = volumeName.MaximumLength = input->NameLength;
  10798. volumeName.Buffer = input->Name;
  10799. VspAcquire(Filter->Root);
  10800. filter = VspFindFilter(Filter->Root, Filter, &volumeName, NULL);
  10801. if (!filter ||
  10802. (filter->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA)) {
  10803. VspRelease(Filter->Root);
  10804. return STATUS_INVALID_PARAMETER;
  10805. }
  10806. if (Filter->DiffAreaVolume) {
  10807. VspRelease(Filter->Root);
  10808. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  10809. STATUS_INVALID_PARAMETER, 5, FALSE);
  10810. return STATUS_INVALID_PARAMETER;
  10811. }
  10812. Filter->DiffAreaVolume = filter;
  10813. VspRelease(Filter->Root);
  10814. return STATUS_SUCCESS;
  10815. }
  10816. NTSTATUS
  10817. VspQueryDiffArea(
  10818. IN PDEVICE_EXTENSION DeviceExtension,
  10819. IN PIRP Irp
  10820. )
  10821. /*++
  10822. Routine Description:
  10823. This routine the list of volumes that make up the diff area for this
  10824. volume.
  10825. Arguments:
  10826. Filter - Supplies the filter extension.
  10827. Irp - Supplies the I/O request packet.
  10828. Return Value:
  10829. NTSTATUS
  10830. --*/
  10831. {
  10832. PFILTER_EXTENSION Filter = (PFILTER_EXTENSION) DeviceExtension;
  10833. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceExtension;
  10834. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  10835. PVOLSNAP_NAMES output;
  10836. PLIST_ENTRY l;
  10837. PFILTER_EXTENSION filter;
  10838. KEVENT event;
  10839. PMOUNTDEV_NAME name;
  10840. CHAR buffer[512];
  10841. PIRP irp;
  10842. IO_STATUS_BLOCK ioStatus;
  10843. NTSTATUS status;
  10844. PWCHAR buf;
  10845. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAMES, Names);
  10846. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  10847. Irp->IoStatus.Information) {
  10848. Irp->IoStatus.Information = 0;
  10849. return STATUS_INVALID_PARAMETER;
  10850. }
  10851. output = (PVOLSNAP_NAMES) Irp->AssociatedIrp.SystemBuffer;
  10852. VspAcquire(Filter->Root);
  10853. output->MultiSzLength = sizeof(WCHAR);
  10854. if (Filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  10855. filter = Filter->DiffAreaVolume;
  10856. } else {
  10857. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  10858. if (extension->DiffAreaFile) {
  10859. filter = extension->DiffAreaFile->Filter;
  10860. } else {
  10861. filter = NULL;
  10862. }
  10863. }
  10864. if (filter) {
  10865. KeInitializeEvent(&event, NotificationEvent, FALSE);
  10866. name = (PMOUNTDEV_NAME) buffer;
  10867. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  10868. filter->TargetObject, NULL, 0,
  10869. name, 500, FALSE, &event,
  10870. &ioStatus);
  10871. if (!irp) {
  10872. VspRelease(Filter->Root);
  10873. Irp->IoStatus.Information = 0;
  10874. return STATUS_INSUFFICIENT_RESOURCES;
  10875. }
  10876. status = IoCallDriver(filter->TargetObject, irp);
  10877. if (status == STATUS_PENDING) {
  10878. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  10879. NULL);
  10880. status = ioStatus.Status;
  10881. }
  10882. if (!NT_SUCCESS(status)) {
  10883. VspRelease(Filter->Root);
  10884. Irp->IoStatus.Information = 0;
  10885. return status;
  10886. }
  10887. output->MultiSzLength += name->NameLength + sizeof(WCHAR);
  10888. }
  10889. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  10890. Irp->IoStatus.Information + output->MultiSzLength) {
  10891. VspRelease(Filter->Root);
  10892. return STATUS_BUFFER_OVERFLOW;
  10893. }
  10894. Irp->IoStatus.Information += output->MultiSzLength;
  10895. buf = output->Names;
  10896. if (Filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  10897. filter = Filter->DiffAreaVolume;
  10898. } else {
  10899. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  10900. if (extension->DiffAreaFile) {
  10901. filter = extension->DiffAreaFile->Filter;
  10902. } else {
  10903. filter = NULL;
  10904. }
  10905. }
  10906. if (filter) {
  10907. KeInitializeEvent(&event, NotificationEvent, FALSE);
  10908. name = (PMOUNTDEV_NAME) buffer;
  10909. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  10910. filter->TargetObject, NULL, 0,
  10911. name, 500, FALSE, &event,
  10912. &ioStatus);
  10913. if (!irp) {
  10914. VspRelease(Filter->Root);
  10915. Irp->IoStatus.Information = 0;
  10916. return STATUS_INSUFFICIENT_RESOURCES;
  10917. }
  10918. status = IoCallDriver(filter->TargetObject, irp);
  10919. if (status == STATUS_PENDING) {
  10920. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  10921. NULL);
  10922. status = ioStatus.Status;
  10923. }
  10924. if (!NT_SUCCESS(status)) {
  10925. VspRelease(Filter->Root);
  10926. Irp->IoStatus.Information = 0;
  10927. return status;
  10928. }
  10929. RtlCopyMemory(buf, name->Name, name->NameLength);
  10930. buf += name->NameLength/sizeof(WCHAR);
  10931. *buf++ = 0;
  10932. }
  10933. *buf = 0;
  10934. VspRelease(Filter->Root);
  10935. return STATUS_SUCCESS;
  10936. }
  10937. NTSTATUS
  10938. VspQueryDiffAreaSizes(
  10939. IN PDEVICE_EXTENSION DeviceExtension,
  10940. IN PIRP Irp
  10941. )
  10942. /*++
  10943. Routine Description:
  10944. This routine returns the diff area sizes for this volume.
  10945. Arguments:
  10946. Filter - Supplies the filter extension.
  10947. Irp - Supplies the I/O request packet.
  10948. Return Value:
  10949. NTSTATUS
  10950. --*/
  10951. {
  10952. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceExtension;
  10953. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceExtension;
  10954. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  10955. PVOLSNAP_DIFF_AREA_SIZES output = (PVOLSNAP_DIFF_AREA_SIZES) Irp->AssociatedIrp.SystemBuffer;
  10956. KIRQL irql;
  10957. Irp->IoStatus.Information = sizeof(VOLSNAP_DIFF_AREA_SIZES);
  10958. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  10959. Irp->IoStatus.Information) {
  10960. Irp->IoStatus.Information = 0;
  10961. return STATUS_INVALID_PARAMETER;
  10962. }
  10963. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  10964. KeAcquireSpinLock(&filter->SpinLock, &irql);
  10965. output->UsedVolumeSpace = filter->UsedVolumeSpace;
  10966. output->AllocatedVolumeSpace = filter->AllocatedVolumeSpace;
  10967. output->MaximumVolumeSpace = filter->MaximumVolumeSpace;
  10968. KeReleaseSpinLock(&filter->SpinLock, irql);
  10969. return STATUS_SUCCESS;
  10970. }
  10971. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  10972. RtlZeroMemory(output, sizeof(VOLSNAP_DIFF_AREA_SIZES));
  10973. VspAcquireNonPagedResource(extension, NULL, FALSE);
  10974. if (extension->DiffAreaFile) {
  10975. output->UsedVolumeSpace = extension->DiffAreaFile->NextAvailable;
  10976. output->AllocatedVolumeSpace =
  10977. extension->DiffAreaFile->AllocatedFileSize;
  10978. }
  10979. VspReleaseNonPagedResource(extension);
  10980. return STATUS_SUCCESS;
  10981. }
  10982. NTSTATUS
  10983. VspQueryOriginalVolumeName(
  10984. IN PVOLUME_EXTENSION Extension,
  10985. IN PIRP Irp
  10986. )
  10987. /*++
  10988. Routine Description:
  10989. This routine returns the original volume name for the given volume
  10990. snapshot.
  10991. Arguments:
  10992. Extension - Supplies the volume extension.
  10993. Irp - Supplies the I/O request packet.
  10994. Return Value:
  10995. NTSTATUS
  10996. --*/
  10997. {
  10998. PFILTER_EXTENSION filter = Extension->Filter;
  10999. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11000. PVOLSNAP_NAME output = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  11001. PMOUNTDEV_NAME name;
  11002. CHAR buffer[512];
  11003. KEVENT event;
  11004. PIRP irp;
  11005. IO_STATUS_BLOCK ioStatus;
  11006. NTSTATUS status;
  11007. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAME, Name);
  11008. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  11009. Irp->IoStatus.Information) {
  11010. Irp->IoStatus.Information = 0;
  11011. return STATUS_INVALID_PARAMETER;
  11012. }
  11013. name = (PMOUNTDEV_NAME) buffer;
  11014. KeInitializeEvent(&event, NotificationEvent, FALSE);
  11015. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  11016. filter->TargetObject, NULL, 0,
  11017. name, 500, FALSE, &event,
  11018. &ioStatus);
  11019. if (!irp) {
  11020. Irp->IoStatus.Information = 0;
  11021. return STATUS_INSUFFICIENT_RESOURCES;
  11022. }
  11023. status = IoCallDriver(filter->TargetObject, irp);
  11024. if (status == STATUS_PENDING) {
  11025. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  11026. status = ioStatus.Status;
  11027. }
  11028. if (!NT_SUCCESS(status)) {
  11029. Irp->IoStatus.Information = 0;
  11030. return status;
  11031. }
  11032. output->NameLength = name->NameLength;
  11033. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  11034. Irp->IoStatus.Information + output->NameLength) {
  11035. return STATUS_BUFFER_OVERFLOW;
  11036. }
  11037. RtlCopyMemory(output->Name, name->Name, output->NameLength);
  11038. Irp->IoStatus.Information += output->NameLength;
  11039. return STATUS_SUCCESS;
  11040. }
  11041. NTSTATUS
  11042. VspQueryConfigInfo(
  11043. IN PVOLUME_EXTENSION Extension,
  11044. IN PIRP Irp
  11045. )
  11046. /*++
  11047. Routine Description:
  11048. This routine returns the configuration information for this volume
  11049. snapshot.
  11050. Arguments:
  11051. Extension - Supplies the volume extension.
  11052. Irp - Supplies the I/O request packet.
  11053. Return Value:
  11054. NTSTATUS
  11055. --*/
  11056. {
  11057. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11058. PVOLSNAP_CONFIG_INFO output = (PVOLSNAP_CONFIG_INFO) Irp->AssociatedIrp.SystemBuffer;
  11059. Irp->IoStatus.Information = sizeof(ULONG);
  11060. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  11061. Irp->IoStatus.Information) {
  11062. Irp->IoStatus.Information = 0;
  11063. return STATUS_INVALID_PARAMETER;
  11064. }
  11065. output->Attributes = 0;
  11066. if (Extension->IsPersistent) {
  11067. output->Attributes |= VOLSNAP_ATTRIBUTE_PERSISTENT;
  11068. }
  11069. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  11070. sizeof(VOLSNAP_CONFIG_INFO)) {
  11071. Irp->IoStatus.Information = sizeof(VOLSNAP_CONFIG_INFO);
  11072. output->Reserved = 0;
  11073. output->SnapshotCreationTime = Extension->CommitTimeStamp;
  11074. }
  11075. return STATUS_SUCCESS;
  11076. }
  11077. NTSTATUS
  11078. VspWriteApplicationInfo(
  11079. IN PVOLUME_EXTENSION Extension
  11080. )
  11081. {
  11082. LONGLONG targetOffset, fileOffset;
  11083. NTSTATUS status;
  11084. PVSP_BLOCK_APP_INFO appInfoBlock;
  11085. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  11086. targetOffset = Extension->DiffAreaFile->ApplicationInfoTargetOffset;
  11087. ASSERT(targetOffset);
  11088. status = VspSynchronousIo(Extension->Filter->SnapshotOnDiskIrp,
  11089. Extension->DiffAreaFile->Filter->TargetObject,
  11090. IRP_MJ_READ, targetOffset, 0);
  11091. if (!NT_SUCCESS(status)) {
  11092. VspReleaseNonPagedResource(Extension);
  11093. return status;
  11094. }
  11095. appInfoBlock = (PVSP_BLOCK_APP_INFO)
  11096. MmGetMdlVirtualAddress(Extension->Filter->SnapshotOnDiskIrp->
  11097. MdlAddress);
  11098. if (appInfoBlock->Header.Signature != VSP_DIFF_AREA_FILE_GUID ||
  11099. appInfoBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  11100. appInfoBlock->Header.BlockType != VSP_BLOCK_TYPE_APP_INFO ||
  11101. appInfoBlock->Header.ThisVolumeOffset != targetOffset ||
  11102. appInfoBlock->Header.NextVolumeOffset) {
  11103. VspReleaseNonPagedResource(Extension);
  11104. return STATUS_INVALID_PARAMETER;
  11105. }
  11106. appInfoBlock->AppInfoSize = Extension->ApplicationInformationSize;
  11107. RtlCopyMemory((PCHAR) appInfoBlock + VSP_OFFSET_TO_APP_INFO,
  11108. Extension->ApplicationInformation,
  11109. Extension->ApplicationInformationSize);
  11110. status = VspSynchronousIo(Extension->Filter->SnapshotOnDiskIrp,
  11111. Extension->DiffAreaFile->Filter->TargetObject,
  11112. IRP_MJ_WRITE, targetOffset, 0);
  11113. if (!NT_SUCCESS(status)) {
  11114. VspReleaseNonPagedResource(Extension);
  11115. return status;
  11116. }
  11117. VspReleaseNonPagedResource(Extension);
  11118. return STATUS_SUCCESS;
  11119. }
  11120. NTSTATUS
  11121. VspSetApplicationInfo(
  11122. IN PVOLUME_EXTENSION Extension,
  11123. IN PIRP Irp
  11124. )
  11125. /*++
  11126. Routine Description:
  11127. This routine sets the application info.
  11128. Arguments:
  11129. Extension - Supplies the volume extension.
  11130. Irp - Supplies the I/O request packet.
  11131. Return Value:
  11132. NTSTATUS
  11133. --*/
  11134. {
  11135. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11136. PVOLSNAP_APPLICATION_INFO input = (PVOLSNAP_APPLICATION_INFO) Irp->AssociatedIrp.SystemBuffer;
  11137. PVOID newAppInfo, oldAppInfo;
  11138. NTSTATUS status;
  11139. Irp->IoStatus.Information = 0;
  11140. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  11141. sizeof(VOLSNAP_APPLICATION_INFO)) {
  11142. return STATUS_INVALID_PARAMETER;
  11143. }
  11144. if (input->InformationLength > VSP_MAX_APP_INFO_SIZE) {
  11145. return STATUS_INVALID_PARAMETER;
  11146. }
  11147. if (input->InformationLength < sizeof(GUID)) {
  11148. return STATUS_INVALID_PARAMETER;
  11149. }
  11150. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  11151. (LONGLONG) FIELD_OFFSET(VOLSNAP_APPLICATION_INFO, Information) +
  11152. input->InformationLength) {
  11153. return STATUS_INVALID_PARAMETER;
  11154. }
  11155. newAppInfo = ExAllocatePoolWithQuotaTag((POOL_TYPE) (NonPagedPool |
  11156. POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
  11157. input->InformationLength, VOLSNAP_TAG_APP_INFO);
  11158. if (!newAppInfo) {
  11159. return STATUS_INSUFFICIENT_RESOURCES;
  11160. }
  11161. RtlCopyMemory(newAppInfo, input->Information, input->InformationLength);
  11162. KeEnterCriticalRegion();
  11163. VspAcquirePagedResource(Extension, NULL);
  11164. Extension->ApplicationInformationSize = input->InformationLength;
  11165. oldAppInfo = Extension->ApplicationInformation;
  11166. Extension->ApplicationInformation = newAppInfo;
  11167. VspReleasePagedResource(Extension);
  11168. KeLeaveCriticalRegion();
  11169. InterlockedIncrement(&Extension->Filter->EpicNumber);
  11170. if (oldAppInfo) {
  11171. ExFreePool(oldAppInfo);
  11172. }
  11173. if (Extension->IsPersistent) {
  11174. status = VspWriteApplicationInfo(Extension);
  11175. if (!NT_SUCCESS(status)) {
  11176. return status;
  11177. }
  11178. }
  11179. return STATUS_SUCCESS;
  11180. }
  11181. NTSTATUS
  11182. VspQueryApplicationInfo(
  11183. IN PVOLUME_EXTENSION Extension,
  11184. IN PIRP Irp
  11185. )
  11186. /*++
  11187. Routine Description:
  11188. This routine queries the application info.
  11189. Arguments:
  11190. Extension - Supplies the volume extension.
  11191. Irp - Supplies the I/O request packet.
  11192. Return Value:
  11193. NTSTATUS
  11194. --*/
  11195. {
  11196. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11197. PVOLSNAP_APPLICATION_INFO output = (PVOLSNAP_APPLICATION_INFO) Irp->AssociatedIrp.SystemBuffer;
  11198. PVOID appInfo;
  11199. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_APPLICATION_INFO,
  11200. Information);
  11201. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  11202. Irp->IoStatus.Information) {
  11203. Irp->IoStatus.Information = 0;
  11204. return STATUS_INVALID_PARAMETER;
  11205. }
  11206. KeEnterCriticalRegion();
  11207. VspAcquirePagedResource(Extension, NULL);
  11208. output->InformationLength = Extension->ApplicationInformationSize;
  11209. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  11210. Irp->IoStatus.Information + output->InformationLength) {
  11211. VspReleasePagedResource(Extension);
  11212. KeLeaveCriticalRegion();
  11213. return STATUS_BUFFER_OVERFLOW;
  11214. }
  11215. Irp->IoStatus.Information += output->InformationLength;
  11216. RtlCopyMemory(output->Information, Extension->ApplicationInformation,
  11217. output->InformationLength);
  11218. VspReleasePagedResource(Extension);
  11219. KeLeaveCriticalRegion();
  11220. return STATUS_SUCCESS;
  11221. }
  11222. NTSTATUS
  11223. VspCheckSecurity(
  11224. IN PFILTER_EXTENSION Filter,
  11225. IN PIRP Irp
  11226. )
  11227. {
  11228. SECURITY_SUBJECT_CONTEXT securityContext;
  11229. BOOLEAN accessGranted;
  11230. NTSTATUS status;
  11231. ACCESS_MASK grantedAccess;
  11232. SeCaptureSubjectContext(&securityContext);
  11233. SeLockSubjectContext(&securityContext);
  11234. accessGranted = FALSE;
  11235. status = STATUS_ACCESS_DENIED;
  11236. _try {
  11237. accessGranted = SeAccessCheck(
  11238. Filter->Pdo->SecurityDescriptor,
  11239. &securityContext, TRUE, FILE_READ_DATA, 0, NULL,
  11240. IoGetFileObjectGenericMapping(), Irp->RequestorMode,
  11241. &grantedAccess, &status);
  11242. } _finally {
  11243. SeUnlockSubjectContext(&securityContext);
  11244. SeReleaseSubjectContext(&securityContext);
  11245. }
  11246. if (!accessGranted) {
  11247. return status;
  11248. }
  11249. return STATUS_SUCCESS;
  11250. }
  11251. NTSTATUS
  11252. VspAutoCleanup(
  11253. IN PFILTER_EXTENSION Filter,
  11254. IN PIRP Irp
  11255. )
  11256. /*++
  11257. Routine Description:
  11258. This routine remembers the given File Object so that when it is
  11259. cleaned up, all snapshots will be cleaned up with it.
  11260. Arguments:
  11261. Filter - Supplies the filter extension.
  11262. Irp - Supplies the I/O request packet.
  11263. Return Value:
  11264. NTSTATUS
  11265. --*/
  11266. {
  11267. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11268. NTSTATUS status;
  11269. KIRQL irql;
  11270. IoAcquireCancelSpinLock(&irql);
  11271. if (Filter->AutoCleanupFileObject) {
  11272. IoReleaseCancelSpinLock(irql);
  11273. return STATUS_INVALID_PARAMETER;
  11274. }
  11275. Filter->AutoCleanupFileObject = irpSp->FileObject;
  11276. IoReleaseCancelSpinLock(irql);
  11277. return STATUS_SUCCESS;
  11278. }
  11279. VOID
  11280. VspDeleteSnapshotWorker(
  11281. IN PDEVICE_OBJECT DeviceObject,
  11282. IN PVOID Context
  11283. )
  11284. {
  11285. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  11286. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  11287. PIRP irp = context->Dispatch.Irp;
  11288. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  11289. PVOLUME_EXTENSION oldestExtension;
  11290. PVOLSNAP_NAME name;
  11291. WCHAR buffer[100];
  11292. UNICODE_STRING name1, name2;
  11293. LIST_ENTRY listOfDiffAreaFileToClose;
  11294. LIST_ENTRY listOfDeviceObjectsToDelete;
  11295. NTSTATUS status;
  11296. ASSERT(context->Type == VSP_CONTEXT_TYPE_DISPATCH);
  11297. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  11298. KernelMode, FALSE, NULL);
  11299. InitializeListHead(&listOfDiffAreaFileToClose);
  11300. InitializeListHead(&listOfDeviceObjectsToDelete);
  11301. VspAcquire(filter->Root);
  11302. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  11303. IOCTL_VOLSNAP_DELETE_SNAPSHOT) {
  11304. if (IsListEmpty(&filter->VolumeList)) {
  11305. status = STATUS_INVALID_PARAMETER;
  11306. } else {
  11307. oldestExtension = CONTAINING_RECORD(filter->VolumeList.Flink,
  11308. VOLUME_EXTENSION, ListEntry);
  11309. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  11310. oldestExtension->VolumeNumber);
  11311. RtlInitUnicodeString(&name1, buffer);
  11312. name = (PVOLSNAP_NAME) irp->AssociatedIrp.SystemBuffer;
  11313. name2.Length = name2.MaximumLength = name->NameLength;
  11314. name2.Buffer = name->Name;
  11315. if (RtlEqualUnicodeString(&name1, &name2, TRUE)) {
  11316. status = STATUS_SUCCESS;
  11317. } else {
  11318. status = STATUS_NOT_SUPPORTED;
  11319. }
  11320. }
  11321. } else {
  11322. status = STATUS_SUCCESS;
  11323. }
  11324. if (NT_SUCCESS(status)) {
  11325. status = VspDeleteOldestSnapshot(filter, &listOfDiffAreaFileToClose,
  11326. &listOfDeviceObjectsToDelete,
  11327. FALSE, FALSE);
  11328. }
  11329. VspRelease(filter->Root);
  11330. VspCloseDiffAreaFiles(&listOfDiffAreaFileToClose,
  11331. &listOfDeviceObjectsToDelete);
  11332. IoFreeWorkItem(context->Dispatch.IoWorkItem);
  11333. VspFreeContext(filter->Root, context);
  11334. irp->IoStatus.Status = status;
  11335. IoCompleteRequest(irp, IO_NO_INCREMENT);
  11336. }
  11337. NTSTATUS
  11338. VspDeleteSnapshotPost(
  11339. IN PFILTER_EXTENSION Filter,
  11340. IN PIRP Irp
  11341. )
  11342. {
  11343. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11344. PVSP_CONTEXT context;
  11345. PVOLSNAP_NAME name;
  11346. Irp->IoStatus.Information = 0;
  11347. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  11348. IOCTL_VOLSNAP_DELETE_SNAPSHOT) {
  11349. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  11350. sizeof(VOLSNAP_NAME)) {
  11351. return STATUS_INVALID_PARAMETER;
  11352. }
  11353. name = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  11354. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  11355. (ULONG) FIELD_OFFSET(VOLSNAP_NAME, Name) + name->NameLength) {
  11356. return STATUS_INVALID_PARAMETER;
  11357. }
  11358. }
  11359. context = VspAllocateContext(Filter->Root);
  11360. if (!context) {
  11361. return STATUS_INSUFFICIENT_RESOURCES;
  11362. }
  11363. context->Type = VSP_CONTEXT_TYPE_DISPATCH;
  11364. context->Dispatch.IoWorkItem = IoAllocateWorkItem(Filter->DeviceObject);
  11365. if (!context->Dispatch.IoWorkItem) {
  11366. VspFreeContext(Filter->Root, context);
  11367. return STATUS_INSUFFICIENT_RESOURCES;
  11368. }
  11369. IoMarkIrpPending(Irp);
  11370. context->Dispatch.Irp = Irp;
  11371. IoQueueWorkItem(context->Dispatch.IoWorkItem,
  11372. VspDeleteSnapshotWorker, DelayedWorkQueue, context);
  11373. return STATUS_PENDING;
  11374. }
  11375. VOID
  11376. VspCheckCodeLocked(
  11377. IN PDO_EXTENSION RootExtension,
  11378. IN BOOLEAN CallerHoldingSemaphore
  11379. )
  11380. {
  11381. if (RootExtension->IsCodeLocked) {
  11382. return;
  11383. }
  11384. if (!CallerHoldingSemaphore) {
  11385. VspAcquire(RootExtension);
  11386. }
  11387. if (RootExtension->IsCodeLocked) {
  11388. if (!CallerHoldingSemaphore) {
  11389. VspRelease(RootExtension);
  11390. }
  11391. return;
  11392. }
  11393. MmLockPagableCodeSection(VspCheckCodeLocked);
  11394. InterlockedExchange(&RootExtension->IsCodeLocked, TRUE);
  11395. if (!CallerHoldingSemaphore) {
  11396. VspRelease(RootExtension);
  11397. }
  11398. }
  11399. NTSTATUS
  11400. VspSetMaxDiffAreaSize(
  11401. IN PFILTER_EXTENSION Filter,
  11402. IN PIRP Irp
  11403. )
  11404. {
  11405. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  11406. PVOLSNAP_DIFF_AREA_SIZES input = (PVOLSNAP_DIFF_AREA_SIZES) Irp->AssociatedIrp.SystemBuffer;
  11407. NTSTATUS status;
  11408. KIRQL irql;
  11409. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  11410. sizeof(VOLSNAP_DIFF_AREA_SIZES)) {
  11411. return STATUS_INVALID_PARAMETER;
  11412. }
  11413. if (input->MaximumVolumeSpace < 0) {
  11414. return STATUS_INVALID_PARAMETER;
  11415. }
  11416. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  11417. status = VspCreateStartBlock(Filter,
  11418. Filter->FirstControlBlockVolumeOffset,
  11419. input->MaximumVolumeSpace);
  11420. if (!NT_SUCCESS(status)) {
  11421. VspReleaseNonPagedResource(Filter);
  11422. return status;
  11423. }
  11424. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  11425. Filter->MaximumVolumeSpace = input->MaximumVolumeSpace;
  11426. InterlockedIncrement(&Filter->EpicNumber);
  11427. KeReleaseSpinLock(&Filter->SpinLock, irql);
  11428. VspReleaseNonPagedResource(Filter);
  11429. VspCheckMaxSize(Filter);
  11430. return STATUS_SUCCESS;
  11431. }
  11432. BOOLEAN
  11433. VspIsNtfsBootSector(
  11434. IN PFILTER_EXTENSION Filter,
  11435. IN PVOID BootSector
  11436. )
  11437. {
  11438. PUCHAR p = (PUCHAR) BootSector;
  11439. LONGLONG numSectors;
  11440. if (p[3] != 'N' || p[4] != 'T' || p[5] != 'F' || p[6] != 'S' &&
  11441. p[510] != 0x55 || p[511] != 0xAA) {
  11442. return FALSE;
  11443. }
  11444. numSectors = *((PLONGLONG) (p + 0x28));
  11445. if (numSectors > VspQueryVolumeSize(Filter)) {
  11446. return FALSE;
  11447. }
  11448. return TRUE;
  11449. }
  11450. NTSTATUS
  11451. VspReadApplicationInfo(
  11452. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  11453. )
  11454. {
  11455. PVOLUME_EXTENSION extension = DiffAreaFile->Extension;
  11456. LONGLONG targetOffset;
  11457. NTSTATUS status;
  11458. PVSP_BLOCK_APP_INFO appInfoBlock;
  11459. targetOffset = DiffAreaFile->ApplicationInfoTargetOffset;
  11460. if (!targetOffset) {
  11461. return STATUS_SUCCESS;
  11462. }
  11463. status = VspSynchronousIo(DiffAreaFile->TableUpdateIrp,
  11464. DiffAreaFile->Filter->TargetObject,
  11465. IRP_MJ_READ, targetOffset, 0);
  11466. if (!NT_SUCCESS(status)) {
  11467. return status;
  11468. }
  11469. appInfoBlock = (PVSP_BLOCK_APP_INFO)
  11470. MmGetMdlVirtualAddress(DiffAreaFile->TableUpdateIrp->MdlAddress);
  11471. if (!IsEqualGUID(appInfoBlock->Header.Signature,
  11472. VSP_DIFF_AREA_FILE_GUID) ||
  11473. appInfoBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  11474. appInfoBlock->Header.BlockType != VSP_BLOCK_TYPE_APP_INFO ||
  11475. appInfoBlock->Header.ThisVolumeOffset != targetOffset ||
  11476. appInfoBlock->Header.NextVolumeOffset ||
  11477. appInfoBlock->AppInfoSize > VSP_MAX_APP_INFO_SIZE) {
  11478. return STATUS_INVALID_PARAMETER;
  11479. }
  11480. ASSERT(!extension->ApplicationInformation);
  11481. if (!appInfoBlock->AppInfoSize) {
  11482. return STATUS_SUCCESS;
  11483. }
  11484. extension->ApplicationInformation =
  11485. ExAllocatePoolWithTag(NonPagedPool, appInfoBlock->AppInfoSize,
  11486. VOLSNAP_TAG_APP_INFO);
  11487. if (!extension->ApplicationInformation) {
  11488. return STATUS_INSUFFICIENT_RESOURCES;
  11489. }
  11490. RtlCopyMemory(extension->ApplicationInformation,
  11491. (PCHAR) appInfoBlock + VSP_OFFSET_TO_APP_INFO,
  11492. appInfoBlock->AppInfoSize);
  11493. extension->ApplicationInformationSize = appInfoBlock->AppInfoSize;
  11494. return STATUS_SUCCESS;
  11495. }
  11496. NTSTATUS
  11497. VspCreateSnapshotExtension(
  11498. IN PFILTER_EXTENSION Filter,
  11499. IN PVSP_LOOKUP_TABLE_ENTRY LookupEntry,
  11500. IN BOOLEAN IsNewestSnapshot
  11501. )
  11502. {
  11503. ULONG volumeNumber, i;
  11504. WCHAR buffer[100];
  11505. UNICODE_STRING volumeName;
  11506. NTSTATUS status, status2;
  11507. PDEVICE_OBJECT deviceObject;
  11508. PVOLUME_EXTENSION extension;
  11509. PVSP_DIFF_AREA_FILE diffAreaFile;
  11510. PVOID buf;
  11511. PMDL mdl;
  11512. KIRQL irql;
  11513. PSECURITY_DESCRIPTOR sd;
  11514. BOOLEAN ma;
  11515. if (IsNewestSnapshot && (LookupEntry->SnapshotControlItemFlags&
  11516. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_CRASHDUMP)) {
  11517. VspLogError(NULL, Filter, VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES,
  11518. STATUS_SUCCESS, 5, FALSE);
  11519. return STATUS_NO_SUCH_DEVICE;
  11520. }
  11521. if (LookupEntry->SnapshotControlItemFlags&
  11522. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION) {
  11523. VspLogError(NULL, Filter, VS_ABORT_DIRTY_DETECTION, STATUS_SUCCESS,
  11524. 0, FALSE);
  11525. return STATUS_NO_SUCH_DEVICE;
  11526. }
  11527. volumeNumber = (ULONG)
  11528. InterlockedIncrement(&Filter->Root->NextVolumeNumber);
  11529. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d", volumeNumber);
  11530. RtlInitUnicodeString(&volumeName, buffer);
  11531. status = IoCreateDevice(Filter->Root->DriverObject,
  11532. sizeof(VOLUME_EXTENSION), &volumeName,
  11533. FILE_DEVICE_VIRTUAL_DISK, 0, FALSE,
  11534. &deviceObject);
  11535. if (!NT_SUCCESS(status)) {
  11536. return status;
  11537. }
  11538. extension = (PVOLUME_EXTENSION) deviceObject->DeviceExtension;
  11539. RtlZeroMemory(extension, sizeof(VOLUME_EXTENSION));
  11540. extension->DeviceObject = deviceObject;
  11541. extension->Root = Filter->Root;
  11542. extension->DeviceExtensionType = DEVICE_EXTENSION_VOLUME;
  11543. KeInitializeSpinLock(&extension->SpinLock);
  11544. extension->Filter = Filter;
  11545. if (LookupEntry->SnapshotControlItemFlags&
  11546. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_OFFLINE) {
  11547. extension->IsOffline = TRUE;
  11548. }
  11549. extension->RefCount = 1;
  11550. InitializeListHead(&extension->WriteContextList);
  11551. KeInitializeEvent(&extension->ZeroRefEvent, NotificationEvent, FALSE);
  11552. extension->HasEndCommit = TRUE;
  11553. extension->IsPersistent = TRUE;
  11554. extension->IsDetected = TRUE;
  11555. extension->RootSemaphoreHeld = TRUE;
  11556. if (LookupEntry->SnapshotControlItemFlags&
  11557. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_VISIBLE) {
  11558. extension->IsVisible = TRUE;
  11559. }
  11560. if (LookupEntry->SnapshotControlItemFlags&
  11561. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_NO_DIFF_AREA_FILL) {
  11562. extension->NoDiffAreaFill = TRUE;
  11563. }
  11564. extension->CommitTimeStamp = LookupEntry->SnapshotTime;
  11565. extension->VolumeNumber = volumeNumber;
  11566. extension->SnapshotGuid = LookupEntry->SnapshotGuid;
  11567. extension->SnapshotOrderNumber = LookupEntry->SnapshotOrderNumber;
  11568. RtlInitializeGenericTable(&extension->VolumeBlockTable,
  11569. VspTableCompareRoutine,
  11570. VspTableAllocateRoutine,
  11571. VspTableFreeRoutine, extension);
  11572. RtlInitializeGenericTable(&extension->TempVolumeBlockTable,
  11573. VspTableCompareRoutine,
  11574. VspTempTableAllocateRoutine,
  11575. VspTempTableFreeRoutine, extension);
  11576. RtlInitializeGenericTable(&extension->CopyBackPointerTable,
  11577. VspTableCompareRoutine,
  11578. VspTableAllocateRoutine,
  11579. VspTableFreeRoutine, extension);
  11580. extension->DiffAreaFileIncrease = NOMINAL_DIFF_AREA_FILE_GROWTH;
  11581. diffAreaFile = (PVSP_DIFF_AREA_FILE)
  11582. ExAllocatePoolWithTag(NonPagedPool,
  11583. sizeof(VSP_DIFF_AREA_FILE),
  11584. VOLSNAP_TAG_DIFF_FILE);
  11585. if (!diffAreaFile) {
  11586. IoDeleteDevice(deviceObject);
  11587. return STATUS_INSUFFICIENT_RESOURCES;
  11588. }
  11589. RtlZeroMemory(diffAreaFile, sizeof(VSP_DIFF_AREA_FILE));
  11590. diffAreaFile->Extension = extension;
  11591. diffAreaFile->Filter = LookupEntry->DiffAreaFilter;
  11592. diffAreaFile->FileHandle = LookupEntry->DiffAreaHandle;
  11593. LookupEntry->DiffAreaHandle = NULL;
  11594. InitializeListHead(&diffAreaFile->UnusedAllocationList);
  11595. diffAreaFile->TableUpdateIrp =
  11596. IoAllocateIrp((CCHAR) extension->Root->StackSize, FALSE);
  11597. if (!diffAreaFile->TableUpdateIrp) {
  11598. ExFreePool(diffAreaFile);
  11599. IoDeleteDevice(deviceObject);
  11600. return STATUS_INSUFFICIENT_RESOURCES;
  11601. }
  11602. buf = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  11603. VOLSNAP_TAG_BUFFER);
  11604. if (!buf) {
  11605. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11606. ExFreePool(diffAreaFile);
  11607. IoDeleteDevice(deviceObject);
  11608. return STATUS_INSUFFICIENT_RESOURCES;
  11609. }
  11610. mdl = IoAllocateMdl(buf, BLOCK_SIZE, FALSE, FALSE, NULL);
  11611. if (!mdl) {
  11612. ExFreePool(buf);
  11613. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11614. ExFreePool(diffAreaFile);
  11615. IoDeleteDevice(deviceObject);
  11616. return STATUS_INSUFFICIENT_RESOURCES;
  11617. }
  11618. MmBuildMdlForNonPagedPool(mdl);
  11619. diffAreaFile->TableUpdateIrp->MdlAddress = mdl;
  11620. diffAreaFile->NextFreeTableEntryOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  11621. diffAreaFile->ApplicationInfoTargetOffset =
  11622. LookupEntry->ApplicationInfoStartingVolumeOffset;
  11623. diffAreaFile->DiffAreaLocationDescriptionTargetOffset =
  11624. LookupEntry->DiffAreaLocationDescriptionVolumeOffset;
  11625. diffAreaFile->InitialBitmapVolumeOffset =
  11626. LookupEntry->InitialBitmapVolumeOffset;
  11627. diffAreaFile->FirstTableTargetOffset =
  11628. LookupEntry->DiffAreaStartingVolumeOffset;
  11629. diffAreaFile->TableTargetOffset =
  11630. LookupEntry->DiffAreaStartingVolumeOffset;
  11631. InitializeListHead(&diffAreaFile->TableUpdateQueue);
  11632. InitializeListHead(&diffAreaFile->TableUpdatesInProgress);
  11633. extension->DiffAreaFile = diffAreaFile;
  11634. KeAcquireSpinLock(&diffAreaFile->Filter->SpinLock, &irql);
  11635. InsertTailList(&diffAreaFile->Filter->DiffAreaFilesOnThisFilter,
  11636. &diffAreaFile->FilterListEntry);
  11637. diffAreaFile->FilterListEntryBeingUsed = TRUE;
  11638. KeReleaseSpinLock(&diffAreaFile->Filter->SpinLock, irql);
  11639. InitializeListHead(&extension->OldHeaps);
  11640. extension->VolumeSize = LookupEntry->VolumeSnapshotSize;
  11641. InitializeListHead(&extension->EmergencyCopyIrpQueue);
  11642. InitializeListHead(&extension->WaitingForPageFileSpace);
  11643. InitializeListHead(&extension->WaitingForDiffAreaSpace);
  11644. status = VspCreateWorkerThread(Filter->Root);
  11645. if (!NT_SUCCESS(status)) {
  11646. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  11647. status, 1, FALSE);
  11648. RemoveEntryList(&diffAreaFile->FilterListEntry);
  11649. IoFreeMdl(mdl);
  11650. ExFreePool(buf);
  11651. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11652. ExFreePool(diffAreaFile);
  11653. IoDeleteDevice(deviceObject);
  11654. return status;
  11655. }
  11656. status = VspCreateInitialHeap(extension, TRUE);
  11657. if (!NT_SUCCESS(status)) {
  11658. VspDeleteWorkerThread(Filter->Root);
  11659. RemoveEntryList(&diffAreaFile->FilterListEntry);
  11660. IoFreeMdl(mdl);
  11661. ExFreePool(buf);
  11662. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11663. ExFreePool(diffAreaFile);
  11664. IoDeleteDevice(deviceObject);
  11665. return status;
  11666. }
  11667. status = VspReadApplicationInfo(diffAreaFile);
  11668. if (!NT_SUCCESS(status)) {
  11669. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  11670. status, 2, FALSE);
  11671. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11672. extension->DiffAreaFileMap);
  11673. ASSERT(NT_SUCCESS(status2));
  11674. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11675. extension->NextDiffAreaFileMap);
  11676. ASSERT(NT_SUCCESS(status2));
  11677. VspDeleteWorkerThread(Filter->Root);
  11678. RemoveEntryList(&diffAreaFile->FilterListEntry);
  11679. IoFreeMdl(mdl);
  11680. ExFreePool(buf);
  11681. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11682. ExFreePool(diffAreaFile);
  11683. IoDeleteDevice(deviceObject);
  11684. return status;
  11685. }
  11686. status = VspReadDiffAreaTable(diffAreaFile);
  11687. if (!NT_SUCCESS(status)) {
  11688. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  11689. status, 3, FALSE);
  11690. if (extension->ApplicationInformation) {
  11691. ExFreePool(extension->ApplicationInformation);
  11692. }
  11693. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11694. extension->DiffAreaFileMap);
  11695. ASSERT(NT_SUCCESS(status2));
  11696. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11697. extension->NextDiffAreaFileMap);
  11698. ASSERT(NT_SUCCESS(status2));
  11699. VspDeleteWorkerThread(Filter->Root);
  11700. RemoveEntryList(&diffAreaFile->FilterListEntry);
  11701. IoFreeMdl(mdl);
  11702. ExFreePool(buf);
  11703. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11704. ExFreePool(diffAreaFile);
  11705. IoDeleteDevice(deviceObject);
  11706. return status;
  11707. }
  11708. status = ObGetObjectSecurity(Filter->Pdo, &sd, &ma);
  11709. if (NT_SUCCESS(status)) {
  11710. status = ObSetSecurityObjectByPointer(deviceObject,
  11711. DACL_SECURITY_INFORMATION, sd);
  11712. ObReleaseObjectSecurity(sd, ma);
  11713. }
  11714. if (NT_SUCCESS(status)) {
  11715. extension->DevnodeNumber = VspClaimNextDevnodeNumber(extension->Root);
  11716. if (!extension->DevnodeNumber) {
  11717. status = STATUS_INSUFFICIENT_RESOURCES;
  11718. }
  11719. }
  11720. if (!NT_SUCCESS(status)) {
  11721. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  11722. status, 9, FALSE);
  11723. if (extension->ApplicationInformation) {
  11724. ExFreePool(extension->ApplicationInformation);
  11725. }
  11726. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11727. extension->DiffAreaFileMap);
  11728. ASSERT(NT_SUCCESS(status2));
  11729. status2 = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  11730. extension->NextDiffAreaFileMap);
  11731. ASSERT(NT_SUCCESS(status2));
  11732. VspDeleteWorkerThread(Filter->Root);
  11733. RemoveEntryList(&diffAreaFile->FilterListEntry);
  11734. IoFreeMdl(mdl);
  11735. ExFreePool(buf);
  11736. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  11737. ExFreePool(diffAreaFile);
  11738. RtlDeleteElementGenericTable(&extension->Root->UsedDevnodeNumbers,
  11739. &extension->DevnodeNumber);
  11740. IoDeleteDevice(deviceObject);
  11741. return status;
  11742. }
  11743. if (LookupEntry->SnapshotControlItemFlags&
  11744. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_HIBERFIL_COPIED) {
  11745. InterlockedExchange(&extension->HiberFileCopied, TRUE);
  11746. }
  11747. if (LookupEntry->SnapshotControlItemFlags&
  11748. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_PAGEFILE_COPIED) {
  11749. InterlockedExchange(&extension->PageFileCopied, TRUE);
  11750. }
  11751. extension->DeviceObject->AlignmentRequirement =
  11752. extension->Filter->Pdo->AlignmentRequirement |
  11753. extension->DiffAreaFile->Filter->Pdo->AlignmentRequirement;
  11754. InsertTailList(&Filter->VolumeList, &extension->ListEntry);
  11755. deviceObject->Flags |= DO_DIRECT_IO;
  11756. deviceObject->StackSize = (CCHAR) Filter->Root->StackSize + 1;
  11757. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  11758. extension->RootSemaphoreHeld = FALSE;
  11759. return STATUS_SUCCESS;
  11760. }
  11761. BOOLEAN
  11762. VspAreSnapshotsComplete(
  11763. IN PFILTER_EXTENSION Filter
  11764. )
  11765. {
  11766. LONGLONG previousOrderNumber;
  11767. PLIST_ENTRY l;
  11768. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  11769. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  11770. previousOrderNumber = 0;
  11771. for (l = Filter->SnapshotLookupTableEntries.Flink;
  11772. l != &Filter->SnapshotLookupTableEntries; l = l->Flink) {
  11773. lookupEntry = CONTAINING_RECORD(l, VSP_LOOKUP_TABLE_ENTRY,
  11774. SnapshotFilterListEntry);
  11775. if (!lookupEntry->DiffAreaFilter) {
  11776. VspReleaseNonPagedResource(Filter);
  11777. return FALSE;
  11778. }
  11779. if (previousOrderNumber &&
  11780. previousOrderNumber + 1 != lookupEntry->SnapshotOrderNumber) {
  11781. VspReleaseNonPagedResource(Filter);
  11782. ASSERT(FALSE);
  11783. return FALSE;
  11784. }
  11785. previousOrderNumber = lookupEntry->SnapshotOrderNumber;
  11786. ASSERT(previousOrderNumber);
  11787. }
  11788. VspReleaseNonPagedResource(Filter);
  11789. return TRUE;
  11790. }
  11791. VOID
  11792. VspSignalWorker(
  11793. IN PVOID Event
  11794. )
  11795. {
  11796. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  11797. }
  11798. PVOID
  11799. VspInsertWithAllocateAndWait(
  11800. IN PVOLUME_EXTENSION Extension,
  11801. IN PRTL_GENERIC_TABLE Table,
  11802. IN PVOID TableEntry
  11803. )
  11804. {
  11805. NTSTATUS status = STATUS_SUCCESS;
  11806. PTRANSLATION_TABLE_ENTRY t1, t2;
  11807. PVOID r;
  11808. PVOID nodeOrParent;
  11809. TABLE_SEARCH_RESULT searchResult;
  11810. KEVENT event;
  11811. KIRQL irql;
  11812. _try {
  11813. t1 = (PTRANSLATION_TABLE_ENTRY)
  11814. RtlLookupElementGenericTableFull(Table, TableEntry, &nodeOrParent,
  11815. &searchResult);
  11816. } _except (EXCEPTION_EXECUTE_HANDLER) {
  11817. status = GetExceptionCode();
  11818. }
  11819. if (!NT_SUCCESS(status)) {
  11820. return NULL;
  11821. }
  11822. if (t1) {
  11823. t2 = (PTRANSLATION_TABLE_ENTRY) TableEntry;
  11824. t1->TargetObject = t2->TargetObject;
  11825. t1->Flags = t2->Flags;
  11826. t1->TargetOffset = t2->TargetOffset;
  11827. return t1;
  11828. }
  11829. _try {
  11830. r = RtlInsertElementGenericTableFull(Table, TableEntry,
  11831. sizeof(TRANSLATION_TABLE_ENTRY),
  11832. NULL, nodeOrParent, searchResult);
  11833. } _except (EXCEPTION_EXECUTE_HANDLER) {
  11834. r = NULL;
  11835. }
  11836. if (!r) {
  11837. KeInitializeEvent(&event, NotificationEvent, FALSE);
  11838. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  11839. if (Extension->PageFileSpaceCreatePending) {
  11840. ExInitializeWorkItem(&Extension->DiffAreaFile->WorkItem,
  11841. VspSignalWorker, &event);
  11842. InsertTailList(&Extension->WaitingForPageFileSpace,
  11843. &Extension->DiffAreaFile->WorkItem.List);
  11844. KeReleaseSpinLock(&Extension->SpinLock, irql);
  11845. KeWaitForSingleObject(&event, Executive, KernelMode,
  11846. FALSE, NULL);
  11847. VspReleasePagedResource(Extension);
  11848. } else {
  11849. KeReleaseSpinLock(&Extension->SpinLock, irql);
  11850. }
  11851. _try {
  11852. r = RtlInsertElementGenericTableFull(Table, TableEntry,
  11853. sizeof(TRANSLATION_TABLE_ENTRY),
  11854. NULL, nodeOrParent,
  11855. searchResult);
  11856. } _except (EXCEPTION_EXECUTE_HANDLER) {
  11857. r = NULL;
  11858. }
  11859. }
  11860. return r;
  11861. }
  11862. NTSTATUS
  11863. VspReadDiffAreaTable(
  11864. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  11865. )
  11866. {
  11867. PVOLUME_EXTENSION extension = DiffAreaFile->Extension;
  11868. LONGLONG tableTargetOffset;
  11869. LONGLONG highestFileOffset, tmp;
  11870. TRANSLATION_TABLE_ENTRY tableEntry;
  11871. NTSTATUS status;
  11872. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  11873. ULONG blockOffset;
  11874. PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY diffAreaTableEntry;
  11875. PVOID r;
  11876. KIRQL irql;
  11877. PTRANSLATION_TABLE_ENTRY backPointer;
  11878. BOOLEAN b;
  11879. LONGLONG initialBitmapTargetOffset;
  11880. tableTargetOffset = DiffAreaFile->TableTargetOffset;
  11881. highestFileOffset = 0;
  11882. RtlZeroMemory(&tableEntry, sizeof(tableEntry));
  11883. for (;;) {
  11884. status = VspSynchronousIo(DiffAreaFile->TableUpdateIrp,
  11885. DiffAreaFile->Filter->TargetObject,
  11886. IRP_MJ_READ, tableTargetOffset, 0);
  11887. if (!NT_SUCCESS(status)) {
  11888. return status;
  11889. }
  11890. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  11891. MmGetMdlVirtualAddress(DiffAreaFile->TableUpdateIrp->MdlAddress);
  11892. if (!IsEqualGUID(diffAreaBlock->Header.Signature,
  11893. VSP_DIFF_AREA_FILE_GUID) ||
  11894. diffAreaBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  11895. diffAreaBlock->Header.BlockType != VSP_BLOCK_TYPE_DIFF_AREA ||
  11896. diffAreaBlock->Header.ThisVolumeOffset != tableTargetOffset ||
  11897. diffAreaBlock->Header.NextVolumeOffset == tableTargetOffset) {
  11898. return STATUS_INVALID_PARAMETER;
  11899. }
  11900. if (diffAreaBlock->Header.ThisFileOffset > highestFileOffset) {
  11901. highestFileOffset = diffAreaBlock->Header.ThisFileOffset;
  11902. }
  11903. for (blockOffset = VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  11904. blockOffset + sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY) <=
  11905. BLOCK_SIZE;
  11906. blockOffset += sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY)) {
  11907. diffAreaTableEntry = (PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY)
  11908. ((PCHAR) diffAreaBlock + blockOffset);
  11909. if (!diffAreaTableEntry->DiffAreaVolumeOffset &&
  11910. !diffAreaTableEntry->Flags) {
  11911. break;
  11912. }
  11913. if (diffAreaTableEntry->SnapshotVolumeOffset >=
  11914. extension->VolumeSize ||
  11915. diffAreaTableEntry->SnapshotVolumeOffset < 0 ||
  11916. (diffAreaTableEntry->SnapshotVolumeOffset&(BLOCK_SIZE - 1)) ||
  11917. diffAreaTableEntry->DiffAreaFileOffset < 0 ||
  11918. diffAreaTableEntry->DiffAreaVolumeOffset < 0 ||
  11919. (diffAreaTableEntry->DiffAreaVolumeOffset&(BLOCK_SIZE - 1))) {
  11920. return STATUS_INVALID_PARAMETER;
  11921. }
  11922. if (diffAreaTableEntry->Flags&
  11923. (~VSP_DIFF_AREA_TABLE_ENTRY_FLAG_MOVE_ENTRY)) {
  11924. return STATUS_INVALID_PARAMETER;
  11925. }
  11926. if (diffAreaTableEntry->Flags) {
  11927. tableEntry.VolumeOffset =
  11928. diffAreaTableEntry->SnapshotVolumeOffset;
  11929. tableEntry.TargetObject = extension->Filter->TargetObject;
  11930. tableEntry.Flags =
  11931. VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY;
  11932. tableEntry.TargetOffset =
  11933. diffAreaTableEntry->DiffAreaFileOffset;
  11934. } else {
  11935. if (diffAreaTableEntry->DiffAreaFileOffset >
  11936. highestFileOffset) {
  11937. highestFileOffset =
  11938. diffAreaTableEntry->DiffAreaFileOffset;
  11939. }
  11940. tableEntry.VolumeOffset =
  11941. diffAreaTableEntry->SnapshotVolumeOffset;
  11942. tableEntry.TargetObject = DiffAreaFile->Filter->TargetObject;
  11943. tableEntry.Flags = 0;
  11944. tableEntry.TargetOffset =
  11945. diffAreaTableEntry->DiffAreaVolumeOffset;
  11946. }
  11947. _try {
  11948. backPointer = (PTRANSLATION_TABLE_ENTRY)
  11949. RtlLookupElementGenericTable(
  11950. &extension->CopyBackPointerTable,
  11951. &tableEntry);
  11952. } _except (EXCEPTION_EXECUTE_HANDLER) {
  11953. status = GetExceptionCode();
  11954. }
  11955. if (!NT_SUCCESS(status)) {
  11956. return status;
  11957. }
  11958. if (backPointer) {
  11959. tmp = backPointer->TargetOffset;
  11960. _try {
  11961. b = RtlDeleteElementGenericTable(
  11962. &extension->CopyBackPointerTable, &tableEntry);
  11963. if (!b) {
  11964. status = STATUS_INVALID_PARAMETER;
  11965. }
  11966. } _except (EXCEPTION_EXECUTE_HANDLER) {
  11967. b = FALSE;
  11968. status = GetExceptionCode();
  11969. }
  11970. if (!b) {
  11971. return status;
  11972. }
  11973. tableEntry.VolumeOffset = tmp;
  11974. }
  11975. r = VspInsertWithAllocateAndWait(extension,
  11976. &extension->VolumeBlockTable,
  11977. &tableEntry);
  11978. if (!r) {
  11979. return STATUS_INSUFFICIENT_RESOURCES;
  11980. }
  11981. if (diffAreaTableEntry->Flags) {
  11982. tmp = tableEntry.VolumeOffset;
  11983. tableEntry.VolumeOffset = tableEntry.TargetOffset;
  11984. tableEntry.TargetOffset = tmp;
  11985. r = VspInsertWithAllocateAndWait(
  11986. extension, &extension->CopyBackPointerTable,
  11987. &tableEntry);
  11988. if (!r) {
  11989. return STATUS_INSUFFICIENT_RESOURCES;
  11990. }
  11991. }
  11992. }
  11993. if (!diffAreaBlock->Header.NextVolumeOffset) {
  11994. break;
  11995. }
  11996. tableTargetOffset = diffAreaBlock->Header.NextVolumeOffset;
  11997. }
  11998. initialBitmapTargetOffset = DiffAreaFile->InitialBitmapVolumeOffset;
  11999. while (initialBitmapTargetOffset) {
  12000. status = VspSynchronousIo(DiffAreaFile->TableUpdateIrp,
  12001. DiffAreaFile->Filter->TargetObject,
  12002. IRP_MJ_READ, initialBitmapTargetOffset, 0);
  12003. if (!NT_SUCCESS(status)) {
  12004. break;
  12005. }
  12006. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA)
  12007. MmGetMdlVirtualAddress(DiffAreaFile->TableUpdateIrp->MdlAddress);
  12008. if (!IsEqualGUID(diffAreaBlock->Header.Signature,
  12009. VSP_DIFF_AREA_FILE_GUID) ||
  12010. diffAreaBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  12011. diffAreaBlock->Header.BlockType !=
  12012. VSP_BLOCK_TYPE_INITIAL_BITMAP ||
  12013. diffAreaBlock->Header.ThisVolumeOffset !=
  12014. initialBitmapTargetOffset ||
  12015. diffAreaBlock->Header.NextVolumeOffset ==
  12016. initialBitmapTargetOffset) {
  12017. break;
  12018. }
  12019. if (diffAreaBlock->Header.ThisFileOffset > highestFileOffset) {
  12020. highestFileOffset = diffAreaBlock->Header.ThisFileOffset;
  12021. }
  12022. initialBitmapTargetOffset = diffAreaBlock->Header.NextVolumeOffset;
  12023. }
  12024. DiffAreaFile->TableTargetOffset = tableTargetOffset;
  12025. DiffAreaFile->NextAvailable = highestFileOffset + BLOCK_SIZE;
  12026. DiffAreaFile->AllocatedFileSize = DiffAreaFile->NextAvailable;
  12027. DiffAreaFile->NextFreeTableEntryOffset = blockOffset;
  12028. KeAcquireSpinLock(&extension->Filter->SpinLock, &irql);
  12029. extension->Filter->UsedVolumeSpace += DiffAreaFile->NextAvailable;
  12030. extension->Filter->AllocatedVolumeSpace += DiffAreaFile->AllocatedFileSize;
  12031. KeReleaseSpinLock(&extension->Filter->SpinLock, irql);
  12032. return STATUS_SUCCESS;
  12033. }
  12034. NTSTATUS
  12035. VspInitializeUnusedAllocationLists(
  12036. IN PVOLUME_EXTENSION Extension
  12037. )
  12038. {
  12039. PVSP_DIFF_AREA_FILE diffAreaFile;
  12040. NTSTATUS status;
  12041. LONGLONG tableTargetOffset;
  12042. LONGLONG nextFileOffset;
  12043. PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION locationBlock;
  12044. ULONG blockOffset;
  12045. PVSP_DIFF_AREA_LOCATION_DESCRIPTOR locationDescriptor;
  12046. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  12047. LONGLONG delta;
  12048. KIRQL irql;
  12049. diffAreaFile = Extension->DiffAreaFile;
  12050. ASSERT(diffAreaFile);
  12051. tableTargetOffset = diffAreaFile->DiffAreaLocationDescriptionTargetOffset;
  12052. nextFileOffset = diffAreaFile->NextAvailable;
  12053. locationBlock = (PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION)
  12054. MmGetMdlVirtualAddress(diffAreaFile->TableUpdateIrp->MdlAddress);
  12055. for (;;) {
  12056. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12057. diffAreaFile->Filter->TargetObject,
  12058. IRP_MJ_READ, tableTargetOffset, 0);
  12059. if (!NT_SUCCESS(status)) {
  12060. return status;
  12061. }
  12062. if (!IsEqualGUID(locationBlock->Header.Signature,
  12063. VSP_DIFF_AREA_FILE_GUID) ||
  12064. locationBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  12065. locationBlock->Header.BlockType !=
  12066. VSP_BLOCK_TYPE_DIFF_AREA_LOCATION_DESCRIPTION ||
  12067. locationBlock->Header.ThisVolumeOffset != tableTargetOffset ||
  12068. locationBlock->Header.NextVolumeOffset == tableTargetOffset) {
  12069. return STATUS_INVALID_PARAMETER;
  12070. }
  12071. for (blockOffset = VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR;
  12072. blockOffset + sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR) <=
  12073. BLOCK_SIZE;
  12074. blockOffset += sizeof(VSP_DIFF_AREA_LOCATION_DESCRIPTOR)) {
  12075. locationDescriptor = (PVSP_DIFF_AREA_LOCATION_DESCRIPTOR)
  12076. ((PCHAR) locationBlock + blockOffset);
  12077. if (!locationDescriptor->VolumeOffset) {
  12078. break;
  12079. }
  12080. if (locationDescriptor->VolumeOffset < 0 ||
  12081. locationDescriptor->FileOffset < 0 ||
  12082. locationDescriptor->Length <= 0) {
  12083. return STATUS_INVALID_PARAMETER;
  12084. }
  12085. if (locationDescriptor->FileOffset +
  12086. locationDescriptor->Length < nextFileOffset) {
  12087. continue;
  12088. }
  12089. if (locationDescriptor->FileOffset < nextFileOffset) {
  12090. delta = nextFileOffset - locationDescriptor->FileOffset;
  12091. locationDescriptor->Length -= delta;
  12092. locationDescriptor->VolumeOffset += delta;
  12093. locationDescriptor->FileOffset = nextFileOffset;
  12094. }
  12095. if (locationDescriptor->FileOffset > nextFileOffset) {
  12096. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  12097. ExAllocatePoolWithTag(NonPagedPool,
  12098. sizeof(DIFF_AREA_FILE_ALLOCATION),
  12099. VOLSNAP_TAG_BIT_HISTORY);
  12100. if (!diffAreaFileAllocation) {
  12101. return STATUS_INSUFFICIENT_RESOURCES;
  12102. }
  12103. diffAreaFileAllocation->Offset = 0;
  12104. diffAreaFileAllocation->NLength =
  12105. nextFileOffset - locationDescriptor->FileOffset;
  12106. InsertTailList(&diffAreaFile->UnusedAllocationList,
  12107. &diffAreaFileAllocation->ListEntry);
  12108. nextFileOffset = locationDescriptor->FileOffset;
  12109. }
  12110. ASSERT(nextFileOffset == locationDescriptor->FileOffset);
  12111. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  12112. ExAllocatePoolWithTag(NonPagedPool,
  12113. sizeof(DIFF_AREA_FILE_ALLOCATION),
  12114. VOLSNAP_TAG_BIT_HISTORY);
  12115. if (!diffAreaFileAllocation) {
  12116. return STATUS_INSUFFICIENT_RESOURCES;
  12117. }
  12118. diffAreaFileAllocation->Offset = locationDescriptor->VolumeOffset;
  12119. diffAreaFileAllocation->NLength = locationDescriptor->Length;
  12120. InsertTailList(&diffAreaFile->UnusedAllocationList,
  12121. &diffAreaFileAllocation->ListEntry);
  12122. nextFileOffset += locationDescriptor->Length;
  12123. }
  12124. if (!locationBlock->Header.NextVolumeOffset) {
  12125. break;
  12126. }
  12127. tableTargetOffset = locationBlock->Header.NextVolumeOffset;
  12128. }
  12129. delta = nextFileOffset - diffAreaFile->AllocatedFileSize;
  12130. diffAreaFile->AllocatedFileSize += delta;
  12131. KeAcquireSpinLock(&Extension->Filter->SpinLock, &irql);
  12132. Extension->Filter->AllocatedVolumeSpace += delta;
  12133. KeReleaseSpinLock(&Extension->Filter->SpinLock, irql);
  12134. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12135. diffAreaFile->Filter->TargetObject,
  12136. IRP_MJ_READ, diffAreaFile->TableTargetOffset, 0);
  12137. return status;
  12138. }
  12139. VOID
  12140. VspCleanupDetectedSnapshots(
  12141. IN PFILTER_EXTENSION Filter
  12142. )
  12143. {
  12144. KIRQL irql;
  12145. PLIST_ENTRY l;
  12146. PVOLUME_EXTENSION extension;
  12147. while (!IsListEmpty(&Filter->VolumeList)) {
  12148. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  12149. l = RemoveHeadList(&Filter->VolumeList);
  12150. KeReleaseSpinLock(&Filter->SpinLock, irql);
  12151. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  12152. KeAcquireSpinLock(&extension->SpinLock, &irql);
  12153. InterlockedExchange(&extension->IsDead, TRUE);
  12154. KeReleaseSpinLock(&extension->SpinLock, irql);
  12155. VspCleanupVolumeSnapshot(extension, NULL, FALSE);
  12156. RtlDeleteElementGenericTable(&extension->Root->UsedDevnodeNumbers,
  12157. &extension->DevnodeNumber);
  12158. IoDeleteDevice(extension->DeviceObject);
  12159. }
  12160. }
  12161. NTSTATUS
  12162. VspProcessInMemoryCopyOnWrites(
  12163. IN PVOLUME_EXTENSION Extension
  12164. )
  12165. {
  12166. PFILTER_EXTENSION filter = Extension->Filter;
  12167. PVSP_DIFF_AREA_FILE diffAreaFile = Extension->DiffAreaFile;
  12168. PFILTER_EXTENSION diffFilter = diffAreaFile->Filter;
  12169. PLIST_ENTRY l;
  12170. PVSP_COPY_ON_WRITE copyOnWrite;
  12171. LONGLONG volumeOffset, targetOffset, fileOffset, tmp;
  12172. PIRP irp;
  12173. PMDL mdl;
  12174. LONGLONG t, f;
  12175. PVSP_BLOCK_DIFF_AREA diffAreaBlock;
  12176. PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY diffAreaTableEntry;
  12177. TRANSLATION_TABLE_ENTRY tableEntry;
  12178. PVOID r;
  12179. PTRANSLATION_TABLE_ENTRY backPointer;
  12180. BOOLEAN b;
  12181. NTSTATUS status;
  12182. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  12183. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  12184. diffAreaBlock = (PVSP_BLOCK_DIFF_AREA) MmGetMdlVirtualAddress(
  12185. diffAreaFile->TableUpdateIrp->MdlAddress);
  12186. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  12187. l = RemoveHeadList(&filter->CopyOnWriteList);
  12188. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  12189. volumeOffset = copyOnWrite->RoundedStart;
  12190. if (RtlCheckBit(Extension->VolumeBlockBitmap,
  12191. volumeOffset>>BLOCK_SHIFT)) {
  12192. ExFreePool(copyOnWrite->Buffer);
  12193. ExFreePool(copyOnWrite);
  12194. continue;
  12195. }
  12196. status = VspAllocateDiffAreaSpace(Extension, &targetOffset,
  12197. &fileOffset, NULL, NULL);
  12198. if (!NT_SUCCESS(status)) {
  12199. ExFreePool(copyOnWrite->Buffer);
  12200. ExFreePool(copyOnWrite);
  12201. goto ErrorOut;
  12202. }
  12203. mdl = IoAllocateMdl(copyOnWrite->Buffer, BLOCK_SIZE, FALSE, FALSE,
  12204. NULL);
  12205. if (!mdl) {
  12206. ExFreePool(copyOnWrite->Buffer);
  12207. ExFreePool(copyOnWrite);
  12208. status = STATUS_INSUFFICIENT_RESOURCES;
  12209. goto ErrorOut;
  12210. }
  12211. irp = IoAllocateIrp(diffFilter->TargetObject->StackSize, FALSE);
  12212. if (!irp) {
  12213. IoFreeMdl(mdl);
  12214. ExFreePool(copyOnWrite->Buffer);
  12215. ExFreePool(copyOnWrite);
  12216. status = STATUS_INSUFFICIENT_RESOURCES;
  12217. goto ErrorOut;
  12218. }
  12219. irp->MdlAddress = mdl;
  12220. MmBuildMdlForNonPagedPool(mdl);
  12221. status = VspSynchronousIo(irp, diffFilter->TargetObject,
  12222. IRP_MJ_WRITE, targetOffset, 0);
  12223. IoFreeIrp(irp);
  12224. IoFreeMdl(mdl);
  12225. ExFreePool(copyOnWrite->Buffer);
  12226. ExFreePool(copyOnWrite);
  12227. if (!NT_SUCCESS(status)) {
  12228. goto ErrorOut;
  12229. }
  12230. if (diffAreaFile->NextFreeTableEntryOffset +
  12231. sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY) > BLOCK_SIZE) {
  12232. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12233. diffFilter->TargetObject,
  12234. IRP_MJ_WRITE,
  12235. diffAreaFile->TableTargetOffset, 0);
  12236. if (!NT_SUCCESS(status)) {
  12237. goto ErrorOut;
  12238. }
  12239. status = VspAllocateDiffAreaSpace(Extension, &t, &f, NULL, NULL);
  12240. if (!NT_SUCCESS(status)) {
  12241. goto ErrorOut;
  12242. }
  12243. RtlZeroMemory(diffAreaBlock, BLOCK_SIZE);
  12244. diffAreaBlock->Header.Signature = VSP_DIFF_AREA_FILE_GUID;
  12245. diffAreaBlock->Header.Version = VOLSNAP_PERSISTENT_VERSION;
  12246. diffAreaBlock->Header.BlockType = VSP_BLOCK_TYPE_DIFF_AREA;
  12247. diffAreaBlock->Header.ThisFileOffset = f;
  12248. diffAreaBlock->Header.ThisVolumeOffset = t;
  12249. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12250. diffFilter->TargetObject,
  12251. IRP_MJ_WRITE, t, 0);
  12252. if (!NT_SUCCESS(status)) {
  12253. goto ErrorOut;
  12254. }
  12255. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12256. diffFilter->TargetObject,
  12257. IRP_MJ_READ,
  12258. diffAreaFile->TableTargetOffset, 0);
  12259. if (!NT_SUCCESS(status)) {
  12260. goto ErrorOut;
  12261. }
  12262. diffAreaBlock->Header.NextVolumeOffset = t;
  12263. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12264. diffFilter->TargetObject,
  12265. IRP_MJ_WRITE,
  12266. diffAreaFile->TableTargetOffset, 0);
  12267. if (!NT_SUCCESS(status)) {
  12268. goto ErrorOut;
  12269. }
  12270. diffAreaFile->TableTargetOffset = t;
  12271. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12272. diffFilter->TargetObject,
  12273. IRP_MJ_READ,
  12274. diffAreaFile->TableTargetOffset, 0);
  12275. if (!NT_SUCCESS(status)) {
  12276. goto ErrorOut;
  12277. }
  12278. diffAreaFile->NextFreeTableEntryOffset =
  12279. VSP_OFFSET_TO_FIRST_TABLE_ENTRY;
  12280. }
  12281. diffAreaTableEntry = (PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY)
  12282. ((PCHAR) diffAreaBlock +
  12283. diffAreaFile->NextFreeTableEntryOffset);
  12284. diffAreaFile->NextFreeTableEntryOffset +=
  12285. sizeof(VSP_BLOCK_DIFF_AREA_TABLE_ENTRY);
  12286. diffAreaTableEntry->SnapshotVolumeOffset = volumeOffset;
  12287. diffAreaTableEntry->DiffAreaFileOffset = fileOffset;
  12288. diffAreaTableEntry->DiffAreaVolumeOffset = targetOffset;
  12289. diffAreaTableEntry->Flags = 0;
  12290. RtlZeroMemory(&tableEntry, sizeof(TRANSLATION_TABLE_ENTRY));
  12291. tableEntry.VolumeOffset = volumeOffset;
  12292. tableEntry.TargetObject = diffAreaFile->Filter->TargetObject;
  12293. tableEntry.TargetOffset = targetOffset;
  12294. _try {
  12295. backPointer = (PTRANSLATION_TABLE_ENTRY)
  12296. RtlLookupElementGenericTable(
  12297. &Extension->CopyBackPointerTable,
  12298. &tableEntry);
  12299. } _except (EXCEPTION_EXECUTE_HANDLER) {
  12300. status = GetExceptionCode();
  12301. }
  12302. if (!NT_SUCCESS(status)) {
  12303. goto ErrorOut;
  12304. }
  12305. if (backPointer) {
  12306. tmp = backPointer->TargetOffset;
  12307. _try {
  12308. b = RtlDeleteElementGenericTable(
  12309. &Extension->CopyBackPointerTable, &tableEntry);
  12310. if (!b) {
  12311. status = STATUS_INVALID_PARAMETER;
  12312. }
  12313. } _except (EXCEPTION_EXECUTE_HANDLER) {
  12314. b = FALSE;
  12315. status = GetExceptionCode();
  12316. }
  12317. if (!b) {
  12318. goto ErrorOut;
  12319. }
  12320. tableEntry.VolumeOffset = tmp;
  12321. }
  12322. r = VspInsertWithAllocateAndWait(Extension,
  12323. &Extension->VolumeBlockTable,
  12324. &tableEntry);
  12325. if (!r) {
  12326. status = STATUS_INSUFFICIENT_RESOURCES;
  12327. goto ErrorOut;
  12328. }
  12329. RtlSetBit(Extension->VolumeBlockBitmap,
  12330. (ULONG) (volumeOffset>>BLOCK_SHIFT));
  12331. }
  12332. status = VspSynchronousIo(diffAreaFile->TableUpdateIrp,
  12333. diffFilter->TargetObject,
  12334. IRP_MJ_WRITE,
  12335. diffAreaFile->TableTargetOffset, 0);
  12336. if (!NT_SUCCESS(status)) {
  12337. goto ErrorOut;
  12338. }
  12339. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  12340. &Extension->SnapshotGuid, FALSE,
  12341. controlItemBuffer, TRUE);
  12342. if (!NT_SUCCESS(status)) {
  12343. goto ErrorOut;
  12344. }
  12345. snapshotControlItem->SnapshotControlItemFlags &=
  12346. ~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION;
  12347. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  12348. &Extension->SnapshotGuid, TRUE,
  12349. controlItemBuffer, TRUE);
  12350. if (!NT_SUCCESS(status)) {
  12351. goto ErrorOut;
  12352. }
  12353. return STATUS_SUCCESS;
  12354. ErrorOut:
  12355. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  12356. l = RemoveHeadList(&filter->CopyOnWriteList);
  12357. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  12358. ExFreePool(copyOnWrite->Buffer);
  12359. ExFreePool(copyOnWrite);
  12360. }
  12361. return status;
  12362. }
  12363. NTSTATUS
  12364. VspActivateSnapshots(
  12365. IN PFILTER_EXTENSION Filter
  12366. )
  12367. {
  12368. PLIST_ENTRY l;
  12369. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  12370. BOOLEAN newest;
  12371. NTSTATUS status;
  12372. PVOLUME_EXTENSION extension;
  12373. PVSP_DIFF_AREA_FILE diffAreaFile;
  12374. ULONG bitmapSize;
  12375. PVOID bitmapBuffer;
  12376. PTRANSLATION_TABLE_ENTRY p;
  12377. PVOID buffer;
  12378. PMDL mdl;
  12379. LARGE_INTEGER timeout;
  12380. BOOLEAN moveEntries;
  12381. for (l = Filter->SnapshotLookupTableEntries.Flink;
  12382. l != &Filter->SnapshotLookupTableEntries; l = l->Flink) {
  12383. lookupEntry = CONTAINING_RECORD(l, VSP_LOOKUP_TABLE_ENTRY,
  12384. SnapshotFilterListEntry);
  12385. ASSERT(lookupEntry->DiffAreaFilter);
  12386. if (l->Flink == &Filter->SnapshotLookupTableEntries) {
  12387. newest = TRUE;
  12388. } else {
  12389. newest = FALSE;
  12390. }
  12391. status = VspCreateSnapshotExtension(Filter, lookupEntry, newest);
  12392. if (!NT_SUCCESS(status)) {
  12393. VspDeleteControlItemsWithGuid(Filter, NULL, FALSE);
  12394. VspCleanupDetectedSnapshots(Filter);
  12395. return status;
  12396. }
  12397. if (!newest) {
  12398. extension = CONTAINING_RECORD(Filter->VolumeList.Blink,
  12399. VOLUME_EXTENSION, ListEntry);
  12400. diffAreaFile = extension->DiffAreaFile;
  12401. if (extension->NextDiffAreaFileMap) {
  12402. status = ZwUnmapViewOfSection(
  12403. extension->DiffAreaFileMapProcess,
  12404. extension->NextDiffAreaFileMap);
  12405. ASSERT(NT_SUCCESS(status));
  12406. extension->NextDiffAreaFileMap = NULL;
  12407. }
  12408. if (diffAreaFile->TableUpdateIrp) {
  12409. ExFreePool(MmGetMdlVirtualAddress(
  12410. diffAreaFile->TableUpdateIrp->MdlAddress));
  12411. IoFreeMdl(diffAreaFile->TableUpdateIrp->MdlAddress);
  12412. IoFreeIrp(diffAreaFile->TableUpdateIrp);
  12413. diffAreaFile->TableUpdateIrp = NULL;
  12414. }
  12415. }
  12416. }
  12417. extension = CONTAINING_RECORD(Filter->VolumeList.Blink, VOLUME_EXTENSION,
  12418. ListEntry);
  12419. extension->VolumeBlockBitmap = (PRTL_BITMAP)
  12420. ExAllocatePoolWithTag(
  12421. NonPagedPool, sizeof(RTL_BITMAP),
  12422. VOLSNAP_TAG_BITMAP);
  12423. if (!extension->VolumeBlockBitmap) {
  12424. VspCleanupDetectedSnapshots(Filter);
  12425. return STATUS_INSUFFICIENT_RESOURCES;
  12426. }
  12427. bitmapSize = (ULONG) ((extension->VolumeSize + BLOCK_SIZE - 1)>>
  12428. BLOCK_SHIFT);
  12429. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  12430. (bitmapSize + 8*sizeof(ULONG) - 1)/
  12431. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  12432. if (!bitmapBuffer) {
  12433. VspLogError(extension, NULL, VS_CANT_ALLOCATE_BITMAP,
  12434. STATUS_INSUFFICIENT_RESOURCES, 3, FALSE);
  12435. ExFreePool(extension->VolumeBlockBitmap);
  12436. extension->VolumeBlockBitmap = NULL;
  12437. VspCleanupDetectedSnapshots(Filter);
  12438. return STATUS_INSUFFICIENT_RESOURCES;
  12439. }
  12440. RtlInitializeBitMap(extension->VolumeBlockBitmap, (PULONG) bitmapBuffer,
  12441. bitmapSize);
  12442. RtlClearAllBits(extension->VolumeBlockBitmap);
  12443. moveEntries = FALSE;
  12444. status = STATUS_SUCCESS;
  12445. _try {
  12446. p = (PTRANSLATION_TABLE_ENTRY)
  12447. RtlEnumerateGenericTable(&extension->VolumeBlockTable, TRUE);
  12448. while (p) {
  12449. RtlSetBit(extension->VolumeBlockBitmap,
  12450. (ULONG) (p->VolumeOffset>>BLOCK_SHIFT));
  12451. if (p->Flags&VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY) {
  12452. moveEntries = TRUE;
  12453. }
  12454. p = (PTRANSLATION_TABLE_ENTRY)
  12455. RtlEnumerateGenericTable(&extension->VolumeBlockTable, FALSE);
  12456. }
  12457. if (moveEntries) {
  12458. p = (PTRANSLATION_TABLE_ENTRY)
  12459. RtlEnumerateGenericTable(&extension->VolumeBlockTable, TRUE);
  12460. while (p) {
  12461. if (p->Flags&VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY) {
  12462. RtlClearBit(extension->VolumeBlockBitmap,
  12463. (ULONG) (p->TargetOffset>>BLOCK_SHIFT));
  12464. }
  12465. p = (PTRANSLATION_TABLE_ENTRY)
  12466. RtlEnumerateGenericTable(&extension->VolumeBlockTable,
  12467. FALSE);
  12468. }
  12469. }
  12470. } _except (EXCEPTION_EXECUTE_HANDLER) {
  12471. status = GetExceptionCode();
  12472. }
  12473. if (!NT_SUCCESS(status)) {
  12474. VspCleanupDetectedSnapshots(Filter);
  12475. return status;
  12476. }
  12477. extension->IgnorableProduct = (PRTL_BITMAP)
  12478. ExAllocatePoolWithTag(
  12479. NonPagedPool, sizeof(RTL_BITMAP),
  12480. VOLSNAP_TAG_BITMAP);
  12481. if (!extension->IgnorableProduct) {
  12482. VspCleanupDetectedSnapshots(Filter);
  12483. return STATUS_INSUFFICIENT_RESOURCES;
  12484. }
  12485. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  12486. (bitmapSize + 8*sizeof(ULONG) - 1)/
  12487. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  12488. if (!bitmapBuffer) {
  12489. VspLogError(extension, NULL, VS_CANT_ALLOCATE_BITMAP,
  12490. STATUS_INSUFFICIENT_RESOURCES, 4, FALSE);
  12491. ExFreePool(extension->IgnorableProduct);
  12492. extension->IgnorableProduct = NULL;
  12493. VspCleanupDetectedSnapshots(Filter);
  12494. return STATUS_INSUFFICIENT_RESOURCES;
  12495. }
  12496. RtlInitializeBitMap(extension->IgnorableProduct, (PULONG) bitmapBuffer,
  12497. bitmapSize);
  12498. RtlSetAllBits(extension->IgnorableProduct);
  12499. extension->EmergencyCopyIrp =
  12500. IoAllocateIrp((CCHAR) extension->Root->StackSize, FALSE);
  12501. if (!extension->EmergencyCopyIrp) {
  12502. VspCleanupDetectedSnapshots(Filter);
  12503. return STATUS_INSUFFICIENT_RESOURCES;
  12504. }
  12505. buffer = ExAllocatePoolWithTag(NonPagedPool,
  12506. BLOCK_SIZE, VOLSNAP_TAG_BUFFER);
  12507. if (!buffer) {
  12508. IoFreeIrp(extension->EmergencyCopyIrp);
  12509. extension->EmergencyCopyIrp = NULL;
  12510. VspCleanupDetectedSnapshots(Filter);
  12511. return STATUS_INSUFFICIENT_RESOURCES;
  12512. }
  12513. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  12514. if (!mdl) {
  12515. ExFreePool(buffer);
  12516. IoFreeIrp(extension->EmergencyCopyIrp);
  12517. extension->EmergencyCopyIrp = NULL;
  12518. VspCleanupDetectedSnapshots(Filter);
  12519. return STATUS_INSUFFICIENT_RESOURCES;
  12520. }
  12521. MmBuildMdlForNonPagedPool(mdl);
  12522. extension->EmergencyCopyIrp->MdlAddress = mdl;
  12523. status = VspInitializeUnusedAllocationLists(extension);
  12524. if (!NT_SUCCESS(status)) {
  12525. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  12526. status, 4, FALSE);
  12527. VspCleanupDetectedSnapshots(Filter);
  12528. return status;
  12529. }
  12530. diffAreaFile = extension->DiffAreaFile;
  12531. if (diffAreaFile->NextAvailable + extension->DiffAreaFileIncrease >
  12532. diffAreaFile->AllocatedFileSize) {
  12533. extension->DetectedNeedForGrow = TRUE;
  12534. }
  12535. if (Filter->FirstWriteProcessed) {
  12536. status = VspProcessInMemoryCopyOnWrites(extension);
  12537. if (!NT_SUCCESS(status)) {
  12538. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  12539. status, 8, FALSE);
  12540. VspCleanupDetectedSnapshots(Filter);
  12541. return status;
  12542. }
  12543. }
  12544. InterlockedExchange(&Filter->SnapshotsPresent, TRUE);
  12545. InterlockedExchange(&Filter->PersistentSnapshots, TRUE);
  12546. Filter->DiffAreaVolume = extension->DiffAreaFile->Filter;
  12547. ObReferenceObject(Filter->DeviceObject);
  12548. timeout.QuadPart = (LONGLONG) -10*1000*1000*120*10; // 20 minutes.
  12549. KeSetTimer(&Filter->EndCommitTimer, timeout, &Filter->EndCommitTimerDpc);
  12550. IoInvalidateDeviceRelations(Filter->Pdo, BusRelations);
  12551. VspCheckMaxSize(Filter);
  12552. return STATUS_SUCCESS;
  12553. }
  12554. VOID
  12555. VspRemoveLookupEntries(
  12556. IN PFILTER_EXTENSION Filter
  12557. )
  12558. {
  12559. PLIST_ENTRY l;
  12560. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  12561. KeWaitForSingleObject(&Filter->Root->LookupTableMutex, Executive,
  12562. KernelMode, FALSE, NULL);
  12563. while (!IsListEmpty(&Filter->SnapshotLookupTableEntries)) {
  12564. l = RemoveHeadList(&Filter->SnapshotLookupTableEntries);
  12565. lookupEntry = CONTAINING_RECORD(l, VSP_LOOKUP_TABLE_ENTRY,
  12566. SnapshotFilterListEntry);
  12567. ASSERT(lookupEntry->SnapshotFilter);
  12568. lookupEntry->SnapshotFilter = NULL;
  12569. if (!lookupEntry->DiffAreaFilter) {
  12570. ASSERT(!lookupEntry->DiffAreaHandle);
  12571. RtlDeleteElementGenericTable(
  12572. &Filter->Root->PersistentSnapshotLookupTable,
  12573. lookupEntry);
  12574. }
  12575. }
  12576. while (!IsListEmpty(&Filter->DiffAreaLookupTableEntries)) {
  12577. l = RemoveHeadList(&Filter->DiffAreaLookupTableEntries);
  12578. lookupEntry = CONTAINING_RECORD(l, VSP_LOOKUP_TABLE_ENTRY,
  12579. DiffAreaFilterListEntry);
  12580. ASSERT(lookupEntry->DiffAreaFilter);
  12581. lookupEntry->DiffAreaFilter = NULL;
  12582. if (lookupEntry->DiffAreaHandle) {
  12583. ZwClose(lookupEntry->DiffAreaHandle);
  12584. lookupEntry->DiffAreaHandle = NULL;
  12585. }
  12586. if (!lookupEntry->SnapshotFilter) {
  12587. RtlDeleteElementGenericTable(
  12588. &Filter->Root->PersistentSnapshotLookupTable,
  12589. lookupEntry);
  12590. }
  12591. }
  12592. KeReleaseMutex(&Filter->Root->LookupTableMutex, FALSE);
  12593. }
  12594. VOID
  12595. VspCleanupControlFile(
  12596. IN PFILTER_EXTENSION Filter
  12597. )
  12598. {
  12599. LONGLONG controlBlockOffset;
  12600. PVSP_BLOCK_CONTROL controlBlock;
  12601. NTSTATUS status;
  12602. ULONG offset;
  12603. PVSP_CONTROL_ITEM_SNAPSHOT controlItem;
  12604. controlBlockOffset = Filter->FirstControlBlockVolumeOffset;
  12605. controlBlock = (PVSP_BLOCK_CONTROL) MmGetMdlVirtualAddress(
  12606. Filter->SnapshotOnDiskIrp->MdlAddress);
  12607. while (controlBlockOffset) {
  12608. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  12609. Filter->TargetObject, IRP_MJ_READ,
  12610. controlBlockOffset, 0);
  12611. if (!NT_SUCCESS(status)) {
  12612. break;
  12613. }
  12614. if (!IsEqualGUID(controlBlock->Header.Signature,
  12615. VSP_DIFF_AREA_FILE_GUID) ||
  12616. controlBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  12617. controlBlock->Header.BlockType != VSP_BLOCK_TYPE_CONTROL ||
  12618. controlBlock->Header.ThisVolumeOffset != controlBlockOffset ||
  12619. controlBlock->Header.NextVolumeOffset == controlBlockOffset) {
  12620. break;
  12621. }
  12622. for (offset = VSP_BYTES_PER_CONTROL_ITEM; offset < BLOCK_SIZE;
  12623. offset += VSP_BYTES_PER_CONTROL_ITEM) {
  12624. controlItem = (PVSP_CONTROL_ITEM_SNAPSHOT)
  12625. ((PCHAR) controlBlock + offset);
  12626. if (controlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_END) {
  12627. break;
  12628. }
  12629. if (controlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_FREE) {
  12630. continue;
  12631. }
  12632. VspRemoveControlItemInfoFromLookupTable(Filter, controlItem);
  12633. }
  12634. controlBlockOffset = controlBlock->Header.NextVolumeOffset;
  12635. if (!controlBlockOffset) {
  12636. break;
  12637. }
  12638. }
  12639. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  12640. VspCreateStartBlock(Filter, 0, Filter->MaximumVolumeSpace);
  12641. Filter->FirstControlBlockVolumeOffset = 0;
  12642. VspReleaseNonPagedResource(Filter);
  12643. }
  12644. VOID
  12645. VspWriteTriggerDpc(
  12646. IN PKDPC TimerDpc,
  12647. IN PVOID Context,
  12648. IN PVOID SystemArgument1,
  12649. IN PVOID SystemArgument2
  12650. )
  12651. {
  12652. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  12653. PFILTER_EXTENSION filter = context->DeleteDiffAreaFiles.Filter;
  12654. KIRQL irql;
  12655. PLIST_ENTRY l;
  12656. PVSP_COPY_ON_WRITE copyOnWrite;
  12657. ASSERT(context->Type == VSP_CONTEXT_TYPE_PNP_WAIT_TIMER);
  12658. ExFreePool(context->PnpWaitTimer.Timer);
  12659. VspFreeContext(filter->Root, context);
  12660. if (!filter->HoldIncomingWrites || !filter->SnapshotDiscoveryPending) {
  12661. ObDereferenceObject(filter->DeviceObject);
  12662. return;
  12663. }
  12664. KeAcquireSpinLock(&filter->SpinLock, &irql);
  12665. if (filter->ActivateStarted || filter->FirstWriteProcessed) {
  12666. KeReleaseSpinLock(&filter->SpinLock, irql);
  12667. ObDereferenceObject(filter->DeviceObject);
  12668. return;
  12669. }
  12670. InterlockedExchange(&filter->FirstWriteProcessed, TRUE);
  12671. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  12672. l = RemoveHeadList(&filter->CopyOnWriteList);
  12673. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  12674. ExFreePool(copyOnWrite->Buffer);
  12675. ExFreePool(copyOnWrite);
  12676. }
  12677. KeReleaseSpinLock(&filter->SpinLock, irql);
  12678. ExInitializeWorkItem(&filter->DestroyContext.WorkItem,
  12679. VspStartCopyOnWriteCache, filter);
  12680. ExQueueWorkItem(&filter->DestroyContext.WorkItem, DelayedWorkQueue);
  12681. }
  12682. VOID
  12683. VspScheduleWriteTrigger(
  12684. IN PFILTER_EXTENSION Filter
  12685. )
  12686. {
  12687. PKTIMER timer;
  12688. PVSP_CONTEXT context;
  12689. LARGE_INTEGER timeout;
  12690. timer = (PKTIMER) ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER),
  12691. VOLSNAP_TAG_SHORT_TERM);
  12692. if (!timer) {
  12693. return;
  12694. }
  12695. context = VspAllocateContext(Filter->Root);
  12696. if (!context) {
  12697. ExFreePool(timer);
  12698. return;
  12699. }
  12700. ObReferenceObject(Filter->DeviceObject);
  12701. KeInitializeTimer(timer);
  12702. context->Type = VSP_CONTEXT_TYPE_PNP_WAIT_TIMER;
  12703. context->PnpWaitTimer.Filter = Filter;
  12704. KeInitializeDpc(&context->PnpWaitTimer.TimerDpc, VspWriteTriggerDpc,
  12705. context);
  12706. context->PnpWaitTimer.Timer = timer;
  12707. timeout.QuadPart = (LONGLONG) 10*(-10*1000*1000); // 10 seconds.
  12708. KeSetTimer(timer, timeout, &context->PnpWaitTimer.TimerDpc);
  12709. }
  12710. VOID
  12711. VspDiscoverSnapshots(
  12712. IN PFILTER_EXTENSION Filter,
  12713. OUT PBOOLEAN NoControlItems
  12714. )
  12715. {
  12716. NTSTATUS status;
  12717. PVOID buffer;
  12718. PVSP_BLOCK_START startBlock;
  12719. LONGLONG controlBlockOffset;
  12720. PVSP_BLOCK_CONTROL controlBlock;
  12721. ULONG offset;
  12722. PVSP_CONTROL_ITEM_SNAPSHOT controlItem;
  12723. BOOLEAN diffAreasFound, snapshotsFound, isComplete;
  12724. PLIST_ENTRY l;
  12725. PFILTER_EXTENSION f;
  12726. KIRQL irql;
  12727. *NoControlItems = TRUE;
  12728. if (!Filter->SnapshotOnDiskIrp) {
  12729. VspCreateSnapshotOnDiskIrp(Filter);
  12730. if (!Filter->SnapshotOnDiskIrp) {
  12731. VspResumeVolumeIo(Filter);
  12732. return;
  12733. }
  12734. }
  12735. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp, Filter->TargetObject,
  12736. IRP_MJ_READ, 0, 0);
  12737. if (!NT_SUCCESS(status)) {
  12738. VspResumeVolumeIo(Filter);
  12739. return;
  12740. }
  12741. buffer = MmGetMdlVirtualAddress(Filter->SnapshotOnDiskIrp->MdlAddress);
  12742. if (!VspIsNtfsBootSector(Filter, buffer)) {
  12743. VspResumeVolumeIo(Filter);
  12744. return;
  12745. }
  12746. startBlock = (PVSP_BLOCK_START) ((PCHAR) buffer + VSP_START_BLOCK_OFFSET);
  12747. if (!IsEqualGUID(startBlock->Header.Signature, VSP_DIFF_AREA_FILE_GUID)) {
  12748. VspResumeVolumeIo(Filter);
  12749. return;
  12750. }
  12751. if (startBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  12752. startBlock->Header.BlockType != VSP_BLOCK_TYPE_START) {
  12753. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  12754. VspCreateStartBlock(Filter, 0, 0);
  12755. Filter->FirstControlBlockVolumeOffset = 0;
  12756. Filter->MaximumVolumeSpace = 0;
  12757. VspReleaseNonPagedResource(Filter);
  12758. VspResumeVolumeIo(Filter);
  12759. return;
  12760. }
  12761. if (startBlock->MaximumDiffAreaSpace >= 0) {
  12762. Filter->MaximumVolumeSpace = startBlock->MaximumDiffAreaSpace;
  12763. }
  12764. controlBlockOffset = startBlock->FirstControlBlockVolumeOffset;
  12765. if (!controlBlockOffset || controlBlockOffset < 0 ||
  12766. (controlBlockOffset&(BLOCK_SIZE - 1))) {
  12767. VspResumeVolumeIo(Filter);
  12768. return;
  12769. }
  12770. Filter->FirstControlBlockVolumeOffset = controlBlockOffset;
  12771. controlBlock = (PVSP_BLOCK_CONTROL) buffer;
  12772. diffAreasFound = snapshotsFound = FALSE;
  12773. for (;;) {
  12774. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  12775. Filter->TargetObject, IRP_MJ_READ,
  12776. controlBlockOffset, 0);
  12777. if (!NT_SUCCESS(status)) {
  12778. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  12779. status, 5, FALSE);
  12780. VspCleanupControlFile(Filter);
  12781. break;
  12782. }
  12783. if (!IsEqualGUID(controlBlock->Header.Signature,
  12784. VSP_DIFF_AREA_FILE_GUID) ||
  12785. controlBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  12786. controlBlock->Header.BlockType != VSP_BLOCK_TYPE_CONTROL ||
  12787. controlBlock->Header.ThisVolumeOffset != controlBlockOffset ||
  12788. controlBlock->Header.NextVolumeOffset == controlBlockOffset) {
  12789. VspLogError(NULL, Filter, VS_ABORT_SNAPSHOTS_DURING_DETECTION,
  12790. STATUS_INVALID_PARAMETER, 6, FALSE);
  12791. VspCleanupControlFile(Filter);
  12792. break;
  12793. }
  12794. for (offset = VSP_BYTES_PER_CONTROL_ITEM; offset < BLOCK_SIZE;
  12795. offset += VSP_BYTES_PER_CONTROL_ITEM) {
  12796. controlItem = (PVSP_CONTROL_ITEM_SNAPSHOT)
  12797. ((PCHAR) controlBlock + offset);
  12798. if (controlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_END) {
  12799. break;
  12800. }
  12801. if (controlItem->ControlItemType == VSP_CONTROL_ITEM_TYPE_FREE) {
  12802. continue;
  12803. }
  12804. VspCheckCodeLocked(Filter->Root, TRUE);
  12805. if (controlItem->ControlItemType ==
  12806. VSP_CONTROL_ITEM_TYPE_SNAPSHOT &&
  12807. !controlItem->SnapshotOrderNumber) {
  12808. VspLogError(NULL, Filter, VS_PARTIAL_CREATE_REVERTED,
  12809. STATUS_SUCCESS, 0, FALSE);
  12810. RtlZeroMemory(controlItem, VSP_BYTES_PER_CONTROL_ITEM);
  12811. controlItem->ControlItemType = VSP_CONTROL_ITEM_TYPE_FREE;
  12812. VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  12813. Filter->TargetObject, IRP_MJ_WRITE,
  12814. controlBlockOffset, 0);
  12815. continue;
  12816. }
  12817. status = VspAddControlItemInfoToLookupTable(Filter, controlItem,
  12818. &isComplete);
  12819. if (!NT_SUCCESS(status)) {
  12820. VspLogError(NULL, Filter, VS_LOSS_OF_CONTROL_ITEM, status,
  12821. 0, FALSE);
  12822. RtlZeroMemory(controlItem, VSP_BYTES_PER_CONTROL_ITEM);
  12823. controlItem->ControlItemType = VSP_CONTROL_ITEM_TYPE_FREE;
  12824. VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  12825. Filter->TargetObject, IRP_MJ_WRITE,
  12826. controlBlockOffset, 0);
  12827. continue;
  12828. }
  12829. if (controlItem->ControlItemType ==
  12830. VSP_CONTROL_ITEM_TYPE_SNAPSHOT) {
  12831. snapshotsFound = TRUE;
  12832. if (isComplete) {
  12833. diffAreasFound = TRUE;
  12834. }
  12835. } else {
  12836. ASSERT(controlItem->ControlItemType ==
  12837. VSP_CONTROL_ITEM_TYPE_DIFF_AREA);
  12838. diffAreasFound = TRUE;
  12839. }
  12840. }
  12841. controlBlockOffset = controlBlock->Header.NextVolumeOffset;
  12842. if (!controlBlockOffset) {
  12843. break;
  12844. }
  12845. }
  12846. if (snapshotsFound) {
  12847. InterlockedExchange(&Filter->SnapshotDiscoveryPending, TRUE);
  12848. KeResetEvent(&Filter->EndCommitProcessCompleted);
  12849. *NoControlItems = FALSE;
  12850. VspScheduleWriteTrigger(Filter);
  12851. } else {
  12852. VspResumeVolumeIo(Filter);
  12853. }
  12854. if (!diffAreasFound) {
  12855. return;
  12856. }
  12857. *NoControlItems = FALSE;
  12858. for (l = Filter->Root->FilterList.Flink; l != &Filter->Root->FilterList;
  12859. l = l->Flink) {
  12860. f = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  12861. if (f->SnapshotDiscoveryPending) {
  12862. if (VspAreSnapshotsComplete(f)) {
  12863. KeAcquireSpinLock(&f->SpinLock, &irql);
  12864. f->ActivateStarted = TRUE;
  12865. if (f->FirstWriteProcessed) {
  12866. KeReleaseSpinLock(&f->SpinLock, irql);
  12867. VspPauseVolumeIo(f);
  12868. } else {
  12869. KeReleaseSpinLock(&f->SpinLock, irql);
  12870. }
  12871. status = VspActivateSnapshots(f);
  12872. InterlockedExchange(&f->SnapshotDiscoveryPending, FALSE);
  12873. if (!NT_SUCCESS(status)) {
  12874. KeSetEvent(&f->EndCommitProcessCompleted,
  12875. IO_NO_INCREMENT, FALSE);
  12876. }
  12877. VspResumeVolumeIo(f);
  12878. }
  12879. }
  12880. }
  12881. }
  12882. VOID
  12883. VspLaunchOpenControlBlockFileWorker(
  12884. IN PFILTER_EXTENSION Filter
  12885. )
  12886. {
  12887. PVSP_CONTEXT context;
  12888. NTSTATUS status;
  12889. context = VspAllocateContext(Filter->Root);
  12890. if (!context) {
  12891. return;
  12892. }
  12893. ObReferenceObject(Filter->DeviceObject);
  12894. ObReferenceObject(Filter->TargetObject);
  12895. context->Type = VSP_CONTEXT_TYPE_FILTER;
  12896. context->Filter.Filter = Filter;
  12897. ExInitializeWorkItem(&context->WorkItem, VspOpenControlBlockFileWorker,
  12898. context);
  12899. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  12900. }
  12901. NTSTATUS
  12902. VspQueryDeviceName(
  12903. IN PVOLUME_EXTENSION Extension,
  12904. IN PIRP Irp
  12905. )
  12906. {
  12907. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  12908. WCHAR nameBuffer[100];
  12909. UNICODE_STRING nameString;
  12910. PMOUNTDEV_NAME name;
  12911. if (!Extension->IsPersistent) {
  12912. return STATUS_INVALID_PARAMETER;
  12913. }
  12914. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  12915. sizeof(MOUNTDEV_NAME)) {
  12916. return STATUS_INVALID_PARAMETER;
  12917. }
  12918. swprintf(nameBuffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  12919. Extension->VolumeNumber);
  12920. RtlInitUnicodeString(&nameString, nameBuffer);
  12921. name = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
  12922. name->NameLength = nameString.Length;
  12923. Irp->IoStatus.Information = name->NameLength + sizeof(USHORT);
  12924. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  12925. Irp->IoStatus.Information) {
  12926. Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
  12927. return STATUS_BUFFER_OVERFLOW;
  12928. }
  12929. RtlCopyMemory(name->Name, nameString.Buffer, name->NameLength);
  12930. return STATUS_SUCCESS;
  12931. }
  12932. NTSTATUS
  12933. VspQueryUniqueId(
  12934. IN OUT PVOLUME_EXTENSION Extension,
  12935. IN OUT PIRP Irp
  12936. )
  12937. /*++
  12938. Routine Description:
  12939. This routine is called to query the unique id for this volume.
  12940. Arguments:
  12941. Extension - Supplies the volume extension.
  12942. Irp - Supplies the IO request packet.
  12943. Return Value:
  12944. NTSTATUS
  12945. --*/
  12946. {
  12947. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  12948. PMOUNTDEV_UNIQUE_ID output;
  12949. if (!Extension->IsPersistent) {
  12950. return STATUS_INVALID_PARAMETER;
  12951. }
  12952. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  12953. sizeof(MOUNTDEV_UNIQUE_ID)) {
  12954. return STATUS_INVALID_PARAMETER;
  12955. }
  12956. output = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
  12957. output->UniqueIdLength = sizeof(GUID);
  12958. Irp->IoStatus.Information = sizeof(USHORT) + output->UniqueIdLength;
  12959. if (Irp->IoStatus.Information >
  12960. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  12961. Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
  12962. return STATUS_BUFFER_OVERFLOW;
  12963. }
  12964. RtlCopyMemory(output->UniqueId, &Extension->SnapshotGuid, sizeof(GUID));
  12965. return STATUS_SUCCESS;
  12966. }
  12967. NTSTATUS
  12968. VspQueryStableGuid(
  12969. IN OUT PVOLUME_EXTENSION Extension,
  12970. IN OUT PIRP Irp
  12971. )
  12972. /*++
  12973. Routine Description:
  12974. This routine is called to query the stable guid for this volume.
  12975. Arguments:
  12976. Extension - Supplies the volume extension.
  12977. Irp - Supplies the IO request packet.
  12978. Return Value:
  12979. NTSTATUS
  12980. --*/
  12981. {
  12982. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  12983. PMOUNTDEV_STABLE_GUID output;
  12984. if (!Extension->IsPersistent) {
  12985. return STATUS_INVALID_PARAMETER;
  12986. }
  12987. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  12988. sizeof(MOUNTDEV_STABLE_GUID)) {
  12989. return STATUS_INVALID_PARAMETER;
  12990. }
  12991. output = (PMOUNTDEV_STABLE_GUID) Irp->AssociatedIrp.SystemBuffer;
  12992. output->StableGuid = Extension->SnapshotGuid;
  12993. Irp->IoStatus.Information = sizeof(MOUNTDEV_STABLE_GUID);
  12994. return STATUS_SUCCESS;
  12995. }
  12996. NTSTATUS
  12997. VspSetGptAttributes(
  12998. IN PVOLUME_EXTENSION Extension,
  12999. IN PIRP Irp
  13000. )
  13001. {
  13002. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13003. PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION input = (PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  13004. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  13005. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  13006. NTSTATUS status;
  13007. BOOLEAN visible;
  13008. status = VspCheckSecurity(Extension->Filter, Irp);
  13009. if (!NT_SUCCESS(status)) {
  13010. return status;
  13011. }
  13012. if (!Extension->IsPersistent) {
  13013. return STATUS_INVALID_PARAMETER;
  13014. }
  13015. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  13016. sizeof(VOLUME_SET_GPT_ATTRIBUTES_INFORMATION)) {
  13017. return STATUS_INVALID_PARAMETER;
  13018. }
  13019. if (input->Reserved1 || input->Reserved2 || input->RevertOnClose ||
  13020. input->ApplyToAllConnectedVolumes) {
  13021. return STATUS_INVALID_PARAMETER;
  13022. }
  13023. if (!(input->GptAttributes&GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER)) {
  13024. return STATUS_INVALID_PARAMETER;
  13025. }
  13026. input->GptAttributes &= ~GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
  13027. if (!(input->GptAttributes&GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY)) {
  13028. return STATUS_INVALID_PARAMETER;
  13029. }
  13030. input->GptAttributes &= ~GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
  13031. if (input->GptAttributes&GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) {
  13032. visible = FALSE;
  13033. } else {
  13034. visible = TRUE;
  13035. }
  13036. input->GptAttributes &= ~GPT_BASIC_DATA_ATTRIBUTE_HIDDEN;
  13037. if (input->GptAttributes) {
  13038. return STATUS_INVALID_PARAMETER;
  13039. }
  13040. VspAcquire(Extension->Root);
  13041. if (visible == Extension->IsVisible) {
  13042. VspRelease(Extension->Root);
  13043. return STATUS_SUCCESS;
  13044. }
  13045. status = VspIoControlItem(Extension->Filter,
  13046. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  13047. &Extension->SnapshotGuid, FALSE,
  13048. controlItemBuffer, TRUE);
  13049. if (!NT_SUCCESS(status)) {
  13050. VspRelease(Extension->Root);
  13051. return status;
  13052. }
  13053. if (visible) {
  13054. snapshotControlItem->SnapshotControlItemFlags |=
  13055. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_VISIBLE;
  13056. } else {
  13057. snapshotControlItem->SnapshotControlItemFlags &=
  13058. ~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_VISIBLE;
  13059. }
  13060. status = VspIoControlItem(Extension->Filter,
  13061. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  13062. &Extension->SnapshotGuid, TRUE,
  13063. controlItemBuffer, TRUE);
  13064. if (!NT_SUCCESS(status)) {
  13065. VspRelease(Extension->Root);
  13066. return status;
  13067. }
  13068. Extension->IsVisible = visible;
  13069. if (Extension->IsVisible) {
  13070. ASSERT(!Extension->MountedDeviceInterfaceName.Buffer);
  13071. status = IoRegisterDeviceInterface(
  13072. Extension->DeviceObject,
  13073. &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL,
  13074. &Extension->MountedDeviceInterfaceName);
  13075. if (NT_SUCCESS(status)) {
  13076. IoSetDeviceInterfaceState(
  13077. &Extension->MountedDeviceInterfaceName, TRUE);
  13078. }
  13079. } else {
  13080. ASSERT(Extension->MountedDeviceInterfaceName.Buffer);
  13081. IoSetDeviceInterfaceState(&Extension->MountedDeviceInterfaceName,
  13082. FALSE);
  13083. ExFreePool(Extension->MountedDeviceInterfaceName.Buffer);
  13084. Extension->MountedDeviceInterfaceName.Buffer = NULL;
  13085. }
  13086. VspRelease(Extension->Root);
  13087. return STATUS_SUCCESS;
  13088. }
  13089. NTSTATUS
  13090. VspGetGptAttributes(
  13091. IN PVOLUME_EXTENSION Extension,
  13092. IN PIRP Irp
  13093. )
  13094. /*++
  13095. Routine Description:
  13096. This routine returns the current GPT attributes definitions for the volume.
  13097. Arguments:
  13098. Extension - Supplies the volume extension.
  13099. Irp - Supplies the I/O request packet.
  13100. Return Value:
  13101. NTSTATUS
  13102. --*/
  13103. {
  13104. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13105. PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION output = (PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  13106. Irp->IoStatus.Information =
  13107. sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
  13108. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  13109. Irp->IoStatus.Information) {
  13110. Irp->IoStatus.Information = 0;
  13111. return STATUS_INVALID_PARAMETER;
  13112. }
  13113. output->GptAttributes = GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER |
  13114. GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
  13115. if (!Extension->IsVisible) {
  13116. output->GptAttributes |= GPT_BASIC_DATA_ATTRIBUTE_HIDDEN;
  13117. }
  13118. return STATUS_SUCCESS;
  13119. }
  13120. NTSTATUS
  13121. VspGetLengthInfo(
  13122. IN PVOLUME_EXTENSION Extension,
  13123. IN PIRP Irp
  13124. )
  13125. {
  13126. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13127. PGET_LENGTH_INFORMATION output = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  13128. Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
  13129. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  13130. Irp->IoStatus.Information) {
  13131. Irp->IoStatus.Information = 0;
  13132. return STATUS_INVALID_PARAMETER;
  13133. }
  13134. output->Length.QuadPart = Extension->VolumeSize;
  13135. return STATUS_SUCCESS;
  13136. }
  13137. VOID
  13138. VspDecrementWaitBlock(
  13139. IN PVOID WaitBlock
  13140. )
  13141. {
  13142. PVSP_WAIT_BLOCK waitBlock = (PVSP_WAIT_BLOCK) WaitBlock;
  13143. if (InterlockedDecrement(&waitBlock->RefCount)) {
  13144. return;
  13145. }
  13146. KeSetEvent(&waitBlock->Event, IO_NO_INCREMENT, FALSE);
  13147. }
  13148. VOID
  13149. VspReleaseTableEntry(
  13150. IN PTEMP_TRANSLATION_TABLE_ENTRY TableEntry
  13151. )
  13152. {
  13153. PVOLUME_EXTENSION extension = TableEntry->Extension;
  13154. ULONG targetBit = (ULONG) (TableEntry->VolumeOffset>>BLOCK_SHIFT);
  13155. KIRQL irql;
  13156. PLIST_ENTRY l;
  13157. PWORK_QUEUE_ITEM workItem;
  13158. PVSP_CONTEXT context;
  13159. KeAcquireSpinLock(&extension->SpinLock, &irql);
  13160. RtlSetBit(extension->VolumeBlockBitmap, targetBit);
  13161. TableEntry->IsComplete = TRUE;
  13162. KeReleaseSpinLock(&extension->SpinLock, irql);
  13163. while (!IsListEmpty(&TableEntry->WaitingQueueDpc)) {
  13164. l = RemoveHeadList(&TableEntry->WaitingQueueDpc);
  13165. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  13166. context = (PVSP_CONTEXT) workItem->Parameter;
  13167. if (context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT) {
  13168. context->ReadSnapshot.TargetObject = TableEntry->TargetObject;
  13169. context->ReadSnapshot.IsCopyTarget = FALSE;
  13170. context->ReadSnapshot.TargetOffset = TableEntry->TargetOffset;
  13171. }
  13172. workItem->WorkerRoutine(workItem->Parameter);
  13173. }
  13174. VspAcquireNonPagedResource(extension, NULL, FALSE);
  13175. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable,
  13176. TableEntry);
  13177. VspReleaseNonPagedResource(extension);
  13178. }
  13179. NTSTATUS
  13180. VspCopyBlock(
  13181. IN PVOLUME_EXTENSION Extension,
  13182. IN LONGLONG Source,
  13183. IN LONGLONG Target,
  13184. IN ULONG Length,
  13185. IN PIRP Irp,
  13186. OUT PBOOLEAN DontDecrement
  13187. )
  13188. {
  13189. PFILTER_EXTENSION filter = Extension->Filter;
  13190. NTSTATUS status, status2;
  13191. ULONG sourceBit, targetBit;
  13192. KIRQL irql;
  13193. PMDL mdl;
  13194. TEMP_TRANSLATION_TABLE_ENTRY keyTableEntry;
  13195. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  13196. PVOID nodeOrParent;
  13197. TABLE_SEARCH_RESULT searchResult;
  13198. VSP_WAIT_BLOCK waitBlock;
  13199. PVSP_WRITE_CONTEXT writeContext;
  13200. PWORK_QUEUE_ITEM workItem;
  13201. PIO_STACK_LOCATION irpSp;
  13202. LONGLONG start, end;
  13203. PLIST_ENTRY l;
  13204. TRANSLATION_TABLE_ENTRY key;
  13205. PVOID r, r2;
  13206. BOOLEAN b;
  13207. LIST_ENTRY q;
  13208. PVSP_CONTEXT context;
  13209. KEVENT event;
  13210. PTRANSLATION_TABLE_ENTRY sourceBackPointer;
  13211. LONGLONG sourceSource;
  13212. PTRANSLATION_TABLE_ENTRY sourceTableEntry;
  13213. PVSP_DIFF_AREA_FILE diffAreaFile;
  13214. BOOLEAN dontNeedWrite;
  13215. *DontDecrement = FALSE;
  13216. status = VspSynchronousIo(Irp, filter->DeviceObject, IRP_MJ_READ,
  13217. Source, Length);
  13218. if (!NT_SUCCESS(status)) {
  13219. return status;
  13220. }
  13221. if (Length < BLOCK_SIZE) {
  13222. VspDecrementRefCount(filter);
  13223. status = VspSynchronousIo(Irp, filter->DeviceObject, IRP_MJ_WRITE,
  13224. Target, Length);
  13225. InterlockedIncrement(&filter->RefCount);
  13226. if (filter->HoldIncomingWrites || !filter->SnapshotsPresent) {
  13227. *DontDecrement = TRUE;
  13228. VspDecrementRefCount(filter);
  13229. return STATUS_INVALID_PARAMETER;
  13230. }
  13231. return status;
  13232. }
  13233. ASSERT(Length == BLOCK_SIZE);
  13234. ASSERT(!(Source&(BLOCK_SIZE - 1)));
  13235. ASSERT(!(Target&(BLOCK_SIZE - 1)));
  13236. sourceBit = (ULONG) (Source>>BLOCK_SHIFT);
  13237. targetBit = (ULONG) (Target>>BLOCK_SHIFT);
  13238. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13239. ASSERT(Extension->VolumeBlockBitmap);
  13240. if (RtlCheckBit(Extension->VolumeBlockBitmap, sourceBit)) {
  13241. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13242. VspDecrementRefCount(filter);
  13243. status = VspSynchronousIo(Irp, filter->DeviceObject, IRP_MJ_WRITE,
  13244. Target, Length);
  13245. InterlockedIncrement(&filter->RefCount);
  13246. if (filter->HoldIncomingWrites || !filter->SnapshotsPresent) {
  13247. *DontDecrement = TRUE;
  13248. VspDecrementRefCount(filter);
  13249. return STATUS_INVALID_PARAMETER;
  13250. }
  13251. return status;
  13252. }
  13253. if (RtlCheckBit(Extension->VolumeBlockBitmap, targetBit)) {
  13254. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13255. } else {
  13256. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13257. VspDecrementRefCount(filter);
  13258. mdl = Irp->MdlAddress;
  13259. Irp->MdlAddress = NULL;
  13260. status = VspSynchronousIo(Irp, filter->DeviceObject, IRP_MJ_WRITE,
  13261. Target, Length);
  13262. Irp->MdlAddress = mdl;
  13263. InterlockedIncrement(&filter->RefCount);
  13264. if (filter->HoldIncomingWrites || !filter->SnapshotsPresent) {
  13265. *DontDecrement = TRUE;
  13266. VspDecrementRefCount(filter);
  13267. return STATUS_INVALID_PARAMETER;
  13268. }
  13269. if (!NT_SUCCESS(status)) {
  13270. return status;
  13271. }
  13272. }
  13273. RtlZeroMemory(&keyTableEntry, sizeof(TEMP_TRANSLATION_TABLE_ENTRY));
  13274. keyTableEntry.VolumeOffset = Target;
  13275. keyTableEntry.Extension = Extension;
  13276. keyTableEntry.TargetObject = filter->TargetObject;
  13277. keyTableEntry.TargetOffset = Target;
  13278. InitializeListHead(&keyTableEntry.WaitingQueueDpc);
  13279. keyTableEntry.IsMoveEntry = TRUE;
  13280. keyTableEntry.FileOffset = Source;
  13281. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  13282. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  13283. RtlLookupElementGenericTableFull(
  13284. &Extension->TempVolumeBlockTable, &keyTableEntry,
  13285. &nodeOrParent, &searchResult);
  13286. if (tableEntry) {
  13287. KeInitializeEvent(&event, NotificationEvent, FALSE);
  13288. tableEntry->WaitEvent = &event;
  13289. VspReleaseNonPagedResource(Extension);
  13290. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  13291. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  13292. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  13293. RtlLookupElementGenericTableFull(
  13294. &Extension->TempVolumeBlockTable, &keyTableEntry,
  13295. &nodeOrParent, &searchResult);
  13296. ASSERT(!tableEntry);
  13297. }
  13298. ASSERT(!Extension->TempTableEntry);
  13299. Extension->TempTableEntry =
  13300. VspAllocateTempTableEntry(Extension->Root);
  13301. if (!Extension->TempTableEntry) {
  13302. VspReleaseNonPagedResource(Extension);
  13303. VspDecrementRefCount(filter);
  13304. status = VspSynchronousIo(Irp, filter->DeviceObject, IRP_MJ_WRITE,
  13305. Target, Length);
  13306. InterlockedIncrement(&filter->RefCount);
  13307. if (filter->HoldIncomingWrites || !filter->SnapshotsPresent) {
  13308. *DontDecrement = TRUE;
  13309. VspDecrementRefCount(filter);
  13310. return STATUS_INVALID_PARAMETER;
  13311. }
  13312. return status;
  13313. }
  13314. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  13315. RtlInsertElementGenericTableFull(
  13316. &Extension->TempVolumeBlockTable, &keyTableEntry,
  13317. sizeof(TEMP_TRANSLATION_TABLE_ENTRY), NULL,
  13318. nodeOrParent, searchResult);
  13319. ASSERT(tableEntry);
  13320. InitializeListHead(&tableEntry->WaitingQueueDpc);
  13321. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13322. RtlClearBit(Extension->VolumeBlockBitmap, targetBit);
  13323. if (Extension->IgnorableProduct) {
  13324. RtlClearBit(Extension->IgnorableProduct, targetBit);
  13325. }
  13326. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13327. VspReleaseNonPagedResource(Extension);
  13328. waitBlock.RefCount = 1;
  13329. KeInitializeEvent(&waitBlock.Event, NotificationEvent, FALSE);
  13330. status = STATUS_SUCCESS;
  13331. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13332. for (l = Extension->WriteContextList.Flink;
  13333. l != &Extension->WriteContextList; l = l->Flink) {
  13334. writeContext = CONTAINING_RECORD(l, VSP_WRITE_CONTEXT, ListEntry);
  13335. irpSp = IoGetCurrentIrpStackLocation(writeContext->Irp);
  13336. start = irpSp->Parameters.Write.ByteOffset.QuadPart;
  13337. end = start + irpSp->Parameters.Write.Length;
  13338. if (start >= Target + Length || Target >= end) {
  13339. continue;
  13340. }
  13341. workItem = (PWORK_QUEUE_ITEM)
  13342. ExAllocatePoolWithTag(NonPagedPool, sizeof(WORK_QUEUE_ITEM),
  13343. VOLSNAP_TAG_SHORT_TERM);
  13344. if (!workItem) {
  13345. status = STATUS_INSUFFICIENT_RESOURCES;
  13346. break;
  13347. }
  13348. InterlockedIncrement(&waitBlock.RefCount);
  13349. ExInitializeWorkItem(workItem, VspDecrementWaitBlock, &waitBlock);
  13350. InsertTailList(&writeContext->CompletionRoutines, &workItem->List);
  13351. }
  13352. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13353. if (InterlockedDecrement(&waitBlock.RefCount)) {
  13354. KeWaitForSingleObject(&waitBlock.Event, Executive, KernelMode, FALSE,
  13355. NULL);
  13356. }
  13357. if (!NT_SUCCESS(status)) {
  13358. VspReleaseTableEntry(tableEntry);
  13359. return status;
  13360. }
  13361. status = VspSynchronousIo(Irp, filter->TargetObject, IRP_MJ_WRITE,
  13362. Target, Length);
  13363. if (!NT_SUCCESS(status)) {
  13364. VspReleaseTableEntry(tableEntry);
  13365. return status;
  13366. }
  13367. RtlZeroMemory(&key, sizeof(TRANSLATION_TABLE_ENTRY));
  13368. key.VolumeOffset = Source;
  13369. key.TargetObject = filter->TargetObject;
  13370. key.Flags = VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY;
  13371. key.TargetOffset = Target;
  13372. VspAcquirePagedResource(Extension, NULL);
  13373. _try {
  13374. sourceBackPointer = (PTRANSLATION_TABLE_ENTRY)
  13375. RtlLookupElementGenericTable(&Extension->CopyBackPointerTable,
  13376. &key);
  13377. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13378. status = GetExceptionCode();
  13379. }
  13380. if (!NT_SUCCESS(status)) {
  13381. VspReleasePagedResource(Extension);
  13382. VspReleaseTableEntry(tableEntry);
  13383. return status;
  13384. }
  13385. if (sourceBackPointer) {
  13386. sourceSource = sourceBackPointer->TargetOffset;
  13387. if (sourceSource == Target) {
  13388. VspReleasePagedResource(Extension);
  13389. VspReleaseTableEntry(tableEntry);
  13390. return STATUS_SUCCESS;
  13391. }
  13392. _try {
  13393. b = RtlDeleteElementGenericTable(&Extension->CopyBackPointerTable,
  13394. &key);
  13395. ASSERT(b);
  13396. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13397. status = GetExceptionCode();
  13398. }
  13399. if (!NT_SUCCESS(status)) {
  13400. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  13401. VspReleasePagedResource(Extension);
  13402. VspReleaseTableEntry(tableEntry);
  13403. return status;
  13404. }
  13405. key.VolumeOffset = Target;
  13406. key.TargetOffset = sourceSource;
  13407. _try {
  13408. r2 = RtlInsertElementGenericTable(&Extension->CopyBackPointerTable,
  13409. &key, sizeof(key), NULL);
  13410. if (!r2) {
  13411. status = STATUS_INSUFFICIENT_RESOURCES;
  13412. }
  13413. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13414. r2 = NULL;
  13415. status = GetExceptionCode();
  13416. }
  13417. if (!r2) {
  13418. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  13419. VspReleasePagedResource(Extension);
  13420. VspReleaseTableEntry(tableEntry);
  13421. return status;
  13422. }
  13423. key.VolumeOffset = sourceSource;
  13424. key.TargetOffset = Target;
  13425. _try {
  13426. sourceTableEntry = (PTRANSLATION_TABLE_ENTRY)
  13427. RtlLookupElementGenericTable(&Extension->VolumeBlockTable,
  13428. &key);
  13429. ASSERT(sourceTableEntry);
  13430. if (!sourceTableEntry) {
  13431. status = STATUS_INVALID_PARAMETER;
  13432. }
  13433. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13434. sourceTableEntry = NULL;
  13435. status = GetExceptionCode();
  13436. }
  13437. if (!sourceTableEntry) {
  13438. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  13439. VspReleasePagedResource(Extension);
  13440. VspReleaseTableEntry(tableEntry);
  13441. return status;
  13442. }
  13443. ASSERT(sourceTableEntry->Flags&
  13444. VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY);
  13445. ASSERT(sourceTableEntry->TargetOffset == Source);
  13446. sourceTableEntry->TargetOffset = Target;
  13447. } else {
  13448. _try {
  13449. r = RtlLookupElementGenericTableFull(&Extension->VolumeBlockTable,
  13450. &key, &nodeOrParent,
  13451. &searchResult);
  13452. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13453. r = (PVOID) 1;
  13454. }
  13455. if (r) {
  13456. VspReleasePagedResource(Extension);
  13457. VspReleaseTableEntry(tableEntry);
  13458. return STATUS_SUCCESS;
  13459. }
  13460. _try {
  13461. r = RtlInsertElementGenericTableFull(&Extension->VolumeBlockTable,
  13462. &key,
  13463. sizeof(TRANSLATION_TABLE_ENTRY),
  13464. NULL, nodeOrParent, searchResult);
  13465. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13466. r = NULL;
  13467. }
  13468. if (!r) {
  13469. VspReleasePagedResource(Extension);
  13470. VspReleaseTableEntry(tableEntry);
  13471. return STATUS_SUCCESS;
  13472. }
  13473. key.VolumeOffset = Target;
  13474. key.TargetOffset = Source;
  13475. _try {
  13476. r2 = RtlInsertElementGenericTable(&Extension->CopyBackPointerTable,
  13477. &key,
  13478. sizeof(TRANSLATION_TABLE_ENTRY),
  13479. NULL);
  13480. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13481. r2 = NULL;
  13482. }
  13483. if (!r2) {
  13484. _try {
  13485. b = RtlDeleteElementGenericTable(&Extension->VolumeBlockTable, r);
  13486. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13487. b = FALSE;
  13488. }
  13489. if (!b) {
  13490. VspDestroyAllSnapshots(Extension->Filter, NULL, FALSE, FALSE);
  13491. }
  13492. VspReleasePagedResource(Extension);
  13493. VspReleaseTableEntry(tableEntry);
  13494. return STATUS_SUCCESS;
  13495. }
  13496. }
  13497. keyTableEntry.VolumeOffset = Source;
  13498. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  13499. r = RtlLookupElementGenericTable(&Extension->TempVolumeBlockTable,
  13500. &keyTableEntry);
  13501. if (!r) {
  13502. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13503. ASSERT(Extension->VolumeBlockBitmap);
  13504. if (RtlCheckBit(Extension->VolumeBlockBitmap, sourceBit)) {
  13505. r = (PVOID) 1;
  13506. }
  13507. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13508. }
  13509. diffAreaFile = Extension->DiffAreaFile;
  13510. if (r) {
  13511. VspReleaseNonPagedResource(Extension);
  13512. if (sourceBackPointer) {
  13513. sourceTableEntry->TargetOffset = Source;
  13514. _try {
  13515. b = RtlDeleteElementGenericTable(
  13516. &Extension->CopyBackPointerTable, r2);
  13517. if (b) {
  13518. key.VolumeOffset = Source;
  13519. key.TargetOffset = sourceSource;
  13520. r = RtlInsertElementGenericTable(
  13521. &Extension->CopyBackPointerTable, &key, sizeof(key),
  13522. NULL);
  13523. b = r ? TRUE : FALSE;
  13524. }
  13525. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13526. b = FALSE;
  13527. }
  13528. } else {
  13529. _try {
  13530. b = RtlDeleteElementGenericTable(&Extension->VolumeBlockTable,
  13531. r);
  13532. if (b) {
  13533. b = RtlDeleteElementGenericTable(
  13534. &Extension->CopyBackPointerTable, r2);
  13535. }
  13536. } _except (EXCEPTION_EXECUTE_HANDLER) {
  13537. b = FALSE;
  13538. }
  13539. }
  13540. if (!b) {
  13541. VspDestroyAllSnapshots(Extension->Filter, NULL, FALSE, FALSE);
  13542. }
  13543. VspReleasePagedResource(Extension);
  13544. VspReleaseTableEntry(tableEntry);
  13545. return STATUS_SUCCESS;
  13546. }
  13547. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13548. ASSERT(Extension->VolumeBlockBitmap);
  13549. RtlSetBit(Extension->VolumeBlockBitmap, sourceBit);
  13550. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13551. if (Extension->IsPersistent) {
  13552. KeInitializeEvent(&event, NotificationEvent, FALSE);
  13553. tableEntry->WaitEvent = &event;
  13554. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  13555. InsertTailList(&diffAreaFile->TableUpdateQueue,
  13556. &tableEntry->TableUpdateListEntry);
  13557. tableEntry->InTableUpdateQueue = TRUE;
  13558. dontNeedWrite = diffAreaFile->TableUpdateInProgress;
  13559. diffAreaFile->TableUpdateInProgress = TRUE;
  13560. KeReleaseSpinLock(&Extension->SpinLock, irql);
  13561. if (!dontNeedWrite) {
  13562. VspWriteTableUpdates(diffAreaFile);
  13563. }
  13564. VspReleaseNonPagedResource(Extension);
  13565. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  13566. VspAcquireNonPagedResource(Extension, NULL, FALSE);
  13567. }
  13568. if (IsListEmpty(&tableEntry->WaitingQueueDpc)) {
  13569. InitializeListHead(&q);
  13570. } else {
  13571. q = tableEntry->WaitingQueueDpc;
  13572. q.Blink->Flink = &q;
  13573. q.Flink->Blink = &q;
  13574. }
  13575. RtlDeleteElementGenericTable(&Extension->TempVolumeBlockTable,
  13576. tableEntry);
  13577. VspReleaseNonPagedResource(Extension);
  13578. VspReleasePagedResource(Extension);
  13579. status2 = STATUS_SUCCESS;
  13580. while (!IsListEmpty(&q)) {
  13581. l = RemoveHeadList(&tableEntry->WaitingQueueDpc);
  13582. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  13583. context = (PVSP_CONTEXT) workItem->Parameter;
  13584. if (context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT) {
  13585. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  13586. context->ReadSnapshot.IsCopyTarget = FALSE;
  13587. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  13588. workItem->WorkerRoutine(workItem->Parameter);
  13589. } else {
  13590. if (NT_SUCCESS(status2)) {
  13591. VspDecrementRefCount(filter);
  13592. }
  13593. mdl = Irp->MdlAddress;
  13594. Irp->MdlAddress = NULL;
  13595. status = VspSynchronousIo(Irp, filter->DeviceObject,
  13596. IRP_MJ_WRITE, Target, Length);
  13597. Irp->MdlAddress = mdl;
  13598. if (!NT_SUCCESS(status)) {
  13599. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  13600. }
  13601. if (NT_SUCCESS(status2)) {
  13602. InterlockedIncrement(&filter->RefCount);
  13603. if (filter->HoldIncomingWrites || !filter->SnapshotsPresent) {
  13604. *DontDecrement = TRUE;
  13605. VspDecrementRefCount(filter);
  13606. status2 = STATUS_INVALID_PARAMETER;
  13607. }
  13608. }
  13609. workItem->WorkerRoutine(workItem->Parameter);
  13610. }
  13611. }
  13612. return status2;
  13613. }
  13614. VOID
  13615. VspCopyDataWorker(
  13616. IN PVOID Context
  13617. )
  13618. {
  13619. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  13620. PVOLUME_EXTENSION extension = context->Extension.Extension;
  13621. PFILTER_EXTENSION filter = extension->Filter;
  13622. PIRP originalIrp = context->Extension.Irp;
  13623. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(originalIrp);
  13624. PDISK_COPY_DATA_PARAMETERS input = (PDISK_COPY_DATA_PARAMETERS) originalIrp->AssociatedIrp.SystemBuffer;
  13625. PVOID buffer = NULL;
  13626. PMDL mdl = NULL;
  13627. PIRP irp = NULL;
  13628. BOOLEAN dontDecrement = FALSE;
  13629. LONGLONG sourceStart, sourceEnd, targetStart, targetEnd;
  13630. NTSTATUS status;
  13631. ULONG delta;
  13632. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  13633. VspFreeContext(filter->Root, context);
  13634. buffer = ExAllocatePoolWithTag(NonPagedPool,
  13635. BLOCK_SIZE, VOLSNAP_TAG_BUFFER);
  13636. if (!buffer) {
  13637. status = STATUS_INSUFFICIENT_RESOURCES;
  13638. goto Finish;
  13639. }
  13640. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  13641. if (!mdl) {
  13642. status = STATUS_INSUFFICIENT_RESOURCES;
  13643. goto Finish;
  13644. }
  13645. irp = IoAllocateIrp(filter->DeviceObject->StackSize, FALSE);
  13646. if (!irp) {
  13647. status = STATUS_INSUFFICIENT_RESOURCES;
  13648. goto Finish;
  13649. }
  13650. MmBuildMdlForNonPagedPool(mdl);
  13651. irp->MdlAddress = mdl;
  13652. sourceStart = input->SourceOffset.QuadPart;
  13653. sourceEnd = sourceStart + input->CopyLength.QuadPart;
  13654. targetStart = input->DestinationOffset.QuadPart;
  13655. targetEnd = targetStart + input->CopyLength.QuadPart;
  13656. ASSERT(sourceStart < sourceEnd);
  13657. status = STATUS_SUCCESS;
  13658. while (sourceStart < sourceEnd) {
  13659. if (sourceStart&(BLOCK_SIZE - 1)) {
  13660. delta = (ULONG) (((sourceStart + BLOCK_SIZE)&(~(BLOCK_SIZE - 1))) -
  13661. sourceStart);
  13662. } else {
  13663. delta = BLOCK_SIZE;
  13664. }
  13665. if (sourceStart + delta > sourceEnd) {
  13666. delta = (ULONG) (sourceEnd - sourceStart);
  13667. }
  13668. status = VspCopyBlock(extension, sourceStart, targetStart, delta, irp,
  13669. &dontDecrement);
  13670. if (!NT_SUCCESS(status)) {
  13671. break;
  13672. }
  13673. sourceStart += delta;
  13674. targetStart += delta;
  13675. }
  13676. Finish:
  13677. if (irp) {
  13678. IoFreeIrp(irp);
  13679. }
  13680. if (mdl) {
  13681. IoFreeMdl(mdl);
  13682. }
  13683. if (buffer) {
  13684. ExFreePool(buffer);
  13685. }
  13686. if (!dontDecrement) {
  13687. VspDecrementRefCount(filter);
  13688. }
  13689. originalIrp->IoStatus.Information = 0;
  13690. originalIrp->IoStatus.Status = status;
  13691. IoCompleteRequest(originalIrp, IO_NO_INCREMENT);
  13692. }
  13693. NTSTATUS
  13694. VspCopyData(
  13695. IN PFILTER_EXTENSION Filter,
  13696. IN PIRP Irp
  13697. )
  13698. {
  13699. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13700. PDISK_COPY_DATA_PARAMETERS input = (PDISK_COPY_DATA_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
  13701. LONGLONG sourceStart, sourceEnd, targetStart, targetEnd;
  13702. PVOLUME_EXTENSION extension;
  13703. PVSP_CONTEXT context;
  13704. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  13705. sizeof(DISK_COPY_DATA_PARAMETERS)) {
  13706. return STATUS_INVALID_PARAMETER;
  13707. }
  13708. if (Filter->IgnoreCopyData || Filter->ProtectedBlocksBitmap) {
  13709. return STATUS_INVALID_DEVICE_REQUEST;
  13710. }
  13711. if (input->Reserved || input->CopyLength.QuadPart < BLOCK_SIZE) {
  13712. return STATUS_INVALID_PARAMETER;
  13713. }
  13714. sourceStart = input->SourceOffset.QuadPart;
  13715. sourceEnd = sourceStart + input->CopyLength.QuadPart;
  13716. targetStart = input->DestinationOffset.QuadPart;
  13717. targetEnd = targetStart + input->CopyLength.QuadPart;
  13718. if (sourceStart < 0 || targetStart < 0 ||
  13719. input->CopyLength.QuadPart <= 0) {
  13720. return STATUS_INVALID_PARAMETER;
  13721. }
  13722. if (sourceStart < targetEnd && targetStart < sourceEnd) {
  13723. return STATUS_INVALID_PARAMETER;
  13724. }
  13725. if (!Filter->SnapshotsPresent) {
  13726. return STATUS_INVALID_PARAMETER;
  13727. }
  13728. if ((sourceStart&(BLOCK_SIZE - 1)) != (targetStart&(BLOCK_SIZE - 1))) {
  13729. return STATUS_INVALID_PARAMETER;
  13730. }
  13731. InterlockedIncrement(&Filter->RefCount);
  13732. if (Filter->HoldIncomingWrites || !Filter->SnapshotsPresent) {
  13733. VspDecrementRefCount(Filter);
  13734. return STATUS_INVALID_PARAMETER;
  13735. }
  13736. extension = CONTAINING_RECORD(Filter->VolumeList.Blink, VOLUME_EXTENSION,
  13737. ListEntry);
  13738. if (sourceEnd > extension->VolumeSize ||
  13739. targetEnd > extension->VolumeSize) {
  13740. VspDecrementRefCount(Filter);
  13741. return STATUS_INVALID_PARAMETER;
  13742. }
  13743. context = VspAllocateContext(Filter->Root);
  13744. if (!context) {
  13745. VspDecrementRefCount(Filter);
  13746. return STATUS_INSUFFICIENT_RESOURCES;
  13747. }
  13748. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  13749. ExInitializeWorkItem(&context->WorkItem, VspCopyDataWorker, context);
  13750. context->Extension.Extension = extension;
  13751. context->Extension.Irp = Irp;
  13752. IoMarkIrpPending(Irp);
  13753. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  13754. return STATUS_PENDING;
  13755. }
  13756. NTSTATUS
  13757. VspQueryEpic(
  13758. IN PFILTER_EXTENSION Filter,
  13759. IN PIRP Irp
  13760. )
  13761. {
  13762. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13763. PVOLSNAP_EPIC output = (PVOLSNAP_EPIC) Irp->AssociatedIrp.SystemBuffer;
  13764. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  13765. sizeof(VOLSNAP_EPIC)) {
  13766. Irp->IoStatus.Information = 0;
  13767. return STATUS_INVALID_PARAMETER;
  13768. }
  13769. output->EpicNumber = Filter->EpicNumber;
  13770. Irp->IoStatus.Information = sizeof(VOLSNAP_EPIC);
  13771. return STATUS_SUCCESS;
  13772. }
  13773. NTSTATUS
  13774. VspQueryOffline(
  13775. IN PFILTER_EXTENSION Filter
  13776. )
  13777. /*++
  13778. Routine Description:
  13779. This routine returns whether or not the given volume can be taken offline
  13780. without any resulting volume snapshots being deleted.
  13781. Arguments:
  13782. Filter - Supplies the filter extension.
  13783. Return Value:
  13784. STATUS_SUCCESS - The volume may be taken offline without any
  13785. snapshots being deleted.
  13786. STATUS_UNSUCCESSFUL - The volume being taken offline will result in the
  13787. destruction of volume snapshots.
  13788. --*/
  13789. {
  13790. PLIST_ENTRY l;
  13791. PVSP_DIFF_AREA_FILE diffAreaFile;
  13792. PVOLUME_EXTENSION extension;
  13793. VspAcquire(Filter->Root);
  13794. for (l = Filter->DiffAreaFilesOnThisFilter.Flink;
  13795. l != &Filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  13796. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  13797. FilterListEntry);
  13798. extension = diffAreaFile->Extension;
  13799. ASSERT(extension);
  13800. ASSERT(extension->Filter);
  13801. if (extension->Filter != Filter &&
  13802. extension->Filter->PreparedSnapshot != extension) {
  13803. VspRelease(Filter->Root);
  13804. return STATUS_UNSUCCESSFUL;
  13805. }
  13806. }
  13807. VspRelease(Filter->Root);
  13808. return STATUS_SUCCESS;
  13809. }
  13810. NTSTATUS
  13811. VolSnapDeviceControl(
  13812. IN PDEVICE_OBJECT DeviceObject,
  13813. IN PIRP Irp
  13814. )
  13815. /*++
  13816. Routine Description:
  13817. This routine is the dispatch for IRP_MJ_DEVICE_CONTROL.
  13818. Arguments:
  13819. DeviceObject - Supplies the device object.
  13820. Irp - Supplies the IO request packet.
  13821. Return Value:
  13822. NTSTATUS
  13823. --*/
  13824. {
  13825. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  13826. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  13827. NTSTATUS status;
  13828. PVOLUME_EXTENSION extension;
  13829. KEVENT event;
  13830. BOOLEAN noControlItems;
  13831. PPARTITION_INFORMATION partInfo;
  13832. PVSP_CONTEXT context;
  13833. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  13834. if (filter->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  13835. IoSkipCurrentIrpStackLocation(Irp);
  13836. return IoCallDriver(filter->TargetObject, Irp);
  13837. }
  13838. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  13839. case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:
  13840. VspCheckCodeLocked(filter->Root, FALSE);
  13841. status = VspFlushAndHoldWrites(filter, Irp);
  13842. break;
  13843. case IOCTL_VOLSNAP_RELEASE_WRITES:
  13844. VspCheckCodeLocked(filter->Root, FALSE);
  13845. status = VspReleaseWrites(filter);
  13846. break;
  13847. case IOCTL_VOLSNAP_PREPARE_FOR_SNAPSHOT:
  13848. VspCheckCodeLocked(filter->Root, FALSE);
  13849. status = VspPrepareForSnapshot(filter, Irp);
  13850. break;
  13851. case IOCTL_VOLSNAP_ABORT_PREPARED_SNAPSHOT:
  13852. VspCheckCodeLocked(filter->Root, FALSE);
  13853. VspAcquireCritical(filter);
  13854. status = VspAbortPreparedSnapshot(filter, TRUE, FALSE);
  13855. VspReleaseCritical(filter);
  13856. break;
  13857. case IOCTL_VOLSNAP_COMMIT_SNAPSHOT:
  13858. VspCheckCodeLocked(filter->Root, FALSE);
  13859. status = VspCommitSnapshot(filter, Irp);
  13860. break;
  13861. case IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT:
  13862. VspCheckCodeLocked(filter->Root, FALSE);
  13863. VspAcquireCritical(filter);
  13864. status = VspEndCommitSnapshot(filter, Irp);
  13865. VspReleaseCritical(filter);
  13866. break;
  13867. case IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS:
  13868. case OLD_IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS:
  13869. status = VspCheckSecurity(filter, Irp);
  13870. if (!NT_SUCCESS(status)) {
  13871. break;
  13872. }
  13873. VspCheckCodeLocked(filter->Root, FALSE);
  13874. status = VspQueryNamesOfSnapshots(filter, Irp);
  13875. break;
  13876. case IOCTL_VOLSNAP_CLEAR_DIFF_AREA:
  13877. VspCheckCodeLocked(filter->Root, FALSE);
  13878. status = VspClearDiffArea(filter, Irp);
  13879. break;
  13880. case IOCTL_VOLSNAP_ADD_VOLUME_TO_DIFF_AREA:
  13881. VspCheckCodeLocked(filter->Root, FALSE);
  13882. status = VspAddVolumeToDiffArea(filter, Irp);
  13883. break;
  13884. case IOCTL_VOLSNAP_QUERY_DIFF_AREA:
  13885. case OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA:
  13886. status = VspCheckSecurity(filter, Irp);
  13887. if (!NT_SUCCESS(status)) {
  13888. break;
  13889. }
  13890. VspCheckCodeLocked(filter->Root, FALSE);
  13891. status = VspQueryDiffArea(filter, Irp);
  13892. break;
  13893. case IOCTL_VOLSNAP_SET_MAX_DIFF_AREA_SIZE:
  13894. VspCheckCodeLocked(filter->Root, FALSE);
  13895. status = VspSetMaxDiffAreaSize(filter, Irp);
  13896. break;
  13897. case IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES:
  13898. case OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES:
  13899. status = VspCheckSecurity(filter, Irp);
  13900. if (!NT_SUCCESS(status)) {
  13901. break;
  13902. }
  13903. VspCheckCodeLocked(filter->Root, FALSE);
  13904. status = VspQueryDiffAreaSizes(filter, Irp);
  13905. break;
  13906. case IOCTL_VOLSNAP_DELETE_OLDEST_SNAPSHOT:
  13907. case IOCTL_VOLSNAP_DELETE_SNAPSHOT:
  13908. VspCheckCodeLocked(filter->Root, FALSE);
  13909. status = VspDeleteSnapshotPost(filter, Irp);
  13910. break;
  13911. case IOCTL_VOLSNAP_AUTO_CLEANUP:
  13912. status = VspCheckSecurity(filter, Irp);
  13913. if (!NT_SUCCESS(status)) {
  13914. break;
  13915. }
  13916. VspCheckCodeLocked(filter->Root, FALSE);
  13917. status = VspAutoCleanup(filter, Irp);
  13918. break;
  13919. case IOCTL_VOLSNAP_QUERY_EPIC:
  13920. status = VspQueryEpic(filter, Irp);
  13921. break;
  13922. case IOCTL_VOLSNAP_QUERY_OFFLINE:
  13923. VspCheckCodeLocked(filter->Root, FALSE);
  13924. Irp->IoStatus.Information = 0;
  13925. status = VspQueryOffline(filter);
  13926. break;
  13927. case IOCTL_VOLUME_ONLINE:
  13928. VspAcquireCritical(filter);
  13929. VspAcquire(filter->Root);
  13930. if (filter->IsOnline) {
  13931. VspRelease(filter->Root);
  13932. KeInitializeEvent(&event, NotificationEvent, FALSE);
  13933. IoCopyCurrentIrpStackLocationToNext(Irp);
  13934. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event,
  13935. TRUE, TRUE, TRUE);
  13936. IoCallDriver(filter->TargetObject, Irp);
  13937. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  13938. NULL);
  13939. VspReleaseCritical(filter);
  13940. status = Irp->IoStatus.Status;
  13941. break;
  13942. }
  13943. context = VspAllocateContext(filter->Root);
  13944. if (!context) {
  13945. status = STATUS_INSUFFICIENT_RESOURCES;
  13946. VspRelease(filter->Root);
  13947. VspReleaseCritical(filter);
  13948. break;
  13949. }
  13950. IoMarkIrpPending(Irp);
  13951. status = STATUS_PENDING;
  13952. context->Type = VSP_CONTEXT_TYPE_FILTER;
  13953. ExInitializeWorkItem(&context->WorkItem, VspOnlineWorker,
  13954. context);
  13955. context->Filter.Filter = filter;
  13956. context->Filter.Irp = Irp;
  13957. ExQueueWorkItem(&context->WorkItem, CriticalWorkQueue);
  13958. break;
  13959. case IOCTL_VOLUME_OFFLINE:
  13960. VspAcquireCritical(filter);
  13961. VspAcquire(filter->Root);
  13962. if (!filter->IsOnline) {
  13963. VspRelease(filter->Root);
  13964. KeInitializeEvent(&event, NotificationEvent, FALSE);
  13965. IoCopyCurrentIrpStackLocationToNext(Irp);
  13966. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event,
  13967. TRUE, TRUE, TRUE);
  13968. IoCallDriver(filter->TargetObject, Irp);
  13969. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  13970. NULL);
  13971. VspReleaseCritical(filter);
  13972. status = Irp->IoStatus.Status;
  13973. break;
  13974. }
  13975. context = VspAllocateContext(filter->Root);
  13976. if (!context) {
  13977. status = STATUS_INSUFFICIENT_RESOURCES;
  13978. VspRelease(filter->Root);
  13979. VspReleaseCritical(filter);
  13980. break;
  13981. }
  13982. IoMarkIrpPending(Irp);
  13983. status = STATUS_PENDING;
  13984. context->Type = VSP_CONTEXT_TYPE_FILTER;
  13985. ExInitializeWorkItem(&context->WorkItem, VspOfflineWorker,
  13986. context);
  13987. context->Filter.Filter = filter;
  13988. context->Filter.Irp = Irp;
  13989. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  13990. break;
  13991. case IOCTL_DISK_COPY_DATA:
  13992. status = VspCopyData(filter, Irp);
  13993. break;
  13994. default:
  13995. IoSkipCurrentIrpStackLocation(Irp);
  13996. return IoCallDriver(filter->TargetObject, Irp);
  13997. }
  13998. if (status == STATUS_PENDING) {
  13999. return status;
  14000. }
  14001. Irp->IoStatus.Status = status;
  14002. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  14003. return status;
  14004. }
  14005. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  14006. extension = (PVOLUME_EXTENSION) filter;
  14007. if (!extension->IsStarted || extension->IsPreExposure) {
  14008. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  14009. Irp->IoStatus.Information = 0;
  14010. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  14011. return STATUS_NO_SUCH_DEVICE;
  14012. }
  14013. status = VspIncrementVolumeRefCount(extension);
  14014. if (!NT_SUCCESS(status)) {
  14015. Irp->IoStatus.Status = status;
  14016. Irp->IoStatus.Information = 0;
  14017. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  14018. return status;
  14019. }
  14020. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  14021. case IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME:
  14022. case OLD_IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME:
  14023. status = VspCheckSecurity(extension->Filter, Irp);
  14024. if (!NT_SUCCESS(status)) {
  14025. break;
  14026. }
  14027. status = VspQueryOriginalVolumeName(extension, Irp);
  14028. break;
  14029. case IOCTL_VOLSNAP_QUERY_CONFIG_INFO:
  14030. case OLD_IOCTL_VOLSNAP_QUERY_CONFIG_INFO:
  14031. status = VspCheckSecurity(extension->Filter, Irp);
  14032. if (!NT_SUCCESS(status)) {
  14033. break;
  14034. }
  14035. status = VspQueryConfigInfo(extension, Irp);
  14036. break;
  14037. case IOCTL_VOLSNAP_SET_APPLICATION_INFO:
  14038. status = VspSetApplicationInfo(extension, Irp);
  14039. break;
  14040. case IOCTL_VOLSNAP_QUERY_APPLICATION_INFO:
  14041. case OLD_IOCTL_VOLSNAP_QUERY_APPLICATION_INFO:
  14042. status = VspCheckSecurity(extension->Filter, Irp);
  14043. if (!NT_SUCCESS(status)) {
  14044. break;
  14045. }
  14046. status = VspQueryApplicationInfo(extension, Irp);
  14047. break;
  14048. case IOCTL_VOLSNAP_QUERY_DIFF_AREA:
  14049. case OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA:
  14050. status = VspCheckSecurity(extension->Filter, Irp);
  14051. if (!NT_SUCCESS(status)) {
  14052. break;
  14053. }
  14054. status = VspQueryDiffArea(extension, Irp);
  14055. break;
  14056. case IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES:
  14057. case OLD_IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES:
  14058. status = VspCheckSecurity(extension->Filter, Irp);
  14059. if (!NT_SUCCESS(status)) {
  14060. break;
  14061. }
  14062. status = VspQueryDiffAreaSizes(extension, Irp);
  14063. break;
  14064. case IOCTL_DISK_SET_PARTITION_INFO:
  14065. status = STATUS_SUCCESS;
  14066. break;
  14067. case IOCTL_DISK_VERIFY:
  14068. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  14069. case IOCTL_DISK_CHECK_VERIFY:
  14070. IoCopyCurrentIrpStackLocationToNext(Irp);
  14071. IoSetCompletionRoutine(Irp, VspVolumeRefCountCompletionRoutine,
  14072. extension, TRUE, TRUE, TRUE);
  14073. IoMarkIrpPending(Irp);
  14074. IoCallDriver(extension->Filter->TargetObject, Irp);
  14075. return STATUS_PENDING;
  14076. case IOCTL_DISK_GET_LENGTH_INFO:
  14077. status = VspGetLengthInfo(extension, Irp);
  14078. break;
  14079. case IOCTL_DISK_GET_PARTITION_INFO:
  14080. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14081. IoCopyCurrentIrpStackLocationToNext(Irp);
  14082. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event,
  14083. TRUE, TRUE, TRUE);
  14084. IoCallDriver(extension->Filter->TargetObject, Irp);
  14085. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  14086. NULL);
  14087. status = Irp->IoStatus.Status;
  14088. if (!NT_SUCCESS(status)) {
  14089. break;
  14090. }
  14091. partInfo = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  14092. partInfo->PartitionLength.QuadPart = extension->VolumeSize;
  14093. break;
  14094. case IOCTL_DISK_IS_WRITABLE:
  14095. status = STATUS_MEDIA_WRITE_PROTECTED;
  14096. break;
  14097. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  14098. status = VspQueryDeviceName(extension, Irp);
  14099. break;
  14100. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  14101. status = VspQueryUniqueId(extension, Irp);
  14102. break;
  14103. case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
  14104. status = VspQueryStableGuid(extension, Irp);
  14105. break;
  14106. case IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE:
  14107. status = STATUS_SUCCESS;
  14108. break;
  14109. case IOCTL_VOLUME_ONLINE:
  14110. if (extension->IsOffline) {
  14111. VspSetOfflineBit(extension, FALSE);
  14112. }
  14113. status = STATUS_SUCCESS;
  14114. break;
  14115. case IOCTL_VOLUME_OFFLINE:
  14116. if (!extension->IsOffline) {
  14117. VspSetOfflineBit(extension, TRUE);
  14118. }
  14119. status = STATUS_SUCCESS;
  14120. break;
  14121. case IOCTL_VOLUME_IS_OFFLINE:
  14122. if (extension->IsOffline) {
  14123. status = STATUS_SUCCESS;
  14124. } else {
  14125. status = STATUS_UNSUCCESSFUL;
  14126. }
  14127. break;
  14128. case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
  14129. status = VspSetGptAttributes(extension, Irp);
  14130. break;
  14131. case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
  14132. status = VspGetGptAttributes(extension, Irp);
  14133. break;
  14134. default:
  14135. status = STATUS_INVALID_DEVICE_REQUEST;
  14136. break;
  14137. }
  14138. VspDecrementVolumeRefCount(extension);
  14139. Irp->IoStatus.Status = status;
  14140. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  14141. return status;
  14142. }
  14143. NTSTATUS
  14144. VspQueryBusRelations(
  14145. IN PFILTER_EXTENSION Filter,
  14146. IN PIRP Irp
  14147. )
  14148. {
  14149. ULONG numVolumes;
  14150. PLIST_ENTRY l;
  14151. NTSTATUS status;
  14152. PDEVICE_RELATIONS deviceRelations, newRelations;
  14153. ULONG size, i;
  14154. PVOLUME_EXTENSION extension;
  14155. if (Filter->SnapshotDiscoveryPending) {
  14156. numVolumes = 0;
  14157. } else {
  14158. numVolumes = 0;
  14159. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  14160. l = l->Flink) {
  14161. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  14162. if (l == Filter->VolumeList.Blink &&
  14163. !extension->HasEndCommit && !extension->IsInstalled) {
  14164. continue;
  14165. }
  14166. InterlockedExchange(&extension->AliveToPnp, TRUE);
  14167. numVolumes++;
  14168. }
  14169. if (Filter->PreparedSnapshot &&
  14170. Filter->PreparedSnapshot->IsPreExposure) {
  14171. InterlockedExchange(&Filter->PreparedSnapshot->AliveToPnp, TRUE);
  14172. numVolumes++;
  14173. }
  14174. }
  14175. status = Irp->IoStatus.Status;
  14176. if (!numVolumes) {
  14177. if (NT_SUCCESS(status)) {
  14178. return status;
  14179. }
  14180. newRelations = (PDEVICE_RELATIONS)
  14181. ExAllocatePoolWithTag(PagedPool,
  14182. sizeof(DEVICE_RELATIONS),
  14183. VOLSNAP_TAG_RELATIONS);
  14184. if (!newRelations) {
  14185. return STATUS_INSUFFICIENT_RESOURCES;
  14186. }
  14187. RtlZeroMemory(newRelations, sizeof(DEVICE_RELATIONS));
  14188. newRelations->Count = 0;
  14189. Irp->IoStatus.Information = (ULONG_PTR) newRelations;
  14190. while (!IsListEmpty(&Filter->DeadVolumeList)) {
  14191. l = RemoveHeadList(&Filter->DeadVolumeList);
  14192. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  14193. InterlockedExchange(&extension->DeadToPnp, TRUE);
  14194. }
  14195. return STATUS_SUCCESS;
  14196. }
  14197. if (NT_SUCCESS(status)) {
  14198. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  14199. size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
  14200. (numVolumes + deviceRelations->Count)*sizeof(PDEVICE_OBJECT);
  14201. newRelations = (PDEVICE_RELATIONS)
  14202. ExAllocatePoolWithTag(PagedPool, size,
  14203. VOLSNAP_TAG_RELATIONS);
  14204. if (!newRelations) {
  14205. for (i = 0; i < deviceRelations->Count; i++) {
  14206. ObDereferenceObject(deviceRelations->Objects[i]);
  14207. }
  14208. ExFreePool(deviceRelations);
  14209. Irp->IoStatus.Information = 0;
  14210. return STATUS_INSUFFICIENT_RESOURCES;
  14211. }
  14212. newRelations->Count = numVolumes + deviceRelations->Count;
  14213. RtlCopyMemory(newRelations->Objects, deviceRelations->Objects,
  14214. deviceRelations->Count*sizeof(PDEVICE_OBJECT));
  14215. i = deviceRelations->Count;
  14216. ExFreePool(deviceRelations);
  14217. } else {
  14218. size = sizeof(DEVICE_RELATIONS) + numVolumes*sizeof(PDEVICE_OBJECT);
  14219. newRelations = (PDEVICE_RELATIONS)
  14220. ExAllocatePoolWithTag(PagedPool, size,
  14221. VOLSNAP_TAG_RELATIONS);
  14222. if (!newRelations) {
  14223. return STATUS_INSUFFICIENT_RESOURCES;
  14224. }
  14225. newRelations->Count = numVolumes;
  14226. i = 0;
  14227. }
  14228. numVolumes = 0;
  14229. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  14230. l = l->Flink) {
  14231. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  14232. if (l == Filter->VolumeList.Blink &&
  14233. !extension->HasEndCommit && !extension->IsInstalled) {
  14234. continue;
  14235. }
  14236. newRelations->Objects[i + numVolumes++] = extension->DeviceObject;
  14237. ObReferenceObject(extension->DeviceObject);
  14238. }
  14239. if (Filter->PreparedSnapshot &&
  14240. Filter->PreparedSnapshot->IsPreExposure) {
  14241. newRelations->Objects[i + numVolumes++] =
  14242. Filter->PreparedSnapshot->DeviceObject;
  14243. ObReferenceObject(Filter->PreparedSnapshot->DeviceObject);
  14244. }
  14245. Irp->IoStatus.Information = (ULONG_PTR) newRelations;
  14246. while (!IsListEmpty(&Filter->DeadVolumeList)) {
  14247. l = RemoveHeadList(&Filter->DeadVolumeList);
  14248. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  14249. InterlockedExchange(&extension->DeadToPnp, TRUE);
  14250. }
  14251. return STATUS_SUCCESS;
  14252. }
  14253. NTSTATUS
  14254. VspQueryId(
  14255. IN PVOLUME_EXTENSION Extension,
  14256. IN PIRP Irp
  14257. )
  14258. {
  14259. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  14260. UNICODE_STRING string;
  14261. NTSTATUS status;
  14262. WCHAR buffer[100];
  14263. PWSTR id;
  14264. switch (irpSp->Parameters.QueryId.IdType) {
  14265. case BusQueryDeviceID:
  14266. RtlInitUnicodeString(&string, L"STORAGE\\VolumeSnapshot");
  14267. break;
  14268. case BusQueryHardwareIDs:
  14269. RtlInitUnicodeString(&string, L"STORAGE\\VolumeSnapshot");
  14270. break;
  14271. case BusQueryInstanceID:
  14272. swprintf(buffer, L"HarddiskVolumeSnapshot%d",
  14273. Extension->DevnodeNumber);
  14274. RtlInitUnicodeString(&string, buffer);
  14275. break;
  14276. default:
  14277. return STATUS_NOT_SUPPORTED;
  14278. }
  14279. id = (PWSTR) ExAllocatePoolWithTag(PagedPool,
  14280. string.Length + 2*sizeof(WCHAR),
  14281. VOLSNAP_TAG_PNP_ID);
  14282. if (!id) {
  14283. return STATUS_INSUFFICIENT_RESOURCES;
  14284. }
  14285. RtlCopyMemory(id, string.Buffer, string.Length);
  14286. id[string.Length/sizeof(WCHAR)] = 0;
  14287. id[string.Length/sizeof(WCHAR) + 1] = 0;
  14288. Irp->IoStatus.Information = (ULONG_PTR) id;
  14289. return STATUS_SUCCESS;
  14290. }
  14291. VOID
  14292. VspDeleteDiffAreaFilesWorker(
  14293. IN PVOID Context
  14294. )
  14295. {
  14296. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  14297. PFILTER_EXTENSION filter = context->DeleteDiffAreaFiles.Filter;
  14298. NTSTATUS status;
  14299. UNICODE_STRING name, fileName;
  14300. OBJECT_ATTRIBUTES oa;
  14301. HANDLE h, fileHandle;
  14302. IO_STATUS_BLOCK ioStatus;
  14303. PFILE_NAMES_INFORMATION fileNamesInfo;
  14304. CHAR buffer[200];
  14305. FILE_DISPOSITION_INFORMATION dispInfo;
  14306. BOOLEAN restartScan, filesLeft, filesDeleted;
  14307. GUID guid;
  14308. ASSERT(context->Type == VSP_CONTEXT_TYPE_DELETE_DA_FILES);
  14309. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  14310. KernelMode, FALSE, NULL);
  14311. VspAcquireCritical(filter);
  14312. if (filter->DeleteTimer != context->DeleteDiffAreaFiles.Timer) {
  14313. VspReleaseCritical(filter);
  14314. ExFreePool(context->DeleteDiffAreaFiles.Timer);
  14315. ExFreePool(context->DeleteDiffAreaFiles.Dpc);
  14316. VspFreeContext(filter->Root, context);
  14317. ObDereferenceObject(filter->DeviceObject);
  14318. return;
  14319. }
  14320. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  14321. KernelMode, FALSE, NULL);
  14322. filter->DeleteTimer = NULL;
  14323. ExFreePool(context->DeleteDiffAreaFiles.Timer);
  14324. ExFreePool(context->DeleteDiffAreaFiles.Dpc);
  14325. VspFreeContext(filter->Root, context);
  14326. VspAcquire(filter->Root);
  14327. if (filter->IsRemoved) {
  14328. VspRelease(filter->Root);
  14329. VspReleaseCritical(filter);
  14330. ObDereferenceObject(filter->DeviceObject);
  14331. return;
  14332. }
  14333. ObReferenceObject(filter->TargetObject);
  14334. VspRelease(filter->Root);
  14335. status = VspCreateDiffAreaFileName(filter->TargetObject, NULL, &name,
  14336. FALSE, NULL);
  14337. if (!NT_SUCCESS(status)) {
  14338. ObDereferenceObject(filter->TargetObject);
  14339. VspReleaseCritical(filter);
  14340. ObDereferenceObject(filter->DeviceObject);
  14341. return;
  14342. }
  14343. name.Length -= 39*sizeof(WCHAR);
  14344. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE |
  14345. OBJ_KERNEL_HANDLE, NULL, NULL);
  14346. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa, &ioStatus,
  14347. FILE_SHARE_READ | FILE_SHARE_WRITE,
  14348. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  14349. if (!NT_SUCCESS(status)) {
  14350. ObDereferenceObject(filter->TargetObject);
  14351. VspReleaseCritical(filter);
  14352. ObDereferenceObject(filter->DeviceObject);
  14353. ExFreePool(name.Buffer);
  14354. return;
  14355. }
  14356. fileName.Buffer = &name.Buffer[name.Length/sizeof(WCHAR)];
  14357. fileName.Length = 39*sizeof(WCHAR);
  14358. fileName.MaximumLength = fileName.Length + sizeof(WCHAR);
  14359. fileNamesInfo = (PFILE_NAMES_INFORMATION) buffer;
  14360. dispInfo.DeleteFile = TRUE;
  14361. restartScan = TRUE;
  14362. filesLeft = FALSE;
  14363. filesDeleted = FALSE;
  14364. for (;;) {
  14365. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  14366. fileNamesInfo, 200, FileNamesInformation,
  14367. TRUE, restartScan ? &fileName : NULL,
  14368. restartScan);
  14369. if (!NT_SUCCESS(status)) {
  14370. break;
  14371. }
  14372. restartScan = FALSE;
  14373. fileName.Length = fileName.MaximumLength =
  14374. (USHORT) fileNamesInfo->FileNameLength;
  14375. fileName.Buffer = fileNamesInfo->FileName;
  14376. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  14377. OBJ_KERNEL_HANDLE, h, NULL);
  14378. status = ZwOpenFile(&fileHandle, DELETE, &oa, &ioStatus,
  14379. FILE_SHARE_DELETE | FILE_SHARE_READ |
  14380. FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE);
  14381. if (!NT_SUCCESS(status)) {
  14382. filesLeft = TRUE;
  14383. continue;
  14384. }
  14385. filesDeleted = TRUE;
  14386. if (fileName.Buffer[0] == '{') {
  14387. fileName.Length = 38*sizeof(WCHAR);
  14388. status = RtlGUIDFromString(&fileName, &guid);
  14389. if (NT_SUCCESS(status)) {
  14390. VspCheckCodeLocked(filter->Root, FALSE);
  14391. VspDeleteControlItemsWithGuid(filter, &guid, FALSE);
  14392. }
  14393. }
  14394. ZwSetInformationFile(fileHandle, &ioStatus, &dispInfo,
  14395. sizeof(dispInfo), FileDispositionInformation);
  14396. ZwClose(fileHandle);
  14397. }
  14398. ZwClose(h);
  14399. ExFreePool(name.Buffer);
  14400. if (!filesLeft && filesDeleted) {
  14401. VspAcquireNonPagedResource(filter, NULL, FALSE);
  14402. ASSERT(!filter->ControlBlockFileHandle);
  14403. filter->FirstControlBlockVolumeOffset = 0;
  14404. VspCreateStartBlock(filter, 0, filter->MaximumVolumeSpace);
  14405. VspReleaseNonPagedResource(filter);
  14406. }
  14407. ObDereferenceObject(filter->TargetObject);
  14408. VspReleaseCritical(filter);
  14409. ObDereferenceObject(filter->DeviceObject);
  14410. }
  14411. NTSTATUS
  14412. VspPnpStart(
  14413. IN PVOLUME_EXTENSION Extension
  14414. )
  14415. {
  14416. PFILTER_EXTENSION filter = Extension->Filter;
  14417. LONG pastReinit;
  14418. NTSTATUS status;
  14419. DEVICE_INSTALL_STATE deviceInstallState;
  14420. ULONG bytes;
  14421. KIRQL irql;
  14422. PVSP_CONTEXT context;
  14423. PKEVENT event;
  14424. if (Extension->IsDead) {
  14425. return STATUS_INVALID_PARAMETER;
  14426. }
  14427. InterlockedExchange(&Extension->IsStarted, TRUE);
  14428. pastReinit = Extension->Root->PastReinit;
  14429. if (pastReinit && !filter->Root->IsSetup) {
  14430. status = IoGetDeviceProperty(Extension->DeviceObject,
  14431. DevicePropertyInstallState,
  14432. sizeof(deviceInstallState),
  14433. &deviceInstallState, &bytes);
  14434. if (!NT_SUCCESS(status) ||
  14435. deviceInstallState != InstallStateInstalled) {
  14436. return STATUS_SUCCESS;
  14437. }
  14438. }
  14439. VspAcquire(Extension->Root);
  14440. if (Extension->IsVisible) {
  14441. ASSERT(!Extension->MountedDeviceInterfaceName.Buffer);
  14442. status = IoRegisterDeviceInterface(
  14443. Extension->DeviceObject,
  14444. &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL,
  14445. &Extension->MountedDeviceInterfaceName);
  14446. if (NT_SUCCESS(status)) {
  14447. IoSetDeviceInterfaceState(
  14448. &Extension->MountedDeviceInterfaceName, TRUE);
  14449. }
  14450. }
  14451. if (Extension->IsInstalled) {
  14452. VspRelease(Extension->Root);
  14453. return STATUS_SUCCESS;
  14454. }
  14455. Extension->IsInstalled = TRUE;
  14456. if (Extension->IsPreExposure) {
  14457. KeSetEvent(&Extension->PreExposureEvent, IO_NO_INCREMENT, FALSE);
  14458. VspRelease(Extension->Root);
  14459. return STATUS_SUCCESS;
  14460. }
  14461. if (Extension->ListEntry.Flink != &filter->VolumeList) {
  14462. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  14463. if (Extension->IgnorableProduct) {
  14464. ExFreePool(Extension->IgnorableProduct->Buffer);
  14465. ExFreePool(Extension->IgnorableProduct);
  14466. Extension->IgnorableProduct = NULL;
  14467. }
  14468. KeReleaseSpinLock(&Extension->SpinLock, irql);
  14469. VspRelease(Extension->Root);
  14470. return STATUS_SUCCESS;
  14471. }
  14472. if (!KeCancelTimer(&filter->EndCommitTimer)) {
  14473. VspRelease(Extension->Root);
  14474. return STATUS_SUCCESS;
  14475. }
  14476. if (filter->IsRemoved) {
  14477. VspRelease(Extension->Root);
  14478. InterlockedExchange(&filter->HibernatePending, FALSE);
  14479. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  14480. FALSE);
  14481. ObDereferenceObject(filter->DeviceObject);
  14482. return STATUS_UNSUCCESSFUL;
  14483. }
  14484. ObReferenceObject(filter->TargetObject);
  14485. VspRelease(Extension->Root);
  14486. context = VspAllocateContext(filter->Root);
  14487. if (!context) {
  14488. InterlockedExchange(&filter->HibernatePending, FALSE);
  14489. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  14490. FALSE);
  14491. ObDereferenceObject(filter->TargetObject);
  14492. ObDereferenceObject(filter->DeviceObject);
  14493. return STATUS_INSUFFICIENT_RESOURCES;
  14494. }
  14495. ObReferenceObject(Extension->DeviceObject);
  14496. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  14497. context->Extension.Extension = Extension;
  14498. context->Extension.Irp = NULL;
  14499. ExInitializeWorkItem(&context->WorkItem,
  14500. VspSetIgnorableBlocksInBitmapWorker, context);
  14501. VspQueueWorkItem(filter->Root, &context->WorkItem, 0);
  14502. return STATUS_SUCCESS;
  14503. }
  14504. NTSTATUS
  14505. VspGetDeviceObjectPointer(
  14506. IN PUNICODE_STRING VolumeName,
  14507. IN ACCESS_MASK DesiredAccess,
  14508. OUT PFILE_OBJECT* FileObject,
  14509. OUT PDEVICE_OBJECT* DeviceObject
  14510. )
  14511. {
  14512. OBJECT_ATTRIBUTES oa;
  14513. HANDLE h;
  14514. PFILE_OBJECT fileObject;
  14515. IO_STATUS_BLOCK ioStatus;
  14516. NTSTATUS status;
  14517. InitializeObjectAttributes(&oa, VolumeName, OBJ_CASE_INSENSITIVE |
  14518. OBJ_KERNEL_HANDLE, NULL, NULL);
  14519. status = ZwOpenFile(&h, DesiredAccess, &oa, &ioStatus, FILE_SHARE_READ |
  14520. FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE);
  14521. if (!NT_SUCCESS(status)) {
  14522. return status;
  14523. }
  14524. status = ObReferenceObjectByHandle(h, 0, *IoFileObjectType, KernelMode,
  14525. (PVOID *) &fileObject, NULL);
  14526. if (!NT_SUCCESS(status)) {
  14527. ZwClose(h);
  14528. return status;
  14529. }
  14530. *FileObject = fileObject;
  14531. *DeviceObject = IoGetRelatedDeviceObject(fileObject);
  14532. ZwClose(h);
  14533. return status;
  14534. }
  14535. NTSTATUS
  14536. VspTakeSnapshot(
  14537. IN PFILTER_EXTENSION Filter
  14538. )
  14539. {
  14540. KEVENT event;
  14541. PMOUNTDEV_NAME name;
  14542. UCHAR buffer[512];
  14543. IO_STATUS_BLOCK ioStatus;
  14544. NTSTATUS status;
  14545. UNICODE_STRING volumeName;
  14546. PFILE_OBJECT fileObject;
  14547. PDEVICE_OBJECT targetObject;
  14548. VOLSNAP_PREPARE_INFO prepareInfo[2];
  14549. PULONG p;
  14550. PIRP irp;
  14551. PIO_STACK_LOCATION irpSp;
  14552. VOLSNAP_FLUSH_AND_HOLD_INPUT flushInput;
  14553. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14554. name = (PMOUNTDEV_NAME) buffer;
  14555. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  14556. Filter->TargetObject, NULL, 0,
  14557. name, 500, FALSE, &event,
  14558. &ioStatus);
  14559. if (!irp) {
  14560. return STATUS_INSUFFICIENT_RESOURCES;
  14561. }
  14562. status = IoCallDriver(Filter->TargetObject, irp);
  14563. if (status == STATUS_PENDING) {
  14564. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14565. status = ioStatus.Status;
  14566. }
  14567. if (!NT_SUCCESS(status)) {
  14568. return status;
  14569. }
  14570. volumeName.Buffer = name->Name;
  14571. volumeName.Length = name->NameLength;
  14572. volumeName.MaximumLength = name->NameLength;
  14573. status = VspGetDeviceObjectPointer(&volumeName, FILE_READ_DATA,
  14574. &fileObject, &targetObject);
  14575. if (!NT_SUCCESS(status)) {
  14576. if (status != STATUS_FILE_LOCK_CONFLICT) {
  14577. return status;
  14578. }
  14579. // Contention with AUTOCHK. Open FILE_READ_ATTRIBUTES.
  14580. status = VspGetDeviceObjectPointer(&volumeName, FILE_READ_ATTRIBUTES,
  14581. &fileObject, &targetObject);
  14582. if (!NT_SUCCESS(status)) {
  14583. return status;
  14584. }
  14585. }
  14586. RtlZeroMemory(prepareInfo, sizeof(VOLSNAP_PREPARE_INFO));
  14587. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14588. p = (PULONG) (prepareInfo + 1);
  14589. *p = 'NPK ';
  14590. irp = IoBuildDeviceIoControlRequest(
  14591. IOCTL_VOLSNAP_PREPARE_FOR_SNAPSHOT, targetObject, prepareInfo,
  14592. sizeof(VOLSNAP_PREPARE_INFO) + sizeof(ULONG), NULL, 0, FALSE, &event,
  14593. &ioStatus);
  14594. if (!irp) {
  14595. ObDereferenceObject(fileObject);
  14596. return STATUS_INSUFFICIENT_RESOURCES;
  14597. }
  14598. irpSp = IoGetNextIrpStackLocation(irp);
  14599. irpSp->FileObject = fileObject;
  14600. status = IoCallDriver(targetObject, irp);
  14601. if (status == STATUS_PENDING) {
  14602. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14603. status = ioStatus.Status;
  14604. }
  14605. if (!NT_SUCCESS(status)) {
  14606. ObDereferenceObject(fileObject);
  14607. return status;
  14608. }
  14609. status = ExUuidCreate(&flushInput.InstanceId);
  14610. if (!NT_SUCCESS(status)) {
  14611. VspAbortPreparedSnapshot(Filter, TRUE, FALSE);
  14612. ObDereferenceObject(fileObject);
  14613. return status;
  14614. }
  14615. flushInput.NumberOfVolumesToFlush = 1;
  14616. flushInput.SecondsToHoldFileSystemsTimeout = 60;
  14617. flushInput.SecondsToHoldIrpsTimeout = 10;
  14618. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14619. irp = IoBuildDeviceIoControlRequest(
  14620. IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES, targetObject, &flushInput,
  14621. sizeof(flushInput), NULL, 0, FALSE, &event, &ioStatus);
  14622. if (!irp) {
  14623. VspAbortPreparedSnapshot(Filter, TRUE, FALSE);
  14624. ObDereferenceObject(fileObject);
  14625. return STATUS_INSUFFICIENT_RESOURCES;
  14626. }
  14627. irpSp = IoGetNextIrpStackLocation(irp);
  14628. irpSp->FileObject = fileObject;
  14629. status = IoCallDriver(targetObject, irp);
  14630. if (status == STATUS_PENDING) {
  14631. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14632. status = ioStatus.Status;
  14633. }
  14634. if (!NT_SUCCESS(status)) {
  14635. VspAbortPreparedSnapshot(Filter, TRUE, FALSE);
  14636. ObDereferenceObject(fileObject);
  14637. return status;
  14638. }
  14639. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14640. irp = IoBuildDeviceIoControlRequest(
  14641. IOCTL_VOLSNAP_COMMIT_SNAPSHOT, targetObject, NULL, 0, NULL,
  14642. 0, FALSE, &event, &ioStatus);
  14643. if (!irp) {
  14644. VspReleaseWrites(Filter);
  14645. VspAbortPreparedSnapshot(Filter, TRUE, FALSE);
  14646. ObDereferenceObject(fileObject);
  14647. return STATUS_INSUFFICIENT_RESOURCES;
  14648. }
  14649. irpSp = IoGetNextIrpStackLocation(irp);
  14650. irpSp->FileObject = fileObject;
  14651. status = IoCallDriver(targetObject, irp);
  14652. if (status == STATUS_PENDING) {
  14653. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14654. status = ioStatus.Status;
  14655. }
  14656. VspReleaseWrites(Filter);
  14657. if (!NT_SUCCESS(status)) {
  14658. VspAbortPreparedSnapshot(Filter, TRUE, FALSE);
  14659. ObDereferenceObject(fileObject);
  14660. return status;
  14661. }
  14662. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14663. irp = IoBuildDeviceIoControlRequest(
  14664. IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT, targetObject, NULL, 0, buffer,
  14665. 200, FALSE, &event, &ioStatus);
  14666. if (!irp) {
  14667. ObDereferenceObject(fileObject);
  14668. return STATUS_INSUFFICIENT_RESOURCES;
  14669. }
  14670. irpSp = IoGetNextIrpStackLocation(irp);
  14671. irpSp->FileObject = fileObject;
  14672. status = IoCallDriver(targetObject, irp);
  14673. if (status == STATUS_PENDING) {
  14674. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14675. status = ioStatus.Status;
  14676. }
  14677. ObDereferenceObject(fileObject);
  14678. return status;
  14679. }
  14680. VOID
  14681. VspCantHibernatePopUp(
  14682. IN PFILTER_EXTENSION Filter
  14683. )
  14684. {
  14685. NTSTATUS status;
  14686. UNICODE_STRING dosName;
  14687. status = IoVolumeDeviceToDosName(Filter->DeviceObject, &dosName);
  14688. if (NT_SUCCESS(status)) {
  14689. IoRaiseInformationalHardError(STATUS_VOLSNAP_PREPARE_HIBERNATE,
  14690. &dosName, NULL);
  14691. ExFreePool(dosName.Buffer);
  14692. }
  14693. InterlockedExchange(&Filter->HibernatePending, TRUE);
  14694. status = VspTakeSnapshot(Filter);
  14695. if (!NT_SUCCESS(status)) {
  14696. InterlockedExchange(&Filter->HibernatePending, FALSE);
  14697. }
  14698. }
  14699. NTSTATUS
  14700. VspCompareFileIds(
  14701. IN PVOLUME_EXTENSION Extension,
  14702. IN PUNICODE_STRING FileName
  14703. )
  14704. {
  14705. PFILTER_EXTENSION filter = Extension->Filter;
  14706. KEVENT event;
  14707. PMOUNTDEV_NAME name;
  14708. UCHAR buffer[512];
  14709. PIRP irp;
  14710. IO_STATUS_BLOCK ioStatus;
  14711. NTSTATUS status;
  14712. UNICODE_STRING dirName;
  14713. OBJECT_ATTRIBUTES oa;
  14714. HANDLE h;
  14715. PFILE_ID_FULL_DIR_INFORMATION fileIdDirInfo;
  14716. LARGE_INTEGER fileId1, fileId2;
  14717. PWCHAR wstring;
  14718. KeInitializeEvent(&event, NotificationEvent, FALSE);
  14719. name = (PMOUNTDEV_NAME) buffer;
  14720. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  14721. filter->TargetObject, NULL, 0,
  14722. name, 500, FALSE, &event,
  14723. &ioStatus);
  14724. if (!irp) {
  14725. return STATUS_INSUFFICIENT_RESOURCES;
  14726. }
  14727. status = IoCallDriver(filter->TargetObject, irp);
  14728. if (status == STATUS_PENDING) {
  14729. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  14730. status = ioStatus.Status;
  14731. }
  14732. if (!NT_SUCCESS(status)) {
  14733. return status;
  14734. }
  14735. dirName.Length = name->NameLength;
  14736. dirName.Buffer = name->Name;
  14737. dirName.Buffer[dirName.Length/sizeof(WCHAR)] = '\\';
  14738. dirName.Length += sizeof(WCHAR);
  14739. dirName.Buffer[dirName.Length/sizeof(WCHAR)] = 0;
  14740. dirName.MaximumLength = dirName.Length + sizeof(WCHAR);
  14741. InitializeObjectAttributes(&oa, &dirName, OBJ_CASE_INSENSITIVE |
  14742. OBJ_KERNEL_HANDLE, NULL, NULL);
  14743. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa,
  14744. &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  14745. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  14746. if (!NT_SUCCESS(status)) {
  14747. return status;
  14748. }
  14749. fileIdDirInfo = (PFILE_ID_FULL_DIR_INFORMATION) buffer;
  14750. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  14751. fileIdDirInfo, 512,
  14752. FileIdFullDirectoryInformation,
  14753. TRUE, FileName, TRUE);
  14754. ZwClose(h);
  14755. if (!NT_SUCCESS(status)) {
  14756. return status;
  14757. }
  14758. fileId1 = fileIdDirInfo->FileId;
  14759. if (Extension->IsOffline) {
  14760. VspSetOfflineBit(Extension, FALSE);
  14761. }
  14762. wstring = (PWCHAR) buffer;
  14763. swprintf(wstring, L"\\Device\\HarddiskVolumeShadowCopy%d\\",
  14764. Extension->VolumeNumber);
  14765. RtlInitUnicodeString(&dirName, wstring);
  14766. InitializeObjectAttributes(&oa, &dirName, OBJ_CASE_INSENSITIVE |
  14767. OBJ_KERNEL_HANDLE, NULL, NULL);
  14768. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa,
  14769. &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  14770. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  14771. if (!NT_SUCCESS(status)) {
  14772. return status;
  14773. }
  14774. fileIdDirInfo = (PFILE_ID_FULL_DIR_INFORMATION) buffer;
  14775. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  14776. fileIdDirInfo, 512,
  14777. FileIdFullDirectoryInformation,
  14778. TRUE, FileName, TRUE);
  14779. ZwClose(h);
  14780. if (!NT_SUCCESS(status)) {
  14781. return status;
  14782. }
  14783. fileId2 = fileIdDirInfo->FileId;
  14784. if (fileId1.QuadPart != fileId2.QuadPart) {
  14785. return STATUS_UNSUCCESSFUL;
  14786. }
  14787. return STATUS_SUCCESS;
  14788. }
  14789. NTSTATUS
  14790. VspMarkCrashdumpDirty(
  14791. IN PVOLUME_EXTENSION Extension
  14792. )
  14793. {
  14794. NTSTATUS status;
  14795. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  14796. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  14797. status = VspIoControlItem(Extension->Filter,
  14798. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  14799. &Extension->SnapshotGuid, FALSE,
  14800. controlItemBuffer, TRUE);
  14801. if (!NT_SUCCESS(status)) {
  14802. return status;
  14803. }
  14804. snapshotControlItem->SnapshotControlItemFlags |=
  14805. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_CRASHDUMP;
  14806. status = VspIoControlItem(Extension->Filter,
  14807. VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  14808. &Extension->SnapshotGuid, TRUE,
  14809. controlItemBuffer, TRUE);
  14810. if (!NT_SUCCESS(status)) {
  14811. return status;
  14812. }
  14813. return STATUS_SUCCESS;
  14814. }
  14815. VOID
  14816. VspTakeSnapshotWorker(
  14817. IN PVOID Context
  14818. )
  14819. {
  14820. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  14821. PFILTER_EXTENSION filter = context->Filter.Filter;
  14822. NTSTATUS status;
  14823. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  14824. VspFreeContext(filter->Root, context);
  14825. status = VspTakeSnapshot(filter);
  14826. if (!NT_SUCCESS(status)) {
  14827. VspLogError(NULL, filter, VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES,
  14828. status, 16, FALSE);
  14829. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  14830. }
  14831. ObDereferenceObject(filter->DeviceObject);
  14832. }
  14833. NTSTATUS
  14834. VspHandleDumpUsageNotification(
  14835. IN PFILTER_EXTENSION Filter,
  14836. IN BOOLEAN InPath
  14837. )
  14838. {
  14839. PVOLUME_EXTENSION extension;
  14840. UNICODE_STRING fileName;
  14841. NTSTATUS status;
  14842. PVSP_CONTEXT context;
  14843. VspAcquire(Filter->Root);
  14844. if (!InPath) {
  14845. Filter->UsedForCrashdump = FALSE;
  14846. VspRelease(Filter->Root);
  14847. return STATUS_SUCCESS;
  14848. }
  14849. if (Filter->UsedForCrashdump) {
  14850. VspRelease(Filter->Root);
  14851. return STATUS_SUCCESS;
  14852. }
  14853. Filter->UsedForCrashdump = TRUE;
  14854. if (!Filter->SnapshotsPresent || !Filter->PersistentSnapshots ||
  14855. IsListEmpty(&Filter->VolumeList)) {
  14856. VspRelease(Filter->Root);
  14857. return STATUS_SUCCESS;
  14858. }
  14859. extension = CONTAINING_RECORD(Filter->VolumeList.Blink, VOLUME_EXTENSION,
  14860. ListEntry);
  14861. ASSERT(extension->IsPersistent);
  14862. ObReferenceObject(extension->DeviceObject);
  14863. VspRelease(Filter->Root);
  14864. if (extension->PageFileCopied) {
  14865. RtlInitUnicodeString(&fileName, L"pagefile.sys");
  14866. status = VspCompareFileIds(extension, &fileName);
  14867. if (!NT_SUCCESS(status)) {
  14868. InterlockedExchange(&extension->PageFileCopied, FALSE);
  14869. }
  14870. }
  14871. if (!extension->PageFileCopied) {
  14872. status = VspMarkCrashdumpDirty(extension);
  14873. if (NT_SUCCESS(status)) {
  14874. context = VspAllocateContext(Filter->Root);
  14875. if (context) {
  14876. context->Type = VSP_CONTEXT_TYPE_FILTER;
  14877. ExInitializeWorkItem(&context->WorkItem, VspTakeSnapshotWorker,
  14878. context);
  14879. context->Filter.Filter = Filter;
  14880. ObReferenceObject(Filter->DeviceObject);
  14881. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  14882. } else {
  14883. status = STATUS_INSUFFICIENT_RESOURCES;
  14884. }
  14885. }
  14886. if (!NT_SUCCESS(status)) {
  14887. VspLogError(NULL, Filter, VS_ABORT_COPY_ON_WRITE_CRASHDUMP_FILES,
  14888. status, 6, FALSE);
  14889. VspDestroyAllSnapshots(Filter, NULL, FALSE, FALSE);
  14890. }
  14891. }
  14892. ObDereferenceObject(extension->DeviceObject);
  14893. return STATUS_SUCCESS;
  14894. }
  14895. VOID
  14896. VspCleanupFilterWorker(
  14897. IN PVOID Context
  14898. )
  14899. {
  14900. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  14901. PFILTER_EXTENSION filter = context->Filter.Filter;
  14902. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  14903. VspFreeContext(filter->Root, context);
  14904. VspAcquireCritical(filter);
  14905. VspAcquire(filter->Root);
  14906. VspCleanupPreamble(filter);
  14907. VspRelease(filter->Root);
  14908. VspCleanupFilter(filter, FALSE, TRUE);
  14909. VspReleaseCritical(filter);
  14910. ObDereferenceObject(filter->TargetObject);
  14911. ObDereferenceObject(filter->DeviceObject);
  14912. }
  14913. VOID
  14914. VspPostCleanupFilter(
  14915. IN PFILTER_EXTENSION Filter
  14916. )
  14917. {
  14918. PVSP_CONTEXT context;
  14919. context = VspAllocateContext(Filter->Root);
  14920. if (!context) {
  14921. return;
  14922. }
  14923. context->Type = VSP_CONTEXT_TYPE_FILTER;
  14924. ExInitializeWorkItem(&context->WorkItem, VspCleanupFilterWorker, context);
  14925. context->Filter.Filter = Filter;
  14926. ObReferenceObject(Filter->DeviceObject);
  14927. ObReferenceObject(Filter->TargetObject);
  14928. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  14929. }
  14930. NTSTATUS
  14931. VolSnapPnp(
  14932. IN PDEVICE_OBJECT DeviceObject,
  14933. IN PIRP Irp
  14934. )
  14935. /*++
  14936. Routine Description:
  14937. This routine is the dispatch for IRP_MJ_PNP.
  14938. Arguments:
  14939. DeviceObject - Supplies the device object.
  14940. Irp - Supplies the IO request packet.
  14941. Return Value:
  14942. NTSTATUS
  14943. --*/
  14944. {
  14945. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  14946. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  14947. PDEVICE_OBJECT targetObject;
  14948. KEVENT event;
  14949. NTSTATUS status;
  14950. PVOLUME_EXTENSION extension;
  14951. BOOLEAN deletePdo;
  14952. PDEVICE_RELATIONS deviceRelations;
  14953. PDEVICE_CAPABILITIES capabilities;
  14954. PKEVENT pevent;
  14955. PLONG p;
  14956. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  14957. if (filter->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  14958. targetObject = filter->TargetObject;
  14959. switch (irpSp->MinorFunction) {
  14960. case IRP_MN_REMOVE_DEVICE:
  14961. VspAcquire(filter->Root);
  14962. if (!filter->NotInFilterList) {
  14963. RemoveEntryList(&filter->ListEntry);
  14964. filter->NotInFilterList = TRUE;
  14965. }
  14966. VspRelease(filter->Root);
  14967. IoDetachDevice(targetObject);
  14968. IoDeleteDevice(filter->DeviceObject);
  14969. //
  14970. // Fall through.
  14971. //
  14972. case IRP_MN_START_DEVICE:
  14973. case IRP_MN_QUERY_REMOVE_DEVICE:
  14974. case IRP_MN_CANCEL_REMOVE_DEVICE:
  14975. case IRP_MN_STOP_DEVICE:
  14976. case IRP_MN_QUERY_STOP_DEVICE:
  14977. case IRP_MN_CANCEL_STOP_DEVICE:
  14978. case IRP_MN_SURPRISE_REMOVAL:
  14979. Irp->IoStatus.Status = STATUS_SUCCESS;
  14980. break;
  14981. }
  14982. IoSkipCurrentIrpStackLocation(Irp);
  14983. return IoCallDriver(targetObject, Irp);
  14984. }
  14985. switch (irpSp->MinorFunction) {
  14986. case IRP_MN_REMOVE_DEVICE:
  14987. case IRP_MN_SURPRISE_REMOVAL:
  14988. targetObject = filter->TargetObject;
  14989. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  14990. VspPostCleanupFilter(filter);
  14991. IoDetachDevice(targetObject);
  14992. IoDeleteDevice(filter->DeviceObject);
  14993. } else {
  14994. VspAcquireCritical(filter);
  14995. VspAcquire(filter->Root);
  14996. VspCleanupPreamble(filter);
  14997. VspRelease(filter->Root);
  14998. VspCleanupFilter(filter, FALSE, FALSE);
  14999. VspReleaseCritical(filter);
  15000. }
  15001. Irp->IoStatus.Status = STATUS_SUCCESS;
  15002. IoSkipCurrentIrpStackLocation(Irp);
  15003. return IoCallDriver(targetObject, Irp);
  15004. case IRP_MN_QUERY_DEVICE_RELATIONS:
  15005. switch (irpSp->Parameters.QueryDeviceRelations.Type) {
  15006. case BusRelations:
  15007. break;
  15008. default:
  15009. IoSkipCurrentIrpStackLocation(Irp);
  15010. return IoCallDriver(filter->TargetObject, Irp);
  15011. }
  15012. KeInitializeEvent(&event, NotificationEvent, FALSE);
  15013. IoCopyCurrentIrpStackLocationToNext(Irp);
  15014. IoSetCompletionRoutine(Irp, VspSignalCompletion,
  15015. &event, TRUE, TRUE, TRUE);
  15016. IoCallDriver(filter->TargetObject, Irp);
  15017. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  15018. NULL);
  15019. VspAcquire(filter->Root);
  15020. switch (irpSp->Parameters.QueryDeviceRelations.Type) {
  15021. case BusRelations:
  15022. status = VspQueryBusRelations(filter, Irp);
  15023. break;
  15024. }
  15025. VspRelease(filter->Root);
  15026. break;
  15027. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  15028. KeInitializeEvent(&event, NotificationEvent, FALSE);
  15029. IoCopyCurrentIrpStackLocationToNext(Irp);
  15030. IoSetCompletionRoutine(Irp, VspSignalCompletion,
  15031. &event, TRUE, TRUE, TRUE);
  15032. IoCallDriver(filter->TargetObject, Irp);
  15033. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  15034. NULL);
  15035. status = Irp->IoStatus.Status;
  15036. if (!NT_SUCCESS(status)) {
  15037. break;
  15038. }
  15039. switch (irpSp->Parameters.UsageNotification.Type) {
  15040. case DeviceUsageTypePaging:
  15041. if (irpSp->Parameters.UsageNotification.InPath) {
  15042. InterlockedExchange(&filter->UsedForPaging, TRUE);
  15043. } else {
  15044. InterlockedExchange(&filter->UsedForPaging, FALSE);
  15045. }
  15046. break;
  15047. case DeviceUsageTypeDumpFile:
  15048. status = VspHandleDumpUsageNotification(filter,
  15049. irpSp->Parameters.UsageNotification.InPath);
  15050. break;
  15051. }
  15052. break;
  15053. case IRP_MN_START_DEVICE:
  15054. case IRP_MN_QUERY_REMOVE_DEVICE:
  15055. case IRP_MN_CANCEL_REMOVE_DEVICE:
  15056. case IRP_MN_STOP_DEVICE:
  15057. case IRP_MN_QUERY_STOP_DEVICE:
  15058. case IRP_MN_CANCEL_STOP_DEVICE:
  15059. Irp->IoStatus.Status = STATUS_SUCCESS;
  15060. //
  15061. // Fall through.
  15062. //
  15063. default:
  15064. IoSkipCurrentIrpStackLocation(Irp);
  15065. return IoCallDriver(filter->TargetObject, Irp);
  15066. }
  15067. Irp->IoStatus.Status = status;
  15068. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  15069. return status;
  15070. }
  15071. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  15072. extension = (PVOLUME_EXTENSION) filter;
  15073. switch (irpSp->MinorFunction) {
  15074. case IRP_MN_START_DEVICE:
  15075. status = VspPnpStart(extension);
  15076. break;
  15077. case IRP_MN_QUERY_REMOVE_DEVICE:
  15078. if (extension->Root->IsSetup) {
  15079. status = STATUS_INVALID_DEVICE_REQUEST;
  15080. } else {
  15081. status = STATUS_SUCCESS;
  15082. }
  15083. break;
  15084. case IRP_MN_CANCEL_REMOVE_DEVICE:
  15085. status = STATUS_SUCCESS;
  15086. break;
  15087. case IRP_MN_QUERY_STOP_DEVICE:
  15088. status = STATUS_UNSUCCESSFUL;
  15089. break;
  15090. case IRP_MN_CANCEL_STOP_DEVICE:
  15091. case IRP_MN_QUERY_RESOURCES:
  15092. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  15093. status = STATUS_SUCCESS;
  15094. break;
  15095. case IRP_MN_REMOVE_DEVICE:
  15096. case IRP_MN_SURPRISE_REMOVAL:
  15097. InterlockedExchange(&extension->IsStarted, FALSE);
  15098. VspAcquire(extension->Root);
  15099. if (extension->MountedDeviceInterfaceName.Buffer) {
  15100. IoSetDeviceInterfaceState(
  15101. &extension->MountedDeviceInterfaceName, FALSE);
  15102. ExFreePool(extension->MountedDeviceInterfaceName.Buffer);
  15103. extension->MountedDeviceInterfaceName.Buffer = NULL;
  15104. }
  15105. VspRelease(extension->Root);
  15106. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  15107. if (extension->DeadToPnp && !extension->DeviceDeleted) {
  15108. InterlockedExchange(&extension->DeviceDeleted, TRUE);
  15109. deletePdo = TRUE;
  15110. } else {
  15111. deletePdo = FALSE;
  15112. }
  15113. } else {
  15114. deletePdo = FALSE;
  15115. }
  15116. if (deletePdo) {
  15117. VspAcquire(extension->Root);
  15118. RtlDeleteElementGenericTable(
  15119. &extension->Root->UsedDevnodeNumbers,
  15120. &extension->DevnodeNumber);
  15121. VspRelease(extension->Root);
  15122. IoDeleteDevice(extension->DeviceObject);
  15123. }
  15124. status = STATUS_SUCCESS;
  15125. break;
  15126. case IRP_MN_QUERY_DEVICE_RELATIONS:
  15127. if (irpSp->Parameters.QueryDeviceRelations.Type !=
  15128. TargetDeviceRelation) {
  15129. status = STATUS_NOT_SUPPORTED;
  15130. break;
  15131. }
  15132. deviceRelations = (PDEVICE_RELATIONS)
  15133. ExAllocatePoolWithTag(PagedPool,
  15134. sizeof(DEVICE_RELATIONS),
  15135. VOLSNAP_TAG_RELATIONS);
  15136. if (!deviceRelations) {
  15137. status = STATUS_INSUFFICIENT_RESOURCES;
  15138. break;
  15139. }
  15140. ObReferenceObject(DeviceObject);
  15141. deviceRelations->Count = 1;
  15142. deviceRelations->Objects[0] = DeviceObject;
  15143. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  15144. status = STATUS_SUCCESS;
  15145. break;
  15146. case IRP_MN_QUERY_CAPABILITIES:
  15147. capabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
  15148. capabilities->SilentInstall = 1;
  15149. capabilities->SurpriseRemovalOK = 1;
  15150. capabilities->RawDeviceOK = 1;
  15151. capabilities->UniqueID = 1;
  15152. capabilities->Address = extension->VolumeNumber;
  15153. status = STATUS_SUCCESS;
  15154. break;
  15155. case IRP_MN_QUERY_ID:
  15156. status = VspQueryId(extension, Irp);
  15157. break;
  15158. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  15159. Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI;
  15160. status = STATUS_SUCCESS;
  15161. break;
  15162. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  15163. status = STATUS_INVALID_DEVICE_REQUEST;
  15164. break;
  15165. default:
  15166. status = STATUS_NOT_SUPPORTED;
  15167. break;
  15168. }
  15169. if (status == STATUS_NOT_SUPPORTED) {
  15170. status = Irp->IoStatus.Status;
  15171. } else {
  15172. Irp->IoStatus.Status = status;
  15173. }
  15174. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  15175. return status;
  15176. }
  15177. VOID
  15178. VspWorkerThread(
  15179. IN PVOID Context
  15180. )
  15181. /*++
  15182. Routine Description:
  15183. This is a worker thread to process work queue items.
  15184. Arguments:
  15185. RootExtension - Supplies the root device extension.
  15186. Return Value:
  15187. None.
  15188. --*/
  15189. {
  15190. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  15191. PDO_EXTENSION rootExtension = context->ThreadCreation.RootExtension;
  15192. ULONG queueNumber = context->ThreadCreation.QueueNumber;
  15193. KIRQL irql;
  15194. PLIST_ENTRY l;
  15195. PWORK_QUEUE_ITEM queueItem;
  15196. ASSERT(queueNumber < NUMBER_OF_THREAD_POOLS);
  15197. ASSERT(context->Type == VSP_CONTEXT_TYPE_THREAD_CREATION);
  15198. VspFreeContext(rootExtension, context);
  15199. if (!queueNumber) {
  15200. KeSetPriorityThread(KeGetCurrentThread(), VSP_HIGH_PRIORITY);
  15201. }
  15202. for (;;) {
  15203. KeWaitForSingleObject(&rootExtension->WorkerSemaphore[queueNumber],
  15204. Executive, KernelMode, FALSE, NULL);
  15205. KeAcquireSpinLock(&rootExtension->SpinLock[queueNumber], &irql);
  15206. if (IsListEmpty(&rootExtension->WorkerQueue[queueNumber])) {
  15207. KeReleaseSpinLock(&rootExtension->SpinLock[queueNumber], irql);
  15208. ASSERT(!rootExtension->ThreadsRefCount);
  15209. PsTerminateSystemThread(STATUS_SUCCESS);
  15210. return;
  15211. }
  15212. l = RemoveHeadList(&rootExtension->WorkerQueue[queueNumber]);
  15213. KeReleaseSpinLock(&rootExtension->SpinLock[queueNumber], irql);
  15214. queueItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  15215. queueItem->WorkerRoutine(queueItem->Parameter);
  15216. }
  15217. }
  15218. NTSTATUS
  15219. VspAddChainToBitmap(
  15220. IN PFILTER_EXTENSION Filter,
  15221. IN LONGLONG ChainOffset,
  15222. IN OUT PRTL_BITMAP Bitmap
  15223. )
  15224. {
  15225. PVSP_BLOCK_HEADER header;
  15226. NTSTATUS status;
  15227. header = (PVSP_BLOCK_HEADER)
  15228. MmGetMdlVirtualAddress(Filter->SnapshotOnDiskIrp->MdlAddress);
  15229. while (ChainOffset) {
  15230. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp,
  15231. Filter->TargetObject, IRP_MJ_READ,
  15232. ChainOffset, 0);
  15233. if (!NT_SUCCESS(status)) {
  15234. return status;
  15235. }
  15236. if (!IsEqualGUID(header->Signature, VSP_DIFF_AREA_FILE_GUID) ||
  15237. header->Version != VOLSNAP_PERSISTENT_VERSION ||
  15238. header->ThisVolumeOffset != ChainOffset ||
  15239. header->NextVolumeOffset == ChainOffset) {
  15240. return STATUS_INVALID_PARAMETER;
  15241. }
  15242. RtlSetBit(Bitmap, (ULONG) (ChainOffset>>BLOCK_SHIFT));
  15243. ChainOffset = header->NextVolumeOffset;
  15244. }
  15245. return STATUS_SUCCESS;
  15246. }
  15247. NTSTATUS
  15248. VspProtectDiffAreaClusters(
  15249. IN PFILTER_EXTENSION Filter
  15250. )
  15251. {
  15252. PRTL_BITMAP bitmap;
  15253. ULONG bitmapSize;
  15254. PVOID bitmapBuffer;
  15255. NTSTATUS status;
  15256. PLIST_ENTRY l, ll;
  15257. PVSP_DIFF_AREA_FILE diffAreaFile;
  15258. PVOLUME_EXTENSION extension;
  15259. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  15260. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  15261. PTRANSLATION_TABLE_ENTRY tableEntry;
  15262. KIRQL irql;
  15263. VspAcquireCritical(Filter);
  15264. Filter->DeleteTimer = NULL;
  15265. VspReleaseCritical(Filter);
  15266. InterlockedExchange(&Filter->Root->VolumesSafeForWriteAccess, TRUE);
  15267. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  15268. KernelMode, FALSE, NULL);
  15269. bitmap = (PRTL_BITMAP) ExAllocatePoolWithTag(NonPagedPool,
  15270. sizeof(RTL_BITMAP),
  15271. VOLSNAP_TAG_BITMAP);
  15272. if (!bitmap) {
  15273. return STATUS_INSUFFICIENT_RESOURCES;
  15274. }
  15275. bitmapSize = (ULONG)
  15276. ((VspQueryVolumeSize(Filter) + BLOCK_SIZE - 1)>>BLOCK_SHIFT);
  15277. if (!bitmapSize) {
  15278. return STATUS_INSUFFICIENT_RESOURCES;
  15279. }
  15280. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  15281. (bitmapSize + 8*sizeof(ULONG) - 1)/
  15282. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  15283. if (!bitmapBuffer) {
  15284. ExFreePool(bitmap);
  15285. return STATUS_INSUFFICIENT_RESOURCES;
  15286. }
  15287. RtlInitializeBitMap(bitmap, (PULONG) bitmapBuffer, bitmapSize);
  15288. RtlClearAllBits(bitmap);
  15289. VspAcquire(Filter->Root);
  15290. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  15291. if (Filter->FirstControlBlockVolumeOffset) {
  15292. status = VspAddChainToBitmap(Filter,
  15293. Filter->FirstControlBlockVolumeOffset,
  15294. bitmap);
  15295. if (!NT_SUCCESS(status)) {
  15296. VspReleaseNonPagedResource(Filter);
  15297. VspRelease(Filter->Root);
  15298. ExFreePool(bitmapBuffer);
  15299. ExFreePool(bitmap);
  15300. return status;
  15301. }
  15302. }
  15303. VspReleaseNonPagedResource(Filter);
  15304. for (l = Filter->DiffAreaFilesOnThisFilter.Flink;
  15305. l != &Filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  15306. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  15307. FilterListEntry);
  15308. if (!diffAreaFile->Extension->IsPersistent) {
  15309. continue;
  15310. }
  15311. extension = diffAreaFile->Extension;
  15312. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  15313. ASSERT(diffAreaFile->ApplicationInfoTargetOffset);
  15314. status = VspAddChainToBitmap(Filter, diffAreaFile->
  15315. ApplicationInfoTargetOffset, bitmap);
  15316. if (!NT_SUCCESS(status)) {
  15317. VspReleaseNonPagedResource(Filter);
  15318. VspRelease(Filter->Root);
  15319. ExFreePool(bitmapBuffer);
  15320. ExFreePool(bitmap);
  15321. return status;
  15322. }
  15323. ASSERT(diffAreaFile->DiffAreaLocationDescriptionTargetOffset);
  15324. status = VspAddChainToBitmap(Filter, diffAreaFile->
  15325. DiffAreaLocationDescriptionTargetOffset,
  15326. bitmap);
  15327. if (!NT_SUCCESS(status)) {
  15328. VspReleaseNonPagedResource(Filter);
  15329. VspRelease(Filter->Root);
  15330. ExFreePool(bitmapBuffer);
  15331. ExFreePool(bitmap);
  15332. return status;
  15333. }
  15334. if (diffAreaFile->InitialBitmapVolumeOffset) {
  15335. status = VspAddChainToBitmap(Filter, diffAreaFile->
  15336. InitialBitmapVolumeOffset, bitmap);
  15337. if (!NT_SUCCESS(status)) {
  15338. VspReleaseNonPagedResource(Filter);
  15339. VspRelease(Filter->Root);
  15340. ExFreePool(bitmapBuffer);
  15341. ExFreePool(bitmap);
  15342. return status;
  15343. }
  15344. }
  15345. ASSERT(diffAreaFile->FirstTableTargetOffset);
  15346. status = VspAddChainToBitmap(Filter, diffAreaFile->
  15347. FirstTableTargetOffset, bitmap);
  15348. if (!NT_SUCCESS(status)) {
  15349. VspReleaseNonPagedResource(Filter);
  15350. VspRelease(Filter->Root);
  15351. ExFreePool(bitmapBuffer);
  15352. ExFreePool(bitmap);
  15353. return status;
  15354. }
  15355. VspReleaseNonPagedResource(Filter);
  15356. VspAcquireNonPagedResource(extension, NULL, FALSE);
  15357. for (ll = diffAreaFile->UnusedAllocationList.Flink;
  15358. ll != &diffAreaFile->UnusedAllocationList; ll = ll->Flink) {
  15359. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  15360. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  15361. if (diffAreaFileAllocation->NLength <= 0) {
  15362. continue;
  15363. }
  15364. ASSERT((diffAreaFileAllocation->NLength&(BLOCK_SIZE - 1)) == 0);
  15365. RtlSetBits(bitmap,
  15366. (ULONG) (diffAreaFileAllocation->Offset>>BLOCK_SHIFT),
  15367. (ULONG) (diffAreaFileAllocation->NLength>>BLOCK_SHIFT));
  15368. }
  15369. tempTableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  15370. RtlEnumerateGenericTable(
  15371. &extension->TempVolumeBlockTable, TRUE);
  15372. while (tempTableEntry) {
  15373. if (!tempTableEntry->IsMoveEntry && tempTableEntry->TargetOffset) {
  15374. RtlSetBit(bitmap,
  15375. (ULONG) (tempTableEntry->TargetOffset>>BLOCK_SHIFT));
  15376. }
  15377. tempTableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  15378. RtlEnumerateGenericTable(
  15379. &extension->TempVolumeBlockTable, FALSE);
  15380. }
  15381. VspReleaseNonPagedResource(extension);
  15382. status = STATUS_SUCCESS;
  15383. VspAcquirePagedResource(extension, NULL);
  15384. _try {
  15385. tableEntry = (PTRANSLATION_TABLE_ENTRY)
  15386. RtlEnumerateGenericTable(
  15387. &extension->VolumeBlockTable, TRUE);
  15388. while (tableEntry) {
  15389. if (!tableEntry->Flags) {
  15390. RtlSetBit(bitmap, (
  15391. ULONG) (tableEntry->TargetOffset>>BLOCK_SHIFT));
  15392. }
  15393. tableEntry = (PTRANSLATION_TABLE_ENTRY)
  15394. RtlEnumerateGenericTable(
  15395. &extension->VolumeBlockTable, FALSE);
  15396. }
  15397. } _except (EXCEPTION_EXECUTE_HANDLER) {
  15398. status = GetExceptionCode();
  15399. }
  15400. VspReleasePagedResource(extension);
  15401. if (!NT_SUCCESS(status)) {
  15402. VspRelease(Filter->Root);
  15403. ExFreePool(bitmapBuffer);
  15404. ExFreePool(bitmap);
  15405. return status;
  15406. }
  15407. }
  15408. VspPauseVolumeIo(Filter);
  15409. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  15410. InterlockedExchangePointer((PVOID*) &Filter->ProtectedBlocksBitmap,
  15411. bitmap);
  15412. KeReleaseSpinLock(&Filter->SpinLock, irql);
  15413. VspResumeVolumeIo(Filter);
  15414. VspRelease(Filter->Root);
  15415. return STATUS_SUCCESS;
  15416. }
  15417. NTSTATUS
  15418. VspOpenAndValidateDiffAreaFiles(
  15419. IN PFILTER_EXTENSION Filter
  15420. )
  15421. {
  15422. NTSTATUS status;
  15423. PVOID buffer;
  15424. PVSP_BLOCK_START startBlock;
  15425. HANDLE h, hh;
  15426. PLIST_ENTRY l;
  15427. PVSP_DIFF_AREA_FILE diffAreaFile;
  15428. UNICODE_STRING fileName;
  15429. OBJECT_ATTRIBUTES oa;
  15430. IO_STATUS_BLOCK ioStatus;
  15431. BOOLEAN checkUnused;
  15432. PVOLUME_EXTENSION extension;
  15433. PVSP_CONTEXT context;
  15434. KIRQL irql;
  15435. h = InterlockedExchangePointer(&Filter->ControlBlockFileHandle, NULL);
  15436. if (h) {
  15437. ZwClose(h);
  15438. }
  15439. if (!Filter->FirstControlBlockVolumeOffset) {
  15440. return STATUS_SUCCESS;
  15441. }
  15442. status = VspOpenControlBlockFile(Filter);
  15443. if (!NT_SUCCESS(status)) {
  15444. return status;
  15445. }
  15446. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  15447. status = VspSynchronousIo(Filter->SnapshotOnDiskIrp, Filter->TargetObject,
  15448. IRP_MJ_READ, 0, 0);
  15449. if (!NT_SUCCESS(status)) {
  15450. VspReleaseNonPagedResource(Filter);
  15451. return status;
  15452. }
  15453. buffer = MmGetMdlVirtualAddress(Filter->SnapshotOnDiskIrp->MdlAddress);
  15454. if (!VspIsNtfsBootSector(Filter, buffer)) {
  15455. VspReleaseNonPagedResource(Filter);
  15456. return STATUS_INVALID_PARAMETER;
  15457. }
  15458. startBlock = (PVSP_BLOCK_START) ((PCHAR) buffer + VSP_START_BLOCK_OFFSET);
  15459. if (!IsEqualGUID(startBlock->Header.Signature, VSP_DIFF_AREA_FILE_GUID) ||
  15460. startBlock->Header.Version != VOLSNAP_PERSISTENT_VERSION ||
  15461. startBlock->Header.BlockType != VSP_BLOCK_TYPE_START) {
  15462. VspReleaseNonPagedResource(Filter);
  15463. return STATUS_INVALID_PARAMETER;
  15464. }
  15465. VspReleaseNonPagedResource(Filter);
  15466. h = VspPinBootStat(Filter);
  15467. if (h) {
  15468. hh = InterlockedExchangePointer(&Filter->BootStatHandle, h);
  15469. if (hh) {
  15470. ZwClose(hh);
  15471. }
  15472. }
  15473. VspAcquire(Filter->Root);
  15474. for (l = Filter->DiffAreaFilesOnThisFilter.Flink;
  15475. l != &Filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  15476. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  15477. FilterListEntry);
  15478. diffAreaFile->ValidateHandleNeeded = TRUE;
  15479. }
  15480. VspRelease(Filter->Root);
  15481. for (;;) {
  15482. VspAcquire(Filter->Root);
  15483. for (l = Filter->DiffAreaFilesOnThisFilter.Flink;
  15484. l != &Filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  15485. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  15486. FilterListEntry);
  15487. if (diffAreaFile->ValidateHandleNeeded) {
  15488. diffAreaFile->ValidateHandleNeeded = FALSE;
  15489. break;
  15490. }
  15491. }
  15492. if (l == &Filter->DiffAreaFilesOnThisFilter) {
  15493. VspRelease(Filter->Root);
  15494. break;
  15495. }
  15496. extension = diffAreaFile->Extension;
  15497. status = VspIncrementVolumeRefCount(extension);
  15498. if (!NT_SUCCESS(status)) {
  15499. VspRelease(Filter->Root);
  15500. continue;
  15501. }
  15502. VspRelease(Filter->Root);
  15503. status = VspCreateDiffAreaFileName(Filter->TargetObject, extension,
  15504. &fileName, FALSE, NULL);
  15505. if (!NT_SUCCESS(status)) {
  15506. VspDecrementVolumeRefCount(extension);
  15507. return status;
  15508. }
  15509. ZwClose(diffAreaFile->FileHandle);
  15510. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE |
  15511. OBJ_KERNEL_HANDLE, NULL, NULL);
  15512. status = ZwOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &oa,
  15513. &ioStatus, 0, FILE_WRITE_THROUGH |
  15514. FILE_SYNCHRONOUS_IO_NONALERT |
  15515. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  15516. FILE_NO_COMPRESSION);
  15517. ExFreePool(fileName.Buffer);
  15518. if (!NT_SUCCESS(status)) {
  15519. VspAcquire(Filter->Root);
  15520. diffAreaFile->FileHandle = NULL;
  15521. VspRelease(Filter->Root);
  15522. VspDecrementVolumeRefCount(extension);
  15523. return status;
  15524. }
  15525. status = VspPinFile(Filter->TargetObject, h);
  15526. if (!NT_SUCCESS(status)) {
  15527. ZwClose(h);
  15528. VspAcquire(Filter->Root);
  15529. diffAreaFile->FileHandle = NULL;
  15530. VspRelease(Filter->Root);
  15531. VspDecrementVolumeRefCount(extension);
  15532. return status;
  15533. }
  15534. KeAcquireSpinLock(&extension->Filter->SpinLock, &irql);
  15535. if (extension->ListEntry.Flink == &extension->Filter->VolumeList) {
  15536. checkUnused = TRUE;
  15537. } else {
  15538. checkUnused = FALSE;
  15539. }
  15540. KeReleaseSpinLock(&extension->Filter->SpinLock, irql);
  15541. status = VspCheckDiffAreaFileLocation(
  15542. Filter, h, diffAreaFile->ApplicationInfoTargetOffset,
  15543. diffAreaFile->FirstTableTargetOffset,
  15544. diffAreaFile->DiffAreaLocationDescriptionTargetOffset,
  15545. diffAreaFile->InitialBitmapVolumeOffset, checkUnused);
  15546. if (!NT_SUCCESS(status)) {
  15547. ZwClose(h);
  15548. VspAcquire(Filter->Root);
  15549. diffAreaFile->FileHandle = NULL;
  15550. VspRelease(Filter->Root);
  15551. VspDecrementVolumeRefCount(extension);
  15552. return status;
  15553. }
  15554. InterlockedExchangePointer(&diffAreaFile->FileHandle, h);
  15555. if (InterlockedExchange(&extension->GrowFailed, FALSE)) {
  15556. context = VspAllocateContext(extension->Root);
  15557. if (context) {
  15558. KeAcquireSpinLock(&extension->SpinLock, &irql);
  15559. ASSERT(!extension->GrowDiffAreaFilePending);
  15560. ASSERT(IsListEmpty(&extension->WaitingForDiffAreaSpace));
  15561. extension->GrowDiffAreaFilePending = TRUE;
  15562. extension->PastFileSystemOperations = FALSE;
  15563. KeReleaseSpinLock(&extension->SpinLock, irql);
  15564. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  15565. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea,
  15566. context);
  15567. context->GrowDiffArea.Extension = extension;
  15568. ObReferenceObject(extension->DeviceObject);
  15569. ASSERT(extension->OkToGrowDiffArea);
  15570. VspQueueWorkItem(extension->Root, &context->WorkItem, 0);
  15571. }
  15572. }
  15573. VspDecrementVolumeRefCount(extension);
  15574. }
  15575. return STATUS_SUCCESS;
  15576. }
  15577. BOOLEAN
  15578. VspIsFileSystemLocked(
  15579. IN PFILTER_EXTENSION Filter
  15580. )
  15581. {
  15582. KEVENT event;
  15583. PMOUNTDEV_NAME name;
  15584. CHAR buffer[512];
  15585. PIRP irp;
  15586. IO_STATUS_BLOCK ioStatus;
  15587. NTSTATUS status;
  15588. UNICODE_STRING volumeName;
  15589. OBJECT_ATTRIBUTES oa;
  15590. HANDLE h;
  15591. KeInitializeEvent(&event, NotificationEvent, FALSE);
  15592. name = (PMOUNTDEV_NAME) buffer;
  15593. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  15594. Filter->TargetObject, NULL, 0,
  15595. name, 500, FALSE, &event,
  15596. &ioStatus);
  15597. if (!irp) {
  15598. return FALSE;
  15599. }
  15600. status = IoCallDriver(Filter->TargetObject, irp);
  15601. if (status == STATUS_PENDING) {
  15602. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  15603. status = ioStatus.Status;
  15604. }
  15605. if (!NT_SUCCESS(status)) {
  15606. return FALSE;
  15607. }
  15608. volumeName.Length = volumeName.MaximumLength = name->NameLength;
  15609. volumeName.Buffer = name->Name;
  15610. InitializeObjectAttributes(&oa, &volumeName, OBJ_CASE_INSENSITIVE |
  15611. OBJ_KERNEL_HANDLE, NULL, NULL);
  15612. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  15613. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  15614. FILE_SYNCHRONOUS_IO_NONALERT);
  15615. if (NT_SUCCESS(status)) {
  15616. ZwClose(h);
  15617. }
  15618. if (status == STATUS_ACCESS_DENIED) {
  15619. return TRUE;
  15620. }
  15621. return FALSE;
  15622. }
  15623. NTSTATUS
  15624. VolSnapTargetDeviceNotification(
  15625. IN PVOID NotificationStructure,
  15626. IN PVOID Filter
  15627. )
  15628. {
  15629. PTARGET_DEVICE_REMOVAL_NOTIFICATION notification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure;
  15630. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  15631. BOOLEAN cleanupBitmap = FALSE;
  15632. NTSTATUS status;
  15633. KIRQL irql;
  15634. PRTL_BITMAP bitmap;
  15635. PLIST_ENTRY l;
  15636. PVSP_DIFF_AREA_FILE diffAreaFile;
  15637. PFILTER_EXTENSION f;
  15638. LIST_ENTRY listOfDiffAreaFilesToClose;
  15639. LIST_ENTRY listOfDeviceObjectsToDelete;
  15640. HANDLE h, hh;
  15641. PVOLUME_EXTENSION extension;
  15642. BOOLEAN b, persistentOk;
  15643. if (IsEqualGUID(notification->Event,
  15644. GUID_TARGET_DEVICE_REMOVE_COMPLETE)) {
  15645. if (filter->TargetDeviceNotificationEntry) {
  15646. IoUnregisterPlugPlayNotification(
  15647. filter->TargetDeviceNotificationEntry);
  15648. filter->TargetDeviceNotificationEntry = NULL;
  15649. }
  15650. return STATUS_SUCCESS;
  15651. }
  15652. if (IsEqualGUID(notification->Event, GUID_IO_VOLUME_MOUNT)) {
  15653. if (!filter->ProtectedBlocksBitmap) {
  15654. return STATUS_SUCCESS;
  15655. }
  15656. status = VspOpenAndValidateDiffAreaFiles(filter);
  15657. if (!NT_SUCCESS(status)) {
  15658. persistentOk = FALSE;
  15659. cleanupBitmap = TRUE;
  15660. goto DeleteSnapshots;
  15661. }
  15662. KeAcquireSpinLock(&filter->SpinLock, &irql);
  15663. bitmap = (PRTL_BITMAP) InterlockedExchangePointer(
  15664. (PVOID*) &filter->ProtectedBlocksBitmap, NULL);
  15665. if (bitmap) {
  15666. ExFreePool(bitmap->Buffer);
  15667. ExFreePool(bitmap);
  15668. }
  15669. KeReleaseSpinLock(&filter->SpinLock, irql);
  15670. return STATUS_SUCCESS;
  15671. }
  15672. if (!IsEqualGUID(notification->Event, GUID_IO_VOLUME_DISMOUNT)) {
  15673. return STATUS_SUCCESS;
  15674. }
  15675. if (VspIsFileSystemLocked(filter)) {
  15676. return STATUS_SUCCESS;
  15677. }
  15678. if (filter->FirstControlBlockVolumeOffset) {
  15679. persistentOk = TRUE;
  15680. } else {
  15681. persistentOk = FALSE;
  15682. }
  15683. if (persistentOk) {
  15684. if (!filter->ProtectedBlocksBitmap) {
  15685. status = VspProtectDiffAreaClusters(filter);
  15686. if (!NT_SUCCESS(status)) {
  15687. persistentOk = FALSE;
  15688. }
  15689. }
  15690. }
  15691. DeleteSnapshots:
  15692. InitializeListHead(&listOfDiffAreaFilesToClose);
  15693. InitializeListHead(&listOfDeviceObjectsToDelete);
  15694. VspAcquire(filter->Root);
  15695. for (;;) {
  15696. for (l = filter->DiffAreaFilesOnThisFilter.Flink;
  15697. l != &filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  15698. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  15699. FilterListEntry);
  15700. if (!persistentOk || !diffAreaFile->Extension->IsPersistent) {
  15701. break;
  15702. }
  15703. }
  15704. if (l == &filter->DiffAreaFilesOnThisFilter) {
  15705. break;
  15706. }
  15707. f = diffAreaFile->Extension->Filter;
  15708. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  15709. VS_ABORT_SNAPSHOTS_DISMOUNT, STATUS_SUCCESS, 1, TRUE);
  15710. VspAbortPreparedSnapshot(f, FALSE, FALSE);
  15711. b = FALSE;
  15712. while (!IsListEmpty(&f->VolumeList)) {
  15713. extension = CONTAINING_RECORD(f->VolumeList.Flink,
  15714. VOLUME_EXTENSION, ListEntry);
  15715. if (persistentOk && extension->IsPersistent) {
  15716. break;
  15717. }
  15718. VspDeleteOldestSnapshot(f, &listOfDiffAreaFilesToClose,
  15719. &listOfDeviceObjectsToDelete, FALSE, TRUE);
  15720. b = TRUE;
  15721. }
  15722. if (b) {
  15723. IoInvalidateDeviceRelations(f->Pdo, BusRelations);
  15724. }
  15725. }
  15726. VspAbortPreparedSnapshot(filter, FALSE, FALSE);
  15727. if (filter->PersistentSnapshots && !persistentOk &&
  15728. !IsListEmpty(&filter->VolumeList)) {
  15729. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  15730. VOLUME_EXTENSION, ListEntry);
  15731. VspLogError(extension, extension->Filter,
  15732. VS_ABORT_SNAPSHOTS_DISMOUNT_ORIGINAL, STATUS_SUCCESS, 2,
  15733. TRUE);
  15734. b = FALSE;
  15735. while (!IsListEmpty(&filter->VolumeList)) {
  15736. VspDeleteOldestSnapshot(filter, &listOfDiffAreaFilesToClose,
  15737. &listOfDeviceObjectsToDelete, FALSE, TRUE);
  15738. b = TRUE;
  15739. }
  15740. if (b) {
  15741. IoInvalidateDeviceRelations(filter->Pdo, BusRelations);
  15742. }
  15743. }
  15744. if (persistentOk) {
  15745. hh = NULL;
  15746. } else {
  15747. hh = InterlockedExchangePointer(&filter->BootStatHandle, NULL);
  15748. }
  15749. if (cleanupBitmap) {
  15750. KeAcquireSpinLock(&filter->SpinLock, &irql);
  15751. bitmap = (PRTL_BITMAP) InterlockedExchangePointer(
  15752. (PVOID*) &filter->ProtectedBlocksBitmap, NULL);
  15753. if (bitmap) {
  15754. ExFreePool(bitmap->Buffer);
  15755. ExFreePool(bitmap);
  15756. }
  15757. KeReleaseSpinLock(&filter->SpinLock, irql);
  15758. }
  15759. VspRelease(filter->Root);
  15760. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  15761. &listOfDeviceObjectsToDelete);
  15762. if (persistentOk) {
  15763. h = NULL;
  15764. } else {
  15765. h = InterlockedExchangePointer(&filter->ControlBlockFileHandle, NULL);
  15766. VspAcquireNonPagedResource(filter, NULL, FALSE);
  15767. filter->FirstControlBlockVolumeOffset = 0;
  15768. if (h) {
  15769. VspCreateStartBlock(filter, 0, filter->MaximumVolumeSpace);
  15770. }
  15771. VspReleaseNonPagedResource(filter);
  15772. }
  15773. if (h) {
  15774. ZwClose(h);
  15775. }
  15776. if (hh) {
  15777. ZwClose(hh);
  15778. }
  15779. return STATUS_SUCCESS;
  15780. }
  15781. NTSTATUS
  15782. VolSnapVolumeDeviceNotification(
  15783. IN PVOID NotificationStructure,
  15784. IN PVOID RootExtension
  15785. )
  15786. /*++
  15787. Routine Description:
  15788. This routine is called whenever a volume comes or goes.
  15789. Arguments:
  15790. NotificationStructure - Supplies the notification structure.
  15791. RootExtension - Supplies the root extension.
  15792. Return Value:
  15793. NTSTATUS
  15794. --*/
  15795. {
  15796. PDEVICE_INTERFACE_CHANGE_NOTIFICATION notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
  15797. PDO_EXTENSION root = (PDO_EXTENSION) RootExtension;
  15798. BOOLEAN errorMode;
  15799. NTSTATUS status;
  15800. PFILE_OBJECT fileObject;
  15801. PDEVICE_OBJECT deviceObject;
  15802. PFILTER_EXTENSION filter;
  15803. if (!IsEqualGUID(notification->Event, GUID_DEVICE_INTERFACE_ARRIVAL)) {
  15804. return STATUS_SUCCESS;
  15805. }
  15806. errorMode = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
  15807. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
  15808. status = IoGetDeviceObjectPointer(notification->SymbolicLinkName,
  15809. FILE_READ_ATTRIBUTES, &fileObject,
  15810. &deviceObject);
  15811. if (!NT_SUCCESS(status)) {
  15812. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  15813. return STATUS_SUCCESS;
  15814. }
  15815. if (fileObject->DeviceObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  15816. ObDereferenceObject(fileObject);
  15817. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  15818. return STATUS_SUCCESS;
  15819. }
  15820. VspAcquire(root);
  15821. filter = VspFindFilter(root, NULL, NULL, fileObject);
  15822. if (!filter || filter->TargetDeviceNotificationEntry) {
  15823. ObDereferenceObject(fileObject);
  15824. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  15825. VspRelease(root);
  15826. return STATUS_SUCCESS;
  15827. }
  15828. ObReferenceObject(filter->DeviceObject);
  15829. VspRelease(root);
  15830. status = IoRegisterPlugPlayNotification(
  15831. EventCategoryTargetDeviceChange, 0, fileObject,
  15832. root->DriverObject, VolSnapTargetDeviceNotification, filter,
  15833. &filter->TargetDeviceNotificationEntry);
  15834. ObDereferenceObject(filter->DeviceObject);
  15835. ObDereferenceObject(fileObject);
  15836. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  15837. return STATUS_SUCCESS;
  15838. }
  15839. VOID
  15840. VspWaitToRegisterWorker(
  15841. IN PVOID Context
  15842. )
  15843. {
  15844. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  15845. PDO_EXTENSION rootExtension = context->RootExtension.RootExtension;
  15846. ASSERT(context->Type == VSP_CONTEXT_TYPE_ROOT_EXTENSION);
  15847. VspFreeContext(rootExtension, context);
  15848. VspWaitForVolumesSafeForWriteAccess(rootExtension);
  15849. if (rootExtension->NotificationEntry) {
  15850. return;
  15851. }
  15852. IoRegisterPlugPlayNotification(
  15853. EventCategoryDeviceInterfaceChange,
  15854. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  15855. (PVOID) &GUID_IO_VOLUME_DEVICE_INTERFACE,
  15856. rootExtension->DriverObject, VolSnapVolumeDeviceNotification,
  15857. rootExtension, &rootExtension->NotificationEntry);
  15858. }
  15859. VOID
  15860. VspDriverBootReinit(
  15861. IN PDRIVER_OBJECT DriverObject,
  15862. IN PVOID RootExtension,
  15863. IN ULONG Count
  15864. )
  15865. /*++
  15866. Routine Description:
  15867. This routine is called after all of the boot drivers are loaded and it
  15868. checks to make sure that we did not boot off of the stale half of a
  15869. mirror.
  15870. Arguments:
  15871. DriverObject - Supplies the drive object.
  15872. RootExtension - Supplies the root extension.
  15873. Count - Supplies the count.
  15874. Return Value:
  15875. None.
  15876. --*/
  15877. {
  15878. PDO_EXTENSION rootExtension = (PDO_EXTENSION) RootExtension;
  15879. PVSP_CONTEXT context;
  15880. KeSetEvent(&rootExtension->PastBootReinit, IO_NO_INCREMENT,
  15881. FALSE);
  15882. }
  15883. VOID
  15884. VspDriverReinit(
  15885. IN PDRIVER_OBJECT DriverObject,
  15886. IN PVOID RootExtension,
  15887. IN ULONG Count
  15888. )
  15889. /*++
  15890. Routine Description:
  15891. This routine is called after all of the boot drivers are loaded and it
  15892. checks to make sure that we did not boot off of the stale half of a
  15893. mirror.
  15894. Arguments:
  15895. DriverObject - Supplies the drive object.
  15896. RootExtension - Supplies the root extension.
  15897. Count - Supplies the count.
  15898. Return Value:
  15899. None.
  15900. --*/
  15901. {
  15902. PDO_EXTENSION rootExtension = (PDO_EXTENSION) RootExtension;
  15903. PLIST_ENTRY l;
  15904. PFILTER_EXTENSION filter;
  15905. HANDLE h, hh;
  15906. PVSP_CONTEXT context;
  15907. VspAcquire(rootExtension);
  15908. for (l = rootExtension->FilterList.Flink;
  15909. l != &rootExtension->FilterList; l = l->Flink) {
  15910. filter = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  15911. if (filter->Pdo->Flags&DO_SYSTEM_BOOT_PARTITION) {
  15912. break;
  15913. }
  15914. }
  15915. if (l == &rootExtension->FilterList ||
  15916. IsListEmpty(&filter->VolumeList)) {
  15917. VspRelease(rootExtension);
  15918. } else {
  15919. VspRelease(rootExtension);
  15920. h = VspPinBootStat(filter);
  15921. if (h) {
  15922. hh = InterlockedExchangePointer(&filter->BootStatHandle, h);
  15923. if (hh) {
  15924. ZwClose(hh);
  15925. }
  15926. }
  15927. }
  15928. InterlockedExchange(&rootExtension->PastReinit, TRUE);
  15929. context = VspAllocateContext(rootExtension);
  15930. if (!context) {
  15931. return;
  15932. }
  15933. context->Type = VSP_CONTEXT_TYPE_ROOT_EXTENSION;
  15934. context->RootExtension.RootExtension = rootExtension;
  15935. ExInitializeWorkItem(&context->WorkItem, VspWaitToRegisterWorker, context);
  15936. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  15937. }
  15938. RTL_GENERIC_COMPARE_RESULTS
  15939. VspSnapshotLookupCompareRoutine(
  15940. IN PRTL_GENERIC_TABLE Table,
  15941. IN PVOID First,
  15942. IN PVOID Second
  15943. )
  15944. {
  15945. SIZE_T r;
  15946. PUCHAR p, q;
  15947. r = RtlCompareMemory(First, Second, sizeof(GUID));
  15948. if (r == sizeof(GUID)) {
  15949. return GenericEqual;
  15950. }
  15951. p = (PUCHAR) First;
  15952. q = (PUCHAR) Second;
  15953. if (p[r] < q[r]) {
  15954. return GenericLessThan;
  15955. }
  15956. return GenericGreaterThan;
  15957. }
  15958. RTL_GENERIC_COMPARE_RESULTS
  15959. VspUsedDevnodeCompareRoutine(
  15960. IN PRTL_GENERIC_TABLE Table,
  15961. IN PVOID First,
  15962. IN PVOID Second
  15963. )
  15964. {
  15965. PULONG f = (PULONG) First;
  15966. PULONG s = (PULONG) Second;
  15967. if (*f == *s) {
  15968. return GenericEqual;
  15969. }
  15970. if (*f < *s) {
  15971. return GenericLessThan;
  15972. }
  15973. return GenericGreaterThan;
  15974. }
  15975. VOID
  15976. VspSnapshotLookupFreeRoutine(
  15977. IN PRTL_GENERIC_TABLE Table,
  15978. IN PVOID Buffer
  15979. )
  15980. {
  15981. ExFreePool(Buffer);
  15982. }
  15983. PVOID
  15984. VspSnapshotLookupAllocateRoutine(
  15985. IN PRTL_GENERIC_TABLE Table,
  15986. IN CLONG Size
  15987. )
  15988. {
  15989. return ExAllocatePoolWithTag(PagedPool, Size, VOLSNAP_TAG_LOOKUP);
  15990. }
  15991. NTSTATUS
  15992. VspCheckForNtfs(
  15993. IN PVOLUME_EXTENSION Extension
  15994. )
  15995. {
  15996. WCHAR buffer[100];
  15997. UNICODE_STRING dirName;
  15998. OBJECT_ATTRIBUTES oa;
  15999. NTSTATUS status;
  16000. HANDLE h;
  16001. IO_STATUS_BLOCK ioStatus;
  16002. BOOLEAN isNtfs;
  16003. if (Extension->IsOffline) {
  16004. VspSetOfflineBit(Extension, FALSE);
  16005. }
  16006. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d\\",
  16007. Extension->VolumeNumber);
  16008. RtlInitUnicodeString(&dirName, buffer);
  16009. InitializeObjectAttributes(&oa, &dirName, OBJ_CASE_INSENSITIVE |
  16010. OBJ_KERNEL_HANDLE, NULL, NULL);
  16011. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa,
  16012. &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  16013. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  16014. if (!NT_SUCCESS(status)) {
  16015. return status;
  16016. }
  16017. status = VspIsNtfs(h, &isNtfs);
  16018. ZwClose(h);
  16019. if (!NT_SUCCESS(status)) {
  16020. return status;
  16021. }
  16022. return isNtfs ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  16023. }
  16024. VOID
  16025. VspHandleHibernatePost(
  16026. IN PVOID Context
  16027. )
  16028. {
  16029. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16030. PVOLUME_EXTENSION extension = context->Extension.Extension;
  16031. PIRP irp = context->Extension.Irp;
  16032. PFILTER_EXTENSION filter = extension->Filter;
  16033. NTSTATUS status;
  16034. UNICODE_STRING fileName;
  16035. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  16036. VspFreeContext(extension->Root, context);
  16037. status = VspCheckForNtfs(extension);
  16038. if (!NT_SUCCESS(status)) {
  16039. VspLogError(NULL, filter, VS_ABORT_NON_NTFS_HIBER_VOLUME, status, 0,
  16040. FALSE);
  16041. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  16042. status = STATUS_SUCCESS;
  16043. goto Finish;
  16044. }
  16045. if (extension->HiberFileCopied) {
  16046. RtlInitUnicodeString(&fileName, L"hiberfil.sys");
  16047. status = VspCompareFileIds(extension, &fileName);
  16048. if (NT_SUCCESS(status)) {
  16049. goto Finish;
  16050. }
  16051. }
  16052. VspCantHibernatePopUp(filter);
  16053. status = STATUS_INVALID_DEVICE_REQUEST;
  16054. Finish:
  16055. irp->IoStatus.Status = status;
  16056. PoStartNextPowerIrp(irp);
  16057. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16058. }
  16059. NTSTATUS
  16060. VspHandleHibernateNotification(
  16061. IN PVOLUME_EXTENSION Extension,
  16062. IN PIRP Irp
  16063. )
  16064. {
  16065. PFILTER_EXTENSION filter = Extension->Filter;
  16066. KIRQL irql;
  16067. PVSP_CONTEXT context;
  16068. if (!(filter->Pdo->Flags&DO_SYSTEM_BOOT_PARTITION)) {
  16069. return STATUS_SUCCESS;
  16070. }
  16071. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16072. if (Extension->ListEntry.Flink != &filter->VolumeList) {
  16073. KeReleaseSpinLock(&filter->SpinLock, irql);
  16074. return STATUS_SUCCESS;
  16075. }
  16076. KeReleaseSpinLock(&filter->SpinLock, irql);
  16077. context = VspAllocateContext(Extension->Root);
  16078. if (!context) {
  16079. return STATUS_INSUFFICIENT_RESOURCES;
  16080. }
  16081. IoMarkIrpPending(Irp);
  16082. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  16083. ExInitializeWorkItem(&context->WorkItem, VspHandleHibernatePost, context);
  16084. context->Extension.Extension = Extension;
  16085. context->Extension.Irp = Irp;
  16086. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  16087. return STATUS_PENDING;
  16088. }
  16089. VOID
  16090. VspDismountCleanupOnWrite(
  16091. IN PVOID Context
  16092. )
  16093. {
  16094. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16095. PFILTER_EXTENSION filter = context->DismountCleanupOnWrite.Filter;
  16096. PIRP irp = context->DismountCleanupOnWrite.Irp;
  16097. PVOLUME_EXTENSION e;
  16098. KIRQL irql;
  16099. PLIST_ENTRY l;
  16100. PVSP_DIFF_AREA_FILE diffAreaFile;
  16101. PFILTER_EXTENSION f, df;
  16102. PRTL_BITMAP bitmap;
  16103. ASSERT(context->Type == VSP_CONTEXT_TYPE_DISMOUNT_CLEANUP);
  16104. for (;;) {
  16105. f = df = NULL;
  16106. e = NULL;
  16107. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16108. for (l = filter->DiffAreaFilesOnThisFilter.Flink;
  16109. l != &filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  16110. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  16111. FilterListEntry);
  16112. f = diffAreaFile->Extension->Filter;
  16113. if (f->SnapshotsPresent && !f->DestroyAllSnapshotsPending) {
  16114. e = diffAreaFile->Extension;
  16115. df = diffAreaFile->Filter;
  16116. ObReferenceObject(f->DeviceObject);
  16117. ObReferenceObject(e->DeviceObject);
  16118. ObReferenceObject(df->DeviceObject);
  16119. break;
  16120. }
  16121. }
  16122. KeReleaseSpinLock(&filter->SpinLock, irql);
  16123. if (l == &filter->DiffAreaFilesOnThisFilter) {
  16124. break;
  16125. }
  16126. if (VspDestroyAllSnapshots(f, NULL, FALSE, FALSE)) {
  16127. VspLogError(e, df, VS_ABORT_SNAPSHOTS_DISMOUNT, STATUS_SUCCESS, 2,
  16128. FALSE);
  16129. VspDeleteControlItemsWithGuid(f, NULL, TRUE);
  16130. }
  16131. ObDereferenceObject(f->DeviceObject);
  16132. ObDereferenceObject(e->DeviceObject);
  16133. ObDereferenceObject(df->DeviceObject);
  16134. }
  16135. if (filter->SnapshotsPresent && !filter->DestroyAllSnapshotsPending) {
  16136. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16137. if (IsListEmpty(&filter->VolumeList)) {
  16138. KeReleaseSpinLock(&filter->SpinLock, irql);
  16139. } else {
  16140. e = CONTAINING_RECORD(filter->VolumeList.Blink, VOLUME_EXTENSION,
  16141. ListEntry);
  16142. ObReferenceObject(e->DeviceObject);
  16143. KeReleaseSpinLock(&filter->SpinLock, irql);
  16144. if (VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE)) {
  16145. VspLogError(e, e->Filter, VS_ABORT_SNAPSHOTS_DISMOUNT_ORIGINAL,
  16146. STATUS_SUCCESS, 1, FALSE);
  16147. VspDeleteControlItemsWithGuid(filter, NULL, TRUE);
  16148. }
  16149. ObDereferenceObject(e->DeviceObject);
  16150. }
  16151. }
  16152. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16153. bitmap = (PRTL_BITMAP) InterlockedExchangePointer(
  16154. (PVOID*) &filter->ProtectedBlocksBitmap, NULL);
  16155. if (bitmap) {
  16156. ExFreePool(bitmap->Buffer);
  16157. ExFreePool(bitmap);
  16158. }
  16159. KeReleaseSpinLock(&filter->SpinLock, irql);
  16160. VspReleaseNonPagedResource(filter);
  16161. VspDecrementRefCount(filter);
  16162. VolSnapWrite(filter->DeviceObject, irp);
  16163. }
  16164. VOID
  16165. VspCreateStartBlockWorker(
  16166. IN PVOID Context
  16167. )
  16168. {
  16169. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16170. PFILTER_EXTENSION filter = context->Filter.Filter;
  16171. PIRP irp = context->Filter.Irp;
  16172. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  16173. VspCreateStartBlock(filter, filter->FirstControlBlockVolumeOffset,
  16174. filter->MaximumVolumeSpace);
  16175. VspReleaseNonPagedResource(filter);
  16176. VspDecrementRefCount(filter);
  16177. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  16178. }
  16179. NTSTATUS
  16180. VspWriteContextCompletionRoutine(
  16181. IN PDEVICE_OBJECT DeviceObject,
  16182. IN PIRP Irp,
  16183. IN PVOID WriteContext
  16184. )
  16185. {
  16186. PVSP_WRITE_CONTEXT writeContext = (PVSP_WRITE_CONTEXT) WriteContext;
  16187. PFILTER_EXTENSION filter = writeContext->Filter;
  16188. PVOLUME_EXTENSION extension = writeContext->Extension;
  16189. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  16190. KIRQL irql;
  16191. PLIST_ENTRY l;
  16192. PWORK_QUEUE_ITEM workItem;
  16193. PVSP_CONTEXT context;
  16194. ASSERT(Irp == writeContext->Irp);
  16195. KeAcquireSpinLock(&extension->SpinLock, &irql);
  16196. RemoveEntryList(&writeContext->ListEntry);
  16197. KeReleaseSpinLock(&extension->SpinLock, irql);
  16198. while (!IsListEmpty(&writeContext->CompletionRoutines)) {
  16199. l = RemoveHeadList(&writeContext->CompletionRoutines);
  16200. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  16201. workItem->WorkerRoutine(workItem->Parameter);
  16202. ExFreePool(workItem);
  16203. }
  16204. VspFreeWriteContext(filter->Root, writeContext);
  16205. if (!filter->ProtectedBlocksBitmap &&
  16206. irpSp->Parameters.Write.ByteOffset.QuadPart <=
  16207. VSP_START_BLOCK_OFFSET &&
  16208. irpSp->Parameters.Write.ByteOffset.QuadPart +
  16209. irpSp->Parameters.Write.Length > VSP_START_BLOCK_OFFSET) {
  16210. context = VspAllocateContext(filter->Root);
  16211. if (context) {
  16212. context->Type = VSP_CONTEXT_TYPE_FILTER;
  16213. ExInitializeWorkItem(&context->WorkItem, VspCreateStartBlockWorker,
  16214. context);
  16215. context->Filter.Filter = filter;
  16216. context->Filter.Irp = Irp;
  16217. VspAcquireNonPagedResource(filter, &context->WorkItem, TRUE);
  16218. return STATUS_MORE_PROCESSING_REQUIRED;
  16219. }
  16220. }
  16221. VspDecrementRefCount(filter);
  16222. return STATUS_SUCCESS;
  16223. }
  16224. VOID
  16225. VspCleanupDanglingSnapshots(
  16226. IN PVOID Filter,
  16227. IN NTSTATUS LogStatus,
  16228. IN ULONG LogUniqueId
  16229. )
  16230. {
  16231. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  16232. NTSTATUS status;
  16233. VspLogError(NULL, filter, VS_ABORT_NO_DIFF_AREA_VOLUME,
  16234. LogStatus, LogUniqueId, FALSE);
  16235. ObReferenceObject(filter->DeviceObject);
  16236. ObReferenceObject(filter->TargetObject);
  16237. VspDeleteControlItemsWithGuid(filter, NULL, FALSE);
  16238. InterlockedExchange(&filter->SnapshotDiscoveryPending, FALSE);
  16239. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  16240. FALSE);
  16241. ASSERT(filter->FirstWriteProcessed);
  16242. VspResumeVolumeIo(filter);
  16243. KeWaitForSingleObject(&filter->Root->PastBootReinit, Executive,
  16244. KernelMode, FALSE, NULL);
  16245. status = VspOpenControlBlockFile(filter);
  16246. if (!NT_SUCCESS(status)) {
  16247. VspAcquireNonPagedResource(filter, NULL, FALSE);
  16248. VspCreateStartBlock(filter, 0, filter->MaximumVolumeSpace);
  16249. filter->FirstControlBlockVolumeOffset = 0;
  16250. VspReleaseNonPagedResource(filter);
  16251. }
  16252. ObDereferenceObject(filter->TargetObject);
  16253. ObDereferenceObject(filter->DeviceObject);
  16254. }
  16255. VOID
  16256. VspPnpCleanupDangling(
  16257. IN PVOID Context
  16258. )
  16259. {
  16260. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16261. PFILTER_EXTENSION filter = context->PnpWaitTimer.Filter;
  16262. KIRQL irql;
  16263. PLIST_ENTRY l;
  16264. PVSP_COPY_ON_WRITE copyOnWrite;
  16265. ASSERT(context->Type == VSP_CONTEXT_TYPE_PNP_WAIT_TIMER);
  16266. VspFreeContext(filter->Root, context);
  16267. VspPauseVolumeIo(filter);
  16268. if (filter->SnapshotDiscoveryPending) {
  16269. VspCleanupDanglingSnapshots(filter, STATUS_SUCCESS, 1);
  16270. } else {
  16271. VspResumeVolumeIo(filter);
  16272. }
  16273. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16274. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  16275. l = RemoveHeadList(&filter->CopyOnWriteList);
  16276. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  16277. ExFreePool(copyOnWrite->Buffer);
  16278. ExFreePool(copyOnWrite);
  16279. }
  16280. KeReleaseSpinLock(&filter->SpinLock, irql);
  16281. ObDereferenceObject(filter->DeviceObject);
  16282. }
  16283. VOID
  16284. VspPnpTimerDpc(
  16285. IN PKDPC TimerDpc,
  16286. IN PVOID Context,
  16287. IN PVOID SystemArgument1,
  16288. IN PVOID SystemArgument2
  16289. )
  16290. {
  16291. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16292. PFILTER_EXTENSION filter = context->PnpWaitTimer.Filter;
  16293. KIRQL irql;
  16294. PLIST_ENTRY l;
  16295. PVSP_COPY_ON_WRITE copyOnWrite;
  16296. ASSERT(context->Type == VSP_CONTEXT_TYPE_PNP_WAIT_TIMER);
  16297. ExFreePool(context->PnpWaitTimer.Timer);
  16298. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16299. filter->PnpWaitTimerContext = NULL;
  16300. KeReleaseSpinLock(&filter->SpinLock, irql);
  16301. if (!filter->SnapshotDiscoveryPending) {
  16302. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16303. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  16304. l = RemoveHeadList(&filter->CopyOnWriteList);
  16305. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  16306. ExFreePool(copyOnWrite->Buffer);
  16307. ExFreePool(copyOnWrite);
  16308. }
  16309. KeReleaseSpinLock(&filter->SpinLock, irql);
  16310. VspFreeContext(filter->Root, context);
  16311. ObDereferenceObject(filter->DeviceObject);
  16312. return;
  16313. }
  16314. ExInitializeWorkItem(&context->WorkItem, VspPnpCleanupDangling,
  16315. context);
  16316. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  16317. }
  16318. VOID
  16319. VspStartCopyOnWriteCache(
  16320. IN PVOID Filter
  16321. )
  16322. {
  16323. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  16324. PVSP_LOOKUP_TABLE_ENTRY lookupEntry;
  16325. NTSTATUS status;
  16326. CHAR controlItemBuffer[VSP_BYTES_PER_CONTROL_ITEM];
  16327. PVSP_CONTROL_ITEM_SNAPSHOT snapshotControlItem = (PVSP_CONTROL_ITEM_SNAPSHOT) controlItemBuffer;
  16328. PVSP_CONTEXT context;
  16329. LARGE_INTEGER timeout;
  16330. KIRQL irql;
  16331. ASSERT(!IsListEmpty(&filter->SnapshotLookupTableEntries));
  16332. lookupEntry = CONTAINING_RECORD(filter->SnapshotLookupTableEntries.Blink,
  16333. VSP_LOOKUP_TABLE_ENTRY,
  16334. SnapshotFilterListEntry);
  16335. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  16336. &lookupEntry->SnapshotGuid, FALSE,
  16337. controlItemBuffer, TRUE);
  16338. if (!NT_SUCCESS(status)) {
  16339. VspCleanupDanglingSnapshots(Filter, status, 2);
  16340. ObDereferenceObject(filter->DeviceObject);
  16341. return;
  16342. }
  16343. if (snapshotControlItem->SnapshotControlItemFlags&
  16344. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION) {
  16345. VspCleanupDanglingSnapshots(Filter, STATUS_SUCCESS, 3);
  16346. ObDereferenceObject(filter->DeviceObject);
  16347. return;
  16348. }
  16349. snapshotControlItem->SnapshotControlItemFlags |=
  16350. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION;
  16351. status = VspIoControlItem(filter, VSP_CONTROL_ITEM_TYPE_SNAPSHOT,
  16352. &lookupEntry->SnapshotGuid, TRUE,
  16353. controlItemBuffer, TRUE);
  16354. if (!NT_SUCCESS(status)) {
  16355. VspCleanupDanglingSnapshots(Filter, status, 4);
  16356. ObDereferenceObject(filter->DeviceObject);
  16357. return;
  16358. }
  16359. ASSERT(lookupEntry->SnapshotControlItemFlags&
  16360. VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION);
  16361. lookupEntry->SnapshotControlItemFlags &=
  16362. ~VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION;
  16363. context = VspAllocateContext(filter->Root);
  16364. if (!context) {
  16365. VspCleanupDanglingSnapshots(Filter, STATUS_INSUFFICIENT_RESOURCES, 5);
  16366. ObDereferenceObject(filter->DeviceObject);
  16367. return;
  16368. }
  16369. context->Type = VSP_CONTEXT_TYPE_PNP_WAIT_TIMER;
  16370. context->PnpWaitTimer.Filter = filter;
  16371. KeInitializeDpc(&context->PnpWaitTimer.TimerDpc,
  16372. VspPnpTimerDpc, context);
  16373. context->PnpWaitTimer.Timer = (PKTIMER)
  16374. ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER),
  16375. VOLSNAP_TAG_SHORT_TERM);
  16376. if (!context->PnpWaitTimer.Timer) {
  16377. VspFreeContext(filter->Root, context);
  16378. VspCleanupDanglingSnapshots(Filter, STATUS_INSUFFICIENT_RESOURCES, 6);
  16379. ObDereferenceObject(filter->DeviceObject);
  16380. return;
  16381. }
  16382. KeInitializeTimer(context->PnpWaitTimer.Timer);
  16383. ObReferenceObject(filter->DeviceObject);
  16384. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16385. filter->PnpWaitTimerContext = context;
  16386. KeReleaseSpinLock(&filter->SpinLock, irql);
  16387. timeout.QuadPart = (LONGLONG) -10*1000*1000*30; // 30 seconds.
  16388. KeSetTimer(context->PnpWaitTimer.Timer, timeout,
  16389. &context->PnpWaitTimer.TimerDpc);
  16390. VspResumeVolumeIo(filter);
  16391. ObDereferenceObject(filter->DeviceObject);
  16392. }
  16393. VOID
  16394. VspAbortCopyOnWrites(
  16395. IN PFILTER_EXTENSION Filter,
  16396. IN PIRP Irp
  16397. )
  16398. {
  16399. KIRQL irql;
  16400. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  16401. if (Filter->PnpWaitTimerContext &&
  16402. KeCancelTimer(Filter->PnpWaitTimerContext->PnpWaitTimer.Timer)) {
  16403. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16404. VspPnpTimerDpc(NULL, Filter->PnpWaitTimerContext, NULL, NULL);
  16405. } else {
  16406. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16407. }
  16408. if (!Irp->MdlAddress) {
  16409. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  16410. Irp->IoStatus.Information = 0;
  16411. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  16412. VspDecrementRefCount(Filter);
  16413. return;
  16414. }
  16415. IoCopyCurrentIrpStackLocationToNext(Irp);
  16416. IoSetCompletionRoutine(Irp, VspRefCountCompletionRoutine, Filter, TRUE,
  16417. TRUE, TRUE);
  16418. IoCallDriver(Filter->TargetObject, Irp);
  16419. }
  16420. NTSTATUS
  16421. VspCopyOnWriteReadCompletion(
  16422. IN PDEVICE_OBJECT DeviceObject,
  16423. IN PIRP Irp,
  16424. IN PVOID Context
  16425. )
  16426. {
  16427. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16428. PFILTER_EXTENSION filter = context->CopyOnWrite.Filter;
  16429. PIRP irp = context->CopyOnWrite.Irp;
  16430. NTSTATUS status = Irp->IoStatus.Status;
  16431. PVSP_COPY_ON_WRITE copyOnWrite, cow;
  16432. KIRQL irql;
  16433. PLIST_ENTRY l;
  16434. ASSERT(context->Type == VSP_CONTEXT_TYPE_COPY_ON_WRITE);
  16435. if (!NT_SUCCESS(status)) {
  16436. VspFreeContext(filter->Root, context);
  16437. ExFreePool(MmGetMdlVirtualAddress(Irp->MdlAddress));
  16438. IoFreeMdl(Irp->MdlAddress);
  16439. IoFreeIrp(Irp);
  16440. VspAbortCopyOnWrites(filter, irp);
  16441. return STATUS_MORE_PROCESSING_REQUIRED;
  16442. }
  16443. copyOnWrite = (PVSP_COPY_ON_WRITE)
  16444. ExAllocatePoolWithTag(NonPagedPool,
  16445. sizeof(VSP_COPY_ON_WRITE),
  16446. VOLSNAP_TAG_COPY);
  16447. if (!copyOnWrite) {
  16448. VspFreeContext(filter->Root, context);
  16449. ExFreePool(MmGetMdlVirtualAddress(Irp->MdlAddress));
  16450. IoFreeMdl(Irp->MdlAddress);
  16451. IoFreeIrp(Irp);
  16452. VspAbortCopyOnWrites(filter, irp);
  16453. return STATUS_MORE_PROCESSING_REQUIRED;
  16454. }
  16455. copyOnWrite->RoundedStart = context->CopyOnWrite.RoundedStart;
  16456. copyOnWrite->Buffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
  16457. IoFreeMdl(Irp->MdlAddress);
  16458. IoFreeIrp(Irp);
  16459. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16460. for (l = filter->CopyOnWriteList.Flink; l != &filter->CopyOnWriteList;
  16461. l = l->Flink) {
  16462. cow = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  16463. if (copyOnWrite->RoundedStart == cow->RoundedStart) {
  16464. break;
  16465. }
  16466. }
  16467. if (l == &filter->CopyOnWriteList) {
  16468. InsertTailList(&filter->CopyOnWriteList, &copyOnWrite->ListEntry);
  16469. } else {
  16470. ExFreePool(copyOnWrite->Buffer);
  16471. ExFreePool(copyOnWrite);
  16472. }
  16473. KeReleaseSpinLock(&filter->SpinLock, irql);
  16474. context->CopyOnWrite.RoundedStart += BLOCK_SIZE;
  16475. VspStartCopyOnWrite(context);
  16476. return STATUS_MORE_PROCESSING_REQUIRED;
  16477. }
  16478. VOID
  16479. VspStartCopyOnWrite(
  16480. IN PVOID Context
  16481. )
  16482. {
  16483. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16484. PFILTER_EXTENSION filter = context->CopyOnWrite.Filter;
  16485. LONGLONG roundedStart = context->CopyOnWrite.RoundedStart;
  16486. LONGLONG roundedEnd = context->CopyOnWrite.RoundedEnd;
  16487. KIRQL irql;
  16488. PLIST_ENTRY l;
  16489. PVSP_COPY_ON_WRITE copyOnWrite;
  16490. PIRP irp;
  16491. PMDL mdl;
  16492. PVOID buffer;
  16493. PIO_STACK_LOCATION nextSp;
  16494. ASSERT(context->Type == VSP_CONTEXT_TYPE_COPY_ON_WRITE);
  16495. for (; roundedStart < roundedEnd; roundedStart += BLOCK_SIZE) {
  16496. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16497. for (l = filter->CopyOnWriteList.Flink;
  16498. l != &filter->CopyOnWriteList; l = l->Flink) {
  16499. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE, ListEntry);
  16500. if (copyOnWrite->RoundedStart == roundedStart) {
  16501. break;
  16502. }
  16503. }
  16504. KeReleaseSpinLock(&filter->SpinLock, irql);
  16505. if (l != &filter->CopyOnWriteList) {
  16506. continue;
  16507. }
  16508. irp = IoAllocateIrp(filter->TargetObject->StackSize, FALSE);
  16509. buffer = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE,
  16510. VOLSNAP_TAG_BUFFER);
  16511. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  16512. if (!irp || !buffer || !mdl) {
  16513. if (irp) {
  16514. IoFreeIrp(irp);
  16515. }
  16516. if (mdl) {
  16517. IoFreeMdl(mdl);
  16518. }
  16519. if (buffer) {
  16520. ExFreePool(buffer);
  16521. }
  16522. irp = context->CopyOnWrite.Irp;
  16523. VspFreeContext(filter->Root, context);
  16524. VspAbortCopyOnWrites(filter, irp);
  16525. return;
  16526. }
  16527. context->CopyOnWrite.RoundedStart = roundedStart;
  16528. MmBuildMdlForNonPagedPool(mdl);
  16529. irp->MdlAddress = mdl;
  16530. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  16531. nextSp = IoGetNextIrpStackLocation(irp);
  16532. nextSp->Parameters.Read.ByteOffset.QuadPart = roundedStart;
  16533. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  16534. nextSp->MajorFunction = IRP_MJ_READ;
  16535. nextSp->DeviceObject = filter->TargetObject;
  16536. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  16537. IoSetCompletionRoutine(irp, VspCopyOnWriteReadCompletion,
  16538. context, TRUE, TRUE, TRUE);
  16539. IoCallDriver(nextSp->DeviceObject, irp);
  16540. return;
  16541. }
  16542. irp = context->CopyOnWrite.Irp;
  16543. VspFreeContext(filter->Root, context);
  16544. if (!irp->MdlAddress) {
  16545. irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  16546. irp->IoStatus.Information = 0;
  16547. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16548. VspDecrementRefCount(filter);
  16549. return;
  16550. }
  16551. IoCopyCurrentIrpStackLocationToNext(irp);
  16552. IoSetCompletionRoutine(irp, VspRefCountCompletionRoutine, filter,
  16553. TRUE, TRUE, TRUE);
  16554. IoCallDriver(filter->TargetObject, irp);
  16555. }
  16556. VOID
  16557. VspCopyOnWriteToNonPagedPool(
  16558. IN PFILTER_EXTENSION Filter,
  16559. IN PIRP Irp
  16560. )
  16561. {
  16562. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  16563. PVSP_CONTEXT context;
  16564. context = VspAllocateContext(Filter->Root);
  16565. if (!context) {
  16566. VspAbortCopyOnWrites(Filter, Irp);
  16567. return;
  16568. }
  16569. context->Type = VSP_CONTEXT_TYPE_COPY_ON_WRITE;
  16570. context->CopyOnWrite.Filter = Filter;
  16571. context->CopyOnWrite.Irp = Irp;
  16572. context->CopyOnWrite.RoundedStart =
  16573. irpSp->Parameters.Write.ByteOffset.QuadPart&(~(BLOCK_SIZE - 1));
  16574. context->CopyOnWrite.RoundedEnd =
  16575. (irpSp->Parameters.Write.ByteOffset.QuadPart +
  16576. irpSp->Parameters.Write.Length + BLOCK_SIZE - 1)&
  16577. (~(BLOCK_SIZE - 1));
  16578. VspStartCopyOnWrite(context);
  16579. }
  16580. #ifdef ALLOC_PRAGMA
  16581. #pragma code_seg()
  16582. #endif
  16583. #if DBG
  16584. VOID
  16585. VspCheckDiffAreaFile(
  16586. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  16587. )
  16588. {
  16589. LONGLONG fileOffset;
  16590. PLIST_ENTRY l;
  16591. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  16592. _try {
  16593. fileOffset = DiffAreaFile->NextAvailable;
  16594. for (l = DiffAreaFile->UnusedAllocationList.Flink;
  16595. l != &DiffAreaFile->UnusedAllocationList; l = l->Flink) {
  16596. diffAreaFileAllocation = CONTAINING_RECORD(l,
  16597. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  16598. if (diffAreaFileAllocation->NLength < 0) {
  16599. fileOffset -= diffAreaFileAllocation->NLength;
  16600. } else {
  16601. fileOffset += diffAreaFileAllocation->NLength;
  16602. }
  16603. }
  16604. ASSERT(fileOffset == DiffAreaFile->AllocatedFileSize);
  16605. } _except (EXCEPTION_EXECUTE_HANDLER) {
  16606. }
  16607. }
  16608. #endif
  16609. VOID
  16610. VspLowPriorityWorkItem(
  16611. IN PVOID RootExtension
  16612. )
  16613. {
  16614. PDO_EXTENSION root = (PDO_EXTENSION) RootExtension;
  16615. KIRQL irql;
  16616. PLIST_ENTRY l;
  16617. for (;;) {
  16618. root->ActualLowPriorityWorkItem->WorkerRoutine(
  16619. root->ActualLowPriorityWorkItem->Parameter);
  16620. KeAcquireSpinLock(&root->ESpinLock, &irql);
  16621. if (IsListEmpty(&root->LowPriorityQueue)) {
  16622. root->WorkerItemInUse = FALSE;
  16623. KeReleaseSpinLock(&root->ESpinLock, irql);
  16624. return;
  16625. }
  16626. l = RemoveHeadList(&root->LowPriorityQueue);
  16627. KeReleaseSpinLock(&root->ESpinLock, irql);
  16628. root->ActualLowPriorityWorkItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM,
  16629. List);
  16630. }
  16631. }
  16632. VOID
  16633. VspQueueLowPriorityWorkItem(
  16634. IN PDO_EXTENSION RootExtension,
  16635. IN PWORK_QUEUE_ITEM WorkItem
  16636. )
  16637. {
  16638. KIRQL irql;
  16639. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  16640. if (RootExtension->WorkerItemInUse) {
  16641. InsertTailList(&RootExtension->LowPriorityQueue, &WorkItem->List);
  16642. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  16643. return;
  16644. }
  16645. RootExtension->WorkerItemInUse = TRUE;
  16646. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  16647. RootExtension->ActualLowPriorityWorkItem = WorkItem;
  16648. ExInitializeWorkItem(&RootExtension->LowPriorityWorkItem,
  16649. VspLowPriorityWorkItem, RootExtension);
  16650. ExQueueWorkItem(&RootExtension->LowPriorityWorkItem, DelayedWorkQueue);
  16651. }
  16652. VOID
  16653. VspCleanupPreamble(
  16654. IN PFILTER_EXTENSION Filter
  16655. )
  16656. {
  16657. KIRQL irql;
  16658. if (!Filter->IsOnline) {
  16659. return;
  16660. }
  16661. Filter->IsOnline = FALSE;
  16662. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  16663. if (Filter->SnapshotDiscoveryPending && !Filter->ActivateStarted &&
  16664. !Filter->FirstWriteProcessed) {
  16665. InterlockedExchange(&Filter->SnapshotDiscoveryPending, FALSE);
  16666. InterlockedExchange(&Filter->FirstWriteProcessed, TRUE);
  16667. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16668. } else {
  16669. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16670. VspPauseVolumeIo(Filter);
  16671. }
  16672. VspResumeVolumeIo(Filter);
  16673. }
  16674. VOID
  16675. VspOfflineWorker(
  16676. IN PVOID Context
  16677. )
  16678. {
  16679. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16680. PFILTER_EXTENSION filter = context->Filter.Filter;
  16681. PIRP irp = context->Filter.Irp;
  16682. KEVENT event;
  16683. KIRQL irql;
  16684. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  16685. VspFreeContext(filter->Root, context);
  16686. KeInitializeEvent(&event, NotificationEvent, FALSE);
  16687. IoCopyCurrentIrpStackLocationToNext(irp);
  16688. IoSetCompletionRoutine(irp, VspSignalCompletion, &event, TRUE, TRUE,
  16689. TRUE);
  16690. IoCallDriver(filter->TargetObject, irp);
  16691. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  16692. if (!NT_SUCCESS(irp->IoStatus.Status)) {
  16693. VspRelease(filter->Root);
  16694. VspReleaseCritical(filter);
  16695. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16696. return;
  16697. }
  16698. VspCleanupPreamble(filter);
  16699. VspRelease(filter->Root);
  16700. VspCleanupFilter(filter, TRUE, FALSE);
  16701. VspReleaseCritical(filter);
  16702. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16703. }
  16704. VOID
  16705. VspStartDiffAreaFileCleanupTimer(
  16706. IN PFILTER_EXTENSION Filter
  16707. )
  16708. {
  16709. PKTIMER timer;
  16710. PKDPC dpc;
  16711. PVSP_CONTEXT context;
  16712. LARGE_INTEGER timeout;
  16713. timer = (PKTIMER) ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER),
  16714. VOLSNAP_TAG_SHORT_TERM);
  16715. if (!timer) {
  16716. return;
  16717. }
  16718. dpc = (PKDPC) ExAllocatePoolWithTag(NonPagedPool, sizeof(KDPC),
  16719. VOLSNAP_TAG_SHORT_TERM);
  16720. if (!dpc) {
  16721. ExFreePool(timer);
  16722. return;
  16723. }
  16724. context = VspAllocateContext(Filter->Root);
  16725. if (!context) {
  16726. ExFreePool(dpc);
  16727. ExFreePool(timer);
  16728. return;
  16729. }
  16730. context->Type = VSP_CONTEXT_TYPE_DELETE_DA_FILES;
  16731. context->DeleteDiffAreaFiles.Filter = Filter;
  16732. context->DeleteDiffAreaFiles.Timer = timer;
  16733. context->DeleteDiffAreaFiles.Dpc = dpc;
  16734. ObReferenceObject(Filter->DeviceObject);
  16735. KeInitializeTimer(timer);
  16736. KeInitializeDpc(dpc, VspDeleteDiffAreaFilesTimerDpc, context);
  16737. Filter->DeleteTimer = timer;
  16738. timeout.QuadPart = (LONGLONG) 21*60*(-10*1000*1000); // 21 minutes.
  16739. KeSetTimer(timer, timeout, dpc);
  16740. }
  16741. BOOLEAN
  16742. FtpSupportsOnlineOffline(
  16743. IN PFILTER_EXTENSION Filter
  16744. )
  16745. {
  16746. KEVENT event;
  16747. PIRP irp;
  16748. IO_STATUS_BLOCK ioStatus;
  16749. NTSTATUS status;
  16750. KeInitializeEvent(&event, NotificationEvent, FALSE);
  16751. irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE,
  16752. Filter->TargetObject, NULL, 0,
  16753. NULL, 0, FALSE, &event, &ioStatus);
  16754. if (!irp) {
  16755. return FALSE;
  16756. }
  16757. status = IoCallDriver(Filter->TargetObject, irp);
  16758. if (status == STATUS_PENDING) {
  16759. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  16760. status = ioStatus.Status;
  16761. }
  16762. if (!NT_SUCCESS(status)) {
  16763. return FALSE;
  16764. }
  16765. return TRUE;
  16766. }
  16767. VOID
  16768. VspOnlineWorker(
  16769. IN PVOID Context
  16770. )
  16771. {
  16772. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  16773. PFILTER_EXTENSION filter = context->Filter.Filter;
  16774. PIRP irp = context->Filter.Irp;
  16775. KEVENT event;
  16776. BOOLEAN noControlItems;
  16777. KIRQL irql;
  16778. ASSERT(context->Type == VSP_CONTEXT_TYPE_FILTER);
  16779. VspFreeContext(filter->Root, context);
  16780. filter->IsOnline = TRUE;
  16781. filter->IsRemoved = FALSE;
  16782. VspPauseVolumeIo(filter);
  16783. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16784. InterlockedExchange(&filter->FirstWriteProcessed, FALSE);
  16785. filter->ActivateStarted = FALSE;
  16786. KeReleaseSpinLock(&filter->SpinLock, irql);
  16787. KeInitializeEvent(&event, NotificationEvent, FALSE);
  16788. IoCopyCurrentIrpStackLocationToNext(irp);
  16789. IoSetCompletionRoutine(irp, VspSignalCompletion, &event, TRUE, TRUE, TRUE);
  16790. IoCallDriver(filter->TargetObject, irp);
  16791. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  16792. if (!NT_SUCCESS(irp->IoStatus.Status)) {
  16793. if (FtpSupportsOnlineOffline(filter)) {
  16794. filter->IsOnline = FALSE;
  16795. VspResumeVolumeIo(filter);
  16796. VspRelease(filter->Root);
  16797. VspReleaseCritical(filter);
  16798. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16799. return;
  16800. }
  16801. }
  16802. VspDiscoverSnapshots(filter, &noControlItems);
  16803. if (!filter->SnapshotDiscoveryPending) {
  16804. if (filter->FirstControlBlockVolumeOffset &&
  16805. !filter->SnapshotsPresent && !noControlItems) {
  16806. VspLaunchOpenControlBlockFileWorker(filter);
  16807. }
  16808. }
  16809. VspRelease(filter->Root);
  16810. VspStartDiffAreaFileCleanupTimer(filter);
  16811. VspReleaseCritical(filter);
  16812. IoCompleteRequest(irp, IO_NO_INCREMENT);
  16813. }
  16814. NTSTATUS
  16815. VspAbortPreparedSnapshot(
  16816. IN PFILTER_EXTENSION Filter,
  16817. IN BOOLEAN NeedLock,
  16818. IN BOOLEAN IsFinalRemove
  16819. )
  16820. /*++
  16821. Routine Description:
  16822. This routine aborts the prepared snapshot.
  16823. Arguments:
  16824. Filter - Supplies the filter extension.
  16825. Return Value:
  16826. NTSTATUS
  16827. --*/
  16828. {
  16829. KIRQL irql;
  16830. PVOLUME_EXTENSION extension;
  16831. if (NeedLock) {
  16832. VspAcquire(Filter->Root);
  16833. }
  16834. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  16835. extension = Filter->PreparedSnapshot;
  16836. Filter->PreparedSnapshot = NULL;
  16837. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16838. if (NeedLock) {
  16839. VspRelease(Filter->Root);
  16840. }
  16841. if (!extension) {
  16842. return STATUS_INVALID_PARAMETER;
  16843. }
  16844. VspCleanupInitialSnapshot(extension, NeedLock, IsFinalRemove);
  16845. return STATUS_SUCCESS;
  16846. }
  16847. VOID
  16848. VspAcquireNonPagedResource(
  16849. IN PDEVICE_EXTENSION Extension,
  16850. IN PWORK_QUEUE_ITEM WorkItem,
  16851. IN BOOLEAN AlwaysPost
  16852. )
  16853. {
  16854. PFILTER_EXTENSION filter;
  16855. KIRQL irql;
  16856. VSP_CONTEXT context;
  16857. BOOLEAN synchronousCall;
  16858. if (Extension->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  16859. filter = (PFILTER_EXTENSION) Extension;
  16860. } else {
  16861. filter = ((PVOLUME_EXTENSION) Extension)->Filter;
  16862. }
  16863. if (WorkItem) {
  16864. synchronousCall = FALSE;
  16865. } else {
  16866. WorkItem = &context.WorkItem;
  16867. context.Type = VSP_CONTEXT_TYPE_EVENT;
  16868. KeInitializeEvent(&context.Event.Event, NotificationEvent, FALSE);
  16869. ExInitializeWorkItem(&context.WorkItem, VspSignalContext, &context);
  16870. synchronousCall = TRUE;
  16871. }
  16872. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16873. if (filter->NonPagedResourceInUse) {
  16874. InsertTailList(&filter->NonPagedResourceList, &WorkItem->List);
  16875. KeReleaseSpinLock(&filter->SpinLock, irql);
  16876. if (synchronousCall) {
  16877. KeWaitForSingleObject(&context.Event.Event, Executive,
  16878. KernelMode, FALSE, NULL);
  16879. }
  16880. return;
  16881. }
  16882. filter->NonPagedResourceInUse = TRUE;
  16883. KeReleaseSpinLock(&filter->SpinLock, irql);
  16884. if (!synchronousCall) {
  16885. if (AlwaysPost) {
  16886. VspQueueWorkItem(filter->Root, WorkItem, 2);
  16887. } else {
  16888. WorkItem->WorkerRoutine(WorkItem->Parameter);
  16889. }
  16890. }
  16891. }
  16892. VOID
  16893. VspReleaseNonPagedResource(
  16894. IN PDEVICE_EXTENSION Extension
  16895. )
  16896. {
  16897. PFILTER_EXTENSION filter;
  16898. KIRQL irql;
  16899. PLIST_ENTRY l;
  16900. PWORK_QUEUE_ITEM workItem;
  16901. PVOLUME_EXTENSION extension;
  16902. if (Extension->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  16903. filter = (PFILTER_EXTENSION) Extension;
  16904. } else {
  16905. filter = ((PVOLUME_EXTENSION) Extension)->Filter;
  16906. }
  16907. KeAcquireSpinLock(&filter->SpinLock, &irql);
  16908. #if DBG
  16909. if (!IsListEmpty(&filter->VolumeList)) {
  16910. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  16911. VOLUME_EXTENSION, ListEntry);
  16912. if (extension->DiffAreaFile) {
  16913. VspCheckDiffAreaFile(extension->DiffAreaFile);
  16914. }
  16915. }
  16916. #endif
  16917. if (IsListEmpty(&filter->NonPagedResourceList)) {
  16918. filter->NonPagedResourceInUse = FALSE;
  16919. KeReleaseSpinLock(&filter->SpinLock, irql);
  16920. return;
  16921. }
  16922. l = RemoveHeadList(&filter->NonPagedResourceList);
  16923. KeReleaseSpinLock(&filter->SpinLock, irql);
  16924. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  16925. if (workItem->WorkerRoutine == VspSignalContext) {
  16926. workItem->WorkerRoutine(workItem->Parameter);
  16927. } else {
  16928. VspQueueWorkItem(Extension->Root, workItem, 2);
  16929. }
  16930. }
  16931. VOID
  16932. VspDeleteDiffAreaFilesTimerDpc(
  16933. IN struct _KDPC *Dpc,
  16934. IN PVOID DeferredContext,
  16935. IN PVOID SystemArgument1,
  16936. IN PVOID SystemArgument2
  16937. )
  16938. {
  16939. PVSP_CONTEXT context = (PVSP_CONTEXT) DeferredContext;
  16940. PFILTER_EXTENSION filter = context->DeleteDiffAreaFiles.Filter;
  16941. ASSERT(context->Type == VSP_CONTEXT_TYPE_DELETE_DA_FILES);
  16942. ExInitializeWorkItem(&context->WorkItem, VspDeleteDiffAreaFilesWorker,
  16943. context);
  16944. VspQueueLowPriorityWorkItem(filter->Root, &context->WorkItem);
  16945. }
  16946. VOID
  16947. VspResumeVolumeIo(
  16948. IN PFILTER_EXTENSION Filter
  16949. )
  16950. {
  16951. KIRQL irql;
  16952. BOOLEAN emptyQueue;
  16953. LIST_ENTRY q;
  16954. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  16955. ASSERT(Filter->HoldIncomingWrites);
  16956. InterlockedIncrement(&Filter->RefCount);
  16957. InterlockedDecrement(&Filter->HoldIncomingWrites);
  16958. if (Filter->HoldIncomingWrites) {
  16959. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16960. VspDecrementRefCount(Filter);
  16961. KeReleaseSemaphore(&Filter->ZeroRefSemaphore, IO_NO_INCREMENT, 1,
  16962. FALSE);
  16963. return;
  16964. }
  16965. if (IsListEmpty(&Filter->HoldQueue)) {
  16966. emptyQueue = FALSE;
  16967. } else {
  16968. emptyQueue = TRUE;
  16969. q = Filter->HoldQueue;
  16970. InitializeListHead(&Filter->HoldQueue);
  16971. }
  16972. KeResetEvent(&Filter->ZeroRefEvent);
  16973. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16974. KeReleaseSemaphore(&Filter->ZeroRefSemaphore, IO_NO_INCREMENT, 1, FALSE);
  16975. if (emptyQueue) {
  16976. q.Blink->Flink = &q;
  16977. q.Flink->Blink = &q;
  16978. VspEmptyIrpQueue(Filter->Root->DriverObject, &q);
  16979. }
  16980. }
  16981. VOID
  16982. VspPauseVolumeIo(
  16983. IN PFILTER_EXTENSION Filter
  16984. )
  16985. {
  16986. KIRQL irql;
  16987. KeWaitForSingleObject(&Filter->ZeroRefSemaphore, Executive, KernelMode,
  16988. FALSE, NULL);
  16989. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  16990. if (Filter->HoldIncomingWrites) {
  16991. InterlockedIncrement(&Filter->HoldIncomingWrites);
  16992. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16993. } else {
  16994. InterlockedIncrement(&Filter->HoldIncomingWrites);
  16995. KeReleaseSpinLock(&Filter->SpinLock, irql);
  16996. VspDecrementRefCount(Filter);
  16997. }
  16998. KeWaitForSingleObject(&Filter->ZeroRefEvent, Executive, KernelMode, FALSE,
  16999. NULL);
  17000. }
  17001. NTSTATUS
  17002. VspSignalCompletion(
  17003. IN PDEVICE_OBJECT DeviceObject,
  17004. IN PIRP Irp,
  17005. IN PVOID Event
  17006. )
  17007. {
  17008. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  17009. return STATUS_MORE_PROCESSING_REQUIRED;
  17010. }
  17011. NTSTATUS
  17012. VspReleaseWrites(
  17013. IN PFILTER_EXTENSION Filter
  17014. )
  17015. /*++
  17016. Routine Description:
  17017. This routine releases previously queued writes. If the writes have
  17018. already been dequeued by a timeout of have never actually been queued
  17019. for some other reason then this routine fails.
  17020. Arguments:
  17021. Filter - Supplies the filter extension.
  17022. Irp - Supplies the I/O request packet.
  17023. Return Value:
  17024. NTSTATUS
  17025. --*/
  17026. {
  17027. KIRQL irql;
  17028. LONG r;
  17029. LIST_ENTRY q;
  17030. PLIST_ENTRY l;
  17031. PIRP irp;
  17032. BOOLEAN emptyQueue;
  17033. if (!KeCancelTimer(&Filter->HoldWritesTimer)) {
  17034. r = InterlockedExchange(&Filter->LastReleaseDueToMemoryPressure,
  17035. FALSE);
  17036. return r ? STATUS_INSUFFICIENT_RESOURCES : STATUS_INVALID_PARAMETER;
  17037. }
  17038. VspIrpsTimerDpc(NULL, Filter, NULL, NULL);
  17039. return STATUS_SUCCESS;
  17040. }
  17041. VOID
  17042. VspDecrementRefCount(
  17043. IN PFILTER_EXTENSION Filter
  17044. )
  17045. {
  17046. KIRQL irql;
  17047. ZERO_REF_CALLBACK callback;
  17048. if (InterlockedDecrement(&Filter->RefCount)) {
  17049. return;
  17050. }
  17051. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  17052. callback = Filter->ZeroRefCallback;
  17053. Filter->ZeroRefCallback = NULL;
  17054. KeReleaseSpinLock(&Filter->SpinLock, irql);
  17055. if (callback) {
  17056. callback(Filter);
  17057. }
  17058. KeSetEvent(&Filter->ZeroRefEvent, IO_NO_INCREMENT, FALSE);
  17059. }
  17060. VOID
  17061. VspCleanupFilter(
  17062. IN PFILTER_EXTENSION Filter,
  17063. IN BOOLEAN IsOffline,
  17064. IN BOOLEAN IsFinalRemove
  17065. )
  17066. /*++
  17067. Routine Description:
  17068. This routine cleans up filter extension data because of an IRP_MN_REMOVE.
  17069. Arguments:
  17070. Filter - Supplies the filter extension.
  17071. Return Value:
  17072. None.
  17073. --*/
  17074. {
  17075. KIRQL irql;
  17076. PIRP irp;
  17077. PRTL_BITMAP bitmap;
  17078. PLIST_ENTRY l, ll;
  17079. PVSP_DIFF_AREA_FILE diffAreaFile;
  17080. PFILTER_EXTENSION f;
  17081. LIST_ENTRY listOfDiffAreaFilesToClose;
  17082. LIST_ENTRY listOfDeviceObjectsToDelete;
  17083. HANDLE h, hh;
  17084. FILE_DISPOSITION_INFORMATION dispInfo;
  17085. IO_STATUS_BLOCK ioStatus;
  17086. PVOLUME_EXTENSION extension;
  17087. BOOLEAN b;
  17088. Filter->DeleteTimer = NULL;
  17089. IoAcquireCancelSpinLock(&irql);
  17090. irp = Filter->FlushAndHoldIrp;
  17091. if (irp) {
  17092. irp->CancelIrql = irql;
  17093. IoSetCancelRoutine(irp, NULL);
  17094. VspCancelRoutine(Filter->DeviceObject, irp);
  17095. } else {
  17096. IoReleaseCancelSpinLock(irql);
  17097. }
  17098. VspReleaseWrites(Filter);
  17099. VspAcquire(Filter->Root);
  17100. Filter->IsRemoved = TRUE;
  17101. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  17102. bitmap = (PRTL_BITMAP) InterlockedExchangePointer(
  17103. (PVOID*) &Filter->ProtectedBlocksBitmap, NULL);
  17104. if (bitmap) {
  17105. ExFreePool(bitmap->Buffer);
  17106. ExFreePool(bitmap);
  17107. }
  17108. KeReleaseSpinLock(&Filter->SpinLock, irql);
  17109. VspRelease(Filter->Root);
  17110. VspAbortPreparedSnapshot(Filter, TRUE, IsFinalRemove);
  17111. InitializeListHead(&listOfDiffAreaFilesToClose);
  17112. InitializeListHead(&listOfDeviceObjectsToDelete);
  17113. VspAcquire(Filter->Root);
  17114. b = FALSE;
  17115. while (!IsListEmpty(&Filter->VolumeList)) {
  17116. VspDeleteOldestSnapshot(Filter, &listOfDiffAreaFilesToClose,
  17117. &listOfDeviceObjectsToDelete, TRUE, TRUE);
  17118. b = TRUE;
  17119. }
  17120. if (b && !IsFinalRemove) {
  17121. IoInvalidateDeviceRelations(Filter->Pdo, BusRelations);
  17122. }
  17123. if (!IsOffline && !Filter->NotInFilterList) {
  17124. RemoveEntryList(&Filter->ListEntry);
  17125. Filter->NotInFilterList = TRUE;
  17126. }
  17127. if (!IsOffline) {
  17128. Filter->DiffAreaVolume = NULL;
  17129. for (l = Filter->Root->FilterList.Flink;
  17130. l != &Filter->Root->FilterList; l = l->Flink) {
  17131. f = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  17132. if (f->DiffAreaVolume == Filter) {
  17133. f->DiffAreaVolume = NULL;
  17134. }
  17135. }
  17136. }
  17137. while (!IsListEmpty(&Filter->DiffAreaFilesOnThisFilter)) {
  17138. l = Filter->DiffAreaFilesOnThisFilter.Flink;
  17139. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  17140. FilterListEntry);
  17141. f = diffAreaFile->Extension->Filter;
  17142. if (IsOffline) {
  17143. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  17144. VS_ABORT_SNAPSHOTS_OFFLINE, STATUS_SUCCESS, 0,
  17145. TRUE);
  17146. } else {
  17147. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  17148. VS_ABORT_SNAPSHOTS_DISMOUNT, STATUS_SUCCESS, 3,
  17149. TRUE);
  17150. }
  17151. VspAbortPreparedSnapshot(f, FALSE, FALSE);
  17152. b = FALSE;
  17153. while (!IsListEmpty(&f->VolumeList)) {
  17154. VspDeleteOldestSnapshot(f, &listOfDiffAreaFilesToClose,
  17155. &listOfDeviceObjectsToDelete, FALSE,
  17156. TRUE);
  17157. b = TRUE;
  17158. }
  17159. if (b) {
  17160. IoInvalidateDeviceRelations(f->Pdo, BusRelations);
  17161. }
  17162. }
  17163. h = InterlockedExchangePointer(&Filter->ControlBlockFileHandle, NULL);
  17164. VspAcquireNonPagedResource(Filter, NULL, FALSE);
  17165. Filter->FirstControlBlockVolumeOffset = 0;
  17166. if (!IsOffline && Filter->SnapshotOnDiskIrp) {
  17167. ExFreePool(MmGetMdlVirtualAddress(
  17168. Filter->SnapshotOnDiskIrp->MdlAddress));
  17169. IoFreeMdl(Filter->SnapshotOnDiskIrp->MdlAddress);
  17170. IoFreeIrp(Filter->SnapshotOnDiskIrp);
  17171. Filter->SnapshotOnDiskIrp = NULL;
  17172. }
  17173. VspRemoveLookupEntries(Filter);
  17174. VspReleaseNonPagedResource(Filter);
  17175. hh = InterlockedExchangePointer(&Filter->BootStatHandle, NULL);
  17176. if (!IsOffline) {
  17177. while (!IsListEmpty(&Filter->DeadVolumeList)) {
  17178. l = RemoveHeadList(&Filter->DeadVolumeList);
  17179. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  17180. InterlockedExchange(&extension->DeadToPnp, TRUE);
  17181. }
  17182. }
  17183. VspRelease(Filter->Root);
  17184. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  17185. &listOfDeviceObjectsToDelete);
  17186. if (h) {
  17187. dispInfo.DeleteFile = FALSE;
  17188. ZwSetInformationFile(h, &ioStatus, &dispInfo, sizeof(dispInfo),
  17189. FileDispositionInformation);
  17190. ZwClose(h);
  17191. }
  17192. if (hh) {
  17193. ZwClose(hh);
  17194. }
  17195. }
  17196. NTSTATUS
  17197. VolSnapPower(
  17198. IN PDEVICE_OBJECT DeviceObject,
  17199. IN PIRP Irp
  17200. )
  17201. /*++
  17202. Routine Description:
  17203. This routine is the dispatch for IRP_MJ_POWER.
  17204. Arguments:
  17205. DeviceObject - Supplies the device object.
  17206. Irp - Supplies the IO request packet.
  17207. Return Value:
  17208. NTSTATUS
  17209. --*/
  17210. {
  17211. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  17212. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  17213. NTSTATUS status;
  17214. PVOLUME_EXTENSION extension;
  17215. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  17216. PoStartNextPowerIrp(Irp);
  17217. IoSkipCurrentIrpStackLocation(Irp);
  17218. return PoCallDriver(filter->TargetObject, Irp);
  17219. }
  17220. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  17221. switch (irpSp->MinorFunction) {
  17222. case IRP_MN_WAIT_WAKE:
  17223. case IRP_MN_POWER_SEQUENCE:
  17224. case IRP_MN_SET_POWER:
  17225. status = STATUS_SUCCESS;
  17226. break;
  17227. case IRP_MN_QUERY_POWER:
  17228. if (irpSp->Parameters.Power.ShutdownType == PowerActionHibernate) {
  17229. extension = (PVOLUME_EXTENSION) filter;
  17230. if (extension->IsPreExposure) {
  17231. status = STATUS_SUCCESS;
  17232. } else {
  17233. status = VspHandleHibernateNotification(extension, Irp);
  17234. }
  17235. } else {
  17236. status = STATUS_SUCCESS;
  17237. }
  17238. break;
  17239. default:
  17240. status = Irp->IoStatus.Status;
  17241. break;
  17242. }
  17243. if (status == STATUS_PENDING) {
  17244. return STATUS_PENDING;
  17245. }
  17246. Irp->IoStatus.Status = status;
  17247. PoStartNextPowerIrp(Irp);
  17248. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17249. return status;
  17250. }
  17251. NTSTATUS
  17252. VolSnapRead(
  17253. IN PDEVICE_OBJECT DeviceObject,
  17254. IN PIRP Irp
  17255. )
  17256. /*++
  17257. Routine Description:
  17258. This routine is the dispatch for IRP_MJ_READ.
  17259. Arguments:
  17260. DeviceObject - Supplies the device object.
  17261. Irp - Supplies the IO request packet.
  17262. Return Value:
  17263. NTSTATUS
  17264. --*/
  17265. {
  17266. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  17267. NTSTATUS status;
  17268. PVOLUME_EXTENSION extension;
  17269. KIRQL irql;
  17270. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  17271. IoSkipCurrentIrpStackLocation(Irp);
  17272. return IoCallDriver(filter->TargetObject, Irp);
  17273. }
  17274. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  17275. extension = (PVOLUME_EXTENSION) filter;
  17276. filter = extension->Filter;
  17277. if (!extension->IsStarted || extension->IsPreExposure) {
  17278. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  17279. Irp->IoStatus.Information = 0;
  17280. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17281. return STATUS_NO_SUCH_DEVICE;
  17282. }
  17283. if (extension->IsOffline) {
  17284. Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
  17285. Irp->IoStatus.Information = 0;
  17286. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17287. return STATUS_DEVICE_OFF_LINE;
  17288. }
  17289. status = VspIncrementVolumeRefCount(extension);
  17290. if (!NT_SUCCESS(status)) {
  17291. Irp->IoStatus.Status = status;
  17292. Irp->IoStatus.Information = 0;
  17293. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17294. return status;
  17295. }
  17296. IoMarkIrpPending(Irp);
  17297. KeAcquireSpinLock(&extension->SpinLock, &irql);
  17298. if (VspAreBitsSet(extension, Irp)) {
  17299. KeReleaseSpinLock(&extension->SpinLock, irql);
  17300. Irp->IoStatus.Status = STATUS_SUCCESS;
  17301. Irp->IoStatus.Information = IoGetCurrentIrpStackLocation(Irp)->
  17302. Parameters.Read.Length;
  17303. VspReadCompletionForReadSnapshot(DeviceObject, Irp, extension);
  17304. return STATUS_PENDING;
  17305. }
  17306. KeReleaseSpinLock(&extension->SpinLock, irql);
  17307. IoCopyCurrentIrpStackLocationToNext(Irp);
  17308. IoSetCompletionRoutine(Irp, VspReadCompletionForReadSnapshot,
  17309. extension, TRUE, TRUE, TRUE);
  17310. IoCallDriver(filter->TargetObject, Irp);
  17311. return STATUS_PENDING;
  17312. }
  17313. NTSTATUS
  17314. VspIncrementRefCount(
  17315. IN PFILTER_EXTENSION Filter,
  17316. IN PIRP Irp
  17317. )
  17318. {
  17319. KIRQL irql;
  17320. InterlockedIncrement(&Filter->RefCount);
  17321. if (!Filter->HoldIncomingWrites) {
  17322. return STATUS_SUCCESS;
  17323. }
  17324. VspDecrementRefCount(Filter);
  17325. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  17326. if (!Filter->HoldIncomingWrites) {
  17327. InterlockedIncrement(&Filter->RefCount);
  17328. KeReleaseSpinLock(&Filter->SpinLock, irql);
  17329. return STATUS_SUCCESS;
  17330. }
  17331. IoMarkIrpPending(Irp);
  17332. InsertTailList(&Filter->HoldQueue, &Irp->Tail.Overlay.ListEntry);
  17333. KeReleaseSpinLock(&Filter->SpinLock, irql);
  17334. return STATUS_PENDING;
  17335. }
  17336. NTSTATUS
  17337. VspRefCountCompletionRoutine(
  17338. IN PDEVICE_OBJECT DeviceObject,
  17339. IN PIRP Irp,
  17340. IN PVOID Filter
  17341. )
  17342. {
  17343. VspDecrementRefCount((PFILTER_EXTENSION) Filter);
  17344. return STATUS_SUCCESS;
  17345. }
  17346. NTSTATUS
  17347. VolSnapWrite(
  17348. IN PDEVICE_OBJECT DeviceObject,
  17349. IN PIRP Irp
  17350. )
  17351. /*++
  17352. Routine Description:
  17353. This routine is the dispatch for IRP_MJ_WRITE.
  17354. Arguments:
  17355. DeviceObject - Supplies the device object.
  17356. Irp - Supplies the IO request packet.
  17357. Return Value:
  17358. NTSTATUS
  17359. --*/
  17360. {
  17361. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  17362. NTSTATUS status;
  17363. LONG r;
  17364. PVOLUME_EXTENSION extension;
  17365. KIRQL irql, irql2;
  17366. PLIST_ENTRY l;
  17367. PVSP_DIFF_AREA_FILE diffAreaFile;
  17368. PIO_STACK_LOCATION nextSp;
  17369. PVSP_CONTEXT context;
  17370. PDO_EXTENSION rootExtension;
  17371. PVSP_WRITE_CONTEXT writeContext;
  17372. PVSP_COPY_ON_WRITE copyOnWrite;
  17373. if (filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME) {
  17374. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  17375. Irp->IoStatus.Information = 0;
  17376. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17377. return STATUS_INVALID_DEVICE_REQUEST;
  17378. }
  17379. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  17380. IoMarkIrpPending(Irp);
  17381. status = VspIncrementRefCount(filter, Irp);
  17382. if (status == STATUS_PENDING) {
  17383. if (filter->SnapshotDiscoveryPending) {
  17384. KeAcquireSpinLock(&filter->SpinLock, &irql);
  17385. if (filter->ActivateStarted) {
  17386. KeReleaseSpinLock(&filter->SpinLock, irql);
  17387. return STATUS_PENDING;
  17388. }
  17389. if (filter->FirstWriteProcessed) {
  17390. KeReleaseSpinLock(&filter->SpinLock, irql);
  17391. return STATUS_PENDING;
  17392. }
  17393. InterlockedExchange(&filter->FirstWriteProcessed, TRUE);
  17394. while (!IsListEmpty(&filter->CopyOnWriteList)) {
  17395. l = RemoveHeadList(&filter->CopyOnWriteList);
  17396. copyOnWrite = CONTAINING_RECORD(l, VSP_COPY_ON_WRITE,
  17397. ListEntry);
  17398. ExFreePool(copyOnWrite->Buffer);
  17399. ExFreePool(copyOnWrite);
  17400. }
  17401. KeReleaseSpinLock(&filter->SpinLock, irql);
  17402. ObReferenceObject(filter->DeviceObject);
  17403. ExInitializeWorkItem(&filter->DestroyContext.WorkItem,
  17404. VspStartCopyOnWriteCache, filter);
  17405. ExQueueWorkItem(&filter->DestroyContext.WorkItem,
  17406. DelayedWorkQueue);
  17407. }
  17408. return STATUS_PENDING;
  17409. }
  17410. if (filter->ProtectedBlocksBitmap) {
  17411. KeAcquireSpinLock(&filter->SpinLock, &irql);
  17412. if (filter->ProtectedBlocksBitmap &&
  17413. !VspAreBitsClear(filter->ProtectedBlocksBitmap, Irp)) {
  17414. KeReleaseSpinLock(&filter->SpinLock, irql);
  17415. context = VspAllocateContext(filter->Root);
  17416. if (!context) {
  17417. rootExtension = filter->Root;
  17418. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  17419. if (rootExtension->EmergencyContextInUse) {
  17420. InsertTailList(&rootExtension->IrpWaitingList,
  17421. &Irp->Tail.Overlay.ListEntry);
  17422. if (!rootExtension->IrpWaitingListNeedsChecking) {
  17423. InterlockedExchange(
  17424. &rootExtension->IrpWaitingListNeedsChecking,
  17425. TRUE);
  17426. }
  17427. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  17428. VspDecrementRefCount(filter);
  17429. return STATUS_PENDING;
  17430. }
  17431. rootExtension->EmergencyContextInUse = TRUE;
  17432. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  17433. context = rootExtension->EmergencyContext;
  17434. }
  17435. context->Type = VSP_CONTEXT_TYPE_DISMOUNT_CLEANUP;
  17436. ExInitializeWorkItem(&context->WorkItem,
  17437. VspDismountCleanupOnWrite, context);
  17438. context->DismountCleanupOnWrite.Filter = filter;
  17439. context->DismountCleanupOnWrite.Irp = Irp;
  17440. VspAcquireNonPagedResource(filter, &context->WorkItem, FALSE);
  17441. return STATUS_PENDING;
  17442. }
  17443. KeReleaseSpinLock(&filter->SpinLock, irql);
  17444. }
  17445. if (filter->SnapshotDiscoveryPending) {
  17446. VspCopyOnWriteToNonPagedPool(filter, Irp);
  17447. return STATUS_PENDING;
  17448. }
  17449. if (!filter->SnapshotsPresent) {
  17450. if (!Irp->MdlAddress) {
  17451. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  17452. Irp->IoStatus.Information = 0;
  17453. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17454. VspDecrementRefCount(filter);
  17455. return STATUS_PENDING;
  17456. }
  17457. IoCopyCurrentIrpStackLocationToNext(Irp);
  17458. IoSetCompletionRoutine(Irp, VspRefCountCompletionRoutine, filter,
  17459. TRUE, TRUE, TRUE);
  17460. IoCallDriver(filter->TargetObject, Irp);
  17461. return STATUS_PENDING;
  17462. }
  17463. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  17464. VOLUME_EXTENSION, ListEntry);
  17465. KeAcquireSpinLock(&extension->SpinLock, &irql);
  17466. if (VspAreBitsSet(extension, Irp)) {
  17467. if (!Irp->MdlAddress) {
  17468. KeReleaseSpinLock(&extension->SpinLock, irql);
  17469. Irp->IoStatus.Status = STATUS_SUCCESS;
  17470. Irp->IoStatus.Information = 0;
  17471. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17472. VspDecrementRefCount(filter);
  17473. return STATUS_PENDING;
  17474. }
  17475. writeContext = VspAllocateWriteContext(filter->Root);
  17476. if (!writeContext) {
  17477. rootExtension = filter->Root;
  17478. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql2);
  17479. if (rootExtension->EmergencyWriteContextInUse) {
  17480. InsertTailList(&rootExtension->WriteContextIrpWaitingList,
  17481. &Irp->Tail.Overlay.ListEntry);
  17482. if (!rootExtension->WriteContextIrpWaitingListNeedsChecking) {
  17483. InterlockedExchange(
  17484. &rootExtension->WriteContextIrpWaitingListNeedsChecking,
  17485. TRUE);
  17486. }
  17487. KeReleaseSpinLock(&rootExtension->ESpinLock, irql2);
  17488. KeReleaseSpinLock(&extension->SpinLock, irql);
  17489. VspDecrementRefCount(filter);
  17490. return STATUS_PENDING;
  17491. }
  17492. rootExtension->EmergencyWriteContextInUse = TRUE;
  17493. KeReleaseSpinLock(&rootExtension->ESpinLock, irql2);
  17494. writeContext = rootExtension->EmergencyWriteContext;
  17495. }
  17496. writeContext->Filter = filter;
  17497. writeContext->Extension = extension;
  17498. writeContext->Irp = Irp;
  17499. InitializeListHead(&writeContext->CompletionRoutines);
  17500. InsertTailList(&extension->WriteContextList, &writeContext->ListEntry);
  17501. KeReleaseSpinLock(&extension->SpinLock, irql);
  17502. IoCopyCurrentIrpStackLocationToNext(Irp);
  17503. IoSetCompletionRoutine(Irp, VspWriteContextCompletionRoutine,
  17504. writeContext, TRUE, TRUE, TRUE);
  17505. IoCallDriver(filter->TargetObject, Irp);
  17506. return STATUS_PENDING;
  17507. }
  17508. KeReleaseSpinLock(&extension->SpinLock, irql);
  17509. context = VspAllocateContext(extension->Root);
  17510. if (!context) {
  17511. rootExtension = extension->Root;
  17512. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  17513. if (rootExtension->EmergencyContextInUse) {
  17514. InsertTailList(&rootExtension->IrpWaitingList,
  17515. &Irp->Tail.Overlay.ListEntry);
  17516. if (!rootExtension->IrpWaitingListNeedsChecking) {
  17517. InterlockedExchange(
  17518. &rootExtension->IrpWaitingListNeedsChecking, TRUE);
  17519. }
  17520. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  17521. VspDecrementRefCount(filter);
  17522. return STATUS_PENDING;
  17523. }
  17524. rootExtension->EmergencyContextInUse = TRUE;
  17525. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  17526. context = rootExtension->EmergencyContext;
  17527. }
  17528. ASSERT(extension->DiffAreaFile);
  17529. diffAreaFile = extension->DiffAreaFile;
  17530. status = VspIncrementRefCount(diffAreaFile->Filter, Irp);
  17531. if (status == STATUS_PENDING) {
  17532. VspFreeContext(extension->Root, context);
  17533. VspDecrementRefCount(filter);
  17534. return STATUS_PENDING;
  17535. }
  17536. nextSp = IoGetNextIrpStackLocation(Irp);
  17537. nextSp->Parameters.Write.Length = 1; // Use this for a ref count.
  17538. context->Type = VSP_CONTEXT_TYPE_WRITE_VOLUME;
  17539. context->WriteVolume.Extension = extension;
  17540. context->WriteVolume.Irp = Irp;
  17541. context->WriteVolume.RoundedStart = 0;
  17542. ExInitializeWorkItem(&context->WorkItem, VspWriteVolume, context);
  17543. if (extension->OnDiskNotCommitted) {
  17544. VspAcquireNonPagedResource(extension, &context->WorkItem, TRUE);
  17545. } else {
  17546. VspAcquireNonPagedResource(extension, &context->WorkItem, FALSE);
  17547. }
  17548. return STATUS_PENDING;
  17549. }
  17550. NTSTATUS
  17551. VolSnapCleanup(
  17552. IN PDEVICE_OBJECT DeviceObject,
  17553. IN PIRP Irp
  17554. )
  17555. /*++
  17556. Routine Description:
  17557. This routine is the dispatch for IRP_MJ_CLEANUP.
  17558. Arguments:
  17559. DeviceObject - Supplies the device object.
  17560. Irp - Supplies the IO request packet.
  17561. Return Value:
  17562. NTSTATUS
  17563. --*/
  17564. {
  17565. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  17566. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  17567. KEVENT event;
  17568. KIRQL irql;
  17569. PIRP irp;
  17570. PVSP_CONTEXT context;
  17571. if (filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME) {
  17572. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  17573. Irp->IoStatus.Information = 0;
  17574. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17575. return STATUS_INVALID_DEVICE_REQUEST;
  17576. }
  17577. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  17578. KeInitializeEvent(&event, NotificationEvent, FALSE);
  17579. IoCopyCurrentIrpStackLocationToNext(Irp);
  17580. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event, TRUE, TRUE,
  17581. TRUE);
  17582. IoCallDriver(filter->TargetObject, Irp);
  17583. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  17584. IoAcquireCancelSpinLock(&irql);
  17585. if (filter->FlushAndHoldIrp) {
  17586. irp = filter->FlushAndHoldIrp;
  17587. if (IoGetCurrentIrpStackLocation(irp)->FileObject ==
  17588. irpSp->FileObject) {
  17589. irp->CancelIrql = irql;
  17590. IoSetCancelRoutine(irp, NULL);
  17591. VspCancelRoutine(DeviceObject, irp);
  17592. } else {
  17593. IoReleaseCancelSpinLock(irql);
  17594. }
  17595. } else {
  17596. IoReleaseCancelSpinLock(irql);
  17597. }
  17598. IoAcquireCancelSpinLock(&irql);
  17599. if (filter->AutoCleanupFileObject == irpSp->FileObject) {
  17600. filter->AutoCleanupFileObject = NULL;
  17601. IoReleaseCancelSpinLock(irql);
  17602. VspDestroyAllSnapshots(filter, NULL, FALSE, FALSE);
  17603. } else {
  17604. IoReleaseCancelSpinLock(irql);
  17605. }
  17606. Irp->IoStatus.Status = STATUS_SUCCESS;
  17607. Irp->IoStatus.Information = 0;
  17608. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  17609. return STATUS_SUCCESS;
  17610. }
  17611. BOOLEAN
  17612. VspIsSetup(
  17613. )
  17614. {
  17615. UNICODE_STRING keyName;
  17616. OBJECT_ATTRIBUTES oa;
  17617. NTSTATUS status;
  17618. HANDLE h;
  17619. ULONG zero, result;
  17620. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  17621. RtlInitUnicodeString(&keyName,
  17622. L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\setupdd");
  17623. InitializeObjectAttributes(&oa, &keyName, OBJ_CASE_INSENSITIVE |
  17624. OBJ_KERNEL_HANDLE, NULL, NULL);
  17625. status = ZwOpenKey(&h, 0, &oa);
  17626. if (NT_SUCCESS(status)) {
  17627. ZwClose(h);
  17628. return TRUE;
  17629. }
  17630. zero = 0;
  17631. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  17632. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  17633. queryTable[0].Name = L"SystemSetupInProgress";
  17634. queryTable[0].EntryContext = &result;
  17635. queryTable[0].DefaultType = REG_DWORD;
  17636. queryTable[0].DefaultData = &zero;
  17637. queryTable[0].DefaultLength = sizeof(ULONG);
  17638. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  17639. L"\\Registry\\Machine\\SYSTEM\\Setup",
  17640. queryTable, NULL, NULL);
  17641. if (!NT_SUCCESS(status)) {
  17642. result = zero;
  17643. }
  17644. return result ? TRUE : FALSE;
  17645. }
  17646. NTSTATUS
  17647. DriverEntry(
  17648. IN PDRIVER_OBJECT DriverObject,
  17649. IN PUNICODE_STRING RegistryPath
  17650. )
  17651. /*++
  17652. Routine Description:
  17653. This routine is called when the driver loads loads.
  17654. Arguments:
  17655. DriverObject - Supplies the driver object.
  17656. RegistryPath - Supplies the registry path.
  17657. Return Value:
  17658. NTSTATUS
  17659. --*/
  17660. {
  17661. ULONG i;
  17662. PDEVICE_OBJECT deviceObject;
  17663. NTSTATUS status;
  17664. PDO_EXTENSION rootExtension;
  17665. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  17666. DriverObject->MajorFunction[i] = VolSnapDefaultDispatch;
  17667. }
  17668. DriverObject->DriverExtension->AddDevice = VolSnapAddDevice;
  17669. DriverObject->MajorFunction[IRP_MJ_CREATE] = VolSnapCreate;
  17670. DriverObject->MajorFunction[IRP_MJ_READ] = VolSnapRead;
  17671. DriverObject->MajorFunction[IRP_MJ_WRITE] = VolSnapWrite;
  17672. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VolSnapDeviceControl;
  17673. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = VolSnapCleanup;
  17674. DriverObject->MajorFunction[IRP_MJ_PNP] = VolSnapPnp;
  17675. DriverObject->MajorFunction[IRP_MJ_POWER] = VolSnapPower;
  17676. status = IoAllocateDriverObjectExtension(DriverObject, VolSnapAddDevice,
  17677. sizeof(DO_EXTENSION),
  17678. (PVOID*) &rootExtension);
  17679. if (!NT_SUCCESS(status)) {
  17680. return status;
  17681. }
  17682. RtlZeroMemory(rootExtension, sizeof(DO_EXTENSION));
  17683. rootExtension->DriverObject = DriverObject;
  17684. InitializeListHead(&rootExtension->FilterList);
  17685. InitializeListHead(&rootExtension->HoldIrps);
  17686. KeInitializeTimer(&rootExtension->HoldTimer);
  17687. KeInitializeDpc(&rootExtension->HoldTimerDpc, VspFsTimerDpc,
  17688. rootExtension);
  17689. KeInitializeSemaphore(&rootExtension->Semaphore, 1, 1);
  17690. for (i = 0; i < NUMBER_OF_THREAD_POOLS; i++) {
  17691. InitializeListHead(&rootExtension->WorkerQueue[i]);
  17692. KeInitializeSemaphore(&rootExtension->WorkerSemaphore[i], 0, MAXLONG);
  17693. KeInitializeSpinLock(&rootExtension->SpinLock[i]);
  17694. }
  17695. KeInitializeSemaphore(&rootExtension->ThreadsRefCountSemaphore, 1, 1);
  17696. InitializeListHead(&rootExtension->LowPriorityQueue);
  17697. IoRegisterDriverReinitialization(DriverObject, VspDriverReinit,
  17698. rootExtension);
  17699. IoRegisterBootDriverReinitialization(DriverObject, VspDriverBootReinit,
  17700. rootExtension);
  17701. ExInitializeNPagedLookasideList(&rootExtension->ContextLookasideList,
  17702. NULL, NULL, 0, sizeof(VSP_CONTEXT),
  17703. VOLSNAP_TAG_CONTEXT, 32);
  17704. rootExtension->EmergencyContext = VspAllocateContext(rootExtension);
  17705. if (!rootExtension->EmergencyContext) {
  17706. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  17707. return STATUS_INSUFFICIENT_RESOURCES;
  17708. }
  17709. InitializeListHead(&rootExtension->IrpWaitingList);
  17710. KeInitializeSpinLock(&rootExtension->ESpinLock);
  17711. ExInitializeNPagedLookasideList(
  17712. &rootExtension->WriteContextLookasideList, NULL, NULL, 0,
  17713. sizeof(VSP_WRITE_CONTEXT), VOLSNAP_TAG_CONTEXT, 32);
  17714. rootExtension->EmergencyWriteContext =
  17715. VspAllocateWriteContext(rootExtension);
  17716. if (!rootExtension->EmergencyWriteContext) {
  17717. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  17718. ExDeleteNPagedLookasideList(&rootExtension->WriteContextLookasideList);
  17719. return STATUS_INSUFFICIENT_RESOURCES;
  17720. }
  17721. InitializeListHead(&rootExtension->WriteContextIrpWaitingList);
  17722. ExInitializeNPagedLookasideList(&rootExtension->TempTableEntryLookasideList,
  17723. NULL, NULL, 0, sizeof(RTL_BALANCED_LINKS) +
  17724. sizeof(TEMP_TRANSLATION_TABLE_ENTRY),
  17725. VOLSNAP_TAG_TEMP_TABLE, 32);
  17726. rootExtension->EmergencyTableEntry =
  17727. VspAllocateTempTableEntry(rootExtension);
  17728. if (!rootExtension->EmergencyTableEntry) {
  17729. ExFreeToNPagedLookasideList(&rootExtension->ContextLookasideList,
  17730. rootExtension->EmergencyContext);
  17731. ExDeleteNPagedLookasideList(&rootExtension->WriteContextLookasideList);
  17732. ExDeleteNPagedLookasideList(
  17733. &rootExtension->TempTableEntryLookasideList);
  17734. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  17735. return STATUS_INSUFFICIENT_RESOURCES;
  17736. }
  17737. InitializeListHead(&rootExtension->WorkItemWaitingList);
  17738. rootExtension->RegistryPath.Length = RegistryPath->Length;
  17739. rootExtension->RegistryPath.MaximumLength =
  17740. rootExtension->RegistryPath.Length + sizeof(WCHAR);
  17741. rootExtension->RegistryPath.Buffer = (PWSTR)
  17742. ExAllocatePoolWithTag(PagedPool,
  17743. rootExtension->RegistryPath.MaximumLength,
  17744. VOLSNAP_TAG_SHORT_TERM);
  17745. if (!rootExtension->RegistryPath.Buffer) {
  17746. VspFreeTempTableEntry(rootExtension,
  17747. rootExtension->EmergencyTableEntry);
  17748. ExFreeToNPagedLookasideList(&rootExtension->ContextLookasideList,
  17749. rootExtension->EmergencyContext);
  17750. ExDeleteNPagedLookasideList(&rootExtension->WriteContextLookasideList);
  17751. ExDeleteNPagedLookasideList(
  17752. &rootExtension->TempTableEntryLookasideList);
  17753. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  17754. return STATUS_INSUFFICIENT_RESOURCES;
  17755. }
  17756. RtlCopyMemory(rootExtension->RegistryPath.Buffer,
  17757. RegistryPath->Buffer, RegistryPath->Length);
  17758. rootExtension->RegistryPath.Buffer[RegistryPath->Length/
  17759. sizeof(WCHAR)] = 0;
  17760. InitializeListHead(&rootExtension->AdjustBitmapQueue);
  17761. KeInitializeEvent(&rootExtension->PastBootReinit, NotificationEvent,
  17762. FALSE);
  17763. RtlInitializeGenericTable(&rootExtension->PersistentSnapshotLookupTable,
  17764. VspSnapshotLookupCompareRoutine,
  17765. VspSnapshotLookupAllocateRoutine,
  17766. VspSnapshotLookupFreeRoutine, NULL);
  17767. KeInitializeMutex(&rootExtension->LookupTableMutex, 0);
  17768. rootExtension->IsSetup = VspIsSetup();
  17769. RtlInitializeGenericTable(&rootExtension->UsedDevnodeNumbers,
  17770. VspUsedDevnodeCompareRoutine,
  17771. VspSnapshotLookupAllocateRoutine,
  17772. VspSnapshotLookupFreeRoutine, NULL);
  17773. return STATUS_SUCCESS;
  17774. }