Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9689 lines
282 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 <ntddsnap.h>
  21. #include <initguid.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. NTSTATUS
  29. DriverEntry(
  30. IN PDRIVER_OBJECT DriverObject,
  31. IN PUNICODE_STRING RegistryPath
  32. );
  33. }
  34. ULONG VsErrorLogSequence = 0;
  35. VOID
  36. VspWriteVolume(
  37. IN PVOID Context
  38. );
  39. NTSTATUS
  40. VspSetIgnorableBlocksInBitmap(
  41. IN PVOID Extension
  42. );
  43. VOID
  44. VspWorkerThread(
  45. IN PVOID RootExtension
  46. );
  47. VOID
  48. VspCleanupInitialSnapshot(
  49. IN PVOLUME_EXTENSION Extension,
  50. IN BOOLEAN NeedLock
  51. );
  52. VOID
  53. VspDestroyAllSnapshots(
  54. IN PFILTER_EXTENSION Filter,
  55. IN PTEMP_TRANSLATION_TABLE_ENTRY TableEntry
  56. );
  57. VOID
  58. VspWriteVolumePhase1(
  59. IN PVOID TableEntry
  60. );
  61. VOID
  62. VspFreeCopyIrp(
  63. IN PVOLUME_EXTENSION Extension,
  64. IN PIRP CopyIrp
  65. );
  66. NTSTATUS
  67. VspMarkFileAllocationInBitmap(
  68. IN PVOLUME_EXTENSION Extension,
  69. IN HANDLE FileHandle,
  70. IN PVSP_DIFF_AREA_FILE DiffAreaFile,
  71. IN BOOLEAN OnlyDiffAreaFile,
  72. IN BOOLEAN ClearBits,
  73. IN PRTL_BITMAP BitmapToSet
  74. );
  75. NTSTATUS
  76. VspAbortPreparedSnapshot(
  77. IN PFILTER_EXTENSION Filter,
  78. IN BOOLEAN NeedLock
  79. );
  80. VOID
  81. VspCleanupBitsSetInOtherPreparedSnapshots(
  82. IN PVOLUME_EXTENSION Extension
  83. );
  84. NTSTATUS
  85. VspReleaseWrites(
  86. IN PFILTER_EXTENSION Filter
  87. );
  88. NTSTATUS
  89. VspSetApplicationInfo(
  90. IN PVOLUME_EXTENSION Extension,
  91. IN PIRP Irp
  92. );
  93. NTSTATUS
  94. VspRefCountCompletionRoutine(
  95. IN PDEVICE_OBJECT DeviceObject,
  96. IN PIRP Irp,
  97. IN PVOID Filter
  98. );
  99. VOID
  100. VspCleanupFilter(
  101. IN PFILTER_EXTENSION Filter
  102. );
  103. VOID
  104. VspDecrementRefCount(
  105. IN PFILTER_EXTENSION Filter
  106. );
  107. NTSTATUS
  108. VspSignalCompletion(
  109. IN PDEVICE_OBJECT DeviceObject,
  110. IN PIRP Irp,
  111. IN PVOID Event
  112. );
  113. NTSTATUS
  114. VspMarkFreeSpaceInBitmap(
  115. IN PVOLUME_EXTENSION Extension,
  116. IN HANDLE UseThisHandle,
  117. IN PRTL_BITMAP BitmapToSet
  118. );
  119. VOID
  120. VspAndBitmaps(
  121. IN OUT PRTL_BITMAP BaseBitmap,
  122. IN PRTL_BITMAP FactorBitmap
  123. );
  124. NTSTATUS
  125. VspDeleteOldestSnapshot(
  126. IN PFILTER_EXTENSION Filter,
  127. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose,
  128. IN OUT PLIST_ENTRY LisfOfDeviceObjectsToDelete
  129. );
  130. VOID
  131. VspCloseDiffAreaFiles(
  132. IN PLIST_ENTRY ListOfDiffAreaFilesToClose,
  133. IN PLIST_ENTRY ListOfDeviceObjectsToDelete
  134. );
  135. NTSTATUS
  136. VspComputeIgnorableProduct(
  137. IN PVOLUME_EXTENSION Extension
  138. );
  139. #ifdef ALLOC_PRAGMA
  140. #pragma alloc_text(INIT, DriverEntry)
  141. #endif
  142. #ifdef ALLOC_PRAGMA
  143. #pragma code_seg("PAGELK")
  144. #endif
  145. VOID
  146. VspAcquire(
  147. IN PDO_EXTENSION RootExtension
  148. )
  149. {
  150. KeWaitForSingleObject(&RootExtension->Semaphore, Executive, KernelMode,
  151. FALSE, NULL);
  152. }
  153. VOID
  154. VspRelease(
  155. IN PDO_EXTENSION RootExtension
  156. )
  157. {
  158. KeReleaseSemaphore(&RootExtension->Semaphore, IO_NO_INCREMENT, 1, FALSE);
  159. }
  160. PVSP_CONTEXT
  161. VspAllocateContext(
  162. IN PDO_EXTENSION RootExtension
  163. )
  164. {
  165. PVSP_CONTEXT context;
  166. context = (PVSP_CONTEXT) ExAllocateFromNPagedLookasideList(
  167. &RootExtension->ContextLookasideList);
  168. return context;
  169. }
  170. VOID
  171. VspFreeContext(
  172. IN PDO_EXTENSION RootExtension,
  173. IN PVSP_CONTEXT Context
  174. )
  175. {
  176. KIRQL irql;
  177. PLIST_ENTRY l;
  178. PIRP irp;
  179. PIO_STACK_LOCATION irpSp;
  180. if (RootExtension->EmergencyContext == Context) {
  181. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  182. RootExtension->EmergencyContextInUse = FALSE;
  183. if (IsListEmpty(&RootExtension->IrpWaitingList)) {
  184. InterlockedExchange(&RootExtension->IrpWaitingListNeedsChecking,
  185. FALSE);
  186. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  187. return;
  188. }
  189. l = RemoveHeadList(&RootExtension->IrpWaitingList);
  190. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  191. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  192. irpSp = IoGetCurrentIrpStackLocation(irp);
  193. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  194. irpSp->DeviceObject, irp);
  195. return;
  196. }
  197. ExFreeToNPagedLookasideList(&RootExtension->ContextLookasideList,
  198. Context);
  199. if (!RootExtension->IrpWaitingListNeedsChecking) {
  200. return;
  201. }
  202. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  203. if (IsListEmpty(&RootExtension->IrpWaitingList)) {
  204. InterlockedExchange(&RootExtension->IrpWaitingListNeedsChecking,
  205. FALSE);
  206. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  207. return;
  208. }
  209. l = RemoveHeadList(&RootExtension->IrpWaitingList);
  210. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  211. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  212. irpSp = IoGetCurrentIrpStackLocation(irp);
  213. RootExtension->DriverObject->MajorFunction[irpSp->MajorFunction](
  214. irpSp->DeviceObject, irp);
  215. }
  216. PVOID
  217. VspAllocateTempTableEntry(
  218. IN PDO_EXTENSION RootExtension
  219. )
  220. {
  221. PVOID tempTableEntry;
  222. tempTableEntry = ExAllocateFromNPagedLookasideList(
  223. &RootExtension->TempTableEntryLookasideList);
  224. return tempTableEntry;
  225. }
  226. VOID
  227. VspQueueWorkItem(
  228. IN PDO_EXTENSION RootExtension,
  229. IN PWORK_QUEUE_ITEM WorkItem,
  230. IN ULONG QueueNumber
  231. )
  232. {
  233. KIRQL irql;
  234. ASSERT(QueueNumber < NUMBER_OF_THREAD_POOLS);
  235. KeAcquireSpinLock(&RootExtension->SpinLock[QueueNumber], &irql);
  236. InsertTailList(&RootExtension->WorkerQueue[QueueNumber], &WorkItem->List);
  237. KeReleaseSpinLock(&RootExtension->SpinLock[QueueNumber], irql);
  238. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[QueueNumber],
  239. IO_NO_INCREMENT, 1, FALSE);
  240. }
  241. VOID
  242. VspFreeTempTableEntry(
  243. IN PDO_EXTENSION RootExtension,
  244. IN PVOID TempTableEntry
  245. )
  246. {
  247. KIRQL irql;
  248. PLIST_ENTRY l;
  249. PWORK_QUEUE_ITEM workItem;
  250. if (RootExtension->EmergencyTableEntry == TempTableEntry) {
  251. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  252. RootExtension->EmergencyTableEntryInUse = FALSE;
  253. if (IsListEmpty(&RootExtension->WorkItemWaitingList)) {
  254. InterlockedExchange(
  255. &RootExtension->WorkItemWaitingListNeedsChecking, FALSE);
  256. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  257. return;
  258. }
  259. l = RemoveHeadList(&RootExtension->WorkItemWaitingList);
  260. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  261. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  262. VspQueueWorkItem(RootExtension, workItem, 2);
  263. return;
  264. }
  265. ExFreeToNPagedLookasideList(&RootExtension->TempTableEntryLookasideList,
  266. TempTableEntry);
  267. if (!RootExtension->WorkItemWaitingListNeedsChecking) {
  268. return;
  269. }
  270. KeAcquireSpinLock(&RootExtension->ESpinLock, &irql);
  271. if (IsListEmpty(&RootExtension->WorkItemWaitingList)) {
  272. InterlockedExchange(&RootExtension->WorkItemWaitingListNeedsChecking,
  273. FALSE);
  274. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  275. return;
  276. }
  277. l = RemoveHeadList(&RootExtension->WorkItemWaitingList);
  278. KeReleaseSpinLock(&RootExtension->ESpinLock, irql);
  279. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  280. VspQueueWorkItem(RootExtension, workItem, 2);
  281. }
  282. VOID
  283. VspLogErrorWorker(
  284. IN PVOID Context
  285. )
  286. {
  287. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  288. PVOLUME_EXTENSION extension = context->ErrorLog.Extension;
  289. PFILTER_EXTENSION diffAreaFilter = context->ErrorLog.DiffAreaFilter;
  290. PFILTER_EXTENSION filter;
  291. NTSTATUS status;
  292. UNICODE_STRING filterDosName, diffAreaFilterDosName;
  293. ULONG extraSpace;
  294. PIO_ERROR_LOG_PACKET errorLogPacket;
  295. PWCHAR p;
  296. ASSERT(context->Type == VSP_CONTEXT_TYPE_ERROR_LOG);
  297. if (extension) {
  298. filter = extension->Filter;
  299. } else {
  300. filter = diffAreaFilter;
  301. diffAreaFilter = NULL;
  302. }
  303. status = IoVolumeDeviceToDosName(filter->DeviceObject, &filterDosName);
  304. if (!NT_SUCCESS(status)) {
  305. goto Cleanup;
  306. }
  307. extraSpace = filterDosName.Length + sizeof(WCHAR);
  308. if (diffAreaFilter) {
  309. status = IoVolumeDeviceToDosName(diffAreaFilter->DeviceObject,
  310. &diffAreaFilterDosName);
  311. if (!NT_SUCCESS(status)) {
  312. ExFreePool(filterDosName.Buffer);
  313. goto Cleanup;
  314. }
  315. extraSpace += diffAreaFilterDosName.Length + sizeof(WCHAR);
  316. }
  317. extraSpace += sizeof(IO_ERROR_LOG_PACKET);
  318. if (extraSpace > 0xFF) {
  319. if (diffAreaFilter) {
  320. ExFreePool(diffAreaFilterDosName.Buffer);
  321. }
  322. ExFreePool(filterDosName.Buffer);
  323. goto Cleanup;
  324. }
  325. errorLogPacket = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(extension ?
  326. extension->DeviceObject : filter->DeviceObject,
  327. (UCHAR) extraSpace);
  328. if (!errorLogPacket) {
  329. if (diffAreaFilter) {
  330. ExFreePool(diffAreaFilterDosName.Buffer);
  331. }
  332. ExFreePool(filterDosName.Buffer);
  333. goto Cleanup;
  334. }
  335. errorLogPacket->ErrorCode = context->ErrorLog.SpecificIoStatus;
  336. errorLogPacket->SequenceNumber = VsErrorLogSequence++;
  337. errorLogPacket->FinalStatus = context->ErrorLog.FinalStatus;
  338. errorLogPacket->UniqueErrorValue = context->ErrorLog.UniqueErrorValue;
  339. errorLogPacket->DumpDataSize = 0;
  340. errorLogPacket->RetryCount = 0;
  341. errorLogPacket->NumberOfStrings = 1;
  342. errorLogPacket->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
  343. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET));
  344. RtlCopyMemory(p, filterDosName.Buffer, filterDosName.Length);
  345. p[filterDosName.Length/sizeof(WCHAR)] = 0;
  346. if (diffAreaFilter) {
  347. errorLogPacket->NumberOfStrings = 2;
  348. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET) +
  349. filterDosName.Length + sizeof(WCHAR));
  350. RtlCopyMemory(p, diffAreaFilterDosName.Buffer,
  351. diffAreaFilterDosName.Length);
  352. p[diffAreaFilterDosName.Length/sizeof(WCHAR)] = 0;
  353. }
  354. IoWriteErrorLogEntry(errorLogPacket);
  355. if (diffAreaFilter) {
  356. ExFreePool(diffAreaFilterDosName.Buffer);
  357. }
  358. ExFreePool(filterDosName.Buffer);
  359. Cleanup:
  360. VspFreeContext(filter->Root, context);
  361. if (extension) {
  362. ObDereferenceObject(extension->DeviceObject);
  363. }
  364. ObDereferenceObject(filter->DeviceObject);
  365. if (diffAreaFilter) {
  366. ObDereferenceObject(diffAreaFilter->DeviceObject);
  367. }
  368. }
  369. VOID
  370. VspLogError(
  371. IN PVOLUME_EXTENSION Extension,
  372. IN PFILTER_EXTENSION DiffAreaFilter,
  373. IN NTSTATUS SpecificIoStatus,
  374. IN NTSTATUS FinalStatus,
  375. IN ULONG UniqueErrorValue
  376. )
  377. {
  378. PDO_EXTENSION root;
  379. PVSP_CONTEXT context;
  380. if (Extension) {
  381. root = Extension->Root;
  382. } else {
  383. root = DiffAreaFilter->Root;
  384. }
  385. context = VspAllocateContext(root);
  386. if (!context) {
  387. return;
  388. }
  389. context->Type = VSP_CONTEXT_TYPE_ERROR_LOG;
  390. context->ErrorLog.Extension = Extension;
  391. context->ErrorLog.DiffAreaFilter = DiffAreaFilter;
  392. context->ErrorLog.SpecificIoStatus = SpecificIoStatus;
  393. context->ErrorLog.FinalStatus = FinalStatus;
  394. context->ErrorLog.UniqueErrorValue = UniqueErrorValue;
  395. if (Extension) {
  396. ObReferenceObject(Extension->DeviceObject);
  397. ObReferenceObject(Extension->Filter->DeviceObject);
  398. }
  399. if (DiffAreaFilter) {
  400. ObReferenceObject(DiffAreaFilter->DeviceObject);
  401. }
  402. ExInitializeWorkItem(&context->WorkItem, VspLogErrorWorker, context);
  403. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  404. }
  405. VOID
  406. VspWaitForWorkerThreadsToExit(
  407. IN PDO_EXTENSION RootExtension
  408. )
  409. {
  410. PVOID threadObject;
  411. CCHAR i, j;
  412. if (!RootExtension->WorkerThreadObjects) {
  413. return;
  414. }
  415. threadObject = RootExtension->WorkerThreadObjects[0];
  416. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE, NULL);
  417. ObDereferenceObject(threadObject);
  418. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  419. for (j = 0; j < KeNumberProcessors; j++) {
  420. threadObject = RootExtension->WorkerThreadObjects[
  421. (i - 1)*KeNumberProcessors + j + 1];
  422. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE,
  423. NULL);
  424. ObDereferenceObject(threadObject);
  425. }
  426. }
  427. ExFreePool(RootExtension->WorkerThreadObjects);
  428. RootExtension->WorkerThreadObjects = NULL;
  429. }
  430. NTSTATUS
  431. VspCreateWorkerThread(
  432. IN PDO_EXTENSION RootExtension
  433. )
  434. /*++
  435. Routine Description:
  436. This routine will create a new thread for a new volume snapshot. Since
  437. a minimum of 2 threads are needed to prevent deadlocks, if there are
  438. no threads then 2 threads will be created by this routine.
  439. Arguments:
  440. RootExtension - Supplies the root extension.
  441. Return Value:
  442. NTSTATUS
  443. Notes:
  444. The caller must be holding 'Root->Semaphore'.
  445. --*/
  446. {
  447. OBJECT_ATTRIBUTES oa;
  448. PVSP_CONTEXT context;
  449. NTSTATUS status;
  450. HANDLE handle;
  451. PVOID threadObject;
  452. CCHAR i, j, k;
  453. KeWaitForSingleObject(&RootExtension->ThreadsRefCountSemaphore,
  454. Executive, KernelMode, FALSE, NULL);
  455. if (RootExtension->ThreadsRefCount) {
  456. RootExtension->ThreadsRefCount++;
  457. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  458. IO_NO_INCREMENT, 1, FALSE);
  459. return STATUS_SUCCESS;
  460. }
  461. VspWaitForWorkerThreadsToExit(RootExtension);
  462. InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
  463. context = VspAllocateContext(RootExtension);
  464. if (!context) {
  465. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  466. IO_NO_INCREMENT, 1, FALSE);
  467. return STATUS_INSUFFICIENT_RESOURCES;
  468. }
  469. context->Type = VSP_CONTEXT_TYPE_THREAD_CREATION;
  470. context->ThreadCreation.RootExtension = RootExtension;
  471. context->ThreadCreation.QueueNumber = 0;
  472. ASSERT(!RootExtension->WorkerThreadObjects);
  473. RootExtension->WorkerThreadObjects = (PVOID*)
  474. ExAllocatePoolWithTag(NonPagedPool,
  475. (KeNumberProcessors*2 + 1)*sizeof(PVOID),
  476. VOLSNAP_TAG_IO_STATUS);
  477. if (!RootExtension->WorkerThreadObjects) {
  478. VspFreeContext(RootExtension, context);
  479. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  480. IO_NO_INCREMENT, 1, FALSE);
  481. return STATUS_INSUFFICIENT_RESOURCES;
  482. }
  483. status = PsCreateSystemThread(&handle, 0, &oa, 0, NULL, VspWorkerThread,
  484. context);
  485. if (!NT_SUCCESS(status)) {
  486. ExFreePool(RootExtension->WorkerThreadObjects);
  487. RootExtension->WorkerThreadObjects = NULL;
  488. VspFreeContext(RootExtension, context);
  489. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  490. IO_NO_INCREMENT, 1, FALSE);
  491. return status;
  492. }
  493. status = ObReferenceObjectByHandle(handle, THREAD_ALL_ACCESS, NULL,
  494. KernelMode, &threadObject, NULL);
  495. if (!NT_SUCCESS(status)) {
  496. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0],
  497. IO_NO_INCREMENT, 1, FALSE);
  498. ZwWaitForSingleObject(handle, FALSE, NULL);
  499. ExFreePool(RootExtension->WorkerThreadObjects);
  500. RootExtension->WorkerThreadObjects = NULL;
  501. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  502. IO_NO_INCREMENT, 1, FALSE);
  503. return status;
  504. }
  505. RootExtension->WorkerThreadObjects[0] = threadObject;
  506. ZwClose(handle);
  507. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  508. for (j = 0; j < KeNumberProcessors; j++) {
  509. context = VspAllocateContext(RootExtension);
  510. if (!context) {
  511. status = STATUS_INSUFFICIENT_RESOURCES;
  512. handle = NULL;
  513. break;
  514. }
  515. context->Type = VSP_CONTEXT_TYPE_THREAD_CREATION;
  516. context->ThreadCreation.RootExtension = RootExtension;
  517. context->ThreadCreation.QueueNumber = i;
  518. status = PsCreateSystemThread(&handle, 0, &oa, 0, NULL,
  519. VspWorkerThread, context);
  520. if (!NT_SUCCESS(status)) {
  521. VspFreeContext(RootExtension, context);
  522. handle = NULL;
  523. break;
  524. }
  525. status = ObReferenceObjectByHandle(
  526. handle, THREAD_ALL_ACCESS, NULL, KernelMode,
  527. &threadObject, NULL);
  528. if (!NT_SUCCESS(status)) {
  529. break;
  530. }
  531. RootExtension->WorkerThreadObjects[
  532. KeNumberProcessors*(i - 1) + j + 1] = threadObject;
  533. ZwClose(handle);
  534. }
  535. if (j < KeNumberProcessors) {
  536. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i],
  537. IO_NO_INCREMENT, j, FALSE);
  538. if (handle) {
  539. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i],
  540. IO_NO_INCREMENT, 1, FALSE);
  541. ZwWaitForSingleObject(handle, FALSE, NULL);
  542. ZwClose(handle);
  543. }
  544. for (k = 0; k < j; k++) {
  545. threadObject = RootExtension->WorkerThreadObjects[
  546. KeNumberProcessors*(i - 1) + k + 1];
  547. KeWaitForSingleObject(threadObject, Executive, KernelMode,
  548. FALSE, NULL);
  549. ObDereferenceObject(threadObject);
  550. }
  551. break;
  552. }
  553. }
  554. if (i < NUMBER_OF_THREAD_POOLS) {
  555. for (k = 1; k < i; k++) {
  556. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[k],
  557. IO_NO_INCREMENT, KeNumberProcessors, FALSE);
  558. for (j = 0; j < KeNumberProcessors; j++) {
  559. threadObject = RootExtension->WorkerThreadObjects[
  560. KeNumberProcessors*(k - 1) + j + 1];
  561. KeWaitForSingleObject(threadObject, Executive, KernelMode,
  562. FALSE, NULL);
  563. ObDereferenceObject(threadObject);
  564. }
  565. }
  566. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0],
  567. IO_NO_INCREMENT, 1, FALSE);
  568. threadObject = RootExtension->WorkerThreadObjects[0];
  569. KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE, NULL);
  570. ObDereferenceObject(threadObject);
  571. ExFreePool(RootExtension->WorkerThreadObjects);
  572. RootExtension->WorkerThreadObjects = NULL;
  573. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  574. IO_NO_INCREMENT, 1, FALSE);
  575. return status;
  576. }
  577. RootExtension->ThreadsRefCount++;
  578. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  579. IO_NO_INCREMENT, 1, FALSE);
  580. return STATUS_SUCCESS;
  581. }
  582. VOID
  583. VspWaitForWorkerThreadsToExitWorker(
  584. IN PVOID RootExtension
  585. )
  586. {
  587. PDO_EXTENSION rootExtension = (PDO_EXTENSION) RootExtension;
  588. KeWaitForSingleObject(&rootExtension->ThreadsRefCountSemaphore,
  589. Executive, KernelMode, FALSE, NULL);
  590. VspWaitForWorkerThreadsToExit(rootExtension);
  591. rootExtension->WaitForWorkerThreadsToExitWorkItemInUse = FALSE;
  592. KeReleaseSemaphore(&rootExtension->ThreadsRefCountSemaphore,
  593. IO_NO_INCREMENT, 1, FALSE);
  594. }
  595. NTSTATUS
  596. VspDeleteWorkerThread(
  597. IN PDO_EXTENSION RootExtension
  598. )
  599. /*++
  600. Routine Description:
  601. This routine will delete a worker thread.
  602. Arguments:
  603. RootExtension - Supplies the root extension.
  604. Return Value:
  605. NTSTATUS
  606. Notes:
  607. The caller must be holding 'Root->Semaphore'.
  608. --*/
  609. {
  610. CCHAR i, j;
  611. KeWaitForSingleObject(&RootExtension->ThreadsRefCountSemaphore,
  612. Executive, KernelMode, FALSE, NULL);
  613. RootExtension->ThreadsRefCount--;
  614. if (RootExtension->ThreadsRefCount) {
  615. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  616. IO_NO_INCREMENT, 1, FALSE);
  617. return STATUS_SUCCESS;
  618. }
  619. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[0], IO_NO_INCREMENT, 1,
  620. FALSE);
  621. for (i = 1; i < NUMBER_OF_THREAD_POOLS; i++) {
  622. KeReleaseSemaphore(&RootExtension->WorkerSemaphore[i], IO_NO_INCREMENT,
  623. KeNumberProcessors, FALSE);
  624. }
  625. if (RootExtension->WaitForWorkerThreadsToExitWorkItemInUse) {
  626. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  627. IO_NO_INCREMENT, 1, FALSE);
  628. return STATUS_SUCCESS;
  629. }
  630. RootExtension->WaitForWorkerThreadsToExitWorkItemInUse = TRUE;
  631. ExInitializeWorkItem(&RootExtension->WaitForWorkerThreadsToExitWorkItem,
  632. VspWaitForWorkerThreadsToExitWorker, RootExtension);
  633. ExQueueWorkItem(&RootExtension->WaitForWorkerThreadsToExitWorkItem,
  634. DelayedWorkQueue);
  635. KeReleaseSemaphore(&RootExtension->ThreadsRefCountSemaphore,
  636. IO_NO_INCREMENT, 1, FALSE);
  637. return STATUS_SUCCESS;
  638. }
  639. VOID
  640. VspQueryDiffAreaFileIncrease(
  641. IN PVOLUME_EXTENSION Extension,
  642. OUT PULONG Increase
  643. )
  644. {
  645. LONGLONG r;
  646. r = (LONGLONG) Extension->MaximumNumberOfTempEntries;
  647. r <<= BLOCK_SHIFT;
  648. if (r < NOMINAL_DIFF_AREA_FILE_GROWTH) {
  649. r = NOMINAL_DIFF_AREA_FILE_GROWTH;
  650. } else if (r > MAXIMUM_DIFF_AREA_FILE_GROWTH) {
  651. r = MAXIMUM_DIFF_AREA_FILE_GROWTH;
  652. }
  653. *Increase = (ULONG) r;
  654. }
  655. NTSTATUS
  656. VolSnapDefaultDispatch(
  657. IN PDEVICE_OBJECT DeviceObject,
  658. IN PIRP Irp
  659. )
  660. /*++
  661. Routine Description:
  662. This routine is the default dispatch which passes down to the next layer.
  663. Arguments:
  664. DeviceObject - Supplies the device object.
  665. Irp - Supplies the IO request packet.
  666. Return Value:
  667. NTSTATUS
  668. --*/
  669. {
  670. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  671. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  672. NTSTATUS status;
  673. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  674. IoSkipCurrentIrpStackLocation(Irp);
  675. return IoCallDriver(filter->TargetObject, Irp);
  676. }
  677. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  678. if (irpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL) {
  679. status = Irp->IoStatus.Status;
  680. } else {
  681. status = STATUS_INVALID_DEVICE_REQUEST;
  682. }
  683. Irp->IoStatus.Status = status;
  684. Irp->IoStatus.Information = 0;
  685. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  686. return status;
  687. }
  688. BOOLEAN
  689. VspAreBitsSet(
  690. IN PVOLUME_EXTENSION Extension,
  691. IN PIRP Irp
  692. )
  693. {
  694. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  695. LONGLONG start;
  696. ULONG startBlock, endBlock;
  697. BOOLEAN b;
  698. if (!Extension->VolumeBlockBitmap) {
  699. return FALSE;
  700. }
  701. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  702. if (start < 0) {
  703. return FALSE;
  704. }
  705. startBlock = (ULONG) (start >> BLOCK_SHIFT);
  706. endBlock = (ULONG) ((start + irpSp->Parameters.Read.Length - 1) >>
  707. BLOCK_SHIFT);
  708. b = RtlAreBitsSet(Extension->VolumeBlockBitmap, startBlock,
  709. endBlock - startBlock + 1);
  710. return b;
  711. }
  712. VOID
  713. VspDecrementVolumeRefCount(
  714. IN PVOLUME_EXTENSION Extension
  715. )
  716. {
  717. KIRQL irql;
  718. if (InterlockedDecrement(&Extension->RefCount)) {
  719. return;
  720. }
  721. ASSERT(Extension->HoldIncomingRequests);
  722. KeSetEvent(&Extension->ZeroRefEvent, IO_NO_INCREMENT, FALSE);
  723. }
  724. NTSTATUS
  725. VspIncrementVolumeRefCount(
  726. IN PVOLUME_EXTENSION Extension,
  727. IN PIRP Irp,
  728. IN PWORK_QUEUE_ITEM WorkItem
  729. )
  730. {
  731. KIRQL irql;
  732. ASSERT(Irp || WorkItem);
  733. ASSERT(!Irp || !WorkItem);
  734. InterlockedIncrement(&Extension->RefCount);
  735. if (Extension->IsDead) {
  736. VspDecrementVolumeRefCount(Extension);
  737. return STATUS_NO_SUCH_DEVICE;
  738. }
  739. if (!Extension->HoldIncomingRequests) {
  740. return STATUS_SUCCESS;
  741. }
  742. VspDecrementVolumeRefCount(Extension);
  743. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  744. if (!Extension->HoldIncomingRequests) {
  745. InterlockedIncrement(&Extension->RefCount);
  746. KeReleaseSpinLock(&Extension->SpinLock, irql);
  747. return STATUS_SUCCESS;
  748. }
  749. if (Irp) {
  750. IoMarkIrpPending(Irp);
  751. InsertTailList(&Extension->HoldIrpQueue, &Irp->Tail.Overlay.ListEntry);
  752. } else {
  753. InsertTailList(&Extension->HoldWorkerQueue, &WorkItem->List);
  754. }
  755. KeReleaseSpinLock(&Extension->SpinLock, irql);
  756. return STATUS_PENDING;
  757. }
  758. VOID
  759. VspSignalContext(
  760. IN PVOID Context
  761. )
  762. {
  763. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  764. ASSERT(context->Type == VSP_CONTEXT_TYPE_EVENT);
  765. KeSetEvent(&context->Event.Event, IO_NO_INCREMENT, FALSE);
  766. }
  767. VOID
  768. VspAcquireNonPagedResource(
  769. IN PVOLUME_EXTENSION Extension,
  770. IN PWORK_QUEUE_ITEM WorkItem
  771. )
  772. {
  773. PFILTER_EXTENSION filter = Extension->Filter;
  774. KIRQL irql;
  775. VSP_CONTEXT context;
  776. BOOLEAN synchronousCall;
  777. if (WorkItem) {
  778. synchronousCall = FALSE;
  779. } else {
  780. WorkItem = &context.WorkItem;
  781. context.Type = VSP_CONTEXT_TYPE_EVENT;
  782. KeInitializeEvent(&context.Event.Event, NotificationEvent, FALSE);
  783. ExInitializeWorkItem(&context.WorkItem, VspSignalContext, &context);
  784. synchronousCall = TRUE;
  785. }
  786. KeAcquireSpinLock(&filter->SpinLock, &irql);
  787. if (filter->NonPagedResourceInUse) {
  788. InsertTailList(&filter->NonPagedResourceList, &WorkItem->List);
  789. KeReleaseSpinLock(&filter->SpinLock, irql);
  790. if (synchronousCall) {
  791. KeWaitForSingleObject(&context.Event.Event, Executive, KernelMode,
  792. FALSE, NULL);
  793. }
  794. return;
  795. }
  796. filter->NonPagedResourceInUse = TRUE;
  797. KeReleaseSpinLock(&filter->SpinLock, irql);
  798. if (!synchronousCall) {
  799. WorkItem->WorkerRoutine(WorkItem->Parameter);
  800. }
  801. }
  802. VOID
  803. VspReleaseNonPagedResource(
  804. IN PVOLUME_EXTENSION Extension
  805. )
  806. {
  807. PFILTER_EXTENSION filter = Extension->Filter;
  808. KIRQL irql;
  809. PLIST_ENTRY l;
  810. PWORK_QUEUE_ITEM workItem;
  811. KeAcquireSpinLock(&filter->SpinLock, &irql);
  812. if (IsListEmpty(&filter->NonPagedResourceList)) {
  813. filter->NonPagedResourceInUse = FALSE;
  814. KeReleaseSpinLock(&filter->SpinLock, irql);
  815. return;
  816. }
  817. l = RemoveHeadList(&filter->NonPagedResourceList);
  818. KeReleaseSpinLock(&filter->SpinLock, irql);
  819. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  820. VspQueueWorkItem(Extension->Root, workItem, 2);
  821. }
  822. VOID
  823. VspAcquirePagedResource(
  824. IN PVOLUME_EXTENSION Extension,
  825. IN PWORK_QUEUE_ITEM WorkItem
  826. )
  827. {
  828. PFILTER_EXTENSION filter = Extension->Filter;
  829. KIRQL irql;
  830. VSP_CONTEXT context;
  831. BOOLEAN synchronousCall;
  832. if (WorkItem) {
  833. synchronousCall = FALSE;
  834. } else {
  835. WorkItem = &context.WorkItem;
  836. context.Type = VSP_CONTEXT_TYPE_EVENT;
  837. KeInitializeEvent(&context.Event.Event, NotificationEvent, FALSE);
  838. ExInitializeWorkItem(&context.WorkItem, VspSignalContext, &context);
  839. synchronousCall = TRUE;
  840. }
  841. KeAcquireSpinLock(&filter->SpinLock, &irql);
  842. if (filter->PagedResourceInUse) {
  843. InsertTailList(&filter->PagedResourceList, &WorkItem->List);
  844. KeReleaseSpinLock(&filter->SpinLock, irql);
  845. if (synchronousCall) {
  846. KeWaitForSingleObject(&context.Event.Event, Executive, KernelMode,
  847. FALSE, NULL);
  848. }
  849. return;
  850. }
  851. filter->PagedResourceInUse = TRUE;
  852. KeReleaseSpinLock(&filter->SpinLock, irql);
  853. if (!synchronousCall) {
  854. VspQueueWorkItem(filter->Root, WorkItem, 1);
  855. }
  856. }
  857. VOID
  858. VspReleasePagedResource(
  859. IN PVOLUME_EXTENSION Extension
  860. )
  861. {
  862. PFILTER_EXTENSION filter = Extension->Filter;
  863. KIRQL irql;
  864. PLIST_ENTRY l;
  865. PWORK_QUEUE_ITEM workItem;
  866. KeAcquireSpinLock(&filter->SpinLock, &irql);
  867. if (IsListEmpty(&filter->PagedResourceList)) {
  868. filter->PagedResourceInUse = FALSE;
  869. KeReleaseSpinLock(&filter->SpinLock, irql);
  870. return;
  871. }
  872. l = RemoveHeadList(&filter->PagedResourceList);
  873. KeReleaseSpinLock(&filter->SpinLock, irql);
  874. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  875. VspQueueWorkItem(filter->Root, workItem, 1);
  876. }
  877. NTSTATUS
  878. VspQueryListOfExtents(
  879. IN HANDLE FileHandle,
  880. IN LONGLONG FileOffset,
  881. OUT PLIST_ENTRY ExtentList
  882. )
  883. {
  884. NTSTATUS status;
  885. IO_STATUS_BLOCK ioStatus;
  886. FILE_FS_SIZE_INFORMATION fsSize;
  887. ULONG bpc;
  888. STARTING_VCN_INPUT_BUFFER input;
  889. RETRIEVAL_POINTERS_BUFFER output;
  890. LONGLONG start, length, delta;
  891. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  892. PLIST_ENTRY l;
  893. InitializeListHead(ExtentList);
  894. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  895. &fsSize, sizeof(fsSize),
  896. FileFsSizeInformation);
  897. if (!NT_SUCCESS(status)) {
  898. return status;
  899. }
  900. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  901. input.StartingVcn.QuadPart = FileOffset/bpc;
  902. for (;;) {
  903. status = ZwFsControlFile(FileHandle, NULL, NULL, NULL, &ioStatus,
  904. FSCTL_GET_RETRIEVAL_POINTERS, &input,
  905. sizeof(input), &output, sizeof(output));
  906. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
  907. break;
  908. }
  909. delta = input.StartingVcn.QuadPart - output.StartingVcn.QuadPart;
  910. start = (output.Extents[0].Lcn.QuadPart + delta)*bpc;
  911. length = (output.Extents[0].NextVcn.QuadPart -
  912. input.StartingVcn.QuadPart)*bpc;
  913. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  914. ExAllocatePoolWithTag(NonPagedPool,
  915. sizeof(DIFF_AREA_FILE_ALLOCATION),
  916. VOLSNAP_TAG_BIT_HISTORY);
  917. if (!diffAreaFileAllocation) {
  918. status = STATUS_INSUFFICIENT_RESOURCES;
  919. break;
  920. }
  921. diffAreaFileAllocation->Offset = start;
  922. diffAreaFileAllocation->Length = length;
  923. InsertTailList(ExtentList, &diffAreaFileAllocation->ListEntry);
  924. if (status != STATUS_BUFFER_OVERFLOW) {
  925. break;
  926. }
  927. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  928. }
  929. if (!NT_SUCCESS(status)) {
  930. while (!IsListEmpty(ExtentList)) {
  931. l = RemoveHeadList(ExtentList);
  932. diffAreaFileAllocation = CONTAINING_RECORD(l,
  933. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  934. ExFreePool(diffAreaFileAllocation);
  935. }
  936. }
  937. return status;
  938. }
  939. NTSTATUS
  940. VspSetFileSizes(
  941. IN HANDLE FileHandle,
  942. IN LONGLONG FileSize
  943. )
  944. {
  945. FILE_ALLOCATION_INFORMATION allocInfo;
  946. NTSTATUS status;
  947. IO_STATUS_BLOCK ioStatus;
  948. allocInfo.AllocationSize.QuadPart = FileSize;
  949. status = ZwSetInformationFile(FileHandle, &ioStatus,
  950. &allocInfo, sizeof(allocInfo),
  951. FileAllocationInformation);
  952. return status;
  953. }
  954. VOID
  955. VspGrowDiffArea(
  956. IN PVOID Context
  957. )
  958. {
  959. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  960. PVOLUME_EXTENSION extension = context->GrowDiffArea.Extension;
  961. PVSP_DIFF_AREA_FILE diffAreaFile = context->GrowDiffArea.DiffAreaFile;
  962. PFILTER_EXTENSION filter = extension->Filter;
  963. LONGLONG usableSpace = 0;
  964. HANDLE handle;
  965. NTSTATUS status;
  966. KIRQL irql;
  967. LIST_ENTRY extentList;
  968. PLIST_ENTRY l;
  969. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  970. ULONG s, n, i, increase;
  971. LONGLONG offset, endOffset, current;
  972. PVOLUME_EXTENSION bitmapExtension;
  973. LIST_ENTRY listOfDiffAreaFilesToClose;
  974. LIST_ENTRY listOfDeviceObjectsToDelete;
  975. ASSERT(context->Type == VSP_CONTEXT_TYPE_GROW_DIFF_AREA);
  976. VspFreeContext(extension->Root, context);
  977. DoOver:
  978. VspAcquire(extension->Root);
  979. if (extension->IsDead) {
  980. VspRelease(extension->Root);
  981. ObDereferenceObject(extension->DeviceObject);
  982. return;
  983. }
  984. handle = diffAreaFile->FileHandle;
  985. current = diffAreaFile->AllocatedFileSize;
  986. increase = extension->DiffAreaFileIncrease;
  987. ObReferenceObject(filter->DeviceObject);
  988. VspRelease(extension->Root);
  989. for (;;) {
  990. KeAcquireSpinLock(&filter->SpinLock, &irql);
  991. if (filter->MaximumVolumeSpace &&
  992. filter->AllocatedVolumeSpace + increase >
  993. filter->MaximumVolumeSpace) {
  994. KeReleaseSpinLock(&filter->SpinLock, irql);
  995. status = STATUS_DISK_FULL;
  996. } else {
  997. KeReleaseSpinLock(&filter->SpinLock, irql);
  998. status = VspSetFileSizes(handle, current + increase);
  999. if (NT_SUCCESS(status)) {
  1000. break;
  1001. }
  1002. }
  1003. if (increase > NOMINAL_DIFF_AREA_FILE_GROWTH) {
  1004. increase = NOMINAL_DIFF_AREA_FILE_GROWTH;
  1005. continue;
  1006. }
  1007. VspAcquire(extension->Root);
  1008. if (extension->IsDead) {
  1009. VspRelease(extension->Root);
  1010. ObDereferenceObject(extension->DeviceObject);
  1011. ObDereferenceObject(filter->DeviceObject);
  1012. return;
  1013. }
  1014. if (status != STATUS_DISK_FULL) {
  1015. VspLogError(extension, diffAreaFile->Filter,
  1016. VS_GROW_DIFF_AREA_FAILED, status, 0);
  1017. VspRelease(extension->Root);
  1018. ObDereferenceObject(extension->DeviceObject);
  1019. ObDereferenceObject(filter->DeviceObject);
  1020. return;
  1021. }
  1022. if (extension->ListEntry.Blink == &filter->VolumeList) {
  1023. VspLogError(extension, diffAreaFile->Filter,
  1024. VS_GROW_DIFF_AREA_FAILED_LOW_DISK_SPACE,
  1025. STATUS_DISK_FULL, 0);
  1026. VspRelease(extension->Root);
  1027. ObDereferenceObject(extension->DeviceObject);
  1028. ObDereferenceObject(filter->DeviceObject);
  1029. return;
  1030. }
  1031. InitializeListHead(&listOfDiffAreaFilesToClose);
  1032. InitializeListHead(&listOfDeviceObjectsToDelete);
  1033. status = VspDeleteOldestSnapshot(filter,
  1034. &listOfDiffAreaFilesToClose,
  1035. &listOfDeviceObjectsToDelete);
  1036. if (!NT_SUCCESS(status)) {
  1037. VspLogError(extension, diffAreaFile->Filter,
  1038. VS_GROW_DIFF_AREA_FAILED_LOW_DISK_SPACE,
  1039. STATUS_DISK_FULL, 0);
  1040. VspRelease(extension->Root);
  1041. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  1042. &listOfDeviceObjectsToDelete);
  1043. ObDereferenceObject(extension->DeviceObject);
  1044. ObDereferenceObject(filter->DeviceObject);
  1045. return;
  1046. }
  1047. VspRelease(extension->Root);
  1048. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  1049. &listOfDeviceObjectsToDelete);
  1050. }
  1051. status = VspQueryListOfExtents(handle, current, &extentList);
  1052. if (!NT_SUCCESS(status)) {
  1053. ObDereferenceObject(extension->DeviceObject);
  1054. ObDereferenceObject(filter->DeviceObject);
  1055. return;
  1056. }
  1057. VspAcquire(extension->Root);
  1058. if (extension->IsDead) {
  1059. VspRelease(extension->Root);
  1060. while (!IsListEmpty(&extentList)) {
  1061. l = RemoveHeadList(&extentList);
  1062. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1063. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1064. ExFreePool(diffAreaFileAllocation);
  1065. }
  1066. ObDereferenceObject(extension->DeviceObject);
  1067. ObDereferenceObject(filter->DeviceObject);
  1068. return;
  1069. }
  1070. if (diffAreaFile->Filter->PreparedSnapshot) {
  1071. status = VspMarkFileAllocationInBitmap(
  1072. diffAreaFile->Filter->PreparedSnapshot,
  1073. diffAreaFile->FileHandle, NULL, FALSE, FALSE, NULL);
  1074. if (!NT_SUCCESS(status)) {
  1075. VspLogError(extension, diffAreaFile->Filter,
  1076. VS_CANT_MAP_DIFF_AREA_FILE, status, 1);
  1077. VspAbortPreparedSnapshot(diffAreaFile->Filter, FALSE);
  1078. }
  1079. }
  1080. if (IsListEmpty(&diffAreaFile->Filter->VolumeList)) {
  1081. bitmapExtension = NULL;
  1082. } else {
  1083. bitmapExtension = CONTAINING_RECORD(
  1084. diffAreaFile->Filter->VolumeList.Blink,
  1085. VOLUME_EXTENSION, ListEntry);
  1086. if (bitmapExtension->IsDead) {
  1087. bitmapExtension = NULL;
  1088. }
  1089. }
  1090. VspAcquireNonPagedResource(extension, NULL);
  1091. while (!IsListEmpty(&extentList)) {
  1092. l = RemoveHeadList(&extentList);
  1093. InsertTailList(&diffAreaFile->UnusedAllocationList, l);
  1094. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1095. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1096. s = (ULONG) ((diffAreaFileAllocation->Offset + BLOCK_SIZE - 1)>>
  1097. BLOCK_SHIFT);
  1098. offset = ((LONGLONG) s)<<BLOCK_SHIFT;
  1099. endOffset = diffAreaFileAllocation->Offset +
  1100. diffAreaFileAllocation->Length;
  1101. if (endOffset < offset) {
  1102. continue;
  1103. }
  1104. n = (ULONG) ((endOffset - offset)>>BLOCK_SHIFT);
  1105. if (!n) {
  1106. continue;
  1107. }
  1108. if (bitmapExtension) {
  1109. KeAcquireSpinLock(&bitmapExtension->SpinLock, &irql);
  1110. for (i = 0; i < n; i++) {
  1111. if (RtlCheckBit(bitmapExtension->VolumeBlockBitmap, s + i)) {
  1112. usableSpace += BLOCK_SIZE;
  1113. }
  1114. }
  1115. KeReleaseSpinLock(&bitmapExtension->SpinLock, irql);
  1116. } else {
  1117. usableSpace += n<<BLOCK_SHIFT;
  1118. }
  1119. }
  1120. diffAreaFile->AllocatedFileSize += increase;
  1121. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1122. filter->AllocatedVolumeSpace += increase;
  1123. KeReleaseSpinLock(&filter->SpinLock, irql);
  1124. VspReleaseNonPagedResource(extension);
  1125. VspRelease(extension->Root);
  1126. ObDereferenceObject(filter->DeviceObject);
  1127. if (usableSpace < increase) {
  1128. goto DoOver;
  1129. }
  1130. ObDereferenceObject(extension->DeviceObject);
  1131. }
  1132. NTSTATUS
  1133. VspAllocateDiffAreaSpace(
  1134. IN PVOLUME_EXTENSION Extension,
  1135. OUT PVSP_DIFF_AREA_FILE* DiffAreaFile,
  1136. OUT PLONGLONG TargetOffset
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This routine allocates file space in a diff area file. The algorithm
  1141. for this allocation is round robin which means that different size
  1142. allocations can make the various files grow to be different sizes. The
  1143. earmarked file is used and grown as necessary to get the space desired.
  1144. Only if it is impossible to use the current file would the allocator go
  1145. to the next one. If a file needs to be grown, the allocator will
  1146. try to grow by 10 MB.
  1147. Arguments:
  1148. Extension - Supplies the volume extension.
  1149. DiffAreaFile - Returns the diff area file used in the allocation.
  1150. FileOffset - Returns the file offset in the diff area file used.
  1151. Return Value:
  1152. NTSTATUS
  1153. Notes:
  1154. Callers of this routine must be holding 'NonPagedResource'.
  1155. --*/
  1156. {
  1157. PFILTER_EXTENSION filter = Extension->Filter;
  1158. NTSTATUS status = STATUS_SUCCESS;
  1159. PVSP_DIFF_AREA_FILE firstDiffAreaFile, diffAreaFile;
  1160. ULONG i;
  1161. PLIST_ENTRY l;
  1162. LONGLONG remainder, delta;
  1163. KIRQL irql;
  1164. PVSP_CONTEXT context;
  1165. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1166. PVOLUME_EXTENSION targetExtension;
  1167. LONGLONG targetOffset;
  1168. ULONG bitToCheck;
  1169. firstDiffAreaFile = Extension->NextDiffAreaFile;
  1170. i = 0;
  1171. targetOffset = 0;
  1172. for (;;) {
  1173. diffAreaFile = Extension->NextDiffAreaFile;
  1174. if (diffAreaFile == firstDiffAreaFile) {
  1175. if (i) {
  1176. status = STATUS_INSUFFICIENT_RESOURCES;
  1177. break;
  1178. }
  1179. i++;
  1180. }
  1181. l = Extension->NextDiffAreaFile->VolumeListEntry.Flink;
  1182. if (l == &Extension->ListOfDiffAreaFiles) {
  1183. l = l->Flink;
  1184. }
  1185. Extension->NextDiffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  1186. VolumeListEntry);
  1187. if (IsListEmpty(&diffAreaFile->Filter->VolumeList)) {
  1188. targetExtension = NULL;
  1189. } else {
  1190. targetExtension = CONTAINING_RECORD(
  1191. diffAreaFile->Filter->VolumeList.Blink,
  1192. VOLUME_EXTENSION, ListEntry);
  1193. }
  1194. delta = 0;
  1195. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  1196. l = diffAreaFile->UnusedAllocationList.Flink;
  1197. diffAreaFileAllocation = CONTAINING_RECORD(l,
  1198. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1199. remainder = BLOCK_SIZE -
  1200. (diffAreaFileAllocation->Offset&(BLOCK_SIZE - 1));
  1201. if (remainder < BLOCK_SIZE) {
  1202. if (diffAreaFileAllocation->Length < remainder) {
  1203. delta += diffAreaFileAllocation->Length;
  1204. RemoveEntryList(l);
  1205. ExFreePool(diffAreaFileAllocation);
  1206. continue;
  1207. }
  1208. delta += remainder;
  1209. diffAreaFileAllocation->Offset += remainder;
  1210. diffAreaFileAllocation->Length -= remainder;
  1211. }
  1212. for (;;) {
  1213. if (diffAreaFileAllocation->Length < BLOCK_SIZE) {
  1214. delta += diffAreaFileAllocation->Length;
  1215. RemoveEntryList(l);
  1216. ExFreePool(diffAreaFileAllocation);
  1217. break;
  1218. }
  1219. if (targetExtension) {
  1220. bitToCheck = (ULONG)
  1221. (diffAreaFileAllocation->Offset>>BLOCK_SHIFT);
  1222. KeAcquireSpinLock(&targetExtension->SpinLock, &irql);
  1223. if (!RtlCheckBit(targetExtension->VolumeBlockBitmap,
  1224. bitToCheck)) {
  1225. KeReleaseSpinLock(&targetExtension->SpinLock, irql);
  1226. delta += BLOCK_SIZE;
  1227. diffAreaFileAllocation->Offset += BLOCK_SIZE;
  1228. diffAreaFileAllocation->Length -= BLOCK_SIZE;
  1229. continue;
  1230. }
  1231. KeReleaseSpinLock(&targetExtension->SpinLock, irql);
  1232. }
  1233. targetOffset = diffAreaFileAllocation->Offset;
  1234. diffAreaFileAllocation->Offset += BLOCK_SIZE;
  1235. diffAreaFileAllocation->Length -= BLOCK_SIZE;
  1236. break;
  1237. }
  1238. if (targetOffset) {
  1239. break;
  1240. }
  1241. }
  1242. if (!targetOffset) {
  1243. continue;
  1244. }
  1245. if (diffAreaFile->NextAvailable + delta + BLOCK_SIZE +
  1246. Extension->DiffAreaFileIncrease <=
  1247. diffAreaFile->AllocatedFileSize) {
  1248. break;
  1249. }
  1250. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease >
  1251. diffAreaFile->AllocatedFileSize) {
  1252. break;
  1253. }
  1254. if (!Extension->OkToGrowDiffArea) {
  1255. VspLogError(Extension, diffAreaFile->Filter,
  1256. VS_GROW_BEFORE_FREE_SPACE, STATUS_SUCCESS, 0);
  1257. break;
  1258. }
  1259. context = VspAllocateContext(Extension->Root);
  1260. if (!context) {
  1261. break;
  1262. }
  1263. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  1264. context->GrowDiffArea.Extension = Extension;
  1265. context->GrowDiffArea.DiffAreaFile = diffAreaFile;
  1266. ObReferenceObject(Extension->DeviceObject);
  1267. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea, context);
  1268. VspQueueWorkItem(Extension->Root, &context->WorkItem, 0);
  1269. break;
  1270. }
  1271. if (NT_SUCCESS(status)) {
  1272. *DiffAreaFile = diffAreaFile;
  1273. if (TargetOffset) {
  1274. *TargetOffset = targetOffset;
  1275. }
  1276. diffAreaFile->NextAvailable += delta + BLOCK_SIZE;
  1277. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1278. filter->UsedVolumeSpace += delta + BLOCK_SIZE;
  1279. KeReleaseSpinLock(&filter->SpinLock, irql);
  1280. }
  1281. return status;
  1282. }
  1283. VOID
  1284. VspDecrementVolumeIrpRefCount(
  1285. IN PVOID Irp
  1286. )
  1287. {
  1288. PIRP irp = (PIRP) Irp;
  1289. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  1290. PIO_STACK_LOCATION irpSp;
  1291. PVOLUME_EXTENSION extension;
  1292. if (InterlockedDecrement((PLONG) &nextSp->Parameters.Read.Length)) {
  1293. return;
  1294. }
  1295. irpSp = IoGetCurrentIrpStackLocation(irp);
  1296. extension = (PVOLUME_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  1297. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  1298. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  1299. VspDecrementVolumeRefCount(extension);
  1300. }
  1301. VOID
  1302. VspDecrementIrpRefCount(
  1303. IN PVOID Irp
  1304. )
  1305. {
  1306. PIRP irp = (PIRP) Irp;
  1307. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  1308. PIO_STACK_LOCATION irpSp;
  1309. PFILTER_EXTENSION filter;
  1310. PVOLUME_EXTENSION extension;
  1311. PLIST_ENTRY l;
  1312. PVSP_DIFF_AREA_FILE diffAreaFile;
  1313. if (InterlockedDecrement((PLONG) &nextSp->Parameters.Read.Length)) {
  1314. return;
  1315. }
  1316. irpSp = IoGetCurrentIrpStackLocation(irp);
  1317. filter = (PFILTER_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  1318. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  1319. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  1320. VOLUME_EXTENSION, ListEntry);
  1321. for (l = extension->ListOfDiffAreaFiles.Flink;
  1322. l != &extension->ListOfDiffAreaFiles; l = l->Flink) {
  1323. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  1324. VolumeListEntry);
  1325. VspDecrementRefCount(diffAreaFile->Filter);
  1326. }
  1327. IoCopyCurrentIrpStackLocationToNext(irp);
  1328. IoSetCompletionRoutine(irp, VspRefCountCompletionRoutine, filter,
  1329. TRUE, TRUE, TRUE);
  1330. IoCallDriver(filter->TargetObject, irp);
  1331. }
  1332. VOID
  1333. VspDecrementIrpRefCountWorker(
  1334. IN PVOID Context
  1335. )
  1336. {
  1337. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1338. PVOLUME_EXTENSION extension = context->Extension.Extension;
  1339. PIRP irp = context->Extension.Irp;
  1340. if (context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME) {
  1341. ExInitializeWorkItem(&context->WorkItem, VspWriteVolume, context);
  1342. VspAcquireNonPagedResource(extension, &context->WorkItem);
  1343. } else {
  1344. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  1345. VspFreeContext(extension->Root, context);
  1346. }
  1347. VspDecrementIrpRefCount(irp);
  1348. }
  1349. VOID
  1350. VspSignalCallback(
  1351. IN PFILTER_EXTENSION Filter
  1352. )
  1353. {
  1354. KeSetEvent((PKEVENT) Filter->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  1355. }
  1356. VOID
  1357. VspCleanupVolumeSnapshot(
  1358. IN PVOLUME_EXTENSION Extension,
  1359. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose
  1360. )
  1361. /*++
  1362. Routine Description:
  1363. This routine kills an existing volume snapshot.
  1364. Arguments:
  1365. Extension - Supplies the volume extension.
  1366. Return Value:
  1367. NTSTATUS
  1368. Notes:
  1369. Root->Semaphore required for calling this routine.
  1370. --*/
  1371. {
  1372. PFILTER_EXTENSION filter = Extension->Filter;
  1373. PLIST_ENTRY l, ll;
  1374. PVSP_DIFF_AREA_FILE diffAreaFile;
  1375. KIRQL irql;
  1376. POLD_HEAP_ENTRY oldHeapEntry;
  1377. NTSTATUS status;
  1378. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  1379. PVOID p;
  1380. VspAcquirePagedResource(Extension, NULL);
  1381. if (Extension->DiffAreaFileMap) {
  1382. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  1383. Extension->DiffAreaFileMap);
  1384. ASSERT(NT_SUCCESS(status));
  1385. Extension->DiffAreaFileMap = NULL;
  1386. }
  1387. if (Extension->NextDiffAreaFileMap) {
  1388. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  1389. Extension->NextDiffAreaFileMap);
  1390. ASSERT(NT_SUCCESS(status));
  1391. Extension->NextDiffAreaFileMap = NULL;
  1392. }
  1393. while (!IsListEmpty(&Extension->OldHeaps)) {
  1394. l = RemoveHeadList(&Extension->OldHeaps);
  1395. oldHeapEntry = CONTAINING_RECORD(l, OLD_HEAP_ENTRY, ListEntry);
  1396. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  1397. oldHeapEntry->DiffAreaFileMap);
  1398. ASSERT(NT_SUCCESS(status));
  1399. ExFreePool(oldHeapEntry);
  1400. }
  1401. VspReleasePagedResource(Extension);
  1402. VspCleanupBitsSetInOtherPreparedSnapshots(Extension);
  1403. while (!IsListEmpty(&Extension->ListOfDiffAreaFiles)) {
  1404. l = RemoveHeadList(&Extension->ListOfDiffAreaFiles);
  1405. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  1406. VolumeListEntry);
  1407. if (diffAreaFile->FilterListEntryBeingUsed) {
  1408. RemoveEntryList(&diffAreaFile->FilterListEntry);
  1409. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  1410. }
  1411. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1412. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  1413. filter->UsedVolumeSpace -= diffAreaFile->NextAvailable;
  1414. KeReleaseSpinLock(&filter->SpinLock, irql);
  1415. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  1416. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  1417. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  1418. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  1419. ExFreePool(diffAreaFileAllocation);
  1420. }
  1421. InsertTailList(ListOfDiffAreaFilesToClose,
  1422. &diffAreaFile->VolumeListEntry);
  1423. }
  1424. Extension->NextDiffAreaFile = NULL;
  1425. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  1426. if (Extension->VolumeBlockBitmap) {
  1427. ExFreePool(Extension->VolumeBlockBitmap->Buffer);
  1428. ExFreePool(Extension->VolumeBlockBitmap);
  1429. Extension->VolumeBlockBitmap = NULL;
  1430. }
  1431. if (Extension->IgnorableProduct) {
  1432. ExFreePool(Extension->IgnorableProduct->Buffer);
  1433. ExFreePool(Extension->IgnorableProduct);
  1434. Extension->IgnorableProduct = NULL;
  1435. }
  1436. KeReleaseSpinLock(&Extension->SpinLock, irql);
  1437. VspAcquirePagedResource(Extension, NULL);
  1438. if (Extension->ApplicationInformation) {
  1439. Extension->ApplicationInformationSize = 0;
  1440. ExFreePool(Extension->ApplicationInformation);
  1441. Extension->ApplicationInformation = NULL;
  1442. }
  1443. VspReleasePagedResource(Extension);
  1444. if (Extension->EmergencyCopyIrp) {
  1445. ExFreePool(MmGetMdlVirtualAddress(
  1446. Extension->EmergencyCopyIrp->MdlAddress));
  1447. IoFreeMdl(Extension->EmergencyCopyIrp->MdlAddress);
  1448. IoFreeIrp(Extension->EmergencyCopyIrp);
  1449. Extension->EmergencyCopyIrp = NULL;
  1450. }
  1451. VspDeleteWorkerThread(filter->Root);
  1452. }
  1453. VOID
  1454. VspEmptyIrpQueue(
  1455. IN PDRIVER_OBJECT DriverObject,
  1456. IN PLIST_ENTRY IrpQueue
  1457. )
  1458. {
  1459. PLIST_ENTRY l;
  1460. PIRP irp;
  1461. PIO_STACK_LOCATION irpSp;
  1462. while (!IsListEmpty(IrpQueue)) {
  1463. l = RemoveHeadList(IrpQueue);
  1464. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  1465. irpSp = IoGetCurrentIrpStackLocation(irp);
  1466. DriverObject->MajorFunction[irpSp->MajorFunction](irpSp->DeviceObject,
  1467. irp);
  1468. }
  1469. }
  1470. VOID
  1471. VspEmptyWorkerQueue(
  1472. IN PLIST_ENTRY WorkerQueue
  1473. )
  1474. {
  1475. PLIST_ENTRY l;
  1476. PWORK_QUEUE_ITEM workItem;
  1477. while (!IsListEmpty(WorkerQueue)) {
  1478. l = RemoveHeadList(WorkerQueue);
  1479. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  1480. workItem->WorkerRoutine(workItem->Parameter);
  1481. }
  1482. }
  1483. VOID
  1484. VspResumeSnapshotIo(
  1485. IN PVOLUME_EXTENSION Extension
  1486. )
  1487. {
  1488. KIRQL irql;
  1489. BOOLEAN emptyQueue, eQQ;
  1490. LIST_ENTRY q, qq;
  1491. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  1492. if (IsListEmpty(&Extension->HoldIrpQueue)) {
  1493. emptyQueue = FALSE;
  1494. } else {
  1495. emptyQueue = TRUE;
  1496. q = Extension->HoldIrpQueue;
  1497. InitializeListHead(&Extension->HoldIrpQueue);
  1498. }
  1499. if (IsListEmpty(&Extension->HoldWorkerQueue)) {
  1500. eQQ = FALSE;
  1501. } else {
  1502. eQQ = TRUE;
  1503. qq = Extension->HoldWorkerQueue;
  1504. InitializeListHead(&Extension->HoldWorkerQueue);
  1505. }
  1506. InterlockedIncrement(&Extension->RefCount);
  1507. InterlockedExchange(&Extension->HoldIncomingRequests, FALSE);
  1508. KeReleaseSpinLock(&Extension->SpinLock, irql);
  1509. if (emptyQueue) {
  1510. q.Blink->Flink = &q;
  1511. q.Flink->Blink = &q;
  1512. VspEmptyIrpQueue(Extension->Root->DriverObject, &q);
  1513. }
  1514. if (eQQ) {
  1515. qq.Blink->Flink = &qq;
  1516. qq.Flink->Blink = &qq;
  1517. VspEmptyWorkerQueue(&qq);
  1518. }
  1519. }
  1520. VOID
  1521. VspPauseSnapshotIo(
  1522. IN PVOLUME_EXTENSION Extension
  1523. )
  1524. {
  1525. KIRQL irql;
  1526. VspReleaseWrites(Extension->Filter);
  1527. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  1528. ASSERT(!Extension->HoldIncomingRequests);
  1529. KeInitializeEvent(&Extension->ZeroRefEvent, NotificationEvent, FALSE);
  1530. InterlockedExchange(&Extension->HoldIncomingRequests, TRUE);
  1531. KeReleaseSpinLock(&Extension->SpinLock, irql);
  1532. VspDecrementVolumeRefCount(Extension);
  1533. KeWaitForSingleObject(&Extension->ZeroRefEvent, Executive, KernelMode,
  1534. FALSE, NULL);
  1535. }
  1536. VOID
  1537. VspResumeVolumeIo(
  1538. IN PFILTER_EXTENSION Filter
  1539. )
  1540. {
  1541. KIRQL irql;
  1542. BOOLEAN emptyQueue;
  1543. LIST_ENTRY q;
  1544. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  1545. InterlockedIncrement(&Filter->RefCount);
  1546. InterlockedExchange(&Filter->HoldIncomingWrites, FALSE);
  1547. if (IsListEmpty(&Filter->HoldQueue)) {
  1548. emptyQueue = FALSE;
  1549. } else {
  1550. emptyQueue = TRUE;
  1551. q = Filter->HoldQueue;
  1552. InitializeListHead(&Filter->HoldQueue);
  1553. }
  1554. KeReleaseSpinLock(&Filter->SpinLock, irql);
  1555. if (emptyQueue) {
  1556. q.Blink->Flink = &q;
  1557. q.Flink->Blink = &q;
  1558. VspEmptyIrpQueue(Filter->Root->DriverObject, &q);
  1559. }
  1560. }
  1561. VOID
  1562. VspPauseVolumeIo(
  1563. IN PFILTER_EXTENSION Filter
  1564. )
  1565. {
  1566. KEVENT event;
  1567. KIRQL irql;
  1568. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1569. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  1570. ASSERT(!Filter->HoldIncomingWrites);
  1571. InterlockedExchange(&Filter->HoldIncomingWrites, TRUE);
  1572. Filter->ZeroRefCallback = VspSignalCallback;
  1573. Filter->ZeroRefContext = &event;
  1574. KeReleaseSpinLock(&Filter->SpinLock, irql);
  1575. VspDecrementRefCount(Filter);
  1576. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1577. }
  1578. NTSTATUS
  1579. VspDeleteOldestSnapshot(
  1580. IN PFILTER_EXTENSION Filter,
  1581. IN OUT PLIST_ENTRY ListOfDiffAreaFilesToClose,
  1582. IN OUT PLIST_ENTRY LisfOfDeviceObjectsToDelete
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. This routine deletes the oldest volume snapshot on the given volume.
  1587. Arguments:
  1588. Filter - Supplies the filter extension.
  1589. Return Value:
  1590. NTSTATUS
  1591. Notes:
  1592. This routine assumes that Root->Semaphore is being held.
  1593. --*/
  1594. {
  1595. PFILTER_EXTENSION filter = Filter;
  1596. PLIST_ENTRY l;
  1597. PVOLUME_EXTENSION extension;
  1598. KIRQL irql;
  1599. if (IsListEmpty(&filter->VolumeList)) {
  1600. return STATUS_INVALID_PARAMETER;
  1601. }
  1602. l = filter->VolumeList.Flink;
  1603. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  1604. KeAcquireSpinLock(&extension->SpinLock, &irql);
  1605. InterlockedExchange(&extension->IsDead, TRUE);
  1606. InterlockedExchange(&extension->IsStarted, FALSE);
  1607. KeReleaseSpinLock(&extension->SpinLock, irql);
  1608. VspPauseSnapshotIo(extension);
  1609. VspResumeSnapshotIo(extension);
  1610. VspPauseVolumeIo(filter);
  1611. ObReferenceObject(extension->DeviceObject);
  1612. KeAcquireSpinLock(&filter->SpinLock, &irql);
  1613. RemoveEntryList(&extension->ListEntry);
  1614. if (IsListEmpty(&filter->VolumeList)) {
  1615. InterlockedExchange(&filter->SnapshotsPresent, FALSE);
  1616. }
  1617. KeReleaseSpinLock(&filter->SpinLock, irql);
  1618. VspResumeVolumeIo(filter);
  1619. VspCleanupVolumeSnapshot(extension, ListOfDiffAreaFilesToClose);
  1620. if (extension->AliveToPnp) {
  1621. InsertTailList(&filter->DeadVolumeList, &extension->ListEntry);
  1622. IoInvalidateDeviceRelations(filter->Pdo, BusRelations);
  1623. } else {
  1624. IoDeleteDevice(extension->DeviceObject);
  1625. }
  1626. InsertTailList(LisfOfDeviceObjectsToDelete, &extension->HoldIrpQueue);
  1627. return STATUS_SUCCESS;
  1628. }
  1629. VOID
  1630. VspCloseDiffAreaFiles(
  1631. IN PLIST_ENTRY ListOfDiffAreaFilesToClose,
  1632. IN PLIST_ENTRY ListOfDeviceObjectsToDelete
  1633. )
  1634. {
  1635. PLIST_ENTRY l;
  1636. PVSP_DIFF_AREA_FILE diffAreaFile;
  1637. PVOLUME_EXTENSION extension;
  1638. while (!IsListEmpty(ListOfDiffAreaFilesToClose)) {
  1639. l = RemoveHeadList(ListOfDiffAreaFilesToClose);
  1640. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  1641. VolumeListEntry);
  1642. ZwClose(diffAreaFile->FileHandle);
  1643. ExFreePool(diffAreaFile);
  1644. }
  1645. while (!IsListEmpty(ListOfDeviceObjectsToDelete)) {
  1646. l = RemoveHeadList(ListOfDeviceObjectsToDelete);
  1647. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, HoldIrpQueue);
  1648. ObDereferenceObject(extension->DeviceObject);
  1649. }
  1650. }
  1651. VOID
  1652. VspDestroyAllSnapshotsWorker(
  1653. IN PVOID Context
  1654. )
  1655. /*++
  1656. Routine Description:
  1657. This routine will delete all of the snapshots in the system.
  1658. Arguments:
  1659. Filter - Supplies the filter extension.
  1660. Return Value:
  1661. None.
  1662. --*/
  1663. {
  1664. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1665. PFILTER_EXTENSION filter = context->Filter.Filter;
  1666. LIST_ENTRY listOfDiffAreaFilesToClose;
  1667. LIST_ENTRY listOfDeviceObjectToDelete;
  1668. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  1669. KernelMode, FALSE, NULL);
  1670. InitializeListHead(&listOfDiffAreaFilesToClose);
  1671. InitializeListHead(&listOfDeviceObjectToDelete);
  1672. VspAcquire(filter->Root);
  1673. while (!IsListEmpty(&filter->VolumeList)) {
  1674. VspDeleteOldestSnapshot(filter, &listOfDiffAreaFilesToClose,
  1675. &listOfDeviceObjectToDelete);
  1676. }
  1677. InterlockedExchange(&filter->DestroyAllSnapshotsPending, FALSE);
  1678. VspRelease(filter->Root);
  1679. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  1680. &listOfDeviceObjectToDelete);
  1681. ObDereferenceObject(filter->DeviceObject);
  1682. }
  1683. VOID
  1684. VspAbortTableEntryWorker(
  1685. IN PVOID TableEntry
  1686. )
  1687. {
  1688. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1689. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1690. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable, tableEntry);
  1691. VspReleaseNonPagedResource(extension);
  1692. ObDereferenceObject(extension->Filter->DeviceObject);
  1693. ObDereferenceObject(extension->DeviceObject);
  1694. }
  1695. VOID
  1696. VspDestroyAllSnapshots(
  1697. IN PFILTER_EXTENSION Filter,
  1698. IN PTEMP_TRANSLATION_TABLE_ENTRY TableEntry
  1699. )
  1700. /*++
  1701. Routine Description:
  1702. This routine will delete all of the snapshots in the system.
  1703. Arguments:
  1704. Filter - Supplies the filter extension.
  1705. Return Value:
  1706. None.
  1707. --*/
  1708. {
  1709. PVOLUME_EXTENSION extension;
  1710. PIRP irp;
  1711. KIRQL irql;
  1712. PWORK_QUEUE_ITEM workItem;
  1713. NTSTATUS status;
  1714. PVSP_CONTEXT context;
  1715. if (TableEntry) {
  1716. extension = TableEntry->Extension;
  1717. irp = TableEntry->WriteIrp;
  1718. TableEntry->WriteIrp = NULL;
  1719. if (TableEntry->CopyIrp) {
  1720. VspFreeCopyIrp(extension, TableEntry->CopyIrp);
  1721. TableEntry->CopyIrp = NULL;
  1722. }
  1723. KeAcquireSpinLock(&extension->SpinLock, &irql);
  1724. RtlSetBit(extension->VolumeBlockBitmap,
  1725. (ULONG) (TableEntry->VolumeOffset>>BLOCK_SHIFT));
  1726. TableEntry->IsComplete = TRUE;
  1727. KeReleaseSpinLock(&extension->SpinLock, irql);
  1728. VspEmptyWorkerQueue(&TableEntry->WaitingQueueDpc);
  1729. ObReferenceObject(extension->DeviceObject);
  1730. ObReferenceObject(extension->Filter->DeviceObject);
  1731. if (irp) {
  1732. VspDecrementIrpRefCount(irp);
  1733. }
  1734. workItem = &TableEntry->WorkItem;
  1735. ExInitializeWorkItem(workItem, VspAbortTableEntryWorker, TableEntry);
  1736. VspAcquireNonPagedResource(extension, workItem);
  1737. }
  1738. if (InterlockedExchange(&Filter->DestroyAllSnapshotsPending, TRUE)) {
  1739. return;
  1740. }
  1741. context = &Filter->DestroyContext;
  1742. context->Type = VSP_CONTEXT_TYPE_FILTER;
  1743. context->Filter.Filter = Filter;
  1744. ObReferenceObject(Filter->DeviceObject);
  1745. ExInitializeWorkItem(&context->WorkItem, VspDestroyAllSnapshotsWorker,
  1746. context);
  1747. VspQueueWorkItem(Filter->Root, &context->WorkItem, 0);
  1748. }
  1749. VOID
  1750. VspWriteVolumePhase5(
  1751. IN PVOID TableEntry
  1752. )
  1753. {
  1754. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1755. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1756. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable, tableEntry);
  1757. VspReleaseNonPagedResource(extension);
  1758. VspDecrementVolumeRefCount(extension);
  1759. }
  1760. VOID
  1761. VspWriteVolumePhase4(
  1762. IN PVOID TableEntry
  1763. )
  1764. /*++
  1765. Routine Description:
  1766. This routine is queued from the completion of writting a block to
  1767. make up a table entry for the write. This routine will create and
  1768. insert the table entry.
  1769. Arguments:
  1770. Context - Supplies the context.
  1771. Return Value:
  1772. None.
  1773. --*/
  1774. {
  1775. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1776. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1777. PFILTER_EXTENSION filter = extension->Filter;
  1778. TRANSLATION_TABLE_ENTRY keyTableEntry;
  1779. PVOID r;
  1780. KIRQL irql;
  1781. RtlZeroMemory(&keyTableEntry, sizeof(TRANSLATION_TABLE_ENTRY));
  1782. keyTableEntry.VolumeOffset = tableEntry->VolumeOffset;
  1783. keyTableEntry.TargetObject = tableEntry->TargetObject;
  1784. keyTableEntry.TargetOffset = tableEntry->TargetOffset;
  1785. _try {
  1786. r = RtlInsertElementGenericTable(&extension->VolumeBlockTable,
  1787. &keyTableEntry,
  1788. sizeof(TRANSLATION_TABLE_ENTRY),
  1789. NULL);
  1790. } _except (EXCEPTION_EXECUTE_HANDLER) {
  1791. r = NULL;
  1792. }
  1793. VspReleasePagedResource(extension);
  1794. if (!r) {
  1795. KeAcquireSpinLock(&extension->SpinLock, &irql);
  1796. if (extension->PageFileSpaceCreatePending) {
  1797. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase4,
  1798. tableEntry);
  1799. InsertTailList(&extension->WaitingForPageFileSpace,
  1800. &tableEntry->WorkItem.List);
  1801. KeReleaseSpinLock(&extension->SpinLock, irql);
  1802. return;
  1803. }
  1804. KeReleaseSpinLock(&extension->SpinLock, irql);
  1805. if (!filter->DestroyAllSnapshotsPending) {
  1806. VspLogError(extension, NULL, VS_ABORT_SNAPSHOTS_NO_HEAP,
  1807. STATUS_SUCCESS, 0);
  1808. }
  1809. VspDestroyAllSnapshots(filter, tableEntry);
  1810. VspDecrementVolumeRefCount(extension);
  1811. return;
  1812. }
  1813. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase5,
  1814. tableEntry);
  1815. VspAcquireNonPagedResource(extension, &tableEntry->WorkItem);
  1816. }
  1817. VOID
  1818. VspWriteVolumeRefCount(
  1819. IN PVOID TableEntry
  1820. )
  1821. {
  1822. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1823. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1824. PWORK_QUEUE_ITEM workItem;
  1825. NTSTATUS status;
  1826. workItem = &tableEntry->WorkItem;
  1827. status = VspIncrementVolumeRefCount(extension, NULL, workItem);
  1828. if (!NT_SUCCESS(status)) {
  1829. VspDestroyAllSnapshots(extension->Filter, tableEntry);
  1830. return;
  1831. }
  1832. if (status == STATUS_PENDING) {
  1833. return;
  1834. }
  1835. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase4,
  1836. tableEntry);
  1837. VspAcquirePagedResource(extension, &tableEntry->WorkItem);
  1838. }
  1839. NTSTATUS
  1840. VspWriteVolumePhase3(
  1841. IN PDEVICE_OBJECT DeviceObject,
  1842. IN PIRP Irp,
  1843. IN PVOID TableEntry
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. This routine is the completion for a write to the diff area file.
  1848. Arguments:
  1849. Context - Supplies the context.
  1850. Return Value:
  1851. STATUS_MORE_PROCESSING_REQUIRED
  1852. --*/
  1853. {
  1854. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1855. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1856. PFILTER_EXTENSION filter = extension->Filter;
  1857. NTSTATUS status = Irp->IoStatus.Status;
  1858. KIRQL irql;
  1859. BOOLEAN emptyQueue;
  1860. PLIST_ENTRY l;
  1861. PWORK_QUEUE_ITEM workItem;
  1862. PVSP_CONTEXT context;
  1863. PIRP irp;
  1864. if (!NT_SUCCESS(status)) {
  1865. if (!filter->DestroyAllSnapshotsPending) {
  1866. VspLogError(extension, NULL, VS_ABORT_SNAPSHOTS_IO_FAILURE,
  1867. status, 1);
  1868. }
  1869. VspDestroyAllSnapshots(filter, tableEntry);
  1870. return STATUS_MORE_PROCESSING_REQUIRED;
  1871. }
  1872. VspFreeCopyIrp(extension, Irp);
  1873. tableEntry->CopyIrp = NULL;
  1874. KeAcquireSpinLock(&extension->SpinLock, &irql);
  1875. RtlSetBit(extension->VolumeBlockBitmap,
  1876. (ULONG) (tableEntry->VolumeOffset>>BLOCK_SHIFT));
  1877. tableEntry->IsComplete = TRUE;
  1878. KeReleaseSpinLock(&extension->SpinLock, irql);
  1879. while (!IsListEmpty(&tableEntry->WaitingQueueDpc)) {
  1880. l = RemoveHeadList(&tableEntry->WaitingQueueDpc);
  1881. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  1882. context = (PVSP_CONTEXT) workItem->Parameter;
  1883. if (context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT) {
  1884. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  1885. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  1886. }
  1887. workItem->WorkerRoutine(workItem->Parameter);
  1888. }
  1889. irp = tableEntry->WriteIrp;
  1890. tableEntry->WriteIrp = NULL;
  1891. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumeRefCount,
  1892. tableEntry);
  1893. status = VspIncrementVolumeRefCount(extension, NULL,
  1894. &tableEntry->WorkItem);
  1895. if (!NT_SUCCESS(status)) {
  1896. VspDestroyAllSnapshots(filter, tableEntry);
  1897. VspDecrementIrpRefCount(irp);
  1898. return STATUS_MORE_PROCESSING_REQUIRED;
  1899. }
  1900. VspDecrementIrpRefCount(irp);
  1901. if (status != STATUS_PENDING) {
  1902. ExInitializeWorkItem(&tableEntry->WorkItem, VspWriteVolumePhase4,
  1903. tableEntry);
  1904. VspAcquirePagedResource(extension, &tableEntry->WorkItem);
  1905. }
  1906. return STATUS_MORE_PROCESSING_REQUIRED;
  1907. }
  1908. NTSTATUS
  1909. VspWriteVolumePhase2(
  1910. IN PDEVICE_OBJECT DeviceObject,
  1911. IN PIRP Irp,
  1912. IN PVOID TableEntry
  1913. )
  1914. /*++
  1915. Routine Description:
  1916. This routine is the completion for a read who's data will create
  1917. the table entry for the block that is being written to.
  1918. Arguments:
  1919. Context - Supplies the context.
  1920. Return Value:
  1921. STATUS_MORE_PROCESSING_REQUIRED
  1922. --*/
  1923. {
  1924. NTSTATUS status = Irp->IoStatus.Status;
  1925. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
  1926. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1927. if (!NT_SUCCESS(status)) {
  1928. if (!tableEntry->Extension->Filter->DestroyAllSnapshotsPending) {
  1929. VspLogError(tableEntry->Extension, NULL,
  1930. VS_ABORT_SNAPSHOTS_IO_FAILURE, status, 2);
  1931. }
  1932. VspDestroyAllSnapshots(tableEntry->Extension->Filter, tableEntry);
  1933. return STATUS_MORE_PROCESSING_REQUIRED;
  1934. }
  1935. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1936. nextSp = IoGetNextIrpStackLocation(Irp);
  1937. nextSp->Parameters.Write.ByteOffset.QuadPart = tableEntry->TargetOffset;
  1938. nextSp->Parameters.Write.Length = BLOCK_SIZE;
  1939. nextSp->MajorFunction = IRP_MJ_WRITE;
  1940. nextSp->DeviceObject = tableEntry->TargetObject;
  1941. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  1942. IoSetCompletionRoutine(Irp, VspWriteVolumePhase3, tableEntry, TRUE, TRUE,
  1943. TRUE);
  1944. IoCallDriver(tableEntry->TargetObject, Irp);
  1945. return STATUS_MORE_PROCESSING_REQUIRED;
  1946. }
  1947. VOID
  1948. VspWriteVolumePhase1(
  1949. IN PVOID TableEntry
  1950. )
  1951. /*++
  1952. Routine Description:
  1953. This routine is the first phase of copying volume data to the diff
  1954. area file. An irp and buffer are created for the initial read of
  1955. the block.
  1956. Arguments:
  1957. Context - Supplies the context.
  1958. Return Value:
  1959. None.
  1960. --*/
  1961. {
  1962. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) TableEntry;
  1963. PVOLUME_EXTENSION extension = tableEntry->Extension;
  1964. PFILTER_EXTENSION filter = extension->Filter;
  1965. PIRP irp = tableEntry->CopyIrp;
  1966. PIO_STACK_LOCATION nextSp;
  1967. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1968. nextSp = IoGetNextIrpStackLocation(irp);
  1969. nextSp->Parameters.Read.ByteOffset.QuadPart = tableEntry->VolumeOffset;
  1970. nextSp->Parameters.Read.Length = BLOCK_SIZE;
  1971. nextSp->MajorFunction = IRP_MJ_READ;
  1972. nextSp->DeviceObject = filter->TargetObject;
  1973. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  1974. if (tableEntry->VolumeOffset + BLOCK_SIZE > extension->VolumeSize) {
  1975. if (extension->VolumeSize > tableEntry->VolumeOffset) {
  1976. nextSp->Parameters.Read.Length = (ULONG) (extension->VolumeSize -
  1977. tableEntry->VolumeOffset);
  1978. }
  1979. }
  1980. IoSetCompletionRoutine(irp, VspWriteVolumePhase2, tableEntry, TRUE, TRUE,
  1981. TRUE);
  1982. IoCallDriver(filter->TargetObject, irp);
  1983. }
  1984. VOID
  1985. VspUnmapNextDiffAreaFileMap(
  1986. IN PVOID Context
  1987. )
  1988. {
  1989. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  1990. PVOLUME_EXTENSION extension = context->Extension.Extension;
  1991. NTSTATUS status;
  1992. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  1993. VspFreeContext(extension->Root, context);
  1994. if (extension->NextDiffAreaFileMap) {
  1995. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  1996. extension->NextDiffAreaFileMap);
  1997. ASSERT(NT_SUCCESS(status));
  1998. extension->NextDiffAreaFileMap = NULL;
  1999. }
  2000. VspReleasePagedResource(extension);
  2001. ObDereferenceObject(extension->Filter->DeviceObject);
  2002. ObDereferenceObject(extension->DeviceObject);
  2003. }
  2004. NTSTATUS
  2005. VspTruncatePreviousDiffArea(
  2006. IN PVOLUME_EXTENSION Extension
  2007. )
  2008. /*++
  2009. Routine Description:
  2010. This routine takes the snapshot that occurred before this one and
  2011. truncates its diff area file to the current used size since diff
  2012. area files can't grow after a new snapshot is added on top.
  2013. Arguments:
  2014. Extension - Supplies the volume extension.
  2015. Return Value:
  2016. NTSTATUS
  2017. --*/
  2018. {
  2019. PFILTER_EXTENSION filter = Extension->Filter;
  2020. PLIST_ENTRY l, ll;
  2021. PVOLUME_EXTENSION extension;
  2022. PVSP_DIFF_AREA_FILE diffAreaFile;
  2023. NTSTATUS status;
  2024. LONGLONG diff;
  2025. KIRQL irql;
  2026. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  2027. PVSP_CONTEXT context;
  2028. l = Extension->ListEntry.Blink;
  2029. if (l == &filter->VolumeList) {
  2030. return STATUS_SUCCESS;
  2031. }
  2032. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  2033. for (l = extension->ListOfDiffAreaFiles.Flink;
  2034. l != &extension->ListOfDiffAreaFiles; l = l->Flink) {
  2035. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  2036. VolumeListEntry);
  2037. status = VspSetFileSizes(diffAreaFile->FileHandle,
  2038. diffAreaFile->NextAvailable);
  2039. if (NT_SUCCESS(status)) {
  2040. VspAcquireNonPagedResource(extension, NULL);
  2041. diff = diffAreaFile->AllocatedFileSize -
  2042. diffAreaFile->NextAvailable;
  2043. diffAreaFile->AllocatedFileSize -= diff;
  2044. VspReleaseNonPagedResource(extension);
  2045. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2046. filter->AllocatedVolumeSpace -= diff;
  2047. KeReleaseSpinLock(&filter->SpinLock, irql);
  2048. }
  2049. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  2050. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  2051. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  2052. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  2053. ExFreePool(diffAreaFileAllocation);
  2054. }
  2055. }
  2056. if (extension->EmergencyCopyIrp) {
  2057. ExFreePool(MmGetMdlVirtualAddress(
  2058. extension->EmergencyCopyIrp->MdlAddress));
  2059. IoFreeMdl(extension->EmergencyCopyIrp->MdlAddress);
  2060. IoFreeIrp(extension->EmergencyCopyIrp);
  2061. extension->EmergencyCopyIrp = NULL;
  2062. }
  2063. context = VspAllocateContext(Extension->Root);
  2064. if (context) {
  2065. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  2066. context->Extension.Extension = extension;
  2067. ExInitializeWorkItem(&context->WorkItem, VspUnmapNextDiffAreaFileMap,
  2068. context);
  2069. ObReferenceObject(extension->DeviceObject);
  2070. ObReferenceObject(extension->Filter->DeviceObject);
  2071. VspAcquirePagedResource(extension, &context->WorkItem);
  2072. }
  2073. return STATUS_SUCCESS;
  2074. }
  2075. VOID
  2076. VspOrBitmaps(
  2077. IN OUT PRTL_BITMAP BaseBitmap,
  2078. IN PRTL_BITMAP FactorBitmap
  2079. )
  2080. {
  2081. ULONG n, i;
  2082. PULONG p, q;
  2083. n = (BaseBitmap->SizeOfBitMap + 8*sizeof(ULONG) - 1)/(8*sizeof(ULONG));
  2084. p = BaseBitmap->Buffer;
  2085. q = FactorBitmap->Buffer;
  2086. for (i = 0; i < n; i++) {
  2087. *p++ |= *q++;
  2088. }
  2089. }
  2090. VOID
  2091. VspAdjustBitmap(
  2092. IN PVOID Context
  2093. )
  2094. {
  2095. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2096. PVOLUME_EXTENSION extension = context->Extension.Extension;
  2097. NTSTATUS status;
  2098. KIRQL irql;
  2099. PLIST_ENTRY l;
  2100. PWORK_QUEUE_ITEM workItem;
  2101. PWORKER_THREAD_ROUTINE workerRoutine;
  2102. PVOID parameter;
  2103. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  2104. VspFreeContext(extension->Root, context);
  2105. status = VspComputeIgnorableProduct(extension);
  2106. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2107. if (extension->IgnorableProduct) {
  2108. if (NT_SUCCESS(status) && extension->VolumeBlockBitmap) {
  2109. VspOrBitmaps(extension->VolumeBlockBitmap,
  2110. extension->IgnorableProduct);
  2111. }
  2112. ExFreePool(extension->IgnorableProduct->Buffer);
  2113. ExFreePool(extension->IgnorableProduct);
  2114. extension->IgnorableProduct = NULL;
  2115. }
  2116. KeReleaseSpinLock(&extension->SpinLock, irql);
  2117. KeAcquireSpinLock(&extension->Root->ESpinLock, &irql);
  2118. ASSERT(extension->Root->AdjustBitmapInProgress);
  2119. if (IsListEmpty(&extension->Root->AdjustBitmapQueue)) {
  2120. extension->Root->AdjustBitmapInProgress = FALSE;
  2121. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  2122. } else {
  2123. l = RemoveHeadList(&extension->Root->AdjustBitmapQueue);
  2124. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  2125. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  2126. workerRoutine = workItem->WorkerRoutine;
  2127. parameter = workItem->Parameter;
  2128. ExInitializeWorkItem(workItem, workerRoutine, parameter);
  2129. ExQueueWorkItem(workItem, DelayedWorkQueue);
  2130. }
  2131. ObDereferenceObject(extension->Filter->DeviceObject);
  2132. ObDereferenceObject(extension->DeviceObject);
  2133. }
  2134. VOID
  2135. VspSetIgnorableBlocksInBitmapWorker(
  2136. IN PVOID Context
  2137. )
  2138. {
  2139. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2140. PVOLUME_EXTENSION extension = context->Extension.Extension;
  2141. NTSTATUS status;
  2142. KIRQL irql;
  2143. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  2144. status = VspSetIgnorableBlocksInBitmap(extension);
  2145. if (NT_SUCCESS(status)) {
  2146. InterlockedExchange(&extension->OkToGrowDiffArea, TRUE);
  2147. } else {
  2148. if (!extension->Filter->DestroyAllSnapshotsPending) {
  2149. VspLogError(extension, NULL,
  2150. VS_ABORT_SNAPSHOTS_FAILED_FREE_SPACE_DETECTION,
  2151. status, 0);
  2152. }
  2153. VspDestroyAllSnapshots(extension->Filter, NULL);
  2154. }
  2155. KeSetEvent(&extension->Filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  2156. FALSE);
  2157. ExInitializeWorkItem(&context->WorkItem, VspAdjustBitmap, context);
  2158. KeAcquireSpinLock(&extension->Root->ESpinLock, &irql);
  2159. if (extension->Root->AdjustBitmapInProgress) {
  2160. InsertTailList(&extension->Root->AdjustBitmapQueue,
  2161. &context->WorkItem.List);
  2162. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  2163. } else {
  2164. extension->Root->AdjustBitmapInProgress = TRUE;
  2165. KeReleaseSpinLock(&extension->Root->ESpinLock, irql);
  2166. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  2167. }
  2168. }
  2169. VOID
  2170. VspFreeCopyIrp(
  2171. IN PVOLUME_EXTENSION Extension,
  2172. IN PIRP CopyIrp
  2173. )
  2174. {
  2175. KIRQL irql;
  2176. PLIST_ENTRY l;
  2177. PWORK_QUEUE_ITEM workItem;
  2178. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  2179. if (Extension->EmergencyCopyIrp == CopyIrp) {
  2180. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2181. if (IsListEmpty(&Extension->EmergencyCopyIrpQueue)) {
  2182. Extension->EmergencyCopyIrpInUse = FALSE;
  2183. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2184. return;
  2185. }
  2186. l = RemoveHeadList(&Extension->EmergencyCopyIrpQueue);
  2187. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2188. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  2189. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) workItem->Parameter;
  2190. tableEntry->CopyIrp = CopyIrp;
  2191. VspWriteVolumePhase1(tableEntry);
  2192. return;
  2193. }
  2194. if (!Extension->EmergencyCopyIrpInUse) {
  2195. ExFreePool(MmGetMdlVirtualAddress(CopyIrp->MdlAddress));
  2196. IoFreeMdl(CopyIrp->MdlAddress);
  2197. IoFreeIrp(CopyIrp);
  2198. return;
  2199. }
  2200. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  2201. if (IsListEmpty(&Extension->EmergencyCopyIrpQueue)) {
  2202. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2203. ExFreePool(MmGetMdlVirtualAddress(CopyIrp->MdlAddress));
  2204. IoFreeMdl(CopyIrp->MdlAddress);
  2205. IoFreeIrp(CopyIrp);
  2206. return;
  2207. }
  2208. l = RemoveHeadList(&Extension->EmergencyCopyIrpQueue);
  2209. KeReleaseSpinLock(&Extension->SpinLock, irql);
  2210. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  2211. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY) workItem->Parameter;
  2212. tableEntry->CopyIrp = CopyIrp;
  2213. VspWriteVolumePhase1(tableEntry);
  2214. }
  2215. VOID
  2216. VspApplyThresholdDelta(
  2217. IN PVOLUME_EXTENSION Extension,
  2218. IN ULONG IncreaseDelta
  2219. )
  2220. {
  2221. PLIST_ENTRY l;
  2222. PVSP_DIFF_AREA_FILE diffAreaFile;
  2223. PVSP_CONTEXT context;
  2224. for (l = Extension->ListOfDiffAreaFiles.Flink;
  2225. l != &Extension->ListOfDiffAreaFiles; l = l->Flink) {
  2226. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  2227. VolumeListEntry);
  2228. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease <=
  2229. diffAreaFile->AllocatedFileSize) {
  2230. continue;
  2231. }
  2232. if (diffAreaFile->NextAvailable + Extension->DiffAreaFileIncrease -
  2233. IncreaseDelta > diffAreaFile->AllocatedFileSize) {
  2234. continue;
  2235. }
  2236. if (!Extension->OkToGrowDiffArea) {
  2237. VspLogError(Extension, diffAreaFile->Filter,
  2238. VS_GROW_BEFORE_FREE_SPACE, STATUS_SUCCESS, 0);
  2239. continue;
  2240. }
  2241. context = VspAllocateContext(Extension->Root);
  2242. if (!context) {
  2243. continue;
  2244. }
  2245. context->Type = VSP_CONTEXT_TYPE_GROW_DIFF_AREA;
  2246. context->GrowDiffArea.Extension = Extension;
  2247. context->GrowDiffArea.DiffAreaFile = diffAreaFile;
  2248. ObReferenceObject(Extension->DeviceObject);
  2249. ExInitializeWorkItem(&context->WorkItem, VspGrowDiffArea, context);
  2250. VspQueueWorkItem(Extension->Root, &context->WorkItem, 0);
  2251. }
  2252. }
  2253. VOID
  2254. VspWriteVolume(
  2255. IN PVOID Context
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. This routine performs a volume write, making sure that all of the
  2260. parts of the volume write have an old version of the data placed
  2261. in the diff area for the snapshot.
  2262. Arguments:
  2263. Irp - Supplies the I/O request packet.
  2264. Return Value:
  2265. None.
  2266. --*/
  2267. {
  2268. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2269. PVOLUME_EXTENSION extension = context->WriteVolume.Extension;
  2270. PIRP irp = (PIRP) context->WriteVolume.Irp;
  2271. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  2272. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  2273. PFILTER_EXTENSION filter = extension->Filter;
  2274. LONGLONG start, end, roundedStart, roundedEnd;
  2275. ULONG irpLength, increase, increaseDelta;
  2276. TEMP_TRANSLATION_TABLE_ENTRY keyTableEntry;
  2277. PTEMP_TRANSLATION_TABLE_ENTRY tableEntry;
  2278. PVOID nodeOrParent;
  2279. TABLE_SEARCH_RESULT searchResult;
  2280. KIRQL irql;
  2281. NTSTATUS status;
  2282. CCHAR stackSize;
  2283. PVSP_DIFF_AREA_FILE diffAreaFile;
  2284. PDO_EXTENSION rootExtension;
  2285. PVOID buffer;
  2286. PMDL mdl;
  2287. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  2288. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  2289. irpLength = irpSp->Parameters.Read.Length;
  2290. end = start + irpLength;
  2291. if (context->WriteVolume.RoundedStart) {
  2292. roundedStart = context->WriteVolume.RoundedStart;
  2293. } else {
  2294. roundedStart = start&(~(BLOCK_SIZE - 1));
  2295. }
  2296. roundedEnd = end&(~(BLOCK_SIZE - 1));
  2297. if (roundedEnd != end) {
  2298. roundedEnd += BLOCK_SIZE;
  2299. }
  2300. ASSERT(extension->VolumeBlockBitmap);
  2301. for (; roundedStart < roundedEnd; roundedStart += BLOCK_SIZE) {
  2302. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2303. if (RtlCheckBit(extension->VolumeBlockBitmap,
  2304. (ULONG) (roundedStart>>BLOCK_SHIFT))) {
  2305. KeReleaseSpinLock(&extension->SpinLock, irql);
  2306. continue;
  2307. }
  2308. KeReleaseSpinLock(&extension->SpinLock, irql);
  2309. keyTableEntry.VolumeOffset = roundedStart;
  2310. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  2311. RtlLookupElementGenericTableFull(
  2312. &extension->TempVolumeBlockTable, &keyTableEntry,
  2313. &nodeOrParent, &searchResult);
  2314. if (tableEntry) {
  2315. context = VspAllocateContext(extension->Root);
  2316. if (context) {
  2317. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  2318. context->Extension.Extension = extension;
  2319. context->Extension.Irp = irp;
  2320. } else {
  2321. context = (PVSP_CONTEXT) Context;
  2322. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  2323. context->WriteVolume.RoundedStart = roundedStart;
  2324. }
  2325. ExInitializeWorkItem(&context->WorkItem,
  2326. VspDecrementIrpRefCountWorker, context);
  2327. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2328. if (tableEntry->IsComplete) {
  2329. KeReleaseSpinLock(&extension->SpinLock, irql);
  2330. if (context->Type == VSP_CONTEXT_TYPE_EXTENSION) {
  2331. VspFreeContext(extension->Root, context);
  2332. }
  2333. continue;
  2334. }
  2335. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  2336. InsertTailList(&tableEntry->WaitingQueueDpc,
  2337. &context->WorkItem.List);
  2338. KeReleaseSpinLock(&extension->SpinLock, irql);
  2339. if (context == Context) {
  2340. VspReleaseNonPagedResource(extension);
  2341. return;
  2342. }
  2343. continue;
  2344. }
  2345. RtlZeroMemory(&keyTableEntry, sizeof(TEMP_TRANSLATION_TABLE_ENTRY));
  2346. keyTableEntry.VolumeOffset = roundedStart;
  2347. ASSERT(!extension->TempTableEntry);
  2348. extension->TempTableEntry = VspAllocateTempTableEntry(extension->Root);
  2349. if (!extension->TempTableEntry) {
  2350. rootExtension = extension->Root;
  2351. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  2352. if (rootExtension->EmergencyTableEntryInUse) {
  2353. context = (PVSP_CONTEXT) Context;
  2354. ASSERT(context->Type == VSP_CONTEXT_TYPE_WRITE_VOLUME);
  2355. context->WriteVolume.RoundedStart = roundedStart;
  2356. InsertTailList(&rootExtension->WorkItemWaitingList,
  2357. &context->WorkItem.List);
  2358. if (!rootExtension->WorkItemWaitingListNeedsChecking) {
  2359. InterlockedExchange(
  2360. &rootExtension->WorkItemWaitingListNeedsChecking,
  2361. TRUE);
  2362. }
  2363. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  2364. VspReleaseNonPagedResource(extension);
  2365. return;
  2366. }
  2367. rootExtension->EmergencyTableEntryInUse = TRUE;
  2368. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  2369. extension->TempTableEntry = rootExtension->EmergencyTableEntry;
  2370. }
  2371. tableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  2372. RtlInsertElementGenericTableFull(
  2373. &extension->TempVolumeBlockTable, &keyTableEntry,
  2374. sizeof(TEMP_TRANSLATION_TABLE_ENTRY), NULL,
  2375. nodeOrParent, searchResult);
  2376. ASSERT(tableEntry);
  2377. if (extension->TempVolumeBlockTable.NumberGenericTableElements >
  2378. extension->MaximumNumberOfTempEntries) {
  2379. extension->MaximumNumberOfTempEntries =
  2380. extension->TempVolumeBlockTable.NumberGenericTableElements;
  2381. VspQueryDiffAreaFileIncrease(extension, &increase);
  2382. ASSERT(increase >= extension->DiffAreaFileIncrease);
  2383. increaseDelta = increase - extension->DiffAreaFileIncrease;
  2384. if (increaseDelta) {
  2385. InterlockedExchange((PLONG) &extension->DiffAreaFileIncrease,
  2386. (LONG) increase);
  2387. VspApplyThresholdDelta(extension, increaseDelta);
  2388. }
  2389. }
  2390. tableEntry->Extension = extension;
  2391. tableEntry->WriteIrp = irp;
  2392. status = VspAllocateDiffAreaSpace(extension, &diffAreaFile,
  2393. &tableEntry->TargetOffset);
  2394. if (!NT_SUCCESS(status)) {
  2395. if (!filter->DestroyAllSnapshotsPending) {
  2396. VspLogError(extension, NULL,
  2397. VS_ABORT_SNAPSHOTS_OUT_OF_DIFF_AREA,
  2398. STATUS_SUCCESS, 0);
  2399. }
  2400. RtlDeleteElementGenericTable(&extension->TempVolumeBlockTable,
  2401. tableEntry);
  2402. VspDestroyAllSnapshots(filter, NULL);
  2403. break;
  2404. }
  2405. tableEntry->TargetObject = diffAreaFile->Filter->TargetObject;
  2406. tableEntry->IsComplete = FALSE;
  2407. InitializeListHead(&tableEntry->WaitingQueueDpc);
  2408. tableEntry->CopyIrp = IoAllocateIrp(
  2409. (CCHAR) extension->Root->StackSize, FALSE);
  2410. buffer = ExAllocatePoolWithTagPriority(NonPagedPool, BLOCK_SIZE,
  2411. VOLSNAP_TAG_BUFFER,
  2412. LowPoolPriority);
  2413. mdl = IoAllocateMdl(buffer, BLOCK_SIZE, FALSE, FALSE, NULL);
  2414. if (!tableEntry->CopyIrp || !buffer || !mdl) {
  2415. if (tableEntry->CopyIrp) {
  2416. IoFreeIrp(tableEntry->CopyIrp);
  2417. tableEntry->CopyIrp = NULL;
  2418. }
  2419. if (buffer) {
  2420. ExFreePool(buffer);
  2421. }
  2422. if (mdl) {
  2423. IoFreeMdl(mdl);
  2424. }
  2425. KeAcquireSpinLock(&extension->SpinLock, &irql);
  2426. if (extension->EmergencyCopyIrpInUse) {
  2427. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  2428. ExInitializeWorkItem(&tableEntry->WorkItem,
  2429. VspWriteVolumePhase1, tableEntry);
  2430. InsertTailList(&extension->EmergencyCopyIrpQueue,
  2431. &tableEntry->WorkItem.List);
  2432. KeReleaseSpinLock(&extension->SpinLock, irql);
  2433. continue;
  2434. }
  2435. extension->EmergencyCopyIrpInUse = TRUE;
  2436. KeReleaseSpinLock(&extension->SpinLock, irql);
  2437. tableEntry->CopyIrp = extension->EmergencyCopyIrp;
  2438. } else {
  2439. MmBuildMdlForNonPagedPool(mdl);
  2440. tableEntry->CopyIrp->MdlAddress = mdl;
  2441. }
  2442. InterlockedIncrement((PLONG) &nextSp->Parameters.Write.Length);
  2443. VspWriteVolumePhase1(tableEntry);
  2444. }
  2445. context = (PVSP_CONTEXT) Context;
  2446. VspFreeContext(filter->Root, context);
  2447. VspReleaseNonPagedResource(extension);
  2448. VspDecrementIrpRefCount(irp);
  2449. }
  2450. VOID
  2451. VspIrpsTimerDpc(
  2452. IN PKDPC TimerDpc,
  2453. IN PVOID Context,
  2454. IN PVOID SystemArgument1,
  2455. IN PVOID SystemArgument2
  2456. )
  2457. {
  2458. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Context;
  2459. KIRQL irql;
  2460. LIST_ENTRY q;
  2461. PLIST_ENTRY l;
  2462. PIRP irp;
  2463. BOOLEAN emptyQueue;
  2464. VspLogError(NULL, filter, VS_FLUSH_AND_HOLD_IRP_TIMEOUT, STATUS_SUCCESS,
  2465. 0);
  2466. IoStopTimer(filter->DeviceObject);
  2467. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2468. InterlockedIncrement(&filter->RefCount);
  2469. InterlockedExchange(&filter->TimerIsSet, FALSE);
  2470. InterlockedExchange(&filter->HoldIncomingWrites, FALSE);
  2471. if (IsListEmpty(&filter->HoldQueue)) {
  2472. emptyQueue = FALSE;
  2473. } else {
  2474. emptyQueue = TRUE;
  2475. q = filter->HoldQueue;
  2476. InitializeListHead(&filter->HoldQueue);
  2477. }
  2478. KeReleaseSpinLock(&filter->SpinLock, irql);
  2479. if (emptyQueue) {
  2480. q.Blink->Flink = &q;
  2481. q.Flink->Blink = &q;
  2482. VspEmptyIrpQueue(filter->Root->DriverObject, &q);
  2483. }
  2484. }
  2485. VOID
  2486. VspEndCommitDpc(
  2487. IN PKDPC TimerDpc,
  2488. IN PVOID Context,
  2489. IN PVOID SystemArgument1,
  2490. IN PVOID SystemArgument2
  2491. )
  2492. {
  2493. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Context;
  2494. VspLogError(NULL, filter, VS_END_COMMIT_TIMEOUT, STATUS_CANCELLED, 0);
  2495. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT, FALSE);
  2496. ObDereferenceObject(filter->DeviceObject);
  2497. }
  2498. NTSTATUS
  2499. VspCheckForMemoryPressure(
  2500. IN PFILTER_EXTENSION Filter
  2501. )
  2502. /*++
  2503. Routine Description:
  2504. This routine will allocate 256 K of paged and non paged pool. If these
  2505. allocs succeed, it indicates that the system is not under memory pressure
  2506. and so it is ok to hold write irps for the next second.
  2507. Arguments:
  2508. Filter - Supplies the filter extension.
  2509. Return Value:
  2510. NTSTATUS
  2511. --*/
  2512. {
  2513. PVOID p, np;
  2514. p = ExAllocatePoolWithTagPriority(PagedPool,
  2515. MEMORY_PRESSURE_CHECK_ALLOC_SIZE, VOLSNAP_TAG_SHORT_TERM,
  2516. LowPoolPriority);
  2517. if (!p) {
  2518. VspLogError(NULL, Filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  2519. STATUS_INSUFFICIENT_RESOURCES, 1);
  2520. return STATUS_INSUFFICIENT_RESOURCES;
  2521. }
  2522. np = ExAllocatePoolWithTagPriority(NonPagedPool,
  2523. MEMORY_PRESSURE_CHECK_ALLOC_SIZE, VOLSNAP_TAG_SHORT_TERM,
  2524. LowPoolPriority);
  2525. if (!np) {
  2526. ExFreePool(p);
  2527. VspLogError(NULL, Filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  2528. STATUS_INSUFFICIENT_RESOURCES, 2);
  2529. return STATUS_INSUFFICIENT_RESOURCES;
  2530. }
  2531. ExFreePool(np);
  2532. ExFreePool(p);
  2533. return STATUS_SUCCESS;
  2534. }
  2535. VOID
  2536. VspOneSecondTimerWorker(
  2537. IN PDEVICE_OBJECT DeviceObject,
  2538. IN PVOID WorkItem
  2539. )
  2540. {
  2541. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  2542. PIO_WORKITEM workItem = (PIO_WORKITEM) WorkItem;
  2543. NTSTATUS status;
  2544. status = VspCheckForMemoryPressure(filter);
  2545. if (!NT_SUCCESS(status)) {
  2546. VspReleaseWrites(filter);
  2547. }
  2548. IoFreeWorkItem(workItem);
  2549. }
  2550. VOID
  2551. VspOneSecondTimer(
  2552. IN PDEVICE_OBJECT DeviceObject,
  2553. IN PVOID Filter
  2554. )
  2555. /*++
  2556. Routine Description:
  2557. This routine will get called once every second after an IoStartTimer.
  2558. This routine checks for memory pressure and aborts the lovelace operation
  2559. if any memory pressure is detected.
  2560. Arguments:
  2561. DeviceObject - Supplies the device object.
  2562. Filter - Supplies the filter extension.
  2563. Return Value:
  2564. None.
  2565. --*/
  2566. {
  2567. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  2568. PIO_WORKITEM workItem;
  2569. workItem = IoAllocateWorkItem(filter->DeviceObject);
  2570. if (!workItem) {
  2571. VspLogError(NULL, filter, VS_MEMORY_PRESSURE_DURING_LOVELACE,
  2572. STATUS_INSUFFICIENT_RESOURCES, 3);
  2573. VspReleaseWrites(filter);
  2574. return;
  2575. }
  2576. IoQueueWorkItem(workItem, VspOneSecondTimerWorker, CriticalWorkQueue,
  2577. workItem);
  2578. }
  2579. NTSTATUS
  2580. VolSnapAddDevice(
  2581. IN PDRIVER_OBJECT DriverObject,
  2582. IN PDEVICE_OBJECT PhysicalDeviceObject
  2583. )
  2584. /*++
  2585. Routine Description:
  2586. This routine creates and initializes a new FILTER for the corresponding
  2587. volume PDO.
  2588. Arguments:
  2589. DriverObject - Supplies the VOLSNAP driver object.
  2590. PhysicalDeviceObject - Supplies the volume PDO.
  2591. Return Value:
  2592. NTSTATUS
  2593. --*/
  2594. {
  2595. PDEVICE_OBJECT attachedDevice;
  2596. NTSTATUS status;
  2597. PDEVICE_OBJECT deviceObject;
  2598. PDO_EXTENSION rootExtension;
  2599. PFILTER_EXTENSION filter;
  2600. PVSP_DIFF_AREA_VOLUME diffAreaVolume;
  2601. attachedDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  2602. if (attachedDevice) {
  2603. if (attachedDevice->Characteristics&FILE_REMOVABLE_MEDIA) {
  2604. ObDereferenceObject(attachedDevice);
  2605. return STATUS_SUCCESS;
  2606. }
  2607. ObDereferenceObject(attachedDevice);
  2608. }
  2609. status = IoCreateDevice(DriverObject, sizeof(FILTER_EXTENSION),
  2610. NULL, FILE_DEVICE_DISK, 0, FALSE, &deviceObject);
  2611. if (!NT_SUCCESS(status)) {
  2612. return status;
  2613. }
  2614. rootExtension = (PDO_EXTENSION)
  2615. IoGetDriverObjectExtension(DriverObject, VolSnapAddDevice);
  2616. if (!rootExtension) {
  2617. IoDeleteDevice(deviceObject);
  2618. return STATUS_NO_SUCH_DEVICE;
  2619. }
  2620. filter = (PFILTER_EXTENSION) deviceObject->DeviceExtension;
  2621. RtlZeroMemory(filter, sizeof(FILTER_EXTENSION));
  2622. filter->DeviceObject = deviceObject;
  2623. filter->Root = rootExtension;
  2624. filter->DeviceExtensionType = DEVICE_EXTENSION_FILTER;
  2625. KeInitializeSpinLock(&filter->SpinLock);
  2626. filter->TargetObject =
  2627. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  2628. if (!filter->TargetObject) {
  2629. IoDeleteDevice(deviceObject);
  2630. return STATUS_NO_SUCH_DEVICE;
  2631. }
  2632. filter->Pdo = PhysicalDeviceObject;
  2633. filter->RefCount = 1;
  2634. InitializeListHead(&filter->HoldQueue);
  2635. KeInitializeTimer(&filter->HoldWritesTimer);
  2636. KeInitializeDpc(&filter->HoldWritesTimerDpc, VspIrpsTimerDpc, filter);
  2637. KeInitializeEvent(&filter->EndCommitProcessCompleted, NotificationEvent,
  2638. TRUE);
  2639. InitializeListHead(&filter->VolumeList);
  2640. InitializeListHead(&filter->DeadVolumeList);
  2641. InitializeListHead(&filter->DiffAreaFilesOnThisFilter);
  2642. InitializeListHead(&filter->DiffAreaVolumes);
  2643. diffAreaVolume = (PVSP_DIFF_AREA_VOLUME)
  2644. ExAllocatePoolWithTag((POOL_TYPE)(PagedPool | POOL_COLD_ALLOCATION),
  2645. sizeof(VSP_DIFF_AREA_VOLUME), VOLSNAP_TAG_DIFF_VOLUME);
  2646. if (!diffAreaVolume) {
  2647. IoDetachDevice(filter->TargetObject);
  2648. IoDeleteDevice(deviceObject);
  2649. return STATUS_INSUFFICIENT_RESOURCES;
  2650. }
  2651. diffAreaVolume->Filter = filter;
  2652. InsertTailList(&filter->DiffAreaVolumes, &diffAreaVolume->ListEntry);
  2653. KeInitializeTimer(&filter->EndCommitTimer);
  2654. KeInitializeDpc(&filter->EndCommitTimerDpc, VspEndCommitDpc, filter);
  2655. InitializeListHead(&filter->NonPagedResourceList);
  2656. InitializeListHead(&filter->PagedResourceList);
  2657. status = IoInitializeTimer(deviceObject, VspOneSecondTimer, filter);
  2658. if (!NT_SUCCESS(status)) {
  2659. IoDetachDevice(filter->TargetObject);
  2660. IoDeleteDevice(deviceObject);
  2661. return status;
  2662. }
  2663. deviceObject->Flags |= DO_DIRECT_IO;
  2664. if (filter->TargetObject->Flags & DO_POWER_PAGABLE) {
  2665. deviceObject->Flags |= DO_POWER_PAGABLE;
  2666. }
  2667. if (filter->TargetObject->Flags & DO_POWER_INRUSH) {
  2668. deviceObject->Flags |= DO_POWER_INRUSH;
  2669. }
  2670. VspAcquire(filter->Root);
  2671. if (filter->TargetObject->StackSize > filter->Root->StackSize) {
  2672. InterlockedExchange(&filter->Root->StackSize,
  2673. (LONG) filter->TargetObject->StackSize);
  2674. }
  2675. InsertTailList(&filter->Root->FilterList, &filter->ListEntry);
  2676. VspRelease(filter->Root);
  2677. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  2678. return STATUS_SUCCESS;
  2679. }
  2680. NTSTATUS
  2681. VolSnapCreate(
  2682. IN PDEVICE_OBJECT DeviceObject,
  2683. IN PIRP Irp
  2684. )
  2685. /*++
  2686. Routine Description:
  2687. This routine is the dispatch for IRP_MJ_CREATE.
  2688. Arguments:
  2689. DeviceObject - Supplies the device object.
  2690. Irp - Supplies the IO request block.
  2691. Return Value:
  2692. NTSTATUS
  2693. --*/
  2694. {
  2695. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  2696. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  2697. IoSkipCurrentIrpStackLocation(Irp);
  2698. return IoCallDriver(filter->TargetObject, Irp);
  2699. }
  2700. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  2701. Irp->IoStatus.Status = STATUS_SUCCESS;
  2702. Irp->IoStatus.Information = 0;
  2703. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2704. return STATUS_SUCCESS;
  2705. }
  2706. NTSTATUS
  2707. VspReadSnapshotPhase2(
  2708. IN PDEVICE_OBJECT DeviceObject,
  2709. IN PIRP Irp,
  2710. IN PVOID Context
  2711. )
  2712. {
  2713. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2714. PVOLUME_EXTENSION extension = context->ReadSnapshot.Extension;
  2715. PIRP irp = context->ReadSnapshot.OriginalReadIrp;
  2716. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  2717. ASSERT(context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT);
  2718. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  2719. irp->IoStatus = Irp->IoStatus;
  2720. }
  2721. IoFreeMdl(Irp->MdlAddress);
  2722. IoFreeIrp(Irp);
  2723. VspFreeContext(extension->Root, context);
  2724. VspDecrementVolumeIrpRefCount(irp);
  2725. return STATUS_MORE_PROCESSING_REQUIRED;
  2726. }
  2727. VOID
  2728. VspReadSnapshotPhase1(
  2729. IN PVOID Context
  2730. )
  2731. /*++
  2732. Routine Description:
  2733. This routine is called when a read snapshot routine is waiting for
  2734. somebody else to finish updating the public area of a table entry.
  2735. When this routine is called, the public area of the table entry is
  2736. valid.
  2737. Arguments:
  2738. Context - Supplies the context.
  2739. Return Value:
  2740. None.
  2741. --*/
  2742. {
  2743. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2744. PVOLUME_EXTENSION extension = context->ReadSnapshot.Extension;
  2745. TEMP_TRANSLATION_TABLE_ENTRY keyTempTableEntry;
  2746. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  2747. TRANSLATION_TABLE_ENTRY keyTableEntry;
  2748. PTRANSLATION_TABLE_ENTRY tableEntry;
  2749. NTSTATUS status;
  2750. PIRP irp;
  2751. PIO_STACK_LOCATION nextSp;
  2752. PCHAR vp;
  2753. PMDL mdl;
  2754. ASSERT(context->Type == VSP_CONTEXT_TYPE_READ_SNAPSHOT);
  2755. if (!context->ReadSnapshot.TargetObject) {
  2756. irp = context->ReadSnapshot.OriginalReadIrp;
  2757. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  2758. irp->IoStatus.Information = 0;
  2759. VspFreeContext(extension->Root, context);
  2760. VspDecrementVolumeIrpRefCount(irp);
  2761. return;
  2762. }
  2763. irp = IoAllocateIrp(context->ReadSnapshot.TargetObject->StackSize, FALSE);
  2764. if (!irp) {
  2765. irp = context->ReadSnapshot.OriginalReadIrp;
  2766. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2767. irp->IoStatus.Information = 0;
  2768. VspFreeContext(extension->Root, context);
  2769. VspDecrementVolumeIrpRefCount(irp);
  2770. return;
  2771. }
  2772. vp = (PCHAR) MmGetMdlVirtualAddress(
  2773. context->ReadSnapshot.OriginalReadIrp->MdlAddress) +
  2774. context->ReadSnapshot.OriginalReadIrpOffset;
  2775. mdl = IoAllocateMdl(vp, context->ReadSnapshot.Length, FALSE, FALSE, NULL);
  2776. if (!mdl) {
  2777. IoFreeIrp(irp);
  2778. irp = context->ReadSnapshot.OriginalReadIrp;
  2779. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2780. irp->IoStatus.Information = 0;
  2781. VspFreeContext(extension->Root, context);
  2782. VspDecrementVolumeIrpRefCount(irp);
  2783. return;
  2784. }
  2785. IoBuildPartialMdl(context->ReadSnapshot.OriginalReadIrp->MdlAddress, mdl,
  2786. vp, context->ReadSnapshot.Length);
  2787. irp->MdlAddress = mdl;
  2788. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  2789. nextSp = IoGetNextIrpStackLocation(irp);
  2790. nextSp->Parameters.Read.ByteOffset.QuadPart =
  2791. context->ReadSnapshot.TargetOffset +
  2792. context->ReadSnapshot.BlockOffset;
  2793. nextSp->Parameters.Read.Length = context->ReadSnapshot.Length;
  2794. nextSp->MajorFunction = IRP_MJ_READ;
  2795. nextSp->DeviceObject = context->ReadSnapshot.TargetObject;
  2796. nextSp->Flags = SL_OVERRIDE_VERIFY_VOLUME;
  2797. IoSetCompletionRoutine(irp, VspReadSnapshotPhase2, context, TRUE, TRUE,
  2798. TRUE);
  2799. IoCallDriver(context->ReadSnapshot.TargetObject, irp);
  2800. }
  2801. VOID
  2802. VspReadSnapshot(
  2803. IN PVOID Context
  2804. )
  2805. /*++
  2806. Routine Description:
  2807. This routine kicks off a read snapshot. First the table is searched
  2808. to see if any of the data for this IRP resides in the diff area. If not,
  2809. then the Irp is sent directly to the original volume and then the diff
  2810. area is checked again when it returns to fill in any gaps that may
  2811. have been written while the IRP was in transit.
  2812. Arguments:
  2813. Irp - Supplies the I/O request packet.
  2814. Return Value:
  2815. None.
  2816. --*/
  2817. {
  2818. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  2819. PVOLUME_EXTENSION extension = context->Extension.Extension;
  2820. PIRP irp = context->Extension.Irp;
  2821. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  2822. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  2823. PFILTER_EXTENSION filter = extension->Filter;
  2824. LONGLONG start, end, roundedStart, roundedEnd;
  2825. ULONG irpOffset, irpLength, length, blockOffset;
  2826. TRANSLATION_TABLE_ENTRY keyTableEntry;
  2827. TEMP_TRANSLATION_TABLE_ENTRY keyTempTableEntry;
  2828. PVOLUME_EXTENSION e;
  2829. PTRANSLATION_TABLE_ENTRY tableEntry;
  2830. PTEMP_TRANSLATION_TABLE_ENTRY tempTableEntry;
  2831. KIRQL irql;
  2832. NTSTATUS status;
  2833. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  2834. VspFreeContext(extension->Root, context);
  2835. start = irpSp->Parameters.Read.ByteOffset.QuadPart;
  2836. irpLength = irpSp->Parameters.Read.Length;
  2837. end = start + irpLength;
  2838. roundedStart = start&(~(BLOCK_SIZE - 1));
  2839. roundedEnd = end&(~(BLOCK_SIZE - 1));
  2840. if (roundedEnd != end) {
  2841. roundedEnd += BLOCK_SIZE;
  2842. }
  2843. irpOffset = 0;
  2844. RtlZeroMemory(&keyTableEntry, sizeof(keyTableEntry));
  2845. for (; roundedStart < roundedEnd; roundedStart += BLOCK_SIZE) {
  2846. if (roundedStart < start) {
  2847. blockOffset = (ULONG) (start - roundedStart);
  2848. } else {
  2849. blockOffset = 0;
  2850. }
  2851. length = BLOCK_SIZE - blockOffset;
  2852. if (irpLength < length) {
  2853. length = irpLength;
  2854. }
  2855. keyTableEntry.VolumeOffset = roundedStart;
  2856. e = extension;
  2857. status = STATUS_SUCCESS;
  2858. for (;;) {
  2859. _try {
  2860. tableEntry = (PTRANSLATION_TABLE_ENTRY)
  2861. RtlLookupElementGenericTable(&e->VolumeBlockTable,
  2862. &keyTableEntry);
  2863. } _except (EXCEPTION_EXECUTE_HANDLER) {
  2864. status = GetExceptionCode();
  2865. tableEntry = NULL;
  2866. }
  2867. if (tableEntry) {
  2868. break;
  2869. }
  2870. if (!NT_SUCCESS(status)) {
  2871. irp->IoStatus.Status = status;
  2872. irp->IoStatus.Information = 0;
  2873. break;
  2874. }
  2875. KeAcquireSpinLock(&filter->SpinLock, &irql);
  2876. if (e->ListEntry.Flink == &filter->VolumeList) {
  2877. KeReleaseSpinLock(&filter->SpinLock, irql);
  2878. break;
  2879. }
  2880. e = CONTAINING_RECORD(e->ListEntry.Flink,
  2881. VOLUME_EXTENSION, ListEntry);
  2882. KeReleaseSpinLock(&filter->SpinLock, irql);
  2883. }
  2884. if (!tableEntry) {
  2885. if (!NT_SUCCESS(status)) {
  2886. break;
  2887. }
  2888. keyTempTableEntry.VolumeOffset = roundedStart;
  2889. VspAcquireNonPagedResource(e, NULL);
  2890. tempTableEntry = (PTEMP_TRANSLATION_TABLE_ENTRY)
  2891. RtlLookupElementGenericTable(
  2892. &e->TempVolumeBlockTable, &keyTempTableEntry);
  2893. if (!tempTableEntry) {
  2894. VspReleaseNonPagedResource(e);
  2895. irpOffset += length;
  2896. irpLength -= length;
  2897. continue;
  2898. }
  2899. }
  2900. context = VspAllocateContext(extension->Root);
  2901. if (!context) {
  2902. if (!tableEntry) {
  2903. VspReleaseNonPagedResource(e);
  2904. }
  2905. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2906. irp->IoStatus.Information = 0;
  2907. break;
  2908. }
  2909. context->Type = VSP_CONTEXT_TYPE_READ_SNAPSHOT;
  2910. context->ReadSnapshot.Extension = extension;
  2911. context->ReadSnapshot.OriginalReadIrp = irp;
  2912. context->ReadSnapshot.OriginalReadIrpOffset = irpOffset;
  2913. context->ReadSnapshot.OriginalVolumeOffset = roundedStart;
  2914. context->ReadSnapshot.BlockOffset = blockOffset;
  2915. context->ReadSnapshot.Length = length;
  2916. context->ReadSnapshot.TargetObject = NULL;
  2917. context->ReadSnapshot.TargetOffset = 0;
  2918. if (!tableEntry) {
  2919. KeAcquireSpinLock(&e->SpinLock, &irql);
  2920. if (!tempTableEntry->IsComplete) {
  2921. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  2922. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshotPhase1,
  2923. context);
  2924. InsertTailList(&tempTableEntry->WaitingQueueDpc,
  2925. &context->WorkItem.List);
  2926. KeReleaseSpinLock(&e->SpinLock, irql);
  2927. VspReleaseNonPagedResource(e);
  2928. irpOffset += length;
  2929. irpLength -= length;
  2930. continue;
  2931. }
  2932. KeReleaseSpinLock(&e->SpinLock, irql);
  2933. context->ReadSnapshot.TargetObject = tempTableEntry->TargetObject;
  2934. context->ReadSnapshot.TargetOffset = tempTableEntry->TargetOffset;
  2935. VspReleaseNonPagedResource(e);
  2936. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  2937. VspReadSnapshotPhase1(context);
  2938. irpOffset += length;
  2939. irpLength -= length;
  2940. continue;
  2941. }
  2942. context->ReadSnapshot.TargetObject = tableEntry->TargetObject;
  2943. context->ReadSnapshot.TargetOffset = tableEntry->TargetOffset;
  2944. InterlockedIncrement((PLONG) &nextSp->Parameters.Read.Length);
  2945. VspReadSnapshotPhase1(context);
  2946. irpOffset += length;
  2947. irpLength -= length;
  2948. }
  2949. VspReleasePagedResource(extension);
  2950. VspDecrementVolumeIrpRefCount(irp);
  2951. }
  2952. NTSTATUS
  2953. VspReadCompletionForReadSnapshot(
  2954. IN PDEVICE_OBJECT DeviceObject,
  2955. IN PIRP Irp,
  2956. IN PVOID Extension
  2957. )
  2958. /*++
  2959. Routine Description:
  2960. This routine is the completion to a read of the filter in
  2961. response to a snapshot read. This completion routine queues
  2962. a worker routine to look at the diff area table and fill in
  2963. any parts of the original that have been invalidated.
  2964. Arguments:
  2965. DeviceObject - Supplies the device object.
  2966. Irp - Supplies the I/O request packet.
  2967. Extension - Supplies the volume extension.
  2968. Return Value:
  2969. NTSTATUS
  2970. --*/
  2971. {
  2972. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  2973. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Irp);
  2974. PVSP_CONTEXT context;
  2975. nextSp->Parameters.Read.Length = 1; ; // Use this for a ref count.
  2976. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  2977. VspDecrementVolumeIrpRefCount(Irp);
  2978. return STATUS_MORE_PROCESSING_REQUIRED;
  2979. }
  2980. context = VspAllocateContext(extension->Root);
  2981. if (!context) {
  2982. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2983. Irp->IoStatus.Information = 0;
  2984. VspDecrementVolumeIrpRefCount(Irp);
  2985. return STATUS_MORE_PROCESSING_REQUIRED;
  2986. }
  2987. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  2988. context->Extension.Extension = extension;
  2989. context->Extension.Irp = Irp;
  2990. ExInitializeWorkItem(&context->WorkItem, VspReadSnapshot, context);
  2991. VspAcquirePagedResource(extension, &context->WorkItem);
  2992. return STATUS_MORE_PROCESSING_REQUIRED;
  2993. }
  2994. RTL_GENERIC_COMPARE_RESULTS
  2995. VspTableCompareRoutine(
  2996. IN PRTL_GENERIC_TABLE Table,
  2997. IN PVOID First,
  2998. IN PVOID Second
  2999. )
  3000. {
  3001. PTRANSLATION_TABLE_ENTRY first = (PTRANSLATION_TABLE_ENTRY) First;
  3002. PTRANSLATION_TABLE_ENTRY second = (PTRANSLATION_TABLE_ENTRY) Second;
  3003. if (first->VolumeOffset < second->VolumeOffset) {
  3004. return GenericLessThan;
  3005. } else if (first->VolumeOffset > second->VolumeOffset) {
  3006. return GenericGreaterThan;
  3007. }
  3008. return GenericEqual;
  3009. }
  3010. VOID
  3011. VspCreateHeap(
  3012. IN PVOID Context
  3013. )
  3014. {
  3015. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  3016. PVOLUME_EXTENSION extension = context->Extension.Extension;
  3017. ULONG increase;
  3018. OBJECT_ATTRIBUTES oa;
  3019. NTSTATUS status;
  3020. SIZE_T size;
  3021. LARGE_INTEGER sectionSize, sectionOffset;
  3022. HANDLE h;
  3023. PVOID mapPointer;
  3024. KIRQL irql;
  3025. BOOLEAN emptyQueue;
  3026. LIST_ENTRY q;
  3027. PLIST_ENTRY l;
  3028. PWORK_QUEUE_ITEM workItem;
  3029. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  3030. VspFreeContext(extension->Root, context);
  3031. increase = extension->DiffAreaFileIncrease;
  3032. increase >>= BLOCK_SHIFT;
  3033. size = increase*(sizeof(TRANSLATION_TABLE_ENTRY) +
  3034. sizeof(RTL_BALANCED_LINKS));
  3035. size = (size + 0xFFFF)&(~0xFFFF);
  3036. ASSERT(size >= MINIMUM_TABLE_HEAP_SIZE);
  3037. InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
  3038. DoOver:
  3039. sectionSize.QuadPart = size;
  3040. status = ZwCreateSection(&h, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
  3041. SECTION_MAP_READ | SECTION_MAP_WRITE, &oa,
  3042. &sectionSize, PAGE_READWRITE, SEC_COMMIT,
  3043. NULL);
  3044. if (!NT_SUCCESS(status)) {
  3045. if (size > MINIMUM_TABLE_HEAP_SIZE) {
  3046. size = MINIMUM_TABLE_HEAP_SIZE;
  3047. goto DoOver;
  3048. }
  3049. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 1);
  3050. goto Finish;
  3051. }
  3052. sectionOffset.QuadPart = 0;
  3053. mapPointer = NULL;
  3054. status = ZwMapViewOfSection(h, NtCurrentProcess(), &mapPointer, 0, 0,
  3055. &sectionOffset, &size, ViewShare, 0,
  3056. PAGE_READWRITE);
  3057. ZwClose(h);
  3058. if (!NT_SUCCESS(status)) {
  3059. if (size > MINIMUM_TABLE_HEAP_SIZE) {
  3060. size = MINIMUM_TABLE_HEAP_SIZE;
  3061. goto DoOver;
  3062. }
  3063. VspLogError(extension, NULL, VS_CANT_CREATE_HEAP, status, 2);
  3064. goto Finish;
  3065. }
  3066. VspAcquire(extension->Root);
  3067. if (extension->IsDead) {
  3068. VspRelease(extension->Root);
  3069. status = ZwUnmapViewOfSection(NtCurrentProcess(), mapPointer);
  3070. ASSERT(NT_SUCCESS(status));
  3071. goto Finish;
  3072. }
  3073. VspAcquirePagedResource(extension, NULL);
  3074. extension->NextDiffAreaFileMap = mapPointer;
  3075. extension->NextDiffAreaFileMapSize = (ULONG) size;
  3076. extension->DiffAreaFileMapProcess = NtCurrentProcess();
  3077. VspReleasePagedResource(extension);
  3078. VspRelease(extension->Root);
  3079. Finish:
  3080. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3081. if (extension->PageFileSpaceCreatePending) {
  3082. extension->PageFileSpaceCreatePending = FALSE;
  3083. if (IsListEmpty(&extension->WaitingForPageFileSpace)) {
  3084. emptyQueue = FALSE;
  3085. } else {
  3086. emptyQueue = TRUE;
  3087. q = extension->WaitingForPageFileSpace;
  3088. InitializeListHead(&extension->WaitingForPageFileSpace);
  3089. }
  3090. } else {
  3091. emptyQueue = FALSE;
  3092. }
  3093. KeReleaseSpinLock(&extension->SpinLock, irql);
  3094. if (emptyQueue) {
  3095. q.Flink->Blink = &q;
  3096. q.Blink->Flink = &q;
  3097. while (!IsListEmpty(&q)) {
  3098. l = RemoveHeadList(&q);
  3099. workItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  3100. VspAcquirePagedResource(extension, workItem);
  3101. }
  3102. }
  3103. ObDereferenceObject(extension->DeviceObject);
  3104. }
  3105. PVOID
  3106. VspTableAllocateRoutine(
  3107. IN PRTL_GENERIC_TABLE Table,
  3108. IN CLONG Size
  3109. )
  3110. {
  3111. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  3112. PVOID p;
  3113. POLD_HEAP_ENTRY oldHeap;
  3114. PVSP_CONTEXT context;
  3115. KIRQL irql;
  3116. if (extension->NextAvailable + Size <= extension->DiffAreaFileMapSize) {
  3117. p = (PCHAR) extension->DiffAreaFileMap + extension->NextAvailable;
  3118. extension->NextAvailable += Size;
  3119. return p;
  3120. }
  3121. if (!extension->NextDiffAreaFileMap) {
  3122. return NULL;
  3123. }
  3124. oldHeap = (POLD_HEAP_ENTRY)
  3125. ExAllocatePoolWithTag(PagedPool, sizeof(OLD_HEAP_ENTRY),
  3126. VOLSNAP_TAG_OLD_HEAP);
  3127. if (!oldHeap) {
  3128. return NULL;
  3129. }
  3130. context = VspAllocateContext(extension->Root);
  3131. if (!context) {
  3132. ExFreePool(oldHeap);
  3133. return NULL;
  3134. }
  3135. KeAcquireSpinLock(&extension->SpinLock, &irql);
  3136. ASSERT(!extension->PageFileSpaceCreatePending);
  3137. ASSERT(IsListEmpty(&extension->WaitingForPageFileSpace));
  3138. extension->PageFileSpaceCreatePending = TRUE;
  3139. KeReleaseSpinLock(&extension->SpinLock, irql);
  3140. oldHeap->DiffAreaFileMap = extension->DiffAreaFileMap;
  3141. InsertTailList(&extension->OldHeaps, &oldHeap->ListEntry);
  3142. extension->DiffAreaFileMap = extension->NextDiffAreaFileMap;
  3143. extension->DiffAreaFileMapSize = extension->NextDiffAreaFileMapSize;
  3144. extension->NextAvailable = 0;
  3145. extension->NextDiffAreaFileMap = NULL;
  3146. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  3147. context->Extension.Extension = extension;
  3148. context->Extension.Irp = NULL;
  3149. ObReferenceObject(extension->DeviceObject);
  3150. ExInitializeWorkItem(&context->WorkItem, VspCreateHeap, context);
  3151. VspQueueWorkItem(extension->Root, &context->WorkItem, 0);
  3152. p = extension->DiffAreaFileMap;
  3153. extension->NextAvailable += Size;
  3154. return p;
  3155. }
  3156. VOID
  3157. VspTableFreeRoutine(
  3158. IN PRTL_GENERIC_TABLE Table,
  3159. IN PVOID Buffer
  3160. )
  3161. {
  3162. }
  3163. PVOID
  3164. VspTempTableAllocateRoutine(
  3165. IN PRTL_GENERIC_TABLE Table,
  3166. IN CLONG Size
  3167. )
  3168. {
  3169. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  3170. PVOID r;
  3171. ASSERT(Size <= sizeof(RTL_BALANCED_LINKS) +
  3172. sizeof(TEMP_TRANSLATION_TABLE_ENTRY));
  3173. r = extension->TempTableEntry;
  3174. extension->TempTableEntry = NULL;
  3175. return r;
  3176. }
  3177. VOID
  3178. VspTempTableFreeRoutine(
  3179. IN PRTL_GENERIC_TABLE Table,
  3180. IN PVOID Buffer
  3181. )
  3182. {
  3183. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Table->TableContext;
  3184. VspFreeTempTableEntry(extension->Root, Buffer);
  3185. }
  3186. PFILTER_EXTENSION
  3187. VspFindFilter(
  3188. IN PDO_EXTENSION RootExtension,
  3189. IN PFILTER_EXTENSION Filter,
  3190. IN PUNICODE_STRING VolumeName,
  3191. IN PFILE_OBJECT FileObject
  3192. )
  3193. {
  3194. NTSTATUS status;
  3195. PDEVICE_OBJECT deviceObject, d;
  3196. PLIST_ENTRY l;
  3197. PFILTER_EXTENSION filter;
  3198. if (VolumeName) {
  3199. status = IoGetDeviceObjectPointer(VolumeName, FILE_READ_ATTRIBUTES,
  3200. &FileObject, &deviceObject);
  3201. if (!NT_SUCCESS(status)) {
  3202. if (Filter) {
  3203. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA, status,
  3204. 1);
  3205. }
  3206. return NULL;
  3207. }
  3208. }
  3209. deviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
  3210. for (l = RootExtension->FilterList.Flink;
  3211. l != &RootExtension->FilterList; l = l->Flink) {
  3212. filter = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  3213. d = IoGetAttachedDeviceReference(filter->DeviceObject);
  3214. ObDereferenceObject(d);
  3215. if (d == deviceObject) {
  3216. break;
  3217. }
  3218. }
  3219. ObDereferenceObject(deviceObject);
  3220. if (VolumeName) {
  3221. ObDereferenceObject(FileObject);
  3222. }
  3223. if (l != &RootExtension->FilterList) {
  3224. return filter;
  3225. }
  3226. if (Filter) {
  3227. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  3228. STATUS_NOT_FOUND, 2);
  3229. }
  3230. return NULL;
  3231. }
  3232. NTSTATUS
  3233. VspIsNtfs(
  3234. IN HANDLE FileHandle,
  3235. OUT PBOOLEAN IsNtfs
  3236. )
  3237. {
  3238. ULONG size;
  3239. PFILE_FS_ATTRIBUTE_INFORMATION fsAttributeInfo;
  3240. NTSTATUS status;
  3241. IO_STATUS_BLOCK ioStatus;
  3242. size = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  3243. 4*sizeof(WCHAR);
  3244. fsAttributeInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)
  3245. ExAllocatePoolWithTag(PagedPool, size,
  3246. VOLSNAP_TAG_SHORT_TERM);
  3247. if (!fsAttributeInfo) {
  3248. return STATUS_INSUFFICIENT_RESOURCES;
  3249. }
  3250. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  3251. fsAttributeInfo, size,
  3252. FileFsAttributeInformation);
  3253. if (status == STATUS_BUFFER_OVERFLOW) {
  3254. *IsNtfs = FALSE;
  3255. ExFreePool(fsAttributeInfo);
  3256. return STATUS_SUCCESS;
  3257. }
  3258. if (!NT_SUCCESS(status)) {
  3259. ExFreePool(fsAttributeInfo);
  3260. return status;
  3261. }
  3262. if (fsAttributeInfo->FileSystemNameLength == 8 &&
  3263. fsAttributeInfo->FileSystemName[0] == 'N' &&
  3264. fsAttributeInfo->FileSystemName[1] == 'T' &&
  3265. fsAttributeInfo->FileSystemName[2] == 'F' &&
  3266. fsAttributeInfo->FileSystemName[3] == 'S') {
  3267. ExFreePool(fsAttributeInfo);
  3268. *IsNtfs = TRUE;
  3269. return STATUS_SUCCESS;
  3270. }
  3271. ExFreePool(fsAttributeInfo);
  3272. *IsNtfs = FALSE;
  3273. return STATUS_SUCCESS;
  3274. }
  3275. LONGLONG
  3276. VspQueryVolumeSize(
  3277. IN PFILTER_EXTENSION Filter
  3278. )
  3279. {
  3280. PDEVICE_OBJECT targetObject;
  3281. KEVENT event;
  3282. PIRP irp;
  3283. GET_LENGTH_INFORMATION lengthInfo;
  3284. IO_STATUS_BLOCK ioStatus;
  3285. NTSTATUS status;
  3286. targetObject = Filter->TargetObject;
  3287. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3288. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_LENGTH_INFO,
  3289. targetObject, NULL, 0, &lengthInfo,
  3290. sizeof(lengthInfo), FALSE, &event,
  3291. &ioStatus);
  3292. if (!irp) {
  3293. return 0;
  3294. }
  3295. status = IoCallDriver(targetObject, irp);
  3296. if (status == STATUS_PENDING) {
  3297. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3298. status = ioStatus.Status;
  3299. }
  3300. if (!NT_SUCCESS(status)) {
  3301. return 0;
  3302. }
  3303. return lengthInfo.Length.QuadPart;
  3304. }
  3305. NTSTATUS
  3306. VspQueryVolumeNumber(
  3307. IN PVOLUME_EXTENSION Extension,
  3308. IN PIRP Irp
  3309. )
  3310. {
  3311. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3312. PVOLUME_NUMBER output;
  3313. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3314. sizeof(VOLUME_NUMBER)) {
  3315. return STATUS_INVALID_PARAMETER;
  3316. }
  3317. output = (PVOLUME_NUMBER) Irp->AssociatedIrp.SystemBuffer;
  3318. output->VolumeNumber = Extension->VolumeNumber;
  3319. RtlCopyMemory(output->VolumeManagerName, L"VOLSNAP ", 16);
  3320. Irp->IoStatus.Information = sizeof(VOLUME_NUMBER);
  3321. return STATUS_SUCCESS;
  3322. }
  3323. VOID
  3324. VspCancelRoutine(
  3325. IN OUT PDEVICE_OBJECT DeviceObject,
  3326. IN OUT PIRP Irp
  3327. )
  3328. /*++
  3329. Routine Description:
  3330. This routine is called on when the given IRP is cancelled. It
  3331. will dequeue this IRP off the work queue and complete the
  3332. request as CANCELLED.
  3333. Arguments:
  3334. DeviceObject - Supplies the device object.
  3335. Irp - Supplies the IRP.
  3336. Return Value:
  3337. None.
  3338. --*/
  3339. {
  3340. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  3341. ASSERT(Irp == filter->FlushAndHoldIrp);
  3342. filter->FlushAndHoldIrp = NULL;
  3343. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  3344. IoReleaseCancelSpinLock(Irp->CancelIrql);
  3345. Irp->IoStatus.Status = STATUS_CANCELLED;
  3346. Irp->IoStatus.Information = 0;
  3347. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3348. }
  3349. VOID
  3350. VspFsTimerDpc(
  3351. IN PKDPC TimerDpc,
  3352. IN PVOID Context,
  3353. IN PVOID SystemArgument1,
  3354. IN PVOID SystemArgument2
  3355. )
  3356. {
  3357. PDO_EXTENSION rootExtension = (PDO_EXTENSION) Context;
  3358. KIRQL irql;
  3359. PIRP irp;
  3360. PFILTER_EXTENSION filter;
  3361. IoAcquireCancelSpinLock(&irql);
  3362. while (!IsListEmpty(&rootExtension->HoldIrps)) {
  3363. irp = CONTAINING_RECORD(rootExtension->HoldIrps.Flink, IRP,
  3364. Tail.Overlay.ListEntry);
  3365. irp->CancelIrql = irql;
  3366. IoSetCancelRoutine(irp, NULL);
  3367. filter = (PFILTER_EXTENSION) IoGetCurrentIrpStackLocation(irp)->
  3368. DeviceObject->DeviceExtension;
  3369. ObReferenceObject(filter->DeviceObject);
  3370. VspCancelRoutine(filter->DeviceObject, irp);
  3371. VspLogError(NULL, filter, VS_FLUSH_AND_HOLD_FS_TIMEOUT,
  3372. STATUS_CANCELLED, 0);
  3373. ObDereferenceObject(filter->DeviceObject);
  3374. IoAcquireCancelSpinLock(&irql);
  3375. }
  3376. rootExtension->HoldRefCount = 0;
  3377. IoReleaseCancelSpinLock(irql);
  3378. }
  3379. VOID
  3380. VspZeroRefCallback(
  3381. IN PFILTER_EXTENSION Filter
  3382. )
  3383. {
  3384. PIRP irp = (PIRP) Filter->ZeroRefContext;
  3385. LARGE_INTEGER timeout;
  3386. timeout.QuadPart = -10*1000*1000*((LONGLONG) Filter->HoldWritesTimeout);
  3387. KeSetTimer(&Filter->HoldWritesTimer, timeout, &Filter->HoldWritesTimerDpc);
  3388. InterlockedExchange(&Filter->TimerIsSet, TRUE);
  3389. irp->IoStatus.Status = STATUS_SUCCESS;
  3390. irp->IoStatus.Information = 0;
  3391. IoCompleteRequest(irp, IO_SOUND_INCREMENT);
  3392. }
  3393. VOID
  3394. VspFlushAndHoldWriteIrps(
  3395. IN PIRP Irp,
  3396. IN ULONG HoldWritesTimeout
  3397. )
  3398. /*++
  3399. Routine Description:
  3400. This routine waits for outstanding write requests to complete while
  3401. holding incoming write requests. This IRP will complete when all
  3402. outstanding IRPs have completed. A timer will be set for the given
  3403. timeout value and held writes irps will be released after that point or
  3404. when IOCTL_VOLSNAP_RELEASE_WRITES comes in, whichever is sooner.
  3405. Arguments:
  3406. Irp - Supplies the I/O request packet.
  3407. HoldWritesTimeout - Supplies the maximum length of time in seconds that a
  3408. write IRP will be held up.
  3409. Return Value:
  3410. None.
  3411. --*/
  3412. {
  3413. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3414. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  3415. KIRQL irql;
  3416. NTSTATUS status;
  3417. KeAcquireSpinLock(&filter->SpinLock, &irql);
  3418. if (filter->HoldIncomingWrites) {
  3419. KeReleaseSpinLock(&filter->SpinLock, irql);
  3420. Irp->IoStatus.Information = 0;
  3421. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3422. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3423. return;
  3424. }
  3425. filter->HoldWritesTimeout = HoldWritesTimeout;
  3426. InterlockedExchange(&filter->HoldIncomingWrites, TRUE);
  3427. filter->ZeroRefCallback = VspZeroRefCallback;
  3428. filter->ZeroRefContext = Irp;
  3429. KeReleaseSpinLock(&filter->SpinLock, irql);
  3430. VspDecrementRefCount(filter);
  3431. IoStartTimer(filter->DeviceObject);
  3432. status = VspCheckForMemoryPressure(filter);
  3433. if (!NT_SUCCESS(status)) {
  3434. VspReleaseWrites(filter);
  3435. }
  3436. }
  3437. NTSTATUS
  3438. VspFlushAndHoldWrites(
  3439. IN PFILTER_EXTENSION Filter,
  3440. IN PIRP Irp
  3441. )
  3442. /*++
  3443. Routine Description:
  3444. This routine is called for multiple volumes at once. On the first
  3445. call the GUID is checked and if it is different than the current one
  3446. then the current set is aborted. If the GUID is new then subsequent
  3447. calls are compared to the GUID passed in here until the required
  3448. number of calls is completed. A timer is used to wait until all
  3449. of the IRPs have reached this driver and then another time out is used
  3450. after all of these calls complete to wait for IOCTL_VOLSNAP_RELEASE_WRITES
  3451. to be sent to all of the volumes involved.
  3452. Arguments:
  3453. Filter - Supplies the filter device extension.
  3454. Irp - Supplies the I/O request packet.
  3455. Return Value:
  3456. NTSTATUS
  3457. --*/
  3458. {
  3459. PDO_EXTENSION rootExtension = Filter->Root;
  3460. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3461. PVOLSNAP_FLUSH_AND_HOLD_INPUT input;
  3462. KIRQL irql;
  3463. LARGE_INTEGER timeout;
  3464. LIST_ENTRY q;
  3465. PLIST_ENTRY l;
  3466. PIRP irp;
  3467. PFILTER_EXTENSION filter;
  3468. ULONG irpTimeout;
  3469. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3470. sizeof(VOLSNAP_FLUSH_AND_HOLD_INPUT)) {
  3471. return STATUS_INVALID_PARAMETER;
  3472. }
  3473. input = (PVOLSNAP_FLUSH_AND_HOLD_INPUT) Irp->AssociatedIrp.SystemBuffer;
  3474. if (!input->NumberOfVolumesToFlush ||
  3475. !input->SecondsToHoldFileSystemsTimeout ||
  3476. !input->SecondsToHoldIrpsTimeout) {
  3477. return STATUS_INVALID_PARAMETER;
  3478. }
  3479. IoAcquireCancelSpinLock(&irql);
  3480. if (Filter->FlushAndHoldIrp) {
  3481. IoReleaseCancelSpinLock(irql);
  3482. VspLogError(NULL, Filter, VS_TWO_FLUSH_AND_HOLDS,
  3483. STATUS_INVALID_PARAMETER, 1);
  3484. return STATUS_INVALID_PARAMETER;
  3485. }
  3486. if (rootExtension->HoldRefCount) {
  3487. if (!IsEqualGUID(rootExtension->HoldInstanceGuid, input->InstanceId)) {
  3488. IoReleaseCancelSpinLock(irql);
  3489. VspLogError(NULL, Filter, VS_TWO_FLUSH_AND_HOLDS,
  3490. STATUS_INVALID_PARAMETER, 2);
  3491. return STATUS_INVALID_PARAMETER;
  3492. }
  3493. } else {
  3494. if (IsEqualGUID(rootExtension->HoldInstanceGuid, input->InstanceId)) {
  3495. IoReleaseCancelSpinLock(irql);
  3496. VspLogError(NULL, Filter, VS_TWO_FLUSH_AND_HOLDS,
  3497. STATUS_INVALID_PARAMETER, 3);
  3498. return STATUS_INVALID_PARAMETER;
  3499. }
  3500. rootExtension->HoldRefCount = input->NumberOfVolumesToFlush + 1;
  3501. rootExtension->HoldInstanceGuid = input->InstanceId;
  3502. rootExtension->SecondsToHoldFsTimeout =
  3503. input->SecondsToHoldFileSystemsTimeout;
  3504. rootExtension->SecondsToHoldIrpTimeout =
  3505. input->SecondsToHoldIrpsTimeout;
  3506. timeout.QuadPart = -10*1000*1000*
  3507. ((LONGLONG) rootExtension->SecondsToHoldFsTimeout);
  3508. KeSetTimer(&rootExtension->HoldTimer, timeout,
  3509. &rootExtension->HoldTimerDpc);
  3510. }
  3511. Filter->FlushAndHoldIrp = Irp;
  3512. InsertTailList(&rootExtension->HoldIrps, &Irp->Tail.Overlay.ListEntry);
  3513. IoSetCancelRoutine(Irp, VspCancelRoutine);
  3514. IoMarkIrpPending(Irp);
  3515. rootExtension->HoldRefCount--;
  3516. if (rootExtension->HoldRefCount != 1) {
  3517. IoReleaseCancelSpinLock(irql);
  3518. return STATUS_PENDING;
  3519. }
  3520. InitializeListHead(&q);
  3521. while (!IsListEmpty(&rootExtension->HoldIrps)) {
  3522. l = RemoveHeadList(&rootExtension->HoldIrps);
  3523. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  3524. filter = (PFILTER_EXTENSION)
  3525. IoGetCurrentIrpStackLocation(irp)->DeviceObject->
  3526. DeviceExtension;
  3527. InsertTailList(&q, l);
  3528. filter->FlushAndHoldIrp = NULL;
  3529. IoSetCancelRoutine(irp, NULL);
  3530. }
  3531. irpTimeout = rootExtension->SecondsToHoldIrpTimeout;
  3532. if (KeCancelTimer(&rootExtension->HoldTimer)) {
  3533. IoReleaseCancelSpinLock(irql);
  3534. VspFsTimerDpc(&rootExtension->HoldTimerDpc,
  3535. rootExtension->HoldTimerDpc.DeferredContext,
  3536. rootExtension->HoldTimerDpc.SystemArgument1,
  3537. rootExtension->HoldTimerDpc.SystemArgument2);
  3538. } else {
  3539. IoReleaseCancelSpinLock(irql);
  3540. }
  3541. while (!IsListEmpty(&q)) {
  3542. l = RemoveHeadList(&q);
  3543. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  3544. VspFlushAndHoldWriteIrps(irp, irpTimeout);
  3545. }
  3546. return STATUS_PENDING;
  3547. }
  3548. NTSTATUS
  3549. VspCreateDiffAreaFileName(
  3550. IN PDEVICE_OBJECT DeviceObject,
  3551. IN ULONG VolumeSnapshotNumber,
  3552. OUT PUNICODE_STRING DiffAreaFileName
  3553. )
  3554. /*++
  3555. Routine Description:
  3556. This routine builds the diff area file name for the given diff area
  3557. volume and the given volume snapshot number. The name formed will
  3558. look like <Diff Area Volume Name>\<Volume Snapshot Number><GUID>.
  3559. Arguments:
  3560. Filter - Supplies the filter extension.
  3561. VolumeSnapshotNumber - Supplies the volume snapshot number.
  3562. DiffAreaFileName - Returns the name of the diff area file.
  3563. Return Value:
  3564. NTSTATUS
  3565. --*/
  3566. {
  3567. PDEVICE_OBJECT targetObject = DeviceObject;
  3568. KEVENT event;
  3569. PMOUNTDEV_NAME name;
  3570. UCHAR buffer[512];
  3571. PIRP irp;
  3572. IO_STATUS_BLOCK ioStatus;
  3573. NTSTATUS status;
  3574. UNICODE_STRING sysvol, guidString, numberString, string;
  3575. WCHAR numberBuffer[20];
  3576. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3577. name = (PMOUNTDEV_NAME) buffer;
  3578. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  3579. targetObject, NULL, 0, name,
  3580. 512, FALSE, &event, &ioStatus);
  3581. if (!irp) {
  3582. return STATUS_INSUFFICIENT_RESOURCES;
  3583. }
  3584. status = IoCallDriver(targetObject, irp);
  3585. if (status == STATUS_PENDING) {
  3586. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3587. status = ioStatus.Status;
  3588. }
  3589. if (!NT_SUCCESS(status)) {
  3590. return status;
  3591. }
  3592. RtlInitUnicodeString(&sysvol, RTL_SYSTEM_VOLUME_INFORMATION_FOLDER);
  3593. if (VolumeSnapshotNumber == (ULONG) -1) {
  3594. swprintf(numberBuffer, L"\\*");
  3595. } else {
  3596. swprintf(numberBuffer, L"\\%d", VolumeSnapshotNumber);
  3597. }
  3598. RtlInitUnicodeString(&numberString, numberBuffer);
  3599. status = RtlStringFromGUID(VSP_DIFF_AREA_FILE_GUID, &guidString);
  3600. if (!NT_SUCCESS(status)) {
  3601. return status;
  3602. }
  3603. string.MaximumLength = name->NameLength + sizeof(WCHAR) + sysvol.Length +
  3604. numberString.Length + guidString.Length +
  3605. sizeof(WCHAR);
  3606. string.Length = 0;
  3607. string.Buffer = (PWCHAR)
  3608. ExAllocatePoolWithTag(PagedPool, string.MaximumLength,
  3609. VOLSNAP_TAG_SHORT_TERM);
  3610. if (!string.Buffer) {
  3611. ExFreePool(guidString.Buffer);
  3612. return STATUS_INSUFFICIENT_RESOURCES;
  3613. }
  3614. string.Length = name->NameLength;
  3615. RtlCopyMemory(string.Buffer, name->Name, string.Length);
  3616. string.Buffer[string.Length/sizeof(WCHAR)] = '\\';
  3617. string.Length += sizeof(WCHAR);
  3618. if (VolumeSnapshotNumber != (ULONG) -1) {
  3619. RtlCreateSystemVolumeInformationFolder(&string);
  3620. }
  3621. RtlAppendUnicodeStringToString(&string, &sysvol);
  3622. RtlAppendUnicodeStringToString(&string, &numberString);
  3623. RtlAppendUnicodeStringToString(&string, &guidString);
  3624. ExFreePool(guidString.Buffer);
  3625. string.Buffer[string.Length/sizeof(WCHAR)] = 0;
  3626. *DiffAreaFileName = string;
  3627. return STATUS_SUCCESS;
  3628. }
  3629. NTSTATUS
  3630. VspCreateSecurityDescriptor(
  3631. OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
  3632. OUT PACL* Acl
  3633. )
  3634. {
  3635. PSECURITY_DESCRIPTOR sd;
  3636. NTSTATUS status;
  3637. ULONG aclLength;
  3638. PACL acl;
  3639. sd = (PSECURITY_DESCRIPTOR)
  3640. ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_DESCRIPTOR),
  3641. VOLSNAP_TAG_SHORT_TERM);
  3642. if (!sd) {
  3643. return STATUS_INSUFFICIENT_RESOURCES;
  3644. }
  3645. status = RtlCreateSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
  3646. if (!NT_SUCCESS(status)) {
  3647. ExFreePool(sd);
  3648. return status;
  3649. }
  3650. aclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
  3651. RtlLengthSid(SeExports->SeWorldSid) - sizeof(ULONG);
  3652. acl = (PACL) ExAllocatePoolWithTag(PagedPool, aclLength,
  3653. VOLSNAP_TAG_SHORT_TERM);
  3654. if (!acl) {
  3655. ExFreePool(sd);
  3656. return STATUS_INSUFFICIENT_RESOURCES;
  3657. }
  3658. status = RtlCreateAcl(acl, aclLength, ACL_REVISION);
  3659. if (!NT_SUCCESS(status)) {
  3660. ExFreePool(acl);
  3661. ExFreePool(sd);
  3662. return status;
  3663. }
  3664. status = RtlAddAccessAllowedAce(acl, ACL_REVISION, DELETE,
  3665. SeExports->SeWorldSid);
  3666. if (!NT_SUCCESS(status)) {
  3667. ExFreePool(acl);
  3668. ExFreePool(sd);
  3669. return status;
  3670. }
  3671. status = RtlSetDaclSecurityDescriptor(sd, TRUE, acl, FALSE);
  3672. if (!NT_SUCCESS(status)) {
  3673. ExFreePool(acl);
  3674. ExFreePool(sd);
  3675. return status;
  3676. }
  3677. *SecurityDescriptor = sd;
  3678. *Acl = acl;
  3679. return STATUS_SUCCESS;
  3680. }
  3681. NTSTATUS
  3682. VspPinFile(
  3683. IN PVSP_DIFF_AREA_FILE DiffAreaFile
  3684. )
  3685. /*++
  3686. Routine Description:
  3687. This routine pins down the extents of the given diff area file so that
  3688. defrag operations are disabled.
  3689. Arguments:
  3690. DiffAreaFile - Supplies the diff area file.
  3691. Return Value:
  3692. NTSTATUS
  3693. --*/
  3694. {
  3695. NTSTATUS status;
  3696. UNICODE_STRING volumeName;
  3697. OBJECT_ATTRIBUTES oa;
  3698. HANDLE h;
  3699. IO_STATUS_BLOCK ioStatus;
  3700. MARK_HANDLE_INFO markHandleInfo;
  3701. status = VspCreateDiffAreaFileName(DiffAreaFile->Filter->TargetObject,
  3702. (ULONG) -1, &volumeName);
  3703. if (!NT_SUCCESS(status)) {
  3704. return status;
  3705. }
  3706. volumeName.Length -= 66*sizeof(WCHAR);
  3707. volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0;
  3708. InitializeObjectAttributes(&oa, &volumeName, OBJ_CASE_INSENSITIVE, NULL,
  3709. NULL);
  3710. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  3711. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3712. FILE_SYNCHRONOUS_IO_NONALERT);
  3713. ExFreePool(volumeName.Buffer);
  3714. if (!NT_SUCCESS(status)) {
  3715. return status;
  3716. }
  3717. RtlZeroMemory(&markHandleInfo, sizeof(MARK_HANDLE_INFO));
  3718. markHandleInfo.VolumeHandle = h;
  3719. markHandleInfo.HandleInfo = MARK_HANDLE_PROTECT_CLUSTERS;
  3720. status = ZwFsControlFile(DiffAreaFile->FileHandle, NULL, NULL, NULL,
  3721. &ioStatus, FSCTL_MARK_HANDLE, &markHandleInfo,
  3722. sizeof(markHandleInfo), NULL, 0);
  3723. ZwClose(h);
  3724. return status;
  3725. }
  3726. NTSTATUS
  3727. VspOptimizeDiffAreaFileLocation(
  3728. IN PFILTER_EXTENSION Filter,
  3729. IN HANDLE FileHandle,
  3730. IN PVOLUME_EXTENSION BitmapExtension,
  3731. IN LONGLONG StartingOffset,
  3732. IN LONGLONG FileSize
  3733. )
  3734. /*++
  3735. Routine Description:
  3736. This routine optimizes the location of the diff area file so that more
  3737. of it can be used.
  3738. Arguments:
  3739. Filter - Supplies the filter extension where the diff area resides.
  3740. FileHandle - Provides a handle to the diff area.
  3741. BitmapExtension - Supplies the extension of the active snapshot on the
  3742. given filter, if any.
  3743. StartingOffset - Supplies the starting point of where to optimize
  3744. the file.
  3745. FileSize - Supplies the allocated size of the file.
  3746. Return Value:
  3747. NTSTATUS
  3748. --*/
  3749. {
  3750. NTSTATUS status;
  3751. IO_STATUS_BLOCK ioStatus;
  3752. FILE_FS_SIZE_INFORMATION fsSize;
  3753. ULONG bitmapSize;
  3754. PVOID bitmapBuffer;
  3755. RTL_BITMAP bitmap;
  3756. PMOUNTDEV_NAME mountdevName;
  3757. UCHAR buffer[200];
  3758. KEVENT event;
  3759. PIRP irp;
  3760. UNICODE_STRING fileName;
  3761. OBJECT_ATTRIBUTES oa;
  3762. HANDLE h;
  3763. KIRQL irql;
  3764. ULONG numBitsToFind, bitIndex, bpc, bitsFound;
  3765. MOVE_FILE_DATA moveFileData;
  3766. // Align the given file and if 'BitmapExtension' is available, try to
  3767. // confine the file to the bits already set in the bitmap in
  3768. // 'BitmapExtension'.
  3769. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus, &fsSize,
  3770. sizeof(fsSize),
  3771. FileFsSizeInformation);
  3772. if (!NT_SUCCESS(status)) {
  3773. return status;
  3774. }
  3775. bitmapSize = (ULONG) (fsSize.TotalAllocationUnits.QuadPart*
  3776. fsSize.SectorsPerAllocationUnit*
  3777. fsSize.BytesPerSector/BLOCK_SIZE);
  3778. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  3779. (bitmapSize + 8*sizeof(ULONG) - 1)/
  3780. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  3781. if (!bitmapBuffer) {
  3782. return STATUS_INSUFFICIENT_RESOURCES;
  3783. }
  3784. RtlInitializeBitMap(&bitmap, (PULONG) bitmapBuffer, bitmapSize);
  3785. RtlClearAllBits(&bitmap);
  3786. mountdevName = (PMOUNTDEV_NAME) buffer;
  3787. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3788. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  3789. Filter->TargetObject, NULL, 0,
  3790. mountdevName, 200, FALSE, &event,
  3791. &ioStatus);
  3792. if (!irp) {
  3793. ExFreePool(bitmapBuffer);
  3794. return STATUS_INSUFFICIENT_RESOURCES;
  3795. }
  3796. status = IoCallDriver(Filter->TargetObject, irp);
  3797. if (status == STATUS_PENDING) {
  3798. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3799. status = ioStatus.Status;
  3800. }
  3801. if (!NT_SUCCESS(status)) {
  3802. ExFreePool(bitmapBuffer);
  3803. return status;
  3804. }
  3805. mountdevName->Name[mountdevName->NameLength/sizeof(WCHAR)] = 0;
  3806. RtlInitUnicodeString(&fileName, mountdevName->Name);
  3807. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE, NULL,
  3808. NULL);
  3809. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  3810. FILE_SHARE_READ | FILE_SHARE_WRITE |
  3811. FILE_SHARE_DELETE,
  3812. FILE_SYNCHRONOUS_IO_NONALERT);
  3813. if (!NT_SUCCESS(status)) {
  3814. ExFreePool(bitmapBuffer);
  3815. return status;
  3816. }
  3817. status = VspMarkFreeSpaceInBitmap(NULL, h, &bitmap);
  3818. if (!NT_SUCCESS(status)) {
  3819. ZwClose(h);
  3820. ExFreePool(bitmapBuffer);
  3821. return status;
  3822. }
  3823. if (BitmapExtension) {
  3824. VspAcquire(BitmapExtension->Root);
  3825. if (!BitmapExtension->IsDead) {
  3826. KeAcquireSpinLock(&BitmapExtension->SpinLock, &irql);
  3827. if (BitmapExtension->VolumeBlockBitmap) {
  3828. if (BitmapExtension->VolumeBlockBitmap->SizeOfBitMap <
  3829. bitmap.SizeOfBitMap) {
  3830. bitmap.SizeOfBitMap =
  3831. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap;
  3832. }
  3833. VspAndBitmaps(&bitmap, BitmapExtension->VolumeBlockBitmap);
  3834. if (bitmap.SizeOfBitMap < bitmapSize) {
  3835. bitmap.SizeOfBitMap = bitmapSize;
  3836. RtlClearBits(&bitmap,
  3837. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap,
  3838. bitmapSize -
  3839. BitmapExtension->VolumeBlockBitmap->SizeOfBitMap);
  3840. }
  3841. }
  3842. KeReleaseSpinLock(&BitmapExtension->SpinLock, irql);
  3843. }
  3844. VspRelease(BitmapExtension->Root);
  3845. }
  3846. numBitsToFind = (ULONG) ((FileSize - StartingOffset)/BLOCK_SIZE);
  3847. bpc = fsSize.SectorsPerAllocationUnit*fsSize.BytesPerSector;
  3848. while (numBitsToFind) {
  3849. bitsFound = numBitsToFind;
  3850. if (bitsFound > 64) {
  3851. bitsFound = 64;
  3852. }
  3853. bitIndex = RtlFindSetBits(&bitmap, bitsFound, 0);
  3854. if (bitIndex == (ULONG) -1) {
  3855. ZwClose(h);
  3856. ExFreePool(bitmapBuffer);
  3857. return STATUS_UNSUCCESSFUL;
  3858. }
  3859. moveFileData.FileHandle = FileHandle;
  3860. moveFileData.StartingVcn.QuadPart = StartingOffset/bpc;
  3861. moveFileData.StartingLcn.QuadPart =
  3862. (((LONGLONG) bitIndex)<<BLOCK_SHIFT)/bpc;
  3863. moveFileData.ClusterCount = (ULONG) ((((LONGLONG) bitsFound)<<
  3864. BLOCK_SHIFT)/bpc);
  3865. status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
  3866. FSCTL_MOVE_FILE, &moveFileData,
  3867. sizeof(moveFileData), NULL, 0);
  3868. RtlClearBits(&bitmap, bitIndex, bitsFound);
  3869. if (!NT_SUCCESS(status)) {
  3870. continue;
  3871. }
  3872. numBitsToFind -= bitsFound;
  3873. StartingOffset += ((LONGLONG) bitsFound)<<BLOCK_SHIFT;
  3874. }
  3875. ZwClose(h);
  3876. ExFreePool(bitmapBuffer);
  3877. return STATUS_SUCCESS;
  3878. }
  3879. NTSTATUS
  3880. VspOpenDiffAreaFile(
  3881. IN OUT PVSP_DIFF_AREA_FILE DiffAreaFile
  3882. )
  3883. {
  3884. LARGE_INTEGER diffAreaFileSize;
  3885. NTSTATUS status;
  3886. UNICODE_STRING diffAreaFileName;
  3887. PSECURITY_DESCRIPTOR securityDescriptor;
  3888. PACL acl;
  3889. OBJECT_ATTRIBUTES oa;
  3890. IO_STATUS_BLOCK ioStatus;
  3891. BOOLEAN isNtfs;
  3892. PVOLUME_EXTENSION bitmapExtension;
  3893. diffAreaFileSize.QuadPart = DiffAreaFile->AllocatedFileSize;
  3894. status = VspCreateDiffAreaFileName(DiffAreaFile->Filter->TargetObject,
  3895. DiffAreaFile->Extension->VolumeNumber,
  3896. &diffAreaFileName);
  3897. if (!NT_SUCCESS(status)) {
  3898. return status;
  3899. }
  3900. status = VspCreateSecurityDescriptor(&securityDescriptor, &acl);
  3901. if (!NT_SUCCESS(status)) {
  3902. ExFreePool(diffAreaFileName.Buffer);
  3903. return status;
  3904. }
  3905. InitializeObjectAttributes(&oa, &diffAreaFileName,
  3906. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  3907. NULL, securityDescriptor);
  3908. status = ZwCreateFile(&DiffAreaFile->FileHandle, FILE_GENERIC_READ |
  3909. FILE_GENERIC_WRITE, &oa, &ioStatus,
  3910. &diffAreaFileSize, FILE_ATTRIBUTE_HIDDEN |
  3911. FILE_ATTRIBUTE_SYSTEM, 0, FILE_OVERWRITE_IF,
  3912. FILE_SYNCHRONOUS_IO_NONALERT |
  3913. FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE |
  3914. FILE_NO_COMPRESSION, NULL, 0);
  3915. ExFreePool(acl);
  3916. ExFreePool(securityDescriptor);
  3917. ExFreePool(diffAreaFileName.Buffer);
  3918. if (!NT_SUCCESS(status)) {
  3919. if (status == STATUS_DISK_FULL) {
  3920. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  3921. VS_DIFF_AREA_CREATE_FAILED_LOW_DISK_SPACE, status, 0);
  3922. } else {
  3923. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  3924. VS_DIFF_AREA_CREATE_FAILED, status, 0);
  3925. }
  3926. return status;
  3927. }
  3928. status = VspIsNtfs(DiffAreaFile->FileHandle, &isNtfs);
  3929. if (!NT_SUCCESS(status) || !isNtfs) {
  3930. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  3931. VS_NOT_NTFS, status, 0);
  3932. ZwClose(DiffAreaFile->FileHandle);
  3933. return STATUS_INVALID_PARAMETER;
  3934. }
  3935. VspAcquire(DiffAreaFile->Filter->Root);
  3936. if (IsListEmpty(&DiffAreaFile->Filter->VolumeList)) {
  3937. bitmapExtension = NULL;
  3938. } else {
  3939. bitmapExtension = CONTAINING_RECORD(
  3940. DiffAreaFile->Filter->VolumeList.Blink,
  3941. VOLUME_EXTENSION, ListEntry);
  3942. if (bitmapExtension->IsDead) {
  3943. bitmapExtension = NULL;
  3944. } else {
  3945. ObReferenceObject(bitmapExtension->DeviceObject);
  3946. }
  3947. }
  3948. VspRelease(DiffAreaFile->Filter->Root);
  3949. VspOptimizeDiffAreaFileLocation(DiffAreaFile->Filter,
  3950. DiffAreaFile->FileHandle,
  3951. bitmapExtension, 0,
  3952. DiffAreaFile->AllocatedFileSize);
  3953. if (bitmapExtension) {
  3954. ObDereferenceObject(bitmapExtension->DeviceObject);
  3955. }
  3956. status = VspPinFile(DiffAreaFile);
  3957. if (!NT_SUCCESS(status)) {
  3958. VspLogError(DiffAreaFile->Extension, DiffAreaFile->Filter,
  3959. VS_PIN_DIFF_AREA_FAILED, status, 0);
  3960. ZwClose(DiffAreaFile->FileHandle);
  3961. return status;
  3962. }
  3963. return STATUS_SUCCESS;
  3964. }
  3965. NTSTATUS
  3966. VspCreateInitialDiffAreaFiles(
  3967. IN PVOLUME_EXTENSION Extension,
  3968. IN LONGLONG InitialDiffAreaAllocation
  3969. )
  3970. /*++
  3971. Routine Description:
  3972. This routine creates the initial diff area file entries for the
  3973. given device extension.
  3974. Arguments:
  3975. Extension - Supplies the volume extension.
  3976. Return Value:
  3977. NTSTATUS
  3978. --*/
  3979. {
  3980. PFILTER_EXTENSION filter = Extension->Filter;
  3981. NTSTATUS status;
  3982. PLIST_ENTRY l;
  3983. PVSP_DIFF_AREA_VOLUME diffAreaVolume;
  3984. PVSP_DIFF_AREA_FILE diffAreaFile;
  3985. KIRQL irql;
  3986. VspAcquire(Extension->Root);
  3987. if (IsListEmpty(&filter->DiffAreaVolumes)) {
  3988. VspRelease(Extension->Root);
  3989. return STATUS_INVALID_PARAMETER;
  3990. }
  3991. status = STATUS_SUCCESS;
  3992. InitializeListHead(&Extension->ListOfDiffAreaFiles);
  3993. for (l = filter->DiffAreaVolumes.Flink; l != &filter->DiffAreaVolumes;
  3994. l = l->Flink) {
  3995. diffAreaVolume = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry);
  3996. diffAreaFile = (PVSP_DIFF_AREA_FILE)
  3997. ExAllocatePoolWithTag(NonPagedPool,
  3998. sizeof(VSP_DIFF_AREA_FILE), VOLSNAP_TAG_DIFF_FILE);
  3999. if (!diffAreaFile) {
  4000. status = STATUS_INSUFFICIENT_RESOURCES;
  4001. break;
  4002. }
  4003. diffAreaFile->Extension = Extension;
  4004. diffAreaFile->Filter = diffAreaVolume->Filter;
  4005. diffAreaFile->FileHandle = NULL;
  4006. diffAreaFile->NextAvailable = 0;
  4007. diffAreaFile->AllocatedFileSize = InitialDiffAreaAllocation;
  4008. InsertTailList(&Extension->ListOfDiffAreaFiles,
  4009. &diffAreaFile->VolumeListEntry);
  4010. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  4011. KeAcquireSpinLock(&filter->SpinLock, &irql);
  4012. filter->AllocatedVolumeSpace += diffAreaFile->AllocatedFileSize;
  4013. KeReleaseSpinLock(&filter->SpinLock, irql);
  4014. InitializeListHead(&diffAreaFile->UnusedAllocationList);
  4015. }
  4016. VspRelease(Extension->Root);
  4017. for (l = Extension->ListOfDiffAreaFiles.Flink;
  4018. l != &Extension->ListOfDiffAreaFiles; l = l->Flink) {
  4019. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4020. VolumeListEntry);
  4021. status = VspOpenDiffAreaFile(diffAreaFile);
  4022. if (!NT_SUCCESS(status)) {
  4023. break;
  4024. }
  4025. }
  4026. if (!NT_SUCCESS(status)) {
  4027. while (!IsListEmpty(&Extension->ListOfDiffAreaFiles)) {
  4028. l = RemoveHeadList(&Extension->ListOfDiffAreaFiles);
  4029. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4030. VolumeListEntry);
  4031. if (diffAreaFile->FileHandle) {
  4032. ZwClose(diffAreaFile->FileHandle);
  4033. }
  4034. KeAcquireSpinLock(&filter->SpinLock, &irql);
  4035. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  4036. KeReleaseSpinLock(&filter->SpinLock, irql);
  4037. ASSERT(!diffAreaFile->FilterListEntryBeingUsed);
  4038. ExFreePool(diffAreaFile);
  4039. }
  4040. return status;
  4041. }
  4042. Extension->NextDiffAreaFile =
  4043. CONTAINING_RECORD(Extension->ListOfDiffAreaFiles.Flink,
  4044. VSP_DIFF_AREA_FILE, VolumeListEntry);
  4045. return status;
  4046. }
  4047. VOID
  4048. VspDeleteInitialDiffAreaFiles(
  4049. IN PVOLUME_EXTENSION Extension
  4050. )
  4051. {
  4052. PFILTER_EXTENSION filter = Extension->Filter;
  4053. PLIST_ENTRY l, ll;
  4054. PVSP_DIFF_AREA_FILE diffAreaFile;
  4055. KIRQL irql;
  4056. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  4057. while (!IsListEmpty(&Extension->ListOfDiffAreaFiles)) {
  4058. l = RemoveHeadList(&Extension->ListOfDiffAreaFiles);
  4059. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4060. VolumeListEntry);
  4061. ZwClose(diffAreaFile->FileHandle);
  4062. KeAcquireSpinLock(&filter->SpinLock, &irql);
  4063. filter->AllocatedVolumeSpace -= diffAreaFile->AllocatedFileSize;
  4064. KeReleaseSpinLock(&filter->SpinLock, irql);
  4065. while (!IsListEmpty(&diffAreaFile->UnusedAllocationList)) {
  4066. ll = RemoveHeadList(&diffAreaFile->UnusedAllocationList);
  4067. diffAreaFileAllocation = CONTAINING_RECORD(ll,
  4068. DIFF_AREA_FILE_ALLOCATION, ListEntry);
  4069. ExFreePool(diffAreaFileAllocation);
  4070. }
  4071. if (diffAreaFile->FilterListEntryBeingUsed) {
  4072. RemoveEntryList(&diffAreaFile->FilterListEntry);
  4073. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  4074. }
  4075. ExFreePool(diffAreaFile);
  4076. }
  4077. Extension->NextDiffAreaFile = NULL;
  4078. }
  4079. NTSTATUS
  4080. VspMarkFileAllocationInBitmap(
  4081. IN PVOLUME_EXTENSION Extension,
  4082. IN HANDLE FileHandle,
  4083. IN PVSP_DIFF_AREA_FILE DiffAreaFile,
  4084. IN BOOLEAN OnlyDiffAreaFile,
  4085. IN BOOLEAN ClearBits,
  4086. IN PRTL_BITMAP BitmapToSet
  4087. )
  4088. {
  4089. NTSTATUS status;
  4090. BOOLEAN isNtfs;
  4091. IO_STATUS_BLOCK ioStatus;
  4092. FILE_FS_SIZE_INFORMATION fsSize;
  4093. ULONG bpc;
  4094. STARTING_VCN_INPUT_BUFFER input;
  4095. RETRIEVAL_POINTERS_BUFFER output;
  4096. LONGLONG start, length, end, roundedStart, roundedEnd;
  4097. ULONG startBit, numBits, i;
  4098. KIRQL irql;
  4099. PDIFF_AREA_FILE_ALLOCATION diffAreaFileAllocation;
  4100. status = VspIsNtfs(FileHandle, &isNtfs);
  4101. if (!NT_SUCCESS(status) || !isNtfs) {
  4102. return status;
  4103. }
  4104. status = ZwQueryVolumeInformationFile(FileHandle, &ioStatus,
  4105. &fsSize, sizeof(fsSize),
  4106. FileFsSizeInformation);
  4107. if (!NT_SUCCESS(status)) {
  4108. return status;
  4109. }
  4110. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  4111. input.StartingVcn.QuadPart = 0;
  4112. for (;;) {
  4113. status = ZwFsControlFile(FileHandle, NULL, NULL, NULL, &ioStatus,
  4114. FSCTL_GET_RETRIEVAL_POINTERS, &input,
  4115. sizeof(input), &output, sizeof(output));
  4116. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) {
  4117. if (status == STATUS_END_OF_FILE) {
  4118. status = STATUS_SUCCESS;
  4119. }
  4120. break;
  4121. }
  4122. start = output.Extents[0].Lcn.QuadPart*bpc;
  4123. length = output.Extents[0].NextVcn.QuadPart -
  4124. output.StartingVcn.QuadPart;
  4125. length *= bpc;
  4126. end = start + length;
  4127. if (DiffAreaFile) {
  4128. diffAreaFileAllocation = (PDIFF_AREA_FILE_ALLOCATION)
  4129. ExAllocatePoolWithTag(NonPagedPool,
  4130. sizeof(DIFF_AREA_FILE_ALLOCATION),
  4131. VOLSNAP_TAG_BIT_HISTORY);
  4132. if (!diffAreaFileAllocation) {
  4133. status = STATUS_INSUFFICIENT_RESOURCES;
  4134. break;
  4135. }
  4136. diffAreaFileAllocation->Offset = start;
  4137. diffAreaFileAllocation->Length = length;
  4138. InsertTailList(&DiffAreaFile->UnusedAllocationList,
  4139. &diffAreaFileAllocation->ListEntry);
  4140. }
  4141. if (OnlyDiffAreaFile) {
  4142. if (status != STATUS_BUFFER_OVERFLOW) {
  4143. break;
  4144. }
  4145. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  4146. continue;
  4147. }
  4148. roundedStart = start&(~(BLOCK_SIZE - 1));
  4149. roundedEnd = end&(~(BLOCK_SIZE - 1));
  4150. if (start != roundedStart) {
  4151. roundedStart += BLOCK_SIZE;
  4152. }
  4153. if (roundedStart >= roundedEnd) {
  4154. if (status != STATUS_BUFFER_OVERFLOW) {
  4155. break;
  4156. }
  4157. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  4158. continue;
  4159. }
  4160. startBit = (ULONG) (roundedStart>>BLOCK_SHIFT);
  4161. numBits = (ULONG) ((roundedEnd - roundedStart)>>BLOCK_SHIFT);
  4162. if (BitmapToSet) {
  4163. ASSERT(!ClearBits);
  4164. RtlSetBits(BitmapToSet, startBit, numBits);
  4165. } else {
  4166. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  4167. if (ClearBits) {
  4168. RtlClearBits(Extension->VolumeBlockBitmap, startBit, numBits);
  4169. } else if (Extension->IgnorableProduct) {
  4170. for (i = 0; i < numBits; i++) {
  4171. if (RtlCheckBit(Extension->IgnorableProduct, i + startBit)) {
  4172. RtlSetBit(Extension->VolumeBlockBitmap, i + startBit);
  4173. }
  4174. }
  4175. } else {
  4176. RtlSetBits(Extension->VolumeBlockBitmap, startBit, numBits);
  4177. }
  4178. KeReleaseSpinLock(&Extension->SpinLock, irql);
  4179. }
  4180. if (status != STATUS_BUFFER_OVERFLOW) {
  4181. break;
  4182. }
  4183. input.StartingVcn.QuadPart = output.Extents[0].NextVcn.QuadPart;
  4184. }
  4185. return status;
  4186. }
  4187. NTSTATUS
  4188. VspSetDiffAreaBlocksInBitmap(
  4189. IN PVOLUME_EXTENSION Extension
  4190. )
  4191. {
  4192. NTSTATUS status, status2;
  4193. PLIST_ENTRY l, ll;
  4194. PVSP_DIFF_AREA_FILE diffAreaFile;
  4195. for (l = Extension->ListOfDiffAreaFiles.Flink;
  4196. l != &Extension->ListOfDiffAreaFiles; l = l->Flink) {
  4197. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4198. VolumeListEntry);
  4199. ASSERT(!diffAreaFile->FilterListEntryBeingUsed);
  4200. InsertTailList(&diffAreaFile->Filter->DiffAreaFilesOnThisFilter,
  4201. &diffAreaFile->FilterListEntry);
  4202. diffAreaFile->FilterListEntryBeingUsed = TRUE;
  4203. if (diffAreaFile->Filter == Extension->Filter) {
  4204. status = VspMarkFileAllocationInBitmap(Extension,
  4205. diffAreaFile->FileHandle,
  4206. diffAreaFile, FALSE, FALSE,
  4207. NULL);
  4208. if (!NT_SUCCESS(status)) {
  4209. VspLogError(Extension, diffAreaFile->Filter,
  4210. VS_CANT_MAP_DIFF_AREA_FILE, status, 2);
  4211. }
  4212. } else {
  4213. if (diffAreaFile->Filter->PreparedSnapshot) {
  4214. status = VspMarkFileAllocationInBitmap(
  4215. diffAreaFile->Filter->PreparedSnapshot,
  4216. diffAreaFile->FileHandle, diffAreaFile, FALSE, FALSE,
  4217. NULL);
  4218. if (!NT_SUCCESS(status)) {
  4219. VspLogError(Extension, diffAreaFile->Filter,
  4220. VS_CANT_MAP_DIFF_AREA_FILE, status, 3);
  4221. }
  4222. } else {
  4223. status = VspMarkFileAllocationInBitmap(
  4224. Extension, diffAreaFile->FileHandle, diffAreaFile,
  4225. TRUE, FALSE, NULL);
  4226. if (!NT_SUCCESS(status)) {
  4227. VspLogError(Extension, diffAreaFile->Filter,
  4228. VS_CANT_MAP_DIFF_AREA_FILE, status, 4);
  4229. }
  4230. }
  4231. }
  4232. if (!NT_SUCCESS(status)) {
  4233. for (ll = Extension->ListOfDiffAreaFiles.Flink; l != ll;
  4234. ll = ll->Flink) {
  4235. diffAreaFile = CONTAINING_RECORD(ll, VSP_DIFF_AREA_FILE,
  4236. VolumeListEntry);
  4237. if (diffAreaFile->FilterListEntryBeingUsed) {
  4238. RemoveEntryList(&diffAreaFile->FilterListEntry);
  4239. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  4240. }
  4241. if (diffAreaFile->Filter != Extension->Filter &&
  4242. diffAreaFile->Filter->PreparedSnapshot) {
  4243. status2 = VspMarkFileAllocationInBitmap(
  4244. diffAreaFile->Filter->PreparedSnapshot,
  4245. diffAreaFile->FileHandle, NULL, FALSE, TRUE,
  4246. NULL);
  4247. if (!NT_SUCCESS(status2)) {
  4248. VspLogError(Extension, diffAreaFile->Filter,
  4249. VS_CANT_MAP_DIFF_AREA_FILE, status, 5);
  4250. VspAbortPreparedSnapshot(diffAreaFile->Filter, FALSE);
  4251. }
  4252. }
  4253. }
  4254. return status;
  4255. }
  4256. }
  4257. for (l = Extension->Filter->DiffAreaFilesOnThisFilter.Flink;
  4258. l != &Extension->Filter->DiffAreaFilesOnThisFilter; l = l->Flink) {
  4259. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4260. FilterListEntry);
  4261. if (diffAreaFile->Extension == Extension) {
  4262. continue;
  4263. }
  4264. status = VspMarkFileAllocationInBitmap(
  4265. Extension, diffAreaFile->FileHandle, NULL, FALSE, FALSE,
  4266. NULL);
  4267. if (!NT_SUCCESS(status)) {
  4268. VspLogError(Extension, diffAreaFile->Filter,
  4269. VS_CANT_MAP_DIFF_AREA_FILE, status, 6);
  4270. VspCleanupBitsSetInOtherPreparedSnapshots(Extension);
  4271. return status;
  4272. }
  4273. }
  4274. return STATUS_SUCCESS;
  4275. }
  4276. NTSTATUS
  4277. VspCreateInitialHeap(
  4278. IN PVOLUME_EXTENSION Extension
  4279. )
  4280. {
  4281. PVSP_CONTEXT context;
  4282. NTSTATUS status;
  4283. context = VspAllocateContext(Extension->Root);
  4284. if (!context) {
  4285. return STATUS_INSUFFICIENT_RESOURCES;
  4286. }
  4287. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  4288. context->Extension.Extension = Extension;
  4289. context->Extension.Irp = NULL;
  4290. ObReferenceObject(Extension->DeviceObject);
  4291. VspCreateHeap(context);
  4292. if (!Extension->NextDiffAreaFileMap) {
  4293. return STATUS_INSUFFICIENT_RESOURCES;
  4294. }
  4295. ASSERT(!Extension->DiffAreaFileMap);
  4296. Extension->DiffAreaFileMap = Extension->NextDiffAreaFileMap;
  4297. Extension->DiffAreaFileMapSize = Extension->NextDiffAreaFileMapSize;
  4298. Extension->NextAvailable = 0;
  4299. Extension->NextDiffAreaFileMap = NULL;
  4300. context = VspAllocateContext(Extension->Root);
  4301. if (!context) {
  4302. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  4303. Extension->DiffAreaFileMap);
  4304. ASSERT(NT_SUCCESS(status));
  4305. Extension->DiffAreaFileMap = NULL;
  4306. return STATUS_INSUFFICIENT_RESOURCES;
  4307. }
  4308. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  4309. context->Extension.Extension = Extension;
  4310. context->Extension.Irp = NULL;
  4311. ObReferenceObject(Extension->DeviceObject);
  4312. VspCreateHeap(context);
  4313. if (!Extension->NextDiffAreaFileMap) {
  4314. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  4315. Extension->DiffAreaFileMap);
  4316. ASSERT(NT_SUCCESS(status));
  4317. Extension->DiffAreaFileMap = NULL;
  4318. return STATUS_INSUFFICIENT_RESOURCES;
  4319. }
  4320. return STATUS_SUCCESS;
  4321. }
  4322. NTSTATUS
  4323. VspComputeIgnorableBitmap(
  4324. IN PVOLUME_EXTENSION Extension,
  4325. IN OUT PRTL_BITMAP Bitmap
  4326. )
  4327. {
  4328. PFILTER_EXTENSION filter = Extension->Filter;
  4329. WCHAR nameBuffer[150];
  4330. UNICODE_STRING name, guidString;
  4331. OBJECT_ATTRIBUTES oa;
  4332. NTSTATUS status;
  4333. HANDLE h, fileHandle;
  4334. IO_STATUS_BLOCK ioStatus;
  4335. CHAR buffer[200];
  4336. PFILE_NAMES_INFORMATION fileNamesInfo;
  4337. BOOLEAN restartScan;
  4338. PLIST_ENTRY l;
  4339. PVOLUME_EXTENSION e;
  4340. PTRANSLATION_TABLE_ENTRY p;
  4341. swprintf(nameBuffer, L"\\Device\\HarddiskVolumeShadowCopy%d\\pagefile.sys",
  4342. Extension->VolumeNumber);
  4343. RtlInitUnicodeString(&name, nameBuffer);
  4344. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
  4345. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  4346. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4347. FILE_SYNCHRONOUS_IO_NONALERT);
  4348. if (NT_SUCCESS(status)) {
  4349. VspMarkFileAllocationInBitmap(NULL, h, NULL, FALSE, FALSE, Bitmap);
  4350. ZwClose(h);
  4351. }
  4352. swprintf(nameBuffer, L"\\Device\\HarddiskVolumeShadowCopy%d\\System Volume Information\\",
  4353. Extension->VolumeNumber);
  4354. RtlInitUnicodeString(&name, nameBuffer);
  4355. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
  4356. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa, &ioStatus,
  4357. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4358. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  4359. if (!NT_SUCCESS(status)) {
  4360. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  4361. status = STATUS_SUCCESS;
  4362. }
  4363. return status;
  4364. }
  4365. status = RtlStringFromGUID(VSP_DIFF_AREA_FILE_GUID, &guidString);
  4366. if (!NT_SUCCESS(status)) {
  4367. ZwClose(h);
  4368. return status;
  4369. }
  4370. name.Buffer = nameBuffer;
  4371. name.Length = sizeof(WCHAR) + guidString.Length;
  4372. name.MaximumLength = name.Length + sizeof(WCHAR);
  4373. name.Buffer[0] = '*';
  4374. RtlCopyMemory(&name.Buffer[1], guidString.Buffer, guidString.Length);
  4375. name.Buffer[name.Length/sizeof(WCHAR)] = 0;
  4376. ExFreePool(guidString.Buffer);
  4377. fileNamesInfo = (PFILE_NAMES_INFORMATION) buffer;
  4378. restartScan = TRUE;
  4379. for (;;) {
  4380. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  4381. fileNamesInfo, 200, FileNamesInformation,
  4382. TRUE, restartScan ? &name : NULL,
  4383. restartScan);
  4384. if (!NT_SUCCESS(status)) {
  4385. break;
  4386. }
  4387. name.Length = name.MaximumLength =
  4388. (USHORT) fileNamesInfo->FileNameLength;
  4389. name.Buffer = fileNamesInfo->FileName;
  4390. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, h, NULL);
  4391. status = ZwOpenFile(&fileHandle, FILE_GENERIC_READ, &oa, &ioStatus,
  4392. FILE_SHARE_DELETE | FILE_SHARE_READ |
  4393. FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
  4394. if (!NT_SUCCESS(status)) {
  4395. continue;
  4396. }
  4397. VspMarkFileAllocationInBitmap(NULL, fileHandle, NULL, FALSE, FALSE,
  4398. Bitmap);
  4399. ZwClose(fileHandle);
  4400. restartScan = FALSE;
  4401. }
  4402. ZwClose(h);
  4403. status = VspMarkFreeSpaceInBitmap(Extension, NULL, Bitmap);
  4404. if (!NT_SUCCESS(status)) {
  4405. return status;
  4406. }
  4407. VspAcquire(Extension->Root);
  4408. if (Extension->IsDead) {
  4409. VspRelease(Extension->Root);
  4410. return STATUS_UNSUCCESSFUL;
  4411. }
  4412. for (l = &Extension->ListEntry; l != &filter->VolumeList; l = l->Flink) {
  4413. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  4414. VspAcquirePagedResource(e, NULL);
  4415. p = (PTRANSLATION_TABLE_ENTRY)
  4416. RtlEnumerateGenericTable(&e->VolumeBlockTable, TRUE);
  4417. while (p) {
  4418. RtlSetBit(Bitmap, (ULONG) (p->VolumeOffset>>BLOCK_SHIFT));
  4419. p = (PTRANSLATION_TABLE_ENTRY)
  4420. RtlEnumerateGenericTable(&e->VolumeBlockTable, FALSE);
  4421. }
  4422. VspReleasePagedResource(e);
  4423. }
  4424. VspRelease(Extension->Root);
  4425. return STATUS_SUCCESS;
  4426. }
  4427. VOID
  4428. VspAndBitmaps(
  4429. IN OUT PRTL_BITMAP BaseBitmap,
  4430. IN PRTL_BITMAP FactorBitmap
  4431. )
  4432. {
  4433. ULONG n, i;
  4434. PULONG p, q;
  4435. n = (BaseBitmap->SizeOfBitMap + 8*sizeof(ULONG) - 1)/(8*sizeof(ULONG));
  4436. p = BaseBitmap->Buffer;
  4437. q = FactorBitmap->Buffer;
  4438. for (i = 0; i < n; i++) {
  4439. *p++ &= *q++;
  4440. }
  4441. }
  4442. NTSTATUS
  4443. VspComputeIgnorableProduct(
  4444. IN PVOLUME_EXTENSION Extension
  4445. )
  4446. {
  4447. PFILTER_EXTENSION filter = Extension->Filter;
  4448. ULONG bitmapSize;
  4449. PVOID bitmapBuffer;
  4450. RTL_BITMAP bitmap;
  4451. ULONG i, j;
  4452. PLIST_ENTRY l;
  4453. PVOLUME_EXTENSION e;
  4454. NTSTATUS status;
  4455. KIRQL irql;
  4456. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  4457. if (!Extension->IgnorableProduct) {
  4458. KeReleaseSpinLock(&Extension->SpinLock, irql);
  4459. return STATUS_INVALID_PARAMETER;
  4460. }
  4461. bitmapSize = Extension->IgnorableProduct->SizeOfBitMap;
  4462. RtlSetAllBits(Extension->IgnorableProduct);
  4463. KeReleaseSpinLock(&Extension->SpinLock, irql);
  4464. bitmapBuffer = ExAllocatePoolWithTag(
  4465. NonPagedPool, (bitmapSize + 8*sizeof(ULONG) - 1)/
  4466. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  4467. if (!bitmapBuffer) {
  4468. return STATUS_INSUFFICIENT_RESOURCES;
  4469. }
  4470. RtlInitializeBitMap(&bitmap, (PULONG) bitmapBuffer, bitmapSize);
  4471. for (i = 1; ; i++) {
  4472. RtlClearAllBits(&bitmap);
  4473. VspAcquire(Extension->Root);
  4474. l = filter->VolumeList.Blink;
  4475. if (l != &Extension->ListEntry) {
  4476. VspRelease(Extension->Root);
  4477. ExFreePool(bitmapBuffer);
  4478. return STATUS_INVALID_PARAMETER;
  4479. }
  4480. j = 0;
  4481. for (;;) {
  4482. if (l == &filter->VolumeList) {
  4483. break;
  4484. }
  4485. j++;
  4486. if (j == i) {
  4487. break;
  4488. }
  4489. l = l->Blink;
  4490. }
  4491. if (j < i) {
  4492. VspRelease(Extension->Root);
  4493. break;
  4494. }
  4495. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  4496. ObReferenceObject(e->DeviceObject);
  4497. VspRelease(Extension->Root);
  4498. status = VspComputeIgnorableBitmap(e, &bitmap);
  4499. if (!NT_SUCCESS(status)) {
  4500. VspAcquire(Extension->Root);
  4501. if (e->IsDead) {
  4502. VspRelease(Extension->Root);
  4503. ObDereferenceObject(e->DeviceObject);
  4504. ExFreePool(bitmapBuffer);
  4505. return STATUS_SUCCESS;
  4506. }
  4507. VspRelease(Extension->Root);
  4508. ObDereferenceObject(e->DeviceObject);
  4509. ExFreePool(bitmapBuffer);
  4510. return status;
  4511. }
  4512. ObDereferenceObject(e->DeviceObject);
  4513. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  4514. if (Extension->IgnorableProduct) {
  4515. VspAndBitmaps(Extension->IgnorableProduct, &bitmap);
  4516. }
  4517. KeReleaseSpinLock(&Extension->SpinLock, irql);
  4518. }
  4519. ExFreePool(bitmapBuffer);
  4520. return STATUS_SUCCESS;
  4521. }
  4522. VOID
  4523. VspQueryMinimumDiffAreaFileSize(
  4524. IN PDO_EXTENSION RootExtension,
  4525. OUT PLONGLONG MinDiffAreaFileSize
  4526. )
  4527. {
  4528. ULONG zero, size;
  4529. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  4530. NTSTATUS status;
  4531. zero = 0;
  4532. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  4533. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  4534. queryTable[0].Name = L"MinDiffAreaFileSize";
  4535. queryTable[0].EntryContext = &size;
  4536. queryTable[0].DefaultType = REG_DWORD;
  4537. queryTable[0].DefaultData = &zero;
  4538. queryTable[0].DefaultLength = sizeof(ULONG);
  4539. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  4540. RootExtension->RegistryPath.Buffer,
  4541. queryTable, NULL, NULL);
  4542. if (!NT_SUCCESS(status)) {
  4543. size = zero;
  4544. }
  4545. *MinDiffAreaFileSize = ((LONGLONG) size)*1024*1024;
  4546. }
  4547. VOID
  4548. VspPrepareForSnapshotWorker(
  4549. IN PDEVICE_OBJECT DeviceObject,
  4550. IN PVOID Context
  4551. )
  4552. {
  4553. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4554. PFILTER_EXTENSION Filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  4555. PIRP Irp = context->Dispatch.Irp;
  4556. PDO_EXTENSION rootExtension = Filter->Root;
  4557. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4558. PVOLSNAP_PREPARE_INFO input = (PVOLSNAP_PREPARE_INFO) Irp->AssociatedIrp.SystemBuffer;
  4559. LONGLONG minDiffAreaFileSize;
  4560. KIRQL irql;
  4561. ULONG volumeNumber;
  4562. WCHAR buffer[100];
  4563. UNICODE_STRING volumeName;
  4564. NTSTATUS status;
  4565. PDEVICE_OBJECT deviceObject;
  4566. PVOLUME_EXTENSION extension, e;
  4567. ULONG bitmapSize, n;
  4568. PVOID bitmapBuffer, p;
  4569. PVOID buf;
  4570. PMDL mdl;
  4571. ASSERT(context->Type == VSP_CONTEXT_TYPE_DISPATCH);
  4572. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  4573. sizeof(VOLSNAP_PREPARE_INFO)) {
  4574. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  4575. goto Finish;
  4576. }
  4577. if (input->Attributes&(~VOLSNAP_ALL_ATTRIBUTES)) {
  4578. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  4579. goto Finish;
  4580. }
  4581. if (input->Attributes&VOLSNAP_ATTRIBUTE_PERSISTENT) {
  4582. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  4583. goto Finish;
  4584. }
  4585. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  4586. KernelMode, FALSE, NULL);
  4587. VspQueryMinimumDiffAreaFileSize(Filter->Root, &minDiffAreaFileSize);
  4588. if (input->InitialDiffAreaAllocation < 2*NOMINAL_DIFF_AREA_FILE_GROWTH) {
  4589. input->InitialDiffAreaAllocation = 2*NOMINAL_DIFF_AREA_FILE_GROWTH;
  4590. }
  4591. if (input->InitialDiffAreaAllocation < minDiffAreaFileSize) {
  4592. input->InitialDiffAreaAllocation = minDiffAreaFileSize;
  4593. }
  4594. for (volumeNumber = 1;; volumeNumber++) {
  4595. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d", volumeNumber);
  4596. RtlInitUnicodeString(&volumeName, buffer);
  4597. status = IoCreateDevice(rootExtension->DriverObject,
  4598. sizeof(VOLUME_EXTENSION), &volumeName,
  4599. FILE_DEVICE_DISK, 0, FALSE, &deviceObject);
  4600. if (status != STATUS_OBJECT_NAME_COLLISION) {
  4601. break;
  4602. }
  4603. }
  4604. if (!NT_SUCCESS(status)) {
  4605. Irp->IoStatus.Status = status;
  4606. goto Finish;
  4607. }
  4608. extension = (PVOLUME_EXTENSION) deviceObject->DeviceExtension;
  4609. RtlZeroMemory(extension, sizeof(VOLUME_EXTENSION));
  4610. extension->DeviceObject = deviceObject;
  4611. extension->Root = Filter->Root;
  4612. extension->DeviceExtensionType = DEVICE_EXTENSION_VOLUME;
  4613. KeInitializeSpinLock(&extension->SpinLock);
  4614. extension->Filter = Filter;
  4615. extension->RefCount = 1;
  4616. InitializeListHead(&extension->HoldIrpQueue);
  4617. InitializeListHead(&extension->HoldWorkerQueue);
  4618. KeInitializeEvent(&extension->ZeroRefEvent, NotificationEvent, FALSE);
  4619. extension->VolumeNumber = volumeNumber;
  4620. RtlInitializeGenericTable(&extension->VolumeBlockTable,
  4621. VspTableCompareRoutine,
  4622. VspTableAllocateRoutine,
  4623. VspTableFreeRoutine, extension);
  4624. RtlInitializeGenericTable(&extension->TempVolumeBlockTable,
  4625. VspTableCompareRoutine,
  4626. VspTempTableAllocateRoutine,
  4627. VspTempTableFreeRoutine, extension);
  4628. extension->DiffAreaFileIncrease = NOMINAL_DIFF_AREA_FILE_GROWTH;
  4629. status = VspCreateInitialDiffAreaFiles(extension,
  4630. input->InitialDiffAreaAllocation);
  4631. if (!NT_SUCCESS(status)) {
  4632. IoDeleteDevice(deviceObject);
  4633. Irp->IoStatus.Status = status;
  4634. goto Finish;
  4635. }
  4636. status = VspCreateWorkerThread(rootExtension);
  4637. if (!NT_SUCCESS(status)) {
  4638. VspLogError(extension, NULL, VS_CREATE_WORKER_THREADS_FAILED, status,
  4639. 0);
  4640. VspDeleteInitialDiffAreaFiles(extension);
  4641. IoDeleteDevice(deviceObject);
  4642. Irp->IoStatus.Status = status;
  4643. goto Finish;
  4644. }
  4645. extension->VolumeBlockBitmap = (PRTL_BITMAP)
  4646. ExAllocatePoolWithTag(
  4647. NonPagedPool, sizeof(RTL_BITMAP),
  4648. VOLSNAP_TAG_BITMAP);
  4649. if (!extension->VolumeBlockBitmap) {
  4650. VspDeleteWorkerThread(rootExtension);
  4651. VspDeleteInitialDiffAreaFiles(extension);
  4652. IoDeleteDevice(deviceObject);
  4653. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4654. goto Finish;
  4655. }
  4656. extension->VolumeSize = VspQueryVolumeSize(Filter);
  4657. if (!extension->VolumeSize) {
  4658. ExFreePool(extension->VolumeBlockBitmap);
  4659. extension->VolumeBlockBitmap = NULL;
  4660. VspDeleteWorkerThread(rootExtension);
  4661. VspDeleteInitialDiffAreaFiles(extension);
  4662. IoDeleteDevice(deviceObject);
  4663. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4664. goto Finish;
  4665. }
  4666. bitmapSize = (ULONG) ((extension->VolumeSize + BLOCK_SIZE - 1)>>
  4667. BLOCK_SHIFT);
  4668. bitmapBuffer = ExAllocatePoolWithTag(NonPagedPool,
  4669. (bitmapSize + 8*sizeof(ULONG) - 1)/
  4670. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  4671. if (!bitmapBuffer) {
  4672. VspLogError(extension, NULL, VS_CANT_ALLOCATE_BITMAP,
  4673. STATUS_INSUFFICIENT_RESOURCES, 0);
  4674. ExFreePool(extension->VolumeBlockBitmap);
  4675. extension->VolumeBlockBitmap = NULL;
  4676. VspDeleteWorkerThread(rootExtension);
  4677. VspDeleteInitialDiffAreaFiles(extension);
  4678. IoDeleteDevice(deviceObject);
  4679. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4680. goto Finish;
  4681. }
  4682. RtlInitializeBitMap(extension->VolumeBlockBitmap, (PULONG) bitmapBuffer,
  4683. bitmapSize);
  4684. RtlClearAllBits(extension->VolumeBlockBitmap);
  4685. status = VspCreateInitialHeap(extension);
  4686. if (!NT_SUCCESS(status)) {
  4687. ExFreePool(bitmapBuffer);
  4688. ExFreePool(extension->VolumeBlockBitmap);
  4689. extension->VolumeBlockBitmap = NULL;
  4690. VspDeleteWorkerThread(rootExtension);
  4691. VspDeleteInitialDiffAreaFiles(extension);
  4692. IoDeleteDevice(deviceObject);
  4693. Irp->IoStatus.Status = status;
  4694. goto Finish;
  4695. }
  4696. InitializeListHead(&extension->OldHeaps);
  4697. extension->EmergencyCopyIrp =
  4698. IoAllocateIrp((CCHAR) extension->Root->StackSize, FALSE);
  4699. if (!extension->EmergencyCopyIrp) {
  4700. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4701. extension->DiffAreaFileMap);
  4702. ASSERT(NT_SUCCESS(status));
  4703. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4704. extension->NextDiffAreaFileMap);
  4705. ASSERT(NT_SUCCESS(status));
  4706. ExFreePool(bitmapBuffer);
  4707. ExFreePool(extension->VolumeBlockBitmap);
  4708. extension->VolumeBlockBitmap = NULL;
  4709. VspDeleteWorkerThread(rootExtension);
  4710. VspDeleteInitialDiffAreaFiles(extension);
  4711. IoDeleteDevice(deviceObject);
  4712. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4713. goto Finish;
  4714. }
  4715. buf = ExAllocatePoolWithTag(NonPagedPool, BLOCK_SIZE, VOLSNAP_TAG_BUFFER);
  4716. if (!buf) {
  4717. IoFreeIrp(extension->EmergencyCopyIrp);
  4718. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4719. extension->DiffAreaFileMap);
  4720. ASSERT(NT_SUCCESS(status));
  4721. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4722. extension->NextDiffAreaFileMap);
  4723. ASSERT(NT_SUCCESS(status));
  4724. ExFreePool(bitmapBuffer);
  4725. ExFreePool(extension->VolumeBlockBitmap);
  4726. extension->VolumeBlockBitmap = NULL;
  4727. VspDeleteWorkerThread(rootExtension);
  4728. VspDeleteInitialDiffAreaFiles(extension);
  4729. IoDeleteDevice(deviceObject);
  4730. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4731. goto Finish;
  4732. }
  4733. mdl = IoAllocateMdl(buf, BLOCK_SIZE, FALSE, FALSE, NULL);
  4734. if (!mdl) {
  4735. ExFreePool(buf);
  4736. IoFreeIrp(extension->EmergencyCopyIrp);
  4737. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4738. extension->DiffAreaFileMap);
  4739. ASSERT(NT_SUCCESS(status));
  4740. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4741. extension->NextDiffAreaFileMap);
  4742. ASSERT(NT_SUCCESS(status));
  4743. ExFreePool(bitmapBuffer);
  4744. ExFreePool(extension->VolumeBlockBitmap);
  4745. extension->VolumeBlockBitmap = NULL;
  4746. VspDeleteWorkerThread(rootExtension);
  4747. VspDeleteInitialDiffAreaFiles(extension);
  4748. IoDeleteDevice(deviceObject);
  4749. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4750. goto Finish;
  4751. }
  4752. MmBuildMdlForNonPagedPool(mdl);
  4753. extension->EmergencyCopyIrp->MdlAddress = mdl;
  4754. InitializeListHead(&extension->EmergencyCopyIrpQueue);
  4755. InitializeListHead(&extension->WaitingForPageFileSpace);
  4756. VspAcquire(rootExtension);
  4757. if (!IsListEmpty(&Filter->VolumeList)) {
  4758. extension->IgnorableProduct = (PRTL_BITMAP)
  4759. ExAllocatePoolWithTag(NonPagedPool, sizeof(RTL_BITMAP),
  4760. VOLSNAP_TAG_BITMAP);
  4761. if (!extension->IgnorableProduct) {
  4762. VspRelease(rootExtension);
  4763. ExFreePool(buf);
  4764. IoFreeIrp(extension->EmergencyCopyIrp);
  4765. IoFreeMdl(mdl);
  4766. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4767. extension->DiffAreaFileMap);
  4768. ASSERT(NT_SUCCESS(status));
  4769. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4770. extension->NextDiffAreaFileMap);
  4771. ASSERT(NT_SUCCESS(status));
  4772. ExFreePool(bitmapBuffer);
  4773. ExFreePool(extension->VolumeBlockBitmap);
  4774. extension->VolumeBlockBitmap = NULL;
  4775. VspDeleteWorkerThread(rootExtension);
  4776. VspDeleteInitialDiffAreaFiles(extension);
  4777. IoDeleteDevice(deviceObject);
  4778. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4779. goto Finish;
  4780. }
  4781. p = ExAllocatePoolWithTag(NonPagedPool,
  4782. (bitmapSize + 8*sizeof(ULONG) - 1)/
  4783. (8*sizeof(ULONG))*sizeof(ULONG), VOLSNAP_TAG_BITMAP);
  4784. if (!p) {
  4785. ExFreePool(extension->IgnorableProduct);
  4786. extension->IgnorableProduct = NULL;
  4787. VspRelease(rootExtension);
  4788. ExFreePool(buf);
  4789. IoFreeMdl(mdl);
  4790. IoFreeIrp(extension->EmergencyCopyIrp);
  4791. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4792. extension->DiffAreaFileMap);
  4793. ASSERT(NT_SUCCESS(status));
  4794. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4795. extension->NextDiffAreaFileMap);
  4796. ASSERT(NT_SUCCESS(status));
  4797. ExFreePool(bitmapBuffer);
  4798. ExFreePool(extension->VolumeBlockBitmap);
  4799. extension->VolumeBlockBitmap = NULL;
  4800. VspDeleteWorkerThread(rootExtension);
  4801. VspDeleteInitialDiffAreaFiles(extension);
  4802. IoDeleteDevice(deviceObject);
  4803. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4804. goto Finish;
  4805. }
  4806. RtlInitializeBitMap(extension->IgnorableProduct, (PULONG) p,
  4807. bitmapSize);
  4808. RtlSetAllBits(extension->IgnorableProduct);
  4809. e = CONTAINING_RECORD(Filter->VolumeList.Blink, VOLUME_EXTENSION,
  4810. ListEntry);
  4811. KeAcquireSpinLock(&e->SpinLock, &irql);
  4812. if (e->VolumeBlockBitmap) {
  4813. n = extension->IgnorableProduct->SizeOfBitMap;
  4814. extension->IgnorableProduct->SizeOfBitMap =
  4815. e->VolumeBlockBitmap->SizeOfBitMap;
  4816. VspAndBitmaps(extension->IgnorableProduct, e->VolumeBlockBitmap);
  4817. extension->IgnorableProduct->SizeOfBitMap = n;
  4818. }
  4819. KeReleaseSpinLock(&e->SpinLock, irql);
  4820. }
  4821. status = VspSetDiffAreaBlocksInBitmap(extension);
  4822. if (!NT_SUCCESS(status)) {
  4823. if (extension->IgnorableProduct) {
  4824. ExFreePool(extension->IgnorableProduct->Buffer);
  4825. ExFreePool(extension->IgnorableProduct);
  4826. extension->IgnorableProduct = NULL;
  4827. }
  4828. VspRelease(rootExtension);
  4829. ExFreePool(buf);
  4830. IoFreeMdl(mdl);
  4831. IoFreeIrp(extension->EmergencyCopyIrp);
  4832. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4833. extension->DiffAreaFileMap);
  4834. ASSERT(NT_SUCCESS(status));
  4835. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4836. extension->NextDiffAreaFileMap);
  4837. ASSERT(NT_SUCCESS(status));
  4838. ExFreePool(bitmapBuffer);
  4839. ExFreePool(extension->VolumeBlockBitmap);
  4840. extension->VolumeBlockBitmap = NULL;
  4841. VspDeleteWorkerThread(rootExtension);
  4842. VspDeleteInitialDiffAreaFiles(extension);
  4843. IoDeleteDevice(deviceObject);
  4844. Irp->IoStatus.Status = status;
  4845. goto Finish;
  4846. }
  4847. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  4848. e = Filter->PreparedSnapshot;
  4849. Filter->PreparedSnapshot = extension;
  4850. KeReleaseSpinLock(&Filter->SpinLock, irql);
  4851. VspRelease(rootExtension);
  4852. if (e) {
  4853. VspCleanupInitialSnapshot(e, TRUE);
  4854. }
  4855. deviceObject->Flags |= DO_DIRECT_IO;
  4856. deviceObject->StackSize = Filter->DeviceObject->StackSize;
  4857. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  4858. Finish:
  4859. IoFreeWorkItem(context->Dispatch.IoWorkItem);
  4860. VspFreeContext(rootExtension, context);
  4861. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4862. }
  4863. NTSTATUS
  4864. VspPrepareForSnapshot(
  4865. IN PFILTER_EXTENSION Filter,
  4866. IN PIRP Irp
  4867. )
  4868. /*++
  4869. Routine Description:
  4870. This routine prepares a snapshot device object to be used later
  4871. for a snapshot. This phase is distict from commit snapshot because
  4872. it can be called before IRPs are held.
  4873. Besides creating the device object, this routine will also pre
  4874. allocate some of the diff area.
  4875. Arguments:
  4876. Filter - Supplies the filter extension.
  4877. Irp - Supplies the I/O request packet.
  4878. Return Value:
  4879. NTSTATUS
  4880. --*/
  4881. {
  4882. PVSP_CONTEXT context;
  4883. Irp->IoStatus.Status = STATUS_SUCCESS;
  4884. Irp->IoStatus.Information = 0;
  4885. context = VspAllocateContext(Filter->Root);
  4886. if (!context) {
  4887. return STATUS_INSUFFICIENT_RESOURCES;
  4888. }
  4889. context->Type = VSP_CONTEXT_TYPE_DISPATCH;
  4890. context->Dispatch.IoWorkItem = IoAllocateWorkItem(Filter->DeviceObject);
  4891. if (!context->Dispatch.IoWorkItem) {
  4892. VspFreeContext(Filter->Root, context);
  4893. return STATUS_INSUFFICIENT_RESOURCES;
  4894. }
  4895. IoMarkIrpPending(Irp);
  4896. context->Dispatch.Irp = Irp;
  4897. IoQueueWorkItem(context->Dispatch.IoWorkItem, VspPrepareForSnapshotWorker,
  4898. DelayedWorkQueue, context);
  4899. return STATUS_PENDING;
  4900. }
  4901. VOID
  4902. VspCleanupBitsSetInOtherPreparedSnapshots(
  4903. IN PVOLUME_EXTENSION Extension
  4904. )
  4905. {
  4906. PLIST_ENTRY l;
  4907. PVSP_DIFF_AREA_FILE diffAreaFile;
  4908. NTSTATUS status;
  4909. for (l = Extension->ListOfDiffAreaFiles.Flink;
  4910. l != &Extension->ListOfDiffAreaFiles; l = l->Flink) {
  4911. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  4912. VolumeListEntry);
  4913. if (diffAreaFile->FilterListEntryBeingUsed) {
  4914. RemoveEntryList(&diffAreaFile->FilterListEntry);
  4915. diffAreaFile->FilterListEntryBeingUsed = FALSE;
  4916. }
  4917. if (diffAreaFile->Filter != Extension->Filter &&
  4918. diffAreaFile->Filter->PreparedSnapshot) {
  4919. status = VspMarkFileAllocationInBitmap(
  4920. diffAreaFile->Filter->PreparedSnapshot,
  4921. diffAreaFile->FileHandle, NULL, FALSE, TRUE, NULL);
  4922. if (!NT_SUCCESS(status)) {
  4923. VspLogError(Extension, diffAreaFile->Filter,
  4924. VS_CANT_MAP_DIFF_AREA_FILE, status, 7);
  4925. VspAbortPreparedSnapshot(diffAreaFile->Filter, FALSE);
  4926. }
  4927. }
  4928. }
  4929. }
  4930. VOID
  4931. VspCleanupInitialMaps(
  4932. IN PVOID Context
  4933. )
  4934. {
  4935. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  4936. PVOLUME_EXTENSION extension = context->Extension.Extension;
  4937. NTSTATUS status;
  4938. ASSERT(context->Type == VSP_CONTEXT_TYPE_EXTENSION);
  4939. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4940. extension->DiffAreaFileMap);
  4941. ASSERT(NT_SUCCESS(status));
  4942. status = ZwUnmapViewOfSection(extension->DiffAreaFileMapProcess,
  4943. extension->NextDiffAreaFileMap);
  4944. ASSERT(NT_SUCCESS(status));
  4945. VspFreeContext(extension->Root, context);
  4946. VspReleasePagedResource(extension);
  4947. ObDereferenceObject(extension->DeviceObject);
  4948. }
  4949. VOID
  4950. VspCleanupInitialSnapshot(
  4951. IN PVOLUME_EXTENSION Extension,
  4952. IN BOOLEAN NeedLock
  4953. )
  4954. {
  4955. PVSP_CONTEXT context;
  4956. NTSTATUS status;
  4957. KIRQL irql;
  4958. context = VspAllocateContext(Extension->Root);
  4959. if (context) {
  4960. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  4961. context->Extension.Extension = Extension;
  4962. context->Extension.Irp = NULL;
  4963. ExInitializeWorkItem(&context->WorkItem, VspCleanupInitialMaps,
  4964. context);
  4965. ObReferenceObject(Extension->DeviceObject);
  4966. VspAcquirePagedResource(Extension, &context->WorkItem);
  4967. } else {
  4968. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  4969. Extension->DiffAreaFileMap);
  4970. ASSERT(NT_SUCCESS(status));
  4971. status = ZwUnmapViewOfSection(Extension->DiffAreaFileMapProcess,
  4972. Extension->NextDiffAreaFileMap);
  4973. ASSERT(NT_SUCCESS(status));
  4974. }
  4975. if (NeedLock) {
  4976. VspAcquire(Extension->Root);
  4977. }
  4978. VspDeleteWorkerThread(Extension->Root);
  4979. VspCleanupBitsSetInOtherPreparedSnapshots(Extension);
  4980. VspDeleteInitialDiffAreaFiles(Extension);
  4981. if (NeedLock) {
  4982. VspRelease(Extension->Root);
  4983. }
  4984. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  4985. ExFreePool(Extension->VolumeBlockBitmap->Buffer);
  4986. ExFreePool(Extension->VolumeBlockBitmap);
  4987. Extension->VolumeBlockBitmap = NULL;
  4988. if (Extension->IgnorableProduct) {
  4989. ExFreePool(Extension->IgnorableProduct->Buffer);
  4990. ExFreePool(Extension->IgnorableProduct);
  4991. Extension->IgnorableProduct = NULL;
  4992. }
  4993. KeReleaseSpinLock(&Extension->SpinLock, irql);
  4994. ExFreePool(MmGetMdlVirtualAddress(
  4995. Extension->EmergencyCopyIrp->MdlAddress));
  4996. IoFreeMdl(Extension->EmergencyCopyIrp->MdlAddress);
  4997. IoFreeIrp(Extension->EmergencyCopyIrp);
  4998. IoDeleteDevice(Extension->DeviceObject);
  4999. }
  5000. NTSTATUS
  5001. VspAbortPreparedSnapshot(
  5002. IN PFILTER_EXTENSION Filter,
  5003. IN BOOLEAN NeedLock
  5004. )
  5005. /*++
  5006. Routine Description:
  5007. This routine aborts the prepared snapshot.
  5008. Arguments:
  5009. Filter - Supplies the filter extension.
  5010. Return Value:
  5011. NTSTATUS
  5012. --*/
  5013. {
  5014. KIRQL irql;
  5015. PVOLUME_EXTENSION extension;
  5016. if (NeedLock) {
  5017. VspAcquire(Filter->Root);
  5018. }
  5019. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  5020. extension = Filter->PreparedSnapshot;
  5021. Filter->PreparedSnapshot = NULL;
  5022. KeReleaseSpinLock(&Filter->SpinLock, irql);
  5023. if (NeedLock) {
  5024. VspRelease(Filter->Root);
  5025. }
  5026. if (!extension) {
  5027. return STATUS_INVALID_PARAMETER;
  5028. }
  5029. VspCleanupInitialSnapshot(extension, NeedLock);
  5030. return STATUS_SUCCESS;
  5031. }
  5032. NTSTATUS
  5033. VspMarkFreeSpaceInBitmap(
  5034. IN PVOLUME_EXTENSION Extension,
  5035. IN HANDLE UseThisHandle,
  5036. IN PRTL_BITMAP BitmapToSet
  5037. )
  5038. /*++
  5039. Routine Description:
  5040. This routine opens the snapshot volume and marks off the free
  5041. space in the NTFS bitmap as 'ignorable'.
  5042. Arguments:
  5043. Extension - Supplies the volume extension.
  5044. Return Value:
  5045. NTSTATUS
  5046. --*/
  5047. {
  5048. WCHAR buffer[100];
  5049. KEVENT event;
  5050. IO_STATUS_BLOCK ioStatus;
  5051. UNICODE_STRING fileName;
  5052. OBJECT_ATTRIBUTES oa;
  5053. NTSTATUS status;
  5054. HANDLE h;
  5055. LARGE_INTEGER timeout;
  5056. BOOLEAN isNtfs;
  5057. FILE_FS_SIZE_INFORMATION fsSize;
  5058. ULONG bitmapSize;
  5059. STARTING_LCN_INPUT_BUFFER input;
  5060. PVOLUME_BITMAP_BUFFER output;
  5061. RTL_BITMAP freeSpaceBitmap;
  5062. ULONG bpc, f, numBits, startBit, s, n, i;
  5063. KIRQL irql;
  5064. ULONG r;
  5065. if (UseThisHandle) {
  5066. h = UseThisHandle;
  5067. } else {
  5068. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  5069. Extension->VolumeNumber);
  5070. RtlInitUnicodeString(&fileName, buffer);
  5071. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE, NULL,
  5072. NULL);
  5073. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5074. timeout.QuadPart = -10*1000; // 1 millisecond.
  5075. for (i = 0; i < 5000; i++) {
  5076. status = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  5077. FILE_SHARE_READ | FILE_SHARE_WRITE |
  5078. FILE_SHARE_DELETE,
  5079. FILE_SYNCHRONOUS_IO_NONALERT);
  5080. if (NT_SUCCESS(status)) {
  5081. break;
  5082. }
  5083. if (status != STATUS_NO_SUCH_DEVICE) {
  5084. return status;
  5085. }
  5086. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  5087. &timeout);
  5088. }
  5089. if (!NT_SUCCESS(status)) {
  5090. return status;
  5091. }
  5092. }
  5093. status = VspIsNtfs(h, &isNtfs);
  5094. if (!NT_SUCCESS(status) || !isNtfs) {
  5095. if (!UseThisHandle) {
  5096. ZwClose(h);
  5097. }
  5098. return status;
  5099. }
  5100. status = ZwQueryVolumeInformationFile(h, &ioStatus, &fsSize,
  5101. sizeof(fsSize),
  5102. FileFsSizeInformation);
  5103. if (!NT_SUCCESS(status)) {
  5104. if (!UseThisHandle) {
  5105. ZwClose(h);
  5106. }
  5107. return status;
  5108. }
  5109. bitmapSize = (ULONG) ((fsSize.TotalAllocationUnits.QuadPart+7)/8 +
  5110. FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + 3);
  5111. input.StartingLcn.QuadPart = 0;
  5112. output = (PVOLUME_BITMAP_BUFFER)
  5113. ExAllocatePoolWithTag(PagedPool, bitmapSize, VOLSNAP_TAG_BITMAP);
  5114. if (!output) {
  5115. if (!UseThisHandle) {
  5116. ZwClose(h);
  5117. }
  5118. return STATUS_INSUFFICIENT_RESOURCES;
  5119. }
  5120. status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus,
  5121. FSCTL_GET_VOLUME_BITMAP, &input,
  5122. sizeof(input), output, bitmapSize);
  5123. if (!UseThisHandle) {
  5124. ZwClose(h);
  5125. }
  5126. if (!NT_SUCCESS(status)) {
  5127. ExFreePool(output);
  5128. return status;
  5129. }
  5130. ASSERT(output->BitmapSize.HighPart == 0);
  5131. RtlInitializeBitMap(&freeSpaceBitmap, (PULONG) output->Buffer,
  5132. output->BitmapSize.LowPart);
  5133. bpc = fsSize.BytesPerSector*fsSize.SectorsPerAllocationUnit;
  5134. if (bpc < BLOCK_SIZE) {
  5135. f = BLOCK_SIZE/bpc;
  5136. } else {
  5137. f = bpc/BLOCK_SIZE;
  5138. }
  5139. startBit = 0;
  5140. for (;;) {
  5141. if (startBit < freeSpaceBitmap.SizeOfBitMap) {
  5142. numBits = RtlFindNextForwardRunClear(&freeSpaceBitmap, startBit,
  5143. &startBit);
  5144. } else {
  5145. numBits = 0;
  5146. }
  5147. if (!numBits) {
  5148. break;
  5149. }
  5150. if (bpc == BLOCK_SIZE) {
  5151. s = startBit;
  5152. n = numBits;
  5153. } else if (bpc < BLOCK_SIZE) {
  5154. s = (startBit + f - 1)/f;
  5155. r = startBit%f;
  5156. if (r) {
  5157. if (numBits > f - r) {
  5158. n = numBits - (f - r);
  5159. } else {
  5160. n = 0;
  5161. }
  5162. } else {
  5163. n = numBits;
  5164. }
  5165. n /= f;
  5166. } else {
  5167. s = startBit*f;
  5168. n = numBits*f;
  5169. }
  5170. if (n) {
  5171. if (BitmapToSet) {
  5172. RtlSetBits(BitmapToSet, s, n);
  5173. } else {
  5174. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  5175. if (Extension->VolumeBlockBitmap) {
  5176. if (Extension->IgnorableProduct) {
  5177. for (i = 0; i < n; i++) {
  5178. if (RtlCheckBit(Extension->IgnorableProduct, i + s)) {
  5179. RtlSetBit(Extension->VolumeBlockBitmap, i + s);
  5180. }
  5181. }
  5182. } else {
  5183. RtlSetBits(Extension->VolumeBlockBitmap, s, n);
  5184. }
  5185. }
  5186. KeReleaseSpinLock(&Extension->SpinLock, irql);
  5187. }
  5188. }
  5189. startBit += numBits;
  5190. }
  5191. ExFreePool(output);
  5192. return STATUS_SUCCESS;
  5193. }
  5194. NTSTATUS
  5195. VspSetIgnorableBlocksInBitmap(
  5196. IN PVOID Extension
  5197. )
  5198. /*++
  5199. Routine Description:
  5200. This routine opens all of the Diff Area files on the given volume
  5201. and marks them off as ignorable in the bitmap to avoid bad
  5202. recursions and to improve performance. The free space is also marked
  5203. off. If a diff area file for this snapshot was allocated on this
  5204. volume then its diff area was pre marked off on the bitmap. This
  5205. routine will check make sure that the location has not moved. This
  5206. routine will eventually mark the pagefile too but that is just pure
  5207. performance and not required.
  5208. Arguments:
  5209. Extension - Supplies the volume extension.
  5210. Return Value:
  5211. NTSTATUS
  5212. --*/
  5213. {
  5214. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  5215. WCHAR nameBuffer[100];
  5216. UNICODE_STRING name;
  5217. OBJECT_ATTRIBUTES oa;
  5218. NTSTATUS status, status2;
  5219. HANDLE h;
  5220. IO_STATUS_BLOCK ioStatus;
  5221. KIRQL irql;
  5222. status = VspMarkFreeSpaceInBitmap(extension, NULL, NULL);
  5223. swprintf(nameBuffer, L"\\Device\\HarddiskVolumeShadowCopy%d\\pagefile.sys",
  5224. extension->VolumeNumber);
  5225. RtlInitUnicodeString(&name, nameBuffer);
  5226. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
  5227. status2 = ZwOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  5228. FILE_SHARE_READ | FILE_SHARE_WRITE |
  5229. FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
  5230. if (NT_SUCCESS(status2)) {
  5231. VspMarkFileAllocationInBitmap(extension, h, NULL, FALSE, FALSE, NULL);
  5232. ZwClose(h);
  5233. }
  5234. return status;
  5235. }
  5236. NTSTATUS
  5237. VspCommitSnapshot(
  5238. IN PFILTER_EXTENSION Filter,
  5239. IN PIRP Irp
  5240. )
  5241. /*++
  5242. Routine Description:
  5243. This routine commits the prepared snapshot.
  5244. Arguments:
  5245. Filter - Supplies the filter extension.
  5246. Irp - Supplies the I/O request packet.
  5247. Return Value:
  5248. NTSTATUS
  5249. --*/
  5250. {
  5251. KIRQL irql;
  5252. PVOLUME_EXTENSION extension, previousExtension;
  5253. PLIST_ENTRY l;
  5254. PVSP_DIFF_AREA_FILE diffAreaFile;
  5255. VspAcquire(Filter->Root);
  5256. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  5257. extension = Filter->PreparedSnapshot;
  5258. Filter->PreparedSnapshot = NULL;
  5259. KeReleaseSpinLock(&Filter->SpinLock, irql);
  5260. if (!extension) {
  5261. VspRelease(Filter->Root);
  5262. return STATUS_INVALID_PARAMETER;
  5263. }
  5264. if (!Filter->HoldIncomingWrites) {
  5265. VspRelease(Filter->Root);
  5266. VspCleanupInitialSnapshot(extension, TRUE);
  5267. return STATUS_INVALID_PARAMETER;
  5268. }
  5269. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  5270. InterlockedExchange(&Filter->SnapshotsPresent, TRUE);
  5271. InsertTailList(&Filter->VolumeList, &extension->ListEntry);
  5272. KeReleaseSpinLock(&Filter->SpinLock, irql);
  5273. l = extension->ListEntry.Blink;
  5274. if (l != &Filter->VolumeList) {
  5275. previousExtension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5276. KeAcquireSpinLock(&previousExtension->SpinLock, &irql);
  5277. ExFreePool(previousExtension->VolumeBlockBitmap->Buffer);
  5278. ExFreePool(previousExtension->VolumeBlockBitmap);
  5279. previousExtension->VolumeBlockBitmap = NULL;
  5280. KeReleaseSpinLock(&previousExtension->SpinLock, irql);
  5281. }
  5282. KeQuerySystemTime(&extension->CommitTimeStamp);
  5283. VspRelease(Filter->Root);
  5284. return STATUS_SUCCESS;
  5285. }
  5286. NTSTATUS
  5287. VspEndCommitSnapshot(
  5288. IN PFILTER_EXTENSION Filter,
  5289. IN PIRP Irp
  5290. )
  5291. /*++
  5292. Routine Description:
  5293. This routine commits the prepared snapshot.
  5294. Arguments:
  5295. Filter - Supplies the filter extension.
  5296. Irp - Supplies the I/O request packet.
  5297. Return Value:
  5298. NTSTATUS
  5299. --*/
  5300. {
  5301. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5302. PLIST_ENTRY l;
  5303. PVOLUME_EXTENSION extension;
  5304. WCHAR buffer[100];
  5305. UNICODE_STRING volumeName;
  5306. PVOLSNAP_NAME output;
  5307. NTSTATUS status;
  5308. LARGE_INTEGER timeout;
  5309. VspAcquire(Filter->Root);
  5310. l = Filter->VolumeList.Blink;
  5311. if (l == &Filter->VolumeList) {
  5312. VspRelease(Filter->Root);
  5313. return STATUS_INVALID_PARAMETER;
  5314. }
  5315. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5316. if (extension->HasEndCommit) {
  5317. VspRelease(Filter->Root);
  5318. return STATUS_INVALID_PARAMETER;
  5319. }
  5320. if (irpSp->Parameters.DeviceIoControl.InputBufferLength) {
  5321. status = VspSetApplicationInfo(extension, Irp);
  5322. if (!NT_SUCCESS(status)) {
  5323. VspRelease(Filter->Root);
  5324. return status;
  5325. }
  5326. }
  5327. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  5328. extension->VolumeNumber);
  5329. RtlInitUnicodeString(&volumeName, buffer);
  5330. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAME, Name) +
  5331. volumeName.Length + sizeof(WCHAR);
  5332. if (Irp->IoStatus.Information >
  5333. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  5334. VspRelease(Filter->Root);
  5335. Irp->IoStatus.Information = 0;
  5336. return STATUS_INVALID_PARAMETER;
  5337. }
  5338. output = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  5339. output->NameLength = volumeName.Length;
  5340. RtlCopyMemory(output->Name, volumeName.Buffer,
  5341. output->NameLength + sizeof(WCHAR));
  5342. extension->HasEndCommit = TRUE;
  5343. VspTruncatePreviousDiffArea(extension);
  5344. if (!KeCancelTimer(&Filter->EndCommitTimer)) {
  5345. ObReferenceObject(Filter->DeviceObject);
  5346. }
  5347. KeResetEvent(&Filter->EndCommitProcessCompleted);
  5348. timeout.QuadPart = (LONGLONG) -10*1000*1000*120*10; // 20 minutes.
  5349. KeSetTimer(&Filter->EndCommitTimer, timeout, &Filter->EndCommitTimerDpc);
  5350. VspRelease(Filter->Root);
  5351. IoInvalidateDeviceRelations(Filter->Pdo, BusRelations);
  5352. return STATUS_SUCCESS;
  5353. }
  5354. NTSTATUS
  5355. VspVolumeRefCountCompletionRoutine(
  5356. IN PDEVICE_OBJECT DeviceObject,
  5357. IN PIRP Irp,
  5358. IN PVOID Extension
  5359. )
  5360. {
  5361. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  5362. VspDecrementVolumeRefCount(extension);
  5363. return STATUS_SUCCESS;
  5364. }
  5365. NTSTATUS
  5366. VspQueryNamesOfSnapshots(
  5367. IN PFILTER_EXTENSION Filter,
  5368. IN PIRP Irp
  5369. )
  5370. /*++
  5371. Routine Description:
  5372. This routine returns the names of all of the snapshots for this filter.
  5373. Arguments:
  5374. Filter - Supplies the filter extension.
  5375. Irp - Supplies the I/O request packet.
  5376. Return Value:
  5377. NTSTATUS
  5378. --*/
  5379. {
  5380. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5381. PVOLSNAP_NAMES output;
  5382. PLIST_ENTRY l;
  5383. PVOLUME_EXTENSION extension;
  5384. WCHAR buffer[100];
  5385. UNICODE_STRING name;
  5386. PWCHAR buf;
  5387. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAMES, Names);
  5388. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5389. Irp->IoStatus.Information) {
  5390. Irp->IoStatus.Information = 0;
  5391. return STATUS_INVALID_PARAMETER;
  5392. }
  5393. KeWaitForSingleObject(&Filter->EndCommitProcessCompleted, Executive,
  5394. KernelMode, FALSE, NULL);
  5395. output = (PVOLSNAP_NAMES) Irp->AssociatedIrp.SystemBuffer;
  5396. VspAcquire(Filter->Root);
  5397. output->MultiSzLength = sizeof(WCHAR);
  5398. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  5399. l = l->Flink) {
  5400. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5401. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  5402. extension->VolumeNumber);
  5403. RtlInitUnicodeString(&name, buffer);
  5404. output->MultiSzLength += name.Length + sizeof(WCHAR);
  5405. }
  5406. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5407. Irp->IoStatus.Information + output->MultiSzLength) {
  5408. VspRelease(Filter->Root);
  5409. return STATUS_BUFFER_OVERFLOW;
  5410. }
  5411. Irp->IoStatus.Information += output->MultiSzLength;
  5412. buf = output->Names;
  5413. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  5414. l = l->Flink) {
  5415. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5416. swprintf(buf, L"\\Device\\HarddiskVolumeShadowCopy%d",
  5417. extension->VolumeNumber);
  5418. RtlInitUnicodeString(&name, buf);
  5419. buf += name.Length/sizeof(WCHAR) + 1;
  5420. }
  5421. *buf = 0;
  5422. VspRelease(Filter->Root);
  5423. return STATUS_SUCCESS;
  5424. }
  5425. NTSTATUS
  5426. VspClearDiffArea(
  5427. IN PFILTER_EXTENSION Filter,
  5428. IN PIRP Irp
  5429. )
  5430. /*++
  5431. Routine Description:
  5432. This routine clears the list of diff areas used by this filter. This
  5433. call will fail if there are any snapshots in flight.
  5434. Arguments:
  5435. Filter - Supplies the filter extension.
  5436. Irp - Supplies the I/O request packet.
  5437. Return Value:
  5438. NTSTATUS
  5439. --*/
  5440. {
  5441. PLIST_ENTRY l;
  5442. PVSP_DIFF_AREA_VOLUME diffAreaVolume;
  5443. VspAcquire(Filter->Root);
  5444. if (Filter->SnapshotsPresent) {
  5445. VspRelease(Filter->Root);
  5446. return STATUS_INVALID_PARAMETER;
  5447. }
  5448. while (!IsListEmpty(&Filter->DiffAreaVolumes)) {
  5449. l = RemoveHeadList(&Filter->DiffAreaVolumes);
  5450. diffAreaVolume = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry);
  5451. ExFreePool(diffAreaVolume);
  5452. }
  5453. VspRelease(Filter->Root);
  5454. return STATUS_SUCCESS;
  5455. }
  5456. VOID
  5457. VspAddVolumeToDiffAreaWorker(
  5458. IN PDEVICE_OBJECT DeviceObject,
  5459. IN PVOID Context
  5460. )
  5461. /*++
  5462. Routine Description:
  5463. This routine adds the given volume to the diff area for this volume.
  5464. All snapshots get a new diff area file.
  5465. Arguments:
  5466. Filter - Supplies the filter extension.
  5467. Irp - Supplies the I/O request packet.
  5468. Return Value:
  5469. NTSTATUS
  5470. --*/
  5471. {
  5472. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  5473. PFILTER_EXTENSION Filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  5474. PIRP Irp = context->Dispatch.Irp;
  5475. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5476. PVOLSNAP_NAME input;
  5477. UNICODE_STRING volumeName;
  5478. PFILTER_EXTENSION filter;
  5479. PVSP_DIFF_AREA_VOLUME diffAreaVolume;
  5480. PLIST_ENTRY l, ll;
  5481. PVOLUME_EXTENSION extension;
  5482. LONGLONG newDiffAreaFileSize, diff;
  5483. PVSP_DIFF_AREA_FILE diffAreaFile;
  5484. NTSTATUS status;
  5485. KIRQL irql;
  5486. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5487. sizeof(VOLSNAP_NAME)) {
  5488. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  5489. STATUS_INVALID_PARAMETER, 3);
  5490. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5491. goto Finish;
  5492. }
  5493. input = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  5494. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5495. (ULONG) FIELD_OFFSET(VOLSNAP_NAME, Name) + input->NameLength) {
  5496. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  5497. STATUS_INVALID_PARAMETER, 4);
  5498. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5499. goto Finish;
  5500. }
  5501. volumeName.Length = volumeName.MaximumLength = input->NameLength;
  5502. volumeName.Buffer = input->Name;
  5503. VspAcquire(Filter->Root);
  5504. filter = VspFindFilter(Filter->Root, Filter, &volumeName, NULL);
  5505. if (!filter ||
  5506. (filter->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA)) {
  5507. VspRelease(Filter->Root);
  5508. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5509. goto Finish;
  5510. }
  5511. for (l = Filter->DiffAreaVolumes.Flink; l != &Filter->DiffAreaVolumes;
  5512. l = l->Flink) {
  5513. diffAreaVolume = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry);
  5514. if (filter == diffAreaVolume->Filter) {
  5515. break;
  5516. }
  5517. }
  5518. if (l != &Filter->DiffAreaVolumes) {
  5519. VspRelease(Filter->Root);
  5520. VspLogError(NULL, Filter, VS_FAILURE_ADDING_DIFF_AREA,
  5521. STATUS_DUPLICATE_OBJECTID, 5);
  5522. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  5523. goto Finish;
  5524. }
  5525. diffAreaVolume = (PVSP_DIFF_AREA_VOLUME)
  5526. ExAllocatePoolWithTag(PagedPool,
  5527. sizeof(VSP_DIFF_AREA_VOLUME), VOLSNAP_TAG_DIFF_VOLUME);
  5528. if (!diffAreaVolume) {
  5529. VspRelease(Filter->Root);
  5530. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5531. goto Finish;
  5532. }
  5533. diffAreaVolume->Filter = filter;
  5534. InsertTailList(&Filter->DiffAreaVolumes, &diffAreaVolume->ListEntry);
  5535. l = Filter->VolumeList.Blink;
  5536. if (l == &Filter->VolumeList) {
  5537. VspRelease(Filter->Root);
  5538. Irp->IoStatus.Status = STATUS_SUCCESS;
  5539. goto Finish;
  5540. }
  5541. VspRelease(Filter->Root);
  5542. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5543. newDiffAreaFileSize = 2*extension->DiffAreaFileIncrease;
  5544. VspAcquireNonPagedResource(extension, NULL);
  5545. for (ll = extension->ListOfDiffAreaFiles.Flink;
  5546. ll != &extension->ListOfDiffAreaFiles; ll = ll->Flink) {
  5547. diffAreaFile = CONTAINING_RECORD(ll, VSP_DIFF_AREA_FILE,
  5548. VolumeListEntry);
  5549. diff = diffAreaFile->AllocatedFileSize - diffAreaFile->NextAvailable;
  5550. if (diff > newDiffAreaFileSize) {
  5551. newDiffAreaFileSize = diff;
  5552. }
  5553. }
  5554. VspReleaseNonPagedResource(extension);
  5555. diffAreaFile = (PVSP_DIFF_AREA_FILE)
  5556. ExAllocatePoolWithTag(NonPagedPool,
  5557. sizeof(VSP_DIFF_AREA_FILE),
  5558. VOLSNAP_TAG_DIFF_FILE);
  5559. if (!diffAreaFile) {
  5560. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  5561. goto Finish;
  5562. }
  5563. diffAreaFile->Extension = extension;
  5564. diffAreaFile->Filter = filter;
  5565. diffAreaFile->NextAvailable = 0;
  5566. diffAreaFile->AllocatedFileSize = newDiffAreaFileSize;
  5567. status = VspOpenDiffAreaFile(diffAreaFile);
  5568. if (!NT_SUCCESS(status)) {
  5569. ExFreePool(diffAreaFile);
  5570. Irp->IoStatus.Status = status;
  5571. goto Finish;
  5572. }
  5573. InitializeListHead(&diffAreaFile->UnusedAllocationList);
  5574. status = VspMarkFileAllocationInBitmap(extension,
  5575. diffAreaFile->FileHandle,
  5576. diffAreaFile, TRUE, FALSE, NULL);
  5577. if (!NT_SUCCESS(status)) {
  5578. VspLogError(extension, diffAreaFile->Filter,
  5579. VS_CANT_MAP_DIFF_AREA_FILE, status, 8);
  5580. ZwClose(diffAreaFile->FileHandle);
  5581. ExFreePool(diffAreaFile);
  5582. Irp->IoStatus.Status = status;
  5583. goto Finish;
  5584. }
  5585. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  5586. Filter->AllocatedVolumeSpace += diffAreaFile->AllocatedFileSize;
  5587. KeReleaseSpinLock(&Filter->SpinLock, irql);
  5588. VspAcquire(Filter->Root);
  5589. diffAreaFile->FilterListEntryBeingUsed = TRUE;
  5590. InsertTailList(&diffAreaFile->Filter->DiffAreaFilesOnThisFilter,
  5591. &diffAreaFile->FilterListEntry);
  5592. VspPauseSnapshotIo(extension);
  5593. VspPauseVolumeIo(extension->Filter);
  5594. VspAcquireNonPagedResource(extension, NULL);
  5595. InsertTailList(&extension->ListOfDiffAreaFiles,
  5596. &diffAreaFile->VolumeListEntry);
  5597. VspReleaseNonPagedResource(extension);
  5598. VspResumeVolumeIo(extension->Filter);
  5599. VspResumeSnapshotIo(extension);
  5600. VspRelease(Filter->Root);
  5601. Finish:
  5602. VspFreeContext(Filter->Root, context);
  5603. IoFreeWorkItem(context->Dispatch.IoWorkItem);
  5604. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5605. }
  5606. NTSTATUS
  5607. VspAddVolumeToDiffArea(
  5608. IN PFILTER_EXTENSION Filter,
  5609. IN PIRP Irp
  5610. )
  5611. /*++
  5612. Routine Description:
  5613. This routine adds the given volume to the diff area for this volume.
  5614. All snapshots get a new diff area file.
  5615. Arguments:
  5616. Filter - Supplies the filter extension.
  5617. Irp - Supplies the I/O request packet.
  5618. Return Value:
  5619. NTSTATUS
  5620. --*/
  5621. {
  5622. PVSP_CONTEXT context;
  5623. Irp->IoStatus.Status = STATUS_SUCCESS;
  5624. Irp->IoStatus.Information = 0;
  5625. context = VspAllocateContext(Filter->Root);
  5626. if (!context) {
  5627. return STATUS_INSUFFICIENT_RESOURCES;
  5628. }
  5629. context->Type = VSP_CONTEXT_TYPE_DISPATCH;
  5630. context->Dispatch.IoWorkItem = IoAllocateWorkItem(Filter->DeviceObject);
  5631. if (!context->Dispatch.IoWorkItem) {
  5632. VspFreeContext(Filter->Root, context);
  5633. return STATUS_INSUFFICIENT_RESOURCES;
  5634. }
  5635. IoMarkIrpPending(Irp);
  5636. context->Dispatch.Irp = Irp;
  5637. IoQueueWorkItem(context->Dispatch.IoWorkItem, VspAddVolumeToDiffAreaWorker,
  5638. DelayedWorkQueue, context);
  5639. return STATUS_PENDING;
  5640. }
  5641. NTSTATUS
  5642. VspQueryDiffArea(
  5643. IN PFILTER_EXTENSION Filter,
  5644. IN PIRP Irp
  5645. )
  5646. /*++
  5647. Routine Description:
  5648. This routine the list of volumes that make up the diff area for this
  5649. volume.
  5650. Arguments:
  5651. Filter - Supplies the filter extension.
  5652. Irp - Supplies the I/O request packet.
  5653. Return Value:
  5654. NTSTATUS
  5655. --*/
  5656. {
  5657. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5658. PVOLSNAP_NAMES output;
  5659. PLIST_ENTRY l;
  5660. PFILTER_EXTENSION filter;
  5661. KEVENT event;
  5662. PMOUNTDEV_NAME name;
  5663. CHAR buffer[512];
  5664. PIRP irp;
  5665. IO_STATUS_BLOCK ioStatus;
  5666. NTSTATUS status;
  5667. PWCHAR buf;
  5668. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAMES, Names);
  5669. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5670. Irp->IoStatus.Information) {
  5671. Irp->IoStatus.Information = 0;
  5672. return STATUS_INVALID_PARAMETER;
  5673. }
  5674. output = (PVOLSNAP_NAMES) Irp->AssociatedIrp.SystemBuffer;
  5675. VspAcquire(Filter->Root);
  5676. output->MultiSzLength = sizeof(WCHAR);
  5677. for (l = Filter->DiffAreaVolumes.Flink; l != &Filter->DiffAreaVolumes;
  5678. l = l->Flink) {
  5679. filter = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry)->Filter;
  5680. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5681. name = (PMOUNTDEV_NAME) buffer;
  5682. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  5683. filter->TargetObject, NULL, 0,
  5684. name, 512, FALSE, &event,
  5685. &ioStatus);
  5686. if (!irp) {
  5687. VspRelease(Filter->Root);
  5688. Irp->IoStatus.Information = 0;
  5689. return STATUS_INSUFFICIENT_RESOURCES;
  5690. }
  5691. status = IoCallDriver(filter->TargetObject, irp);
  5692. if (status == STATUS_PENDING) {
  5693. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5694. status = ioStatus.Status;
  5695. }
  5696. if (!NT_SUCCESS(status)) {
  5697. VspRelease(Filter->Root);
  5698. Irp->IoStatus.Information = 0;
  5699. return status;
  5700. }
  5701. output->MultiSzLength += name->NameLength + sizeof(WCHAR);
  5702. }
  5703. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5704. Irp->IoStatus.Information + output->MultiSzLength) {
  5705. VspRelease(Filter->Root);
  5706. return STATUS_BUFFER_OVERFLOW;
  5707. }
  5708. Irp->IoStatus.Information += output->MultiSzLength;
  5709. buf = output->Names;
  5710. for (l = Filter->DiffAreaVolumes.Flink; l != &Filter->DiffAreaVolumes;
  5711. l = l->Flink) {
  5712. filter = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry)->Filter;
  5713. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5714. name = (PMOUNTDEV_NAME) buffer;
  5715. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  5716. filter->TargetObject, NULL, 0,
  5717. name, 512, FALSE, &event,
  5718. &ioStatus);
  5719. if (!irp) {
  5720. VspRelease(Filter->Root);
  5721. Irp->IoStatus.Information = 0;
  5722. return STATUS_INSUFFICIENT_RESOURCES;
  5723. }
  5724. status = IoCallDriver(filter->TargetObject, irp);
  5725. if (status == STATUS_PENDING) {
  5726. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5727. status = ioStatus.Status;
  5728. }
  5729. if (!NT_SUCCESS(status)) {
  5730. VspRelease(Filter->Root);
  5731. Irp->IoStatus.Information = 0;
  5732. return status;
  5733. }
  5734. RtlCopyMemory(buf, name->Name, name->NameLength);
  5735. buf += name->NameLength/sizeof(WCHAR);
  5736. *buf++ = 0;
  5737. }
  5738. *buf = 0;
  5739. VspRelease(Filter->Root);
  5740. return STATUS_SUCCESS;
  5741. }
  5742. NTSTATUS
  5743. VspQueryDiffAreaSize(
  5744. IN PFILTER_EXTENSION Filter,
  5745. IN PIRP Irp
  5746. )
  5747. /*++
  5748. Routine Description:
  5749. This routine returns the diff area sizes for this volume.
  5750. Arguments:
  5751. Filter - Supplies the filter extension.
  5752. Irp - Supplies the I/O request packet.
  5753. Return Value:
  5754. NTSTATUS
  5755. --*/
  5756. {
  5757. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5758. PVOLSNAP_DIFF_AREA_SIZES output = (PVOLSNAP_DIFF_AREA_SIZES) Irp->AssociatedIrp.SystemBuffer;
  5759. KIRQL irql;
  5760. Irp->IoStatus.Information = sizeof(VOLSNAP_DIFF_AREA_SIZES);
  5761. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5762. Irp->IoStatus.Information) {
  5763. Irp->IoStatus.Information = 0;
  5764. return STATUS_INVALID_PARAMETER;
  5765. }
  5766. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  5767. output->UsedVolumeSpace = Filter->UsedVolumeSpace;
  5768. output->AllocatedVolumeSpace = Filter->AllocatedVolumeSpace;
  5769. output->MaximumVolumeSpace = Filter->MaximumVolumeSpace;
  5770. KeReleaseSpinLock(&Filter->SpinLock, irql);
  5771. return STATUS_SUCCESS;
  5772. }
  5773. NTSTATUS
  5774. VspQueryOriginalVolumeName(
  5775. IN PVOLUME_EXTENSION Extension,
  5776. IN PIRP Irp
  5777. )
  5778. /*++
  5779. Routine Description:
  5780. This routine returns the original volume name for the given volume
  5781. snapshot.
  5782. Arguments:
  5783. Extension - Supplies the volume extension.
  5784. Irp - Supplies the I/O request packet.
  5785. Return Value:
  5786. NTSTATUS
  5787. --*/
  5788. {
  5789. PFILTER_EXTENSION filter = Extension->Filter;
  5790. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5791. PVOLSNAP_NAME output = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  5792. PMOUNTDEV_NAME name;
  5793. CHAR buffer[512];
  5794. KEVENT event;
  5795. PIRP irp;
  5796. IO_STATUS_BLOCK ioStatus;
  5797. NTSTATUS status;
  5798. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_NAME, Name);
  5799. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5800. Irp->IoStatus.Information) {
  5801. Irp->IoStatus.Information = 0;
  5802. return STATUS_INVALID_PARAMETER;
  5803. }
  5804. name = (PMOUNTDEV_NAME) buffer;
  5805. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5806. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  5807. filter->TargetObject, NULL, 0,
  5808. name, 512, FALSE, &event,
  5809. &ioStatus);
  5810. if (!irp) {
  5811. Irp->IoStatus.Information = 0;
  5812. return STATUS_INSUFFICIENT_RESOURCES;
  5813. }
  5814. status = IoCallDriver(filter->TargetObject, irp);
  5815. if (status == STATUS_PENDING) {
  5816. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5817. status = ioStatus.Status;
  5818. }
  5819. if (!NT_SUCCESS(status)) {
  5820. Irp->IoStatus.Information = 0;
  5821. return status;
  5822. }
  5823. output->NameLength = name->NameLength;
  5824. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5825. Irp->IoStatus.Information + output->NameLength) {
  5826. return STATUS_BUFFER_OVERFLOW;
  5827. }
  5828. RtlCopyMemory(output->Name, name->Name, output->NameLength);
  5829. Irp->IoStatus.Information += output->NameLength;
  5830. return STATUS_SUCCESS;
  5831. }
  5832. NTSTATUS
  5833. VspQueryConfigInfo(
  5834. IN PVOLUME_EXTENSION Extension,
  5835. IN PIRP Irp
  5836. )
  5837. /*++
  5838. Routine Description:
  5839. This routine returns the configuration information for this volume
  5840. snapshot.
  5841. Arguments:
  5842. Extension - Supplies the volume extension.
  5843. Irp - Supplies the I/O request packet.
  5844. Return Value:
  5845. NTSTATUS
  5846. --*/
  5847. {
  5848. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5849. PVOLSNAP_CONFIG_INFO output = (PVOLSNAP_CONFIG_INFO) Irp->AssociatedIrp.SystemBuffer;
  5850. Irp->IoStatus.Information = sizeof(ULONG);
  5851. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5852. Irp->IoStatus.Information) {
  5853. return STATUS_INVALID_PARAMETER;
  5854. }
  5855. output->Attributes = 0;
  5856. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  5857. sizeof(VOLSNAP_CONFIG_INFO)) {
  5858. Irp->IoStatus.Information = sizeof(VOLSNAP_CONFIG_INFO);
  5859. output->Reserved = 0;
  5860. output->SnapshotCreationTime = Extension->CommitTimeStamp;
  5861. }
  5862. return STATUS_SUCCESS;
  5863. }
  5864. NTSTATUS
  5865. VspSetApplicationInfo(
  5866. IN PVOLUME_EXTENSION Extension,
  5867. IN PIRP Irp
  5868. )
  5869. /*++
  5870. Routine Description:
  5871. This routine sets the application info.
  5872. Arguments:
  5873. Extension - Supplies the volume extension.
  5874. Irp - Supplies the I/O request packet.
  5875. Return Value:
  5876. NTSTATUS
  5877. --*/
  5878. {
  5879. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5880. PVOLSNAP_APPLICATION_INFO input = (PVOLSNAP_APPLICATION_INFO) Irp->AssociatedIrp.SystemBuffer;
  5881. PVOID newAppInfo, oldAppInfo;
  5882. Irp->IoStatus.Information = 0;
  5883. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5884. sizeof(VOLSNAP_APPLICATION_INFO)) {
  5885. return STATUS_INVALID_PARAMETER;
  5886. }
  5887. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5888. (LONGLONG) FIELD_OFFSET(VOLSNAP_APPLICATION_INFO, Information) +
  5889. input->InformationLength) {
  5890. return STATUS_INVALID_PARAMETER;
  5891. }
  5892. newAppInfo = ExAllocatePoolWithQuotaTag((POOL_TYPE) (PagedPool |
  5893. POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
  5894. input->InformationLength, VOLSNAP_TAG_APP_INFO);
  5895. if (!newAppInfo) {
  5896. return STATUS_INSUFFICIENT_RESOURCES;
  5897. }
  5898. RtlCopyMemory(newAppInfo, input->Information, input->InformationLength);
  5899. KeEnterCriticalRegion();
  5900. VspAcquirePagedResource(Extension, NULL);
  5901. Extension->ApplicationInformationSize = input->InformationLength;
  5902. oldAppInfo = Extension->ApplicationInformation;
  5903. Extension->ApplicationInformation = newAppInfo;
  5904. VspReleasePagedResource(Extension);
  5905. KeLeaveCriticalRegion();
  5906. if (oldAppInfo) {
  5907. ExFreePool(oldAppInfo);
  5908. }
  5909. return STATUS_SUCCESS;
  5910. }
  5911. NTSTATUS
  5912. VspQueryApplicationInfo(
  5913. IN PVOLUME_EXTENSION Extension,
  5914. IN PIRP Irp
  5915. )
  5916. /*++
  5917. Routine Description:
  5918. This routine queries the application info.
  5919. Arguments:
  5920. Extension - Supplies the volume extension.
  5921. Irp - Supplies the I/O request packet.
  5922. Return Value:
  5923. NTSTATUS
  5924. --*/
  5925. {
  5926. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5927. PVOLSNAP_APPLICATION_INFO output = (PVOLSNAP_APPLICATION_INFO) Irp->AssociatedIrp.SystemBuffer;
  5928. PVOID appInfo;
  5929. Irp->IoStatus.Information = FIELD_OFFSET(VOLSNAP_APPLICATION_INFO,
  5930. Information);
  5931. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5932. Irp->IoStatus.Information) {
  5933. return STATUS_INVALID_PARAMETER;
  5934. }
  5935. VspAcquirePagedResource(Extension, NULL);
  5936. output->InformationLength = Extension->ApplicationInformationSize;
  5937. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5938. Irp->IoStatus.Information + output->InformationLength) {
  5939. VspReleasePagedResource(Extension);
  5940. return STATUS_BUFFER_OVERFLOW;
  5941. }
  5942. Irp->IoStatus.Information += output->InformationLength;
  5943. RtlCopyMemory(output->Information, Extension->ApplicationInformation,
  5944. output->InformationLength);
  5945. VspReleasePagedResource(Extension);
  5946. return STATUS_SUCCESS;
  5947. }
  5948. NTSTATUS
  5949. VspCheckSecurity(
  5950. IN PFILTER_EXTENSION Filter,
  5951. IN PIRP Irp
  5952. )
  5953. {
  5954. SECURITY_SUBJECT_CONTEXT securityContext;
  5955. BOOLEAN accessGranted;
  5956. NTSTATUS status;
  5957. ACCESS_MASK grantedAccess;
  5958. SeCaptureSubjectContext(&securityContext);
  5959. SeLockSubjectContext(&securityContext);
  5960. accessGranted = FALSE;
  5961. status = STATUS_ACCESS_DENIED;
  5962. _try {
  5963. accessGranted = SeAccessCheck(
  5964. Filter->Pdo->SecurityDescriptor,
  5965. &securityContext, TRUE, FILE_READ_DATA, 0, NULL,
  5966. IoGetFileObjectGenericMapping(), Irp->RequestorMode,
  5967. &grantedAccess, &status);
  5968. } _finally {
  5969. SeUnlockSubjectContext(&securityContext);
  5970. SeReleaseSubjectContext(&securityContext);
  5971. }
  5972. if (!accessGranted) {
  5973. return status;
  5974. }
  5975. return STATUS_SUCCESS;
  5976. }
  5977. NTSTATUS
  5978. VspAutoCleanup(
  5979. IN PFILTER_EXTENSION Filter,
  5980. IN PIRP Irp
  5981. )
  5982. /*++
  5983. Routine Description:
  5984. This routine remembers the given File Object so that when it is
  5985. cleaned up, all snapshots will be cleaned up with it.
  5986. Arguments:
  5987. Filter - Supplies the filter extension.
  5988. Irp - Supplies the I/O request packet.
  5989. Return Value:
  5990. NTSTATUS
  5991. --*/
  5992. {
  5993. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5994. NTSTATUS status;
  5995. KIRQL irql;
  5996. status = VspCheckSecurity(Filter, Irp);
  5997. if (!NT_SUCCESS(status)) {
  5998. return status;
  5999. }
  6000. IoAcquireCancelSpinLock(&irql);
  6001. if (Filter->AutoCleanupFileObject) {
  6002. IoReleaseCancelSpinLock(irql);
  6003. return STATUS_INVALID_PARAMETER;
  6004. }
  6005. Filter->AutoCleanupFileObject = irpSp->FileObject;
  6006. IoReleaseCancelSpinLock(irql);
  6007. return STATUS_SUCCESS;
  6008. }
  6009. VOID
  6010. VspDeleteSnapshotWorker(
  6011. IN PDEVICE_OBJECT DeviceObject,
  6012. IN PVOID Context
  6013. )
  6014. {
  6015. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  6016. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  6017. PIRP irp = context->Dispatch.Irp;
  6018. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  6019. PVOLUME_EXTENSION oldestExtension;
  6020. PVOLSNAP_NAME name;
  6021. WCHAR buffer[100];
  6022. UNICODE_STRING name1, name2;
  6023. LIST_ENTRY listOfDiffAreaFileToClose;
  6024. LIST_ENTRY listOfDeviceObjectsToDelete;
  6025. NTSTATUS status;
  6026. ASSERT(context->Type == VSP_CONTEXT_TYPE_DISPATCH);
  6027. KeWaitForSingleObject(&filter->EndCommitProcessCompleted, Executive,
  6028. KernelMode, FALSE, NULL);
  6029. InitializeListHead(&listOfDiffAreaFileToClose);
  6030. InitializeListHead(&listOfDeviceObjectsToDelete);
  6031. VspAcquire(filter->Root);
  6032. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  6033. IOCTL_VOLSNAP_DELETE_SNAPSHOT) {
  6034. if (IsListEmpty(&filter->VolumeList)) {
  6035. status = STATUS_INVALID_PARAMETER;
  6036. } else {
  6037. oldestExtension = CONTAINING_RECORD(filter->VolumeList.Flink,
  6038. VOLUME_EXTENSION, ListEntry);
  6039. swprintf(buffer, L"\\Device\\HarddiskVolumeShadowCopy%d",
  6040. oldestExtension->VolumeNumber);
  6041. RtlInitUnicodeString(&name1, buffer);
  6042. name = (PVOLSNAP_NAME) irp->AssociatedIrp.SystemBuffer;
  6043. name2.Length = name2.MaximumLength = name->NameLength;
  6044. name2.Buffer = name->Name;
  6045. if (RtlEqualUnicodeString(&name1, &name2, TRUE)) {
  6046. status = STATUS_SUCCESS;
  6047. } else {
  6048. status = STATUS_NOT_SUPPORTED;
  6049. }
  6050. }
  6051. } else {
  6052. status = STATUS_SUCCESS;
  6053. }
  6054. if (NT_SUCCESS(status)) {
  6055. status = VspDeleteOldestSnapshot(filter, &listOfDiffAreaFileToClose,
  6056. &listOfDeviceObjectsToDelete);
  6057. }
  6058. VspRelease(filter->Root);
  6059. VspCloseDiffAreaFiles(&listOfDiffAreaFileToClose,
  6060. &listOfDeviceObjectsToDelete);
  6061. IoFreeWorkItem(context->Dispatch.IoWorkItem);
  6062. VspFreeContext(filter->Root, context);
  6063. irp->IoStatus.Status = status;
  6064. IoCompleteRequest(irp, IO_NO_INCREMENT);
  6065. }
  6066. NTSTATUS
  6067. VspDeleteSnapshotPost(
  6068. IN PFILTER_EXTENSION Filter,
  6069. IN PIRP Irp
  6070. )
  6071. {
  6072. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6073. PVSP_CONTEXT context;
  6074. PVOLSNAP_NAME name;
  6075. Irp->IoStatus.Information = 0;
  6076. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  6077. IOCTL_VOLSNAP_DELETE_SNAPSHOT) {
  6078. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6079. sizeof(VOLSNAP_NAME)) {
  6080. return STATUS_INVALID_PARAMETER;
  6081. }
  6082. name = (PVOLSNAP_NAME) Irp->AssociatedIrp.SystemBuffer;
  6083. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6084. (ULONG) FIELD_OFFSET(VOLSNAP_NAME, Name) + name->NameLength) {
  6085. return STATUS_INVALID_PARAMETER;
  6086. }
  6087. }
  6088. context = VspAllocateContext(Filter->Root);
  6089. if (!context) {
  6090. return STATUS_INSUFFICIENT_RESOURCES;
  6091. }
  6092. context->Type = VSP_CONTEXT_TYPE_DISPATCH;
  6093. context->Dispatch.IoWorkItem = IoAllocateWorkItem(Filter->DeviceObject);
  6094. if (!context->Dispatch.IoWorkItem) {
  6095. VspFreeContext(Filter->Root, context);
  6096. return STATUS_INSUFFICIENT_RESOURCES;
  6097. }
  6098. IoMarkIrpPending(Irp);
  6099. context->Dispatch.Irp = Irp;
  6100. IoQueueWorkItem(context->Dispatch.IoWorkItem,
  6101. VspDeleteSnapshotWorker, DelayedWorkQueue, context);
  6102. return STATUS_PENDING;
  6103. }
  6104. VOID
  6105. VspCheckCodeLocked(
  6106. IN PDO_EXTENSION RootExtension
  6107. )
  6108. {
  6109. if (RootExtension->IsCodeLocked) {
  6110. return;
  6111. }
  6112. VspAcquire(RootExtension);
  6113. if (RootExtension->IsCodeLocked) {
  6114. VspRelease(RootExtension);
  6115. return;
  6116. }
  6117. MmLockPagableCodeSection(VspCheckCodeLocked);
  6118. InterlockedExchange(&RootExtension->IsCodeLocked, TRUE);
  6119. VspRelease(RootExtension);
  6120. }
  6121. NTSTATUS
  6122. VspSetMaxDiffAreaSize(
  6123. IN PFILTER_EXTENSION Filter,
  6124. IN PIRP Irp
  6125. )
  6126. {
  6127. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6128. PVOLSNAP_DIFF_AREA_SIZES input = (PVOLSNAP_DIFF_AREA_SIZES) Irp->AssociatedIrp.SystemBuffer;
  6129. KIRQL irql;
  6130. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6131. sizeof(VOLSNAP_DIFF_AREA_SIZES)) {
  6132. return STATUS_INVALID_PARAMETER;
  6133. }
  6134. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  6135. Filter->MaximumVolumeSpace = input->MaximumVolumeSpace;
  6136. KeReleaseSpinLock(&Filter->SpinLock, irql);
  6137. return STATUS_SUCCESS;
  6138. }
  6139. NTSTATUS
  6140. VolSnapDeviceControl(
  6141. IN PDEVICE_OBJECT DeviceObject,
  6142. IN PIRP Irp
  6143. )
  6144. /*++
  6145. Routine Description:
  6146. This routine is the dispatch for IRP_MJ_DEVICE_CONTROL.
  6147. Arguments:
  6148. DeviceObject - Supplies the device object.
  6149. Irp - Supplies the IO request packet.
  6150. Return Value:
  6151. NTSTATUS
  6152. --*/
  6153. {
  6154. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  6155. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6156. NTSTATUS status;
  6157. PVOLUME_EXTENSION extension;
  6158. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  6159. if (filter->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  6160. IoSkipCurrentIrpStackLocation(Irp);
  6161. return IoCallDriver(filter->TargetObject, Irp);
  6162. }
  6163. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  6164. case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:
  6165. VspCheckCodeLocked(filter->Root);
  6166. status = VspFlushAndHoldWrites(filter, Irp);
  6167. break;
  6168. case IOCTL_VOLSNAP_RELEASE_WRITES:
  6169. VspCheckCodeLocked(filter->Root);
  6170. status = VspReleaseWrites(filter);
  6171. break;
  6172. case IOCTL_VOLSNAP_PREPARE_FOR_SNAPSHOT:
  6173. VspCheckCodeLocked(filter->Root);
  6174. status = VspPrepareForSnapshot(filter, Irp);
  6175. break;
  6176. case IOCTL_VOLSNAP_ABORT_PREPARED_SNAPSHOT:
  6177. VspCheckCodeLocked(filter->Root);
  6178. status = VspAbortPreparedSnapshot(filter, TRUE);
  6179. break;
  6180. case IOCTL_VOLSNAP_COMMIT_SNAPSHOT:
  6181. VspCheckCodeLocked(filter->Root);
  6182. status = VspCommitSnapshot(filter, Irp);
  6183. break;
  6184. case IOCTL_VOLSNAP_END_COMMIT_SNAPSHOT:
  6185. VspCheckCodeLocked(filter->Root);
  6186. status = VspEndCommitSnapshot(filter, Irp);
  6187. break;
  6188. case IOCTL_VOLSNAP_QUERY_NAMES_OF_SNAPSHOTS:
  6189. VspCheckCodeLocked(filter->Root);
  6190. status = VspQueryNamesOfSnapshots(filter, Irp);
  6191. break;
  6192. case IOCTL_VOLSNAP_CLEAR_DIFF_AREA:
  6193. VspCheckCodeLocked(filter->Root);
  6194. status = VspClearDiffArea(filter, Irp);
  6195. break;
  6196. case IOCTL_VOLSNAP_ADD_VOLUME_TO_DIFF_AREA:
  6197. VspCheckCodeLocked(filter->Root);
  6198. status = VspAddVolumeToDiffArea(filter, Irp);
  6199. break;
  6200. case IOCTL_VOLSNAP_QUERY_DIFF_AREA:
  6201. VspCheckCodeLocked(filter->Root);
  6202. status = VspQueryDiffArea(filter, Irp);
  6203. break;
  6204. case IOCTL_VOLSNAP_SET_MAX_DIFF_AREA_SIZE:
  6205. VspCheckCodeLocked(filter->Root);
  6206. status = VspSetMaxDiffAreaSize(filter, Irp);
  6207. break;
  6208. case IOCTL_VOLSNAP_QUERY_DIFF_AREA_SIZES:
  6209. VspCheckCodeLocked(filter->Root);
  6210. status = VspQueryDiffAreaSize(filter, Irp);
  6211. break;
  6212. case IOCTL_VOLSNAP_DELETE_OLDEST_SNAPSHOT:
  6213. case IOCTL_VOLSNAP_DELETE_SNAPSHOT:
  6214. VspCheckCodeLocked(filter->Root);
  6215. status = VspDeleteSnapshotPost(filter, Irp);
  6216. break;
  6217. case IOCTL_VOLSNAP_AUTO_CLEANUP:
  6218. VspCheckCodeLocked(filter->Root);
  6219. status = VspAutoCleanup(filter, Irp);
  6220. break;
  6221. default:
  6222. IoSkipCurrentIrpStackLocation(Irp);
  6223. return IoCallDriver(filter->TargetObject, Irp);
  6224. }
  6225. if (status == STATUS_PENDING) {
  6226. return status;
  6227. }
  6228. Irp->IoStatus.Status = status;
  6229. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6230. return status;
  6231. }
  6232. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  6233. extension = (PVOLUME_EXTENSION) filter;
  6234. if (!extension->IsStarted) {
  6235. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  6236. Irp->IoStatus.Information = 0;
  6237. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6238. return STATUS_NO_SUCH_DEVICE;
  6239. }
  6240. status = VspIncrementVolumeRefCount(extension, Irp, NULL);
  6241. if (!NT_SUCCESS(status)) {
  6242. Irp->IoStatus.Status = status;
  6243. Irp->IoStatus.Information = 0;
  6244. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6245. return status;
  6246. }
  6247. if (status == STATUS_PENDING) {
  6248. return status;
  6249. }
  6250. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  6251. case IOCTL_VOLSNAP_QUERY_ORIGINAL_VOLUME_NAME:
  6252. status = VspQueryOriginalVolumeName(extension, Irp);
  6253. break;
  6254. case IOCTL_VOLSNAP_QUERY_CONFIG_INFO:
  6255. status = VspQueryConfigInfo(extension, Irp);
  6256. break;
  6257. case IOCTL_VOLSNAP_SET_APPLICATION_INFO:
  6258. status = VspSetApplicationInfo(extension, Irp);
  6259. break;
  6260. case IOCTL_VOLSNAP_QUERY_APPLICATION_INFO:
  6261. status = VspQueryApplicationInfo(extension, Irp);
  6262. break;
  6263. case IOCTL_VOLUME_QUERY_VOLUME_NUMBER:
  6264. status = VspQueryVolumeNumber(extension, Irp);
  6265. break;
  6266. case IOCTL_DISK_SET_PARTITION_INFO:
  6267. status = STATUS_SUCCESS;
  6268. break;
  6269. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
  6270. case IOCTL_DISK_VERIFY:
  6271. case IOCTL_DISK_GET_PARTITION_INFO:
  6272. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  6273. case IOCTL_DISK_GET_LENGTH_INFO:
  6274. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  6275. case IOCTL_DISK_CHECK_VERIFY:
  6276. IoCopyCurrentIrpStackLocationToNext(Irp);
  6277. IoSetCompletionRoutine(Irp, VspVolumeRefCountCompletionRoutine,
  6278. extension, TRUE, TRUE, TRUE);
  6279. IoMarkIrpPending(Irp);
  6280. IoCallDriver(extension->Filter->TargetObject, Irp);
  6281. return STATUS_PENDING;
  6282. case IOCTL_DISK_IS_WRITABLE:
  6283. status = STATUS_MEDIA_WRITE_PROTECTED;
  6284. break;
  6285. default:
  6286. status = STATUS_INVALID_DEVICE_REQUEST;
  6287. break;
  6288. }
  6289. VspDecrementVolumeRefCount(extension);
  6290. Irp->IoStatus.Status = status;
  6291. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6292. return status;
  6293. }
  6294. NTSTATUS
  6295. VspQueryBusRelations(
  6296. IN PFILTER_EXTENSION Filter,
  6297. IN PIRP Irp
  6298. )
  6299. {
  6300. ULONG numVolumes;
  6301. PLIST_ENTRY l;
  6302. NTSTATUS status;
  6303. PDEVICE_RELATIONS deviceRelations, newRelations;
  6304. ULONG size, i;
  6305. PVOLUME_EXTENSION extension;
  6306. numVolumes = 0;
  6307. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  6308. l = l->Flink) {
  6309. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6310. if (!extension->HasEndCommit) {
  6311. continue;
  6312. }
  6313. InterlockedExchange(&extension->AliveToPnp, TRUE);
  6314. numVolumes++;
  6315. }
  6316. status = Irp->IoStatus.Status;
  6317. if (!numVolumes) {
  6318. if (NT_SUCCESS(status)) {
  6319. return status;
  6320. }
  6321. newRelations = (PDEVICE_RELATIONS)
  6322. ExAllocatePoolWithTag(PagedPool,
  6323. sizeof(DEVICE_RELATIONS),
  6324. VOLSNAP_TAG_RELATIONS);
  6325. if (!newRelations) {
  6326. return STATUS_INSUFFICIENT_RESOURCES;
  6327. }
  6328. RtlZeroMemory(newRelations, sizeof(DEVICE_RELATIONS));
  6329. newRelations->Count = 0;
  6330. Irp->IoStatus.Information = (ULONG_PTR) newRelations;
  6331. while (!IsListEmpty(&Filter->DeadVolumeList)) {
  6332. l = RemoveHeadList(&Filter->DeadVolumeList);
  6333. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6334. InterlockedExchange(&extension->DeadToPnp, TRUE);
  6335. }
  6336. return STATUS_SUCCESS;
  6337. }
  6338. if (NT_SUCCESS(status)) {
  6339. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  6340. size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
  6341. (numVolumes + deviceRelations->Count)*sizeof(PDEVICE_OBJECT);
  6342. newRelations = (PDEVICE_RELATIONS)
  6343. ExAllocatePoolWithTag(PagedPool, size,
  6344. VOLSNAP_TAG_RELATIONS);
  6345. if (!newRelations) {
  6346. for (i = 0; i < deviceRelations->Count; i++) {
  6347. ObDereferenceObject(deviceRelations->Objects[i]);
  6348. }
  6349. ExFreePool(deviceRelations);
  6350. Irp->IoStatus.Information = 0;
  6351. return STATUS_INSUFFICIENT_RESOURCES;
  6352. }
  6353. newRelations->Count = numVolumes + deviceRelations->Count;
  6354. RtlCopyMemory(newRelations->Objects, deviceRelations->Objects,
  6355. deviceRelations->Count*sizeof(PDEVICE_OBJECT));
  6356. i = deviceRelations->Count;
  6357. ExFreePool(deviceRelations);
  6358. } else {
  6359. size = sizeof(DEVICE_RELATIONS) + numVolumes*sizeof(PDEVICE_OBJECT);
  6360. newRelations = (PDEVICE_RELATIONS)
  6361. ExAllocatePoolWithTag(PagedPool, size,
  6362. VOLSNAP_TAG_RELATIONS);
  6363. if (!newRelations) {
  6364. return STATUS_INSUFFICIENT_RESOURCES;
  6365. }
  6366. newRelations->Count = numVolumes;
  6367. i = 0;
  6368. }
  6369. numVolumes = 0;
  6370. for (l = Filter->VolumeList.Flink; l != &Filter->VolumeList;
  6371. l = l->Flink) {
  6372. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6373. if (!extension->HasEndCommit) {
  6374. continue;
  6375. }
  6376. newRelations->Objects[i + numVolumes++] = extension->DeviceObject;
  6377. ObReferenceObject(extension->DeviceObject);
  6378. }
  6379. Irp->IoStatus.Information = (ULONG_PTR) newRelations;
  6380. while (!IsListEmpty(&Filter->DeadVolumeList)) {
  6381. l = RemoveHeadList(&Filter->DeadVolumeList);
  6382. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6383. InterlockedExchange(&extension->DeadToPnp, TRUE);
  6384. }
  6385. return STATUS_SUCCESS;
  6386. }
  6387. NTSTATUS
  6388. VspQueryId(
  6389. IN PVOLUME_EXTENSION Extension,
  6390. IN PIRP Irp
  6391. )
  6392. {
  6393. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6394. UNICODE_STRING string;
  6395. NTSTATUS status;
  6396. WCHAR buffer[100];
  6397. PWSTR id;
  6398. switch (irpSp->Parameters.QueryId.IdType) {
  6399. case BusQueryDeviceID:
  6400. RtlInitUnicodeString(&string, L"STORAGE\\VolumeSnapshot");
  6401. break;
  6402. case BusQueryHardwareIDs:
  6403. RtlInitUnicodeString(&string, L"STORAGE\\VolumeSnapshot");
  6404. break;
  6405. case BusQueryInstanceID:
  6406. swprintf(buffer, L"HarddiskVolumeSnapshot%d",
  6407. Extension->VolumeNumber);
  6408. RtlInitUnicodeString(&string, buffer);
  6409. break;
  6410. default:
  6411. return STATUS_NOT_SUPPORTED;
  6412. }
  6413. id = (PWSTR) ExAllocatePoolWithTag(PagedPool,
  6414. string.Length + 2*sizeof(WCHAR),
  6415. VOLSNAP_TAG_PNP_ID);
  6416. if (!id) {
  6417. return STATUS_INSUFFICIENT_RESOURCES;
  6418. }
  6419. RtlCopyMemory(id, string.Buffer, string.Length);
  6420. id[string.Length/sizeof(WCHAR)] = 0;
  6421. id[string.Length/sizeof(WCHAR) + 1] = 0;
  6422. Irp->IoStatus.Information = (ULONG_PTR) id;
  6423. return STATUS_SUCCESS;
  6424. }
  6425. VOID
  6426. VspDeleteDiffAreaFilesWorker(
  6427. IN PDEVICE_OBJECT DeviceObject,
  6428. IN PVOID WorkItem
  6429. )
  6430. {
  6431. NTSTATUS status;
  6432. UNICODE_STRING name, fileName;
  6433. OBJECT_ATTRIBUTES oa;
  6434. HANDLE h, fileHandle;
  6435. IO_STATUS_BLOCK ioStatus;
  6436. PFILE_NAMES_INFORMATION fileNamesInfo;
  6437. CHAR buffer[200];
  6438. FILE_DISPOSITION_INFORMATION dispInfo;
  6439. BOOLEAN restartScan;
  6440. LARGE_INTEGER timeout;
  6441. status = VspCreateDiffAreaFileName(DeviceObject, (ULONG) -1, &name);
  6442. if (!NT_SUCCESS(status)) {
  6443. IoFreeWorkItem((PIO_WORKITEM) WorkItem);
  6444. return;
  6445. }
  6446. name.Length -= 39*sizeof(WCHAR);
  6447. InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
  6448. status = ZwOpenFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, &oa, &ioStatus,
  6449. FILE_SHARE_READ | FILE_SHARE_WRITE,
  6450. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  6451. if (!NT_SUCCESS(status)) {
  6452. ExFreePool(name.Buffer);
  6453. IoFreeWorkItem((PIO_WORKITEM) WorkItem);
  6454. return;
  6455. }
  6456. fileName.Buffer = &name.Buffer[name.Length/sizeof(WCHAR)];
  6457. fileName.Length = 39*sizeof(WCHAR);
  6458. fileName.MaximumLength = fileName.Length + sizeof(WCHAR);
  6459. fileNamesInfo = (PFILE_NAMES_INFORMATION) buffer;
  6460. dispInfo.DeleteFile = TRUE;
  6461. restartScan = TRUE;
  6462. for (;;) {
  6463. status = ZwQueryDirectoryFile(h, NULL, NULL, NULL, &ioStatus,
  6464. fileNamesInfo, 200, FileNamesInformation,
  6465. TRUE, restartScan ? &fileName : NULL,
  6466. restartScan);
  6467. if (!NT_SUCCESS(status)) {
  6468. break;
  6469. }
  6470. fileName.Length = fileName.MaximumLength =
  6471. (USHORT) fileNamesInfo->FileNameLength;
  6472. fileName.Buffer = fileNamesInfo->FileName;
  6473. InitializeObjectAttributes(&oa, &fileName, OBJ_CASE_INSENSITIVE, h,
  6474. NULL);
  6475. status = ZwOpenFile(&fileHandle, DELETE, &oa, &ioStatus,
  6476. FILE_SHARE_DELETE | FILE_SHARE_READ |
  6477. FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE);
  6478. if (!NT_SUCCESS(status)) {
  6479. continue;
  6480. }
  6481. ZwSetInformationFile(fileHandle, &ioStatus, &dispInfo,
  6482. sizeof(dispInfo), FileDispositionInformation);
  6483. ZwClose(fileHandle);
  6484. restartScan = FALSE;
  6485. }
  6486. ZwClose(h);
  6487. ExFreePool(name.Buffer);
  6488. IoFreeWorkItem((PIO_WORKITEM) WorkItem);
  6489. }
  6490. NTSTATUS
  6491. VolSnapPnp(
  6492. IN PDEVICE_OBJECT DeviceObject,
  6493. IN PIRP Irp
  6494. )
  6495. /*++
  6496. Routine Description:
  6497. This routine is the dispatch for IRP_MJ_PNP.
  6498. Arguments:
  6499. DeviceObject - Supplies the device object.
  6500. Irp - Supplies the IO request packet.
  6501. Return Value:
  6502. NTSTATUS
  6503. --*/
  6504. {
  6505. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  6506. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6507. PDEVICE_OBJECT targetObject;
  6508. KEVENT event;
  6509. NTSTATUS status;
  6510. PVOLUME_EXTENSION extension;
  6511. BOOLEAN deletePdo;
  6512. PDEVICE_RELATIONS deviceRelations;
  6513. PDEVICE_CAPABILITIES capabilities;
  6514. KIRQL irql;
  6515. PIRP irp;
  6516. DEVICE_INSTALL_STATE deviceInstallState;
  6517. ULONG bytes;
  6518. PVSP_CONTEXT context;
  6519. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  6520. switch (irpSp->MinorFunction) {
  6521. case IRP_MN_REMOVE_DEVICE:
  6522. case IRP_MN_SURPRISE_REMOVAL:
  6523. VspCleanupFilter(filter);
  6524. targetObject = filter->TargetObject;
  6525. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  6526. IoDetachDevice(targetObject);
  6527. IoDeleteDevice(filter->DeviceObject);
  6528. }
  6529. IoSkipCurrentIrpStackLocation(Irp);
  6530. return IoCallDriver(targetObject, Irp);
  6531. case IRP_MN_QUERY_DEVICE_RELATIONS:
  6532. switch (irpSp->Parameters.QueryDeviceRelations.Type) {
  6533. case BusRelations:
  6534. break;
  6535. default:
  6536. IoSkipCurrentIrpStackLocation(Irp);
  6537. return IoCallDriver(filter->TargetObject, Irp);
  6538. }
  6539. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6540. IoCopyCurrentIrpStackLocationToNext(Irp);
  6541. IoSetCompletionRoutine(Irp, VspSignalCompletion,
  6542. &event, TRUE, TRUE, TRUE);
  6543. IoCallDriver(filter->TargetObject, Irp);
  6544. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  6545. NULL);
  6546. VspAcquire(filter->Root);
  6547. switch (irpSp->Parameters.QueryDeviceRelations.Type) {
  6548. case BusRelations:
  6549. status = VspQueryBusRelations(filter, Irp);
  6550. break;
  6551. }
  6552. VspRelease(filter->Root);
  6553. break;
  6554. default:
  6555. IoSkipCurrentIrpStackLocation(Irp);
  6556. return IoCallDriver(filter->TargetObject, Irp);
  6557. }
  6558. Irp->IoStatus.Status = status;
  6559. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6560. return status;
  6561. }
  6562. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  6563. extension = (PVOLUME_EXTENSION) filter;
  6564. switch (irpSp->MinorFunction) {
  6565. case IRP_MN_START_DEVICE:
  6566. filter = extension->Filter;
  6567. if (extension->IsDead) {
  6568. status = STATUS_INVALID_PARAMETER;
  6569. break;
  6570. }
  6571. InterlockedExchange(&extension->IsStarted, TRUE);
  6572. status = IoGetDeviceProperty(extension->DeviceObject,
  6573. DevicePropertyInstallState,
  6574. sizeof(deviceInstallState),
  6575. &deviceInstallState, &bytes);
  6576. if (!NT_SUCCESS(status) ||
  6577. deviceInstallState != InstallStateInstalled) {
  6578. status = STATUS_SUCCESS;
  6579. break;
  6580. }
  6581. VspAcquire(extension->Root);
  6582. extension->IsInstalled = TRUE;
  6583. if (extension->ListEntry.Flink != &filter->VolumeList) {
  6584. KeAcquireSpinLock(&extension->SpinLock, &irql);
  6585. if (extension->IgnorableProduct) {
  6586. ExFreePool(extension->IgnorableProduct->Buffer);
  6587. ExFreePool(extension->IgnorableProduct);
  6588. extension->IgnorableProduct = NULL;
  6589. }
  6590. KeReleaseSpinLock(&extension->SpinLock, irql);
  6591. VspRelease(extension->Root);
  6592. break;
  6593. }
  6594. if (!KeCancelTimer(&filter->EndCommitTimer)) {
  6595. VspRelease(extension->Root);
  6596. break;
  6597. }
  6598. VspRelease(extension->Root);
  6599. context = VspAllocateContext(filter->Root);
  6600. if (!context) {
  6601. KeSetEvent(&filter->EndCommitProcessCompleted, IO_NO_INCREMENT,
  6602. FALSE);
  6603. ObDereferenceObject(filter->DeviceObject);
  6604. status = STATUS_INSUFFICIENT_RESOURCES;
  6605. break;
  6606. }
  6607. ObReferenceObject(extension->DeviceObject);
  6608. context->Type = VSP_CONTEXT_TYPE_EXTENSION;
  6609. context->Extension.Extension = extension;
  6610. context->Extension.Irp = NULL;
  6611. ExInitializeWorkItem(&context->WorkItem,
  6612. VspSetIgnorableBlocksInBitmapWorker, context);
  6613. VspQueueWorkItem(filter->Root, &context->WorkItem, 0);
  6614. break;
  6615. case IRP_MN_QUERY_REMOVE_DEVICE:
  6616. case IRP_MN_CANCEL_REMOVE_DEVICE:
  6617. status = STATUS_SUCCESS;
  6618. break;
  6619. case IRP_MN_QUERY_STOP_DEVICE:
  6620. status = STATUS_UNSUCCESSFUL;
  6621. break;
  6622. case IRP_MN_CANCEL_STOP_DEVICE:
  6623. case IRP_MN_QUERY_RESOURCES:
  6624. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  6625. status = STATUS_SUCCESS;
  6626. break;
  6627. case IRP_MN_REMOVE_DEVICE:
  6628. case IRP_MN_SURPRISE_REMOVAL:
  6629. InterlockedExchange(&extension->IsStarted, FALSE);
  6630. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  6631. if (extension->DeadToPnp && !extension->DeviceDeleted) {
  6632. InterlockedExchange(&extension->DeviceDeleted, TRUE);
  6633. deletePdo = TRUE;
  6634. } else {
  6635. deletePdo = FALSE;
  6636. }
  6637. } else {
  6638. deletePdo = FALSE;
  6639. }
  6640. if (deletePdo) {
  6641. IoDeleteDevice(extension->DeviceObject);
  6642. }
  6643. status = STATUS_SUCCESS;
  6644. break;
  6645. case IRP_MN_QUERY_DEVICE_RELATIONS:
  6646. if (irpSp->Parameters.QueryDeviceRelations.Type !=
  6647. TargetDeviceRelation) {
  6648. status = STATUS_NOT_SUPPORTED;
  6649. break;
  6650. }
  6651. deviceRelations = (PDEVICE_RELATIONS)
  6652. ExAllocatePoolWithTag(PagedPool,
  6653. sizeof(DEVICE_RELATIONS),
  6654. VOLSNAP_TAG_RELATIONS);
  6655. if (!deviceRelations) {
  6656. status = STATUS_INSUFFICIENT_RESOURCES;
  6657. break;
  6658. }
  6659. ObReferenceObject(DeviceObject);
  6660. deviceRelations->Count = 1;
  6661. deviceRelations->Objects[0] = DeviceObject;
  6662. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  6663. status = STATUS_SUCCESS;
  6664. break;
  6665. case IRP_MN_QUERY_CAPABILITIES:
  6666. capabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
  6667. capabilities->SilentInstall = 1;
  6668. capabilities->SurpriseRemovalOK = 1;
  6669. capabilities->RawDeviceOK = 1;
  6670. capabilities->Address = extension->VolumeNumber;
  6671. status = STATUS_SUCCESS;
  6672. break;
  6673. case IRP_MN_QUERY_ID:
  6674. status = VspQueryId(extension, Irp);
  6675. break;
  6676. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  6677. Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI;
  6678. status = STATUS_SUCCESS;
  6679. break;
  6680. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  6681. status = STATUS_INVALID_DEVICE_REQUEST;
  6682. break;
  6683. default:
  6684. status = STATUS_NOT_SUPPORTED;
  6685. break;
  6686. }
  6687. if (status == STATUS_NOT_SUPPORTED) {
  6688. status = Irp->IoStatus.Status;
  6689. } else {
  6690. Irp->IoStatus.Status = status;
  6691. }
  6692. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6693. return status;
  6694. }
  6695. VOID
  6696. VspWorkerThread(
  6697. IN PVOID Context
  6698. )
  6699. /*++
  6700. Routine Description:
  6701. This is a worker thread to process work queue items.
  6702. Arguments:
  6703. RootExtension - Supplies the root device extension.
  6704. Return Value:
  6705. None.
  6706. --*/
  6707. {
  6708. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  6709. PDO_EXTENSION rootExtension = context->ThreadCreation.RootExtension;
  6710. ULONG queueNumber = context->ThreadCreation.QueueNumber;
  6711. KIRQL irql;
  6712. PLIST_ENTRY l;
  6713. PWORK_QUEUE_ITEM queueItem;
  6714. ASSERT(queueNumber < NUMBER_OF_THREAD_POOLS);
  6715. ASSERT(context->Type == VSP_CONTEXT_TYPE_THREAD_CREATION);
  6716. VspFreeContext(rootExtension, context);
  6717. if (!queueNumber) {
  6718. KeSetPriorityThread(KeGetCurrentThread(), 20);
  6719. }
  6720. for (;;) {
  6721. KeWaitForSingleObject(&rootExtension->WorkerSemaphore[queueNumber],
  6722. Executive, KernelMode, FALSE, NULL);
  6723. KeAcquireSpinLock(&rootExtension->SpinLock[queueNumber], &irql);
  6724. if (IsListEmpty(&rootExtension->WorkerQueue[queueNumber])) {
  6725. KeReleaseSpinLock(&rootExtension->SpinLock[queueNumber], irql);
  6726. ASSERT(!rootExtension->ThreadsRefCount);
  6727. PsTerminateSystemThread(STATUS_SUCCESS);
  6728. return;
  6729. }
  6730. l = RemoveHeadList(&rootExtension->WorkerQueue[queueNumber]);
  6731. KeReleaseSpinLock(&rootExtension->SpinLock[queueNumber], irql);
  6732. queueItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  6733. queueItem->WorkerRoutine(queueItem->Parameter);
  6734. }
  6735. }
  6736. NTSTATUS
  6737. VolSnapTargetDeviceNotification(
  6738. IN PVOID NotificationStructure,
  6739. IN PVOID Filter
  6740. )
  6741. {
  6742. PTARGET_DEVICE_REMOVAL_NOTIFICATION notification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure;
  6743. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) Filter;
  6744. PLIST_ENTRY l;
  6745. PVSP_DIFF_AREA_FILE diffAreaFile;
  6746. PFILTER_EXTENSION f;
  6747. LIST_ENTRY listOfDiffAreaFilesToClose;
  6748. LIST_ENTRY listOfDeviceObjectsToDelete;
  6749. if (IsEqualGUID(notification->Event,
  6750. GUID_TARGET_DEVICE_REMOVE_COMPLETE)) {
  6751. if (filter->TargetDeviceNotificationEntry) {
  6752. IoUnregisterPlugPlayNotification(
  6753. filter->TargetDeviceNotificationEntry);
  6754. filter->TargetDeviceNotificationEntry = NULL;
  6755. }
  6756. return STATUS_SUCCESS;
  6757. }
  6758. if (!IsEqualGUID(notification->Event, GUID_IO_VOLUME_DISMOUNT)) {
  6759. return STATUS_SUCCESS;
  6760. }
  6761. InitializeListHead(&listOfDiffAreaFilesToClose);
  6762. InitializeListHead(&listOfDeviceObjectsToDelete);
  6763. VspAcquire(filter->Root);
  6764. while (!IsListEmpty(&filter->DiffAreaFilesOnThisFilter)) {
  6765. l = filter->DiffAreaFilesOnThisFilter.Flink;
  6766. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  6767. FilterListEntry);
  6768. f = diffAreaFile->Extension->Filter;
  6769. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  6770. VS_ABORT_SNAPSHOTS_DISMOUNT, STATUS_SUCCESS, 0);
  6771. VspAbortPreparedSnapshot(f, FALSE);
  6772. while (!IsListEmpty(&f->VolumeList)) {
  6773. VspDeleteOldestSnapshot(f, &listOfDiffAreaFilesToClose,
  6774. &listOfDeviceObjectsToDelete);
  6775. }
  6776. }
  6777. VspRelease(filter->Root);
  6778. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  6779. &listOfDeviceObjectsToDelete);
  6780. return STATUS_SUCCESS;
  6781. }
  6782. NTSTATUS
  6783. VolSnapVolumeDeviceNotification(
  6784. IN PVOID NotificationStructure,
  6785. IN PVOID RootExtension
  6786. )
  6787. /*++
  6788. Routine Description:
  6789. This routine is called whenever a volume comes or goes.
  6790. Arguments:
  6791. NotificationStructure - Supplies the notification structure.
  6792. RootExtension - Supplies the root extension.
  6793. Return Value:
  6794. NTSTATUS
  6795. --*/
  6796. {
  6797. PDEVICE_INTERFACE_CHANGE_NOTIFICATION notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
  6798. PDO_EXTENSION root = (PDO_EXTENSION) RootExtension;
  6799. BOOLEAN errorMode;
  6800. NTSTATUS status;
  6801. PFILE_OBJECT fileObject;
  6802. PDEVICE_OBJECT deviceObject;
  6803. PIO_WORKITEM workItem;
  6804. PFILTER_EXTENSION filter;
  6805. if (!IsEqualGUID(notification->Event, GUID_DEVICE_INTERFACE_ARRIVAL)) {
  6806. return STATUS_SUCCESS;
  6807. }
  6808. errorMode = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
  6809. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
  6810. status = IoGetDeviceObjectPointer(notification->SymbolicLinkName,
  6811. FILE_READ_ATTRIBUTES, &fileObject,
  6812. &deviceObject);
  6813. if (!NT_SUCCESS(status)) {
  6814. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  6815. return STATUS_SUCCESS;
  6816. }
  6817. if (fileObject->DeviceObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  6818. ObDereferenceObject(fileObject);
  6819. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  6820. return STATUS_SUCCESS;
  6821. }
  6822. VspAcquire(root);
  6823. filter = VspFindFilter(root, NULL, NULL, fileObject);
  6824. if (!filter || filter->TargetDeviceNotificationEntry) {
  6825. ObDereferenceObject(fileObject);
  6826. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  6827. VspRelease(root);
  6828. return STATUS_SUCCESS;
  6829. }
  6830. ObReferenceObject(filter->DeviceObject);
  6831. VspRelease(root);
  6832. status = IoRegisterPlugPlayNotification(
  6833. EventCategoryTargetDeviceChange, 0, fileObject,
  6834. root->DriverObject, VolSnapTargetDeviceNotification, filter,
  6835. &filter->TargetDeviceNotificationEntry);
  6836. ObDereferenceObject(filter->DeviceObject);
  6837. if (!NT_SUCCESS(status)) {
  6838. ObDereferenceObject(fileObject);
  6839. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  6840. return STATUS_SUCCESS;
  6841. }
  6842. workItem = IoAllocateWorkItem(deviceObject);
  6843. if (workItem) {
  6844. IoQueueWorkItem(workItem, VspDeleteDiffAreaFilesWorker,
  6845. DelayedWorkQueue, workItem);
  6846. }
  6847. ObDereferenceObject(fileObject);
  6848. PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), errorMode);
  6849. return STATUS_SUCCESS;
  6850. }
  6851. VOID
  6852. VspWaitToRegisterWorker(
  6853. IN PVOID Context
  6854. )
  6855. {
  6856. PVSP_CONTEXT context = (PVSP_CONTEXT) Context;
  6857. PDO_EXTENSION rootExtension = context->RootExtension.RootExtension;
  6858. UNICODE_STRING volumeSafeEventName;
  6859. OBJECT_ATTRIBUTES oa;
  6860. KEVENT event;
  6861. LARGE_INTEGER timeout;
  6862. ULONG i;
  6863. NTSTATUS status;
  6864. HANDLE volumeSafeEvent;
  6865. ASSERT(context->Type == VSP_CONTEXT_TYPE_ROOT_EXTENSION);
  6866. VspFreeContext(rootExtension, context);
  6867. RtlInitUnicodeString(&volumeSafeEventName,
  6868. L"\\Device\\VolumesSafeForWriteAccess");
  6869. InitializeObjectAttributes(&oa, &volumeSafeEventName,
  6870. OBJ_CASE_INSENSITIVE, NULL, NULL);
  6871. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6872. timeout.QuadPart = -10*1000*1000; // 1 second
  6873. for (i = 0; i < 1000; i++) {
  6874. status = ZwOpenEvent(&volumeSafeEvent, EVENT_ALL_ACCESS, &oa);
  6875. if (NT_SUCCESS(status)) {
  6876. break;
  6877. }
  6878. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
  6879. }
  6880. if (i == 1000) {
  6881. return;
  6882. }
  6883. ZwWaitForSingleObject(volumeSafeEvent, FALSE, NULL);
  6884. ZwClose(volumeSafeEvent);
  6885. if (rootExtension->NotificationEntry) {
  6886. return;
  6887. }
  6888. IoRegisterPlugPlayNotification(
  6889. EventCategoryDeviceInterfaceChange,
  6890. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  6891. (PVOID) &GUID_IO_VOLUME_DEVICE_INTERFACE,
  6892. rootExtension->DriverObject, VolSnapVolumeDeviceNotification,
  6893. rootExtension, &rootExtension->NotificationEntry);
  6894. }
  6895. VOID
  6896. VspDriverReinit(
  6897. IN PDRIVER_OBJECT DriverObject,
  6898. IN PVOID RootExtension,
  6899. IN ULONG Count
  6900. )
  6901. /*++
  6902. Routine Description:
  6903. This routine is called after all of the boot drivers are loaded and it
  6904. checks to make sure that we did not boot off of the stale half of a
  6905. mirror.
  6906. Arguments:
  6907. DriverObject - Supplies the drive object.
  6908. RootExtension - Supplies the root extension.
  6909. Count - Supplies the count.
  6910. Return Value:
  6911. None.
  6912. --*/
  6913. {
  6914. PDO_EXTENSION rootExtension = (PDO_EXTENSION) RootExtension;
  6915. PVSP_CONTEXT context;
  6916. context = VspAllocateContext(rootExtension);
  6917. if (!context) {
  6918. return;
  6919. }
  6920. context->Type = VSP_CONTEXT_TYPE_ROOT_EXTENSION;
  6921. context->RootExtension.RootExtension = rootExtension;
  6922. ExInitializeWorkItem(&context->WorkItem, VspWaitToRegisterWorker, context);
  6923. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  6924. }
  6925. #ifdef ALLOC_PRAGMA
  6926. #pragma code_seg()
  6927. #endif
  6928. #if DBG
  6929. #define NUMBER_OF_TRACE_ENTRIES (0x100)
  6930. VSP_TRACE_STRUCTURE TraceStructures[NUMBER_OF_TRACE_ENTRIES];
  6931. LONG CurrentTraceStructure;
  6932. PVSP_TRACE_STRUCTURE
  6933. VspAllocateTraceStructure(
  6934. )
  6935. {
  6936. LONG next;
  6937. next = InterlockedIncrement(&CurrentTraceStructure);
  6938. return &TraceStructures[next&0xFF];
  6939. }
  6940. #endif // DBG
  6941. NTSTATUS
  6942. VspSignalCompletion(
  6943. IN PDEVICE_OBJECT DeviceObject,
  6944. IN PIRP Irp,
  6945. IN PVOID Event
  6946. )
  6947. {
  6948. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  6949. return STATUS_MORE_PROCESSING_REQUIRED;
  6950. }
  6951. NTSTATUS
  6952. VspReleaseWrites(
  6953. IN PFILTER_EXTENSION Filter
  6954. )
  6955. /*++
  6956. Routine Description:
  6957. This routine releases previously queued writes. If the writes have
  6958. already been dequeued by a timeout of have never actually been queued
  6959. for some other reason then this routine fails.
  6960. Arguments:
  6961. Filter - Supplies the filter extension.
  6962. Irp - Supplies the I/O request packet.
  6963. Return Value:
  6964. NTSTATUS
  6965. --*/
  6966. {
  6967. KIRQL irql;
  6968. LIST_ENTRY q;
  6969. PLIST_ENTRY l;
  6970. PIRP irp;
  6971. BOOLEAN emptyQueue;
  6972. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  6973. if (!Filter->HoldIncomingWrites || !Filter->TimerIsSet) {
  6974. KeReleaseSpinLock(&Filter->SpinLock, irql);
  6975. return STATUS_INVALID_PARAMETER;
  6976. }
  6977. if (!KeCancelTimer(&Filter->HoldWritesTimer)) {
  6978. KeReleaseSpinLock(&Filter->SpinLock, irql);
  6979. return STATUS_INVALID_PARAMETER;
  6980. }
  6981. IoStopTimer(Filter->DeviceObject);
  6982. InterlockedIncrement(&Filter->RefCount);
  6983. InterlockedExchange(&Filter->TimerIsSet, FALSE);
  6984. InterlockedExchange(&Filter->HoldIncomingWrites, FALSE);
  6985. if (IsListEmpty(&Filter->HoldQueue)) {
  6986. emptyQueue = FALSE;
  6987. } else {
  6988. emptyQueue = TRUE;
  6989. q = Filter->HoldQueue;
  6990. InitializeListHead(&Filter->HoldQueue);
  6991. }
  6992. KeReleaseSpinLock(&Filter->SpinLock, irql);
  6993. if (emptyQueue) {
  6994. q.Blink->Flink = &q;
  6995. q.Flink->Blink = &q;
  6996. VspEmptyIrpQueue(Filter->Root->DriverObject, &q);
  6997. }
  6998. return STATUS_SUCCESS;
  6999. }
  7000. VOID
  7001. VspDecrementRefCount(
  7002. IN PFILTER_EXTENSION Filter
  7003. )
  7004. {
  7005. KIRQL irql;
  7006. ZERO_REF_CALLBACK callback;
  7007. if (InterlockedDecrement(&Filter->RefCount)) {
  7008. return;
  7009. }
  7010. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  7011. callback = Filter->ZeroRefCallback;
  7012. Filter->ZeroRefCallback = NULL;
  7013. KeReleaseSpinLock(&Filter->SpinLock, irql);
  7014. if (callback) {
  7015. callback(Filter);
  7016. }
  7017. }
  7018. VOID
  7019. VspCleanupFilter(
  7020. IN PFILTER_EXTENSION Filter
  7021. )
  7022. /*++
  7023. Routine Description:
  7024. This routine cleans up filter extension data because of an IRP_MN_REMOVE.
  7025. Arguments:
  7026. Filter - Supplies the filter extension.
  7027. Return Value:
  7028. None.
  7029. --*/
  7030. {
  7031. KIRQL irql;
  7032. PIRP irp;
  7033. PVOLUME_EXTENSION extension;
  7034. PLIST_ENTRY l, ll;
  7035. PVSP_DIFF_AREA_FILE diffAreaFile;
  7036. PVSP_DIFF_AREA_VOLUME diffAreaVolume;
  7037. PFILTER_EXTENSION f;
  7038. LIST_ENTRY listOfDiffAreaFilesToClose;
  7039. LIST_ENTRY listOfDeviceObjectsToDelete;
  7040. PVSP_CONTEXT context;
  7041. IoAcquireCancelSpinLock(&irql);
  7042. irp = Filter->FlushAndHoldIrp;
  7043. if (irp) {
  7044. irp->CancelIrql = irql;
  7045. IoSetCancelRoutine(irp, NULL);
  7046. VspCancelRoutine(Filter->DeviceObject, irp);
  7047. } else {
  7048. IoReleaseCancelSpinLock(irql);
  7049. }
  7050. VspReleaseWrites(Filter);
  7051. VspAcquire(Filter->Root);
  7052. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  7053. extension = Filter->PreparedSnapshot;
  7054. Filter->PreparedSnapshot = NULL;
  7055. KeReleaseSpinLock(&Filter->SpinLock, irql);
  7056. VspRelease(Filter->Root);
  7057. if (extension) {
  7058. VspCleanupInitialSnapshot(extension, TRUE);
  7059. }
  7060. KeWaitForSingleObject(&Filter->Root->ThreadsRefCountSemaphore, Executive,
  7061. KernelMode, FALSE, NULL);
  7062. if (Filter->Root->ThreadsRefCount) {
  7063. if (Filter->SnapshotsPresent) {
  7064. context = VspAllocateContext(Filter->Root);
  7065. if (context) {
  7066. context->Type = VSP_CONTEXT_TYPE_ERROR_LOG;
  7067. context->ErrorLog.Extension = NULL;
  7068. context->ErrorLog.DiffAreaFilter = Filter;
  7069. context->ErrorLog.SpecificIoStatus =
  7070. VS_ABORT_SNAPSHOT_VOLUME_REMOVED;
  7071. context->ErrorLog.FinalStatus = STATUS_SUCCESS;
  7072. context->ErrorLog.UniqueErrorValue = 0;
  7073. ObReferenceObject(Filter->DeviceObject);
  7074. VspLogErrorWorker(context);
  7075. }
  7076. }
  7077. VspDestroyAllSnapshots(Filter, NULL);
  7078. }
  7079. KeReleaseSemaphore(&Filter->Root->ThreadsRefCountSemaphore,
  7080. IO_NO_INCREMENT, 1, FALSE);
  7081. InitializeListHead(&listOfDiffAreaFilesToClose);
  7082. InitializeListHead(&listOfDeviceObjectsToDelete);
  7083. VspAcquire(Filter->Root);
  7084. if (!Filter->NotInFilterList) {
  7085. RemoveEntryList(&Filter->ListEntry);
  7086. Filter->NotInFilterList = TRUE;
  7087. }
  7088. while (!IsListEmpty(&Filter->DiffAreaVolumes)) {
  7089. l = RemoveHeadList(&Filter->DiffAreaVolumes);
  7090. diffAreaVolume = CONTAINING_RECORD(l, VSP_DIFF_AREA_VOLUME, ListEntry);
  7091. ExFreePool(diffAreaVolume);
  7092. }
  7093. for (l = Filter->Root->FilterList.Flink;
  7094. l != &Filter->Root->FilterList; l = l->Flink) {
  7095. f = CONTAINING_RECORD(l, FILTER_EXTENSION, ListEntry);
  7096. for (ll = f->DiffAreaVolumes.Flink;
  7097. ll != &f->DiffAreaVolumes; ll = ll->Flink) {
  7098. diffAreaVolume = CONTAINING_RECORD(ll, VSP_DIFF_AREA_VOLUME,
  7099. ListEntry);
  7100. if (diffAreaVolume->Filter == Filter) {
  7101. RemoveEntryList(ll);
  7102. ExFreePool(diffAreaVolume);
  7103. break;
  7104. }
  7105. }
  7106. }
  7107. while (!IsListEmpty(&Filter->DiffAreaFilesOnThisFilter)) {
  7108. l = Filter->DiffAreaFilesOnThisFilter.Flink;
  7109. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  7110. FilterListEntry);
  7111. f = diffAreaFile->Extension->Filter;
  7112. VspLogError(diffAreaFile->Extension, diffAreaFile->Filter,
  7113. VS_ABORT_SNAPSHOTS_DISMOUNT, STATUS_SUCCESS, 0);
  7114. VspAbortPreparedSnapshot(f, FALSE);
  7115. while (!IsListEmpty(&f->VolumeList)) {
  7116. VspDeleteOldestSnapshot(f, &listOfDiffAreaFilesToClose,
  7117. &listOfDeviceObjectsToDelete);
  7118. }
  7119. }
  7120. VspRelease(Filter->Root);
  7121. VspCloseDiffAreaFiles(&listOfDiffAreaFilesToClose,
  7122. &listOfDeviceObjectsToDelete);
  7123. }
  7124. NTSTATUS
  7125. VolSnapPower(
  7126. IN PDEVICE_OBJECT DeviceObject,
  7127. IN PIRP Irp
  7128. )
  7129. /*++
  7130. Routine Description:
  7131. This routine is the dispatch for IRP_MJ_POWER.
  7132. Arguments:
  7133. DeviceObject - Supplies the device object.
  7134. Irp - Supplies the IO request packet.
  7135. Return Value:
  7136. NTSTATUS
  7137. --*/
  7138. {
  7139. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  7140. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  7141. NTSTATUS status;
  7142. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  7143. PoStartNextPowerIrp(Irp);
  7144. IoSkipCurrentIrpStackLocation(Irp);
  7145. return PoCallDriver(filter->TargetObject, Irp);
  7146. }
  7147. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  7148. switch (irpSp->MinorFunction) {
  7149. case IRP_MN_WAIT_WAKE:
  7150. case IRP_MN_POWER_SEQUENCE:
  7151. case IRP_MN_SET_POWER:
  7152. case IRP_MN_QUERY_POWER:
  7153. status = STATUS_SUCCESS;
  7154. break;
  7155. default:
  7156. status = Irp->IoStatus.Status;
  7157. break;
  7158. }
  7159. Irp->IoStatus.Status = status;
  7160. PoStartNextPowerIrp(Irp);
  7161. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7162. return status;
  7163. }
  7164. NTSTATUS
  7165. VolSnapRead(
  7166. IN PDEVICE_OBJECT DeviceObject,
  7167. IN PIRP Irp
  7168. )
  7169. /*++
  7170. Routine Description:
  7171. This routine is the dispatch for IRP_MJ_READ.
  7172. Arguments:
  7173. DeviceObject - Supplies the device object.
  7174. Irp - Supplies the IO request packet.
  7175. Return Value:
  7176. NTSTATUS
  7177. --*/
  7178. {
  7179. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  7180. NTSTATUS status;
  7181. PVOLUME_EXTENSION extension;
  7182. KIRQL irql;
  7183. if (filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER) {
  7184. IoSkipCurrentIrpStackLocation(Irp);
  7185. return IoCallDriver(filter->TargetObject, Irp);
  7186. }
  7187. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  7188. extension = (PVOLUME_EXTENSION) filter;
  7189. filter = extension->Filter;
  7190. if (!extension->IsStarted) {
  7191. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  7192. Irp->IoStatus.Information = 0;
  7193. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7194. return STATUS_NO_SUCH_DEVICE;
  7195. }
  7196. status = VspIncrementVolumeRefCount(extension, Irp, NULL);
  7197. if (!NT_SUCCESS(status)) {
  7198. Irp->IoStatus.Status = status;
  7199. Irp->IoStatus.Information = 0;
  7200. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7201. return status;
  7202. }
  7203. if (status == STATUS_PENDING) {
  7204. return status;
  7205. }
  7206. IoMarkIrpPending(Irp);
  7207. KeAcquireSpinLock(&extension->SpinLock, &irql);
  7208. if (VspAreBitsSet(extension, Irp)) {
  7209. KeReleaseSpinLock(&extension->SpinLock, irql);
  7210. Irp->IoStatus.Status = STATUS_SUCCESS;
  7211. Irp->IoStatus.Information = IoGetCurrentIrpStackLocation(Irp)->
  7212. Parameters.Read.Length;
  7213. VspReadCompletionForReadSnapshot(DeviceObject, Irp, extension);
  7214. return STATUS_PENDING;
  7215. }
  7216. KeReleaseSpinLock(&extension->SpinLock, irql);
  7217. IoCopyCurrentIrpStackLocationToNext(Irp);
  7218. IoSetCompletionRoutine(Irp, VspReadCompletionForReadSnapshot,
  7219. extension, TRUE, TRUE, TRUE);
  7220. IoCallDriver(filter->TargetObject, Irp);
  7221. return STATUS_PENDING;
  7222. }
  7223. NTSTATUS
  7224. VspIncrementRefCount(
  7225. IN PFILTER_EXTENSION Filter,
  7226. IN PIRP Irp
  7227. )
  7228. {
  7229. KIRQL irql;
  7230. InterlockedIncrement(&Filter->RefCount);
  7231. if (!Filter->HoldIncomingWrites) {
  7232. return STATUS_SUCCESS;
  7233. }
  7234. VspDecrementRefCount(Filter);
  7235. KeAcquireSpinLock(&Filter->SpinLock, &irql);
  7236. if (!Filter->HoldIncomingWrites) {
  7237. InterlockedIncrement(&Filter->RefCount);
  7238. KeReleaseSpinLock(&Filter->SpinLock, irql);
  7239. return STATUS_SUCCESS;
  7240. }
  7241. IoMarkIrpPending(Irp);
  7242. InsertTailList(&Filter->HoldQueue, &Irp->Tail.Overlay.ListEntry);
  7243. KeReleaseSpinLock(&Filter->SpinLock, irql);
  7244. return STATUS_PENDING;
  7245. }
  7246. NTSTATUS
  7247. VspRefCountCompletionRoutine(
  7248. IN PDEVICE_OBJECT DeviceObject,
  7249. IN PIRP Irp,
  7250. IN PVOID Filter
  7251. )
  7252. {
  7253. VspDecrementRefCount((PFILTER_EXTENSION) Filter);
  7254. return STATUS_SUCCESS;
  7255. }
  7256. NTSTATUS
  7257. VolSnapWrite(
  7258. IN PDEVICE_OBJECT DeviceObject,
  7259. IN PIRP Irp
  7260. )
  7261. /*++
  7262. Routine Description:
  7263. This routine is the dispatch for IRP_MJ_WRITE.
  7264. Arguments:
  7265. DeviceObject - Supplies the device object.
  7266. Irp - Supplies the IO request packet.
  7267. Return Value:
  7268. NTSTATUS
  7269. --*/
  7270. {
  7271. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  7272. NTSTATUS status;
  7273. PVOLUME_EXTENSION extension;
  7274. KIRQL irql;
  7275. PLIST_ENTRY l, ll;
  7276. PVSP_DIFF_AREA_FILE diffAreaFile;
  7277. PIO_STACK_LOCATION nextSp;
  7278. PVSP_CONTEXT context;
  7279. PDO_EXTENSION rootExtension;
  7280. if (filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME) {
  7281. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  7282. Irp->IoStatus.Information = 0;
  7283. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7284. return STATUS_INVALID_DEVICE_REQUEST;
  7285. }
  7286. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  7287. IoMarkIrpPending(Irp);
  7288. status = VspIncrementRefCount(filter, Irp);
  7289. if (status == STATUS_PENDING) {
  7290. return status;
  7291. }
  7292. if (!filter->SnapshotsPresent) {
  7293. IoCopyCurrentIrpStackLocationToNext(Irp);
  7294. IoSetCompletionRoutine(Irp, VspRefCountCompletionRoutine, filter,
  7295. TRUE, TRUE, TRUE);
  7296. IoCallDriver(filter->TargetObject, Irp);
  7297. return STATUS_PENDING;
  7298. }
  7299. extension = CONTAINING_RECORD(filter->VolumeList.Blink,
  7300. VOLUME_EXTENSION, ListEntry);
  7301. KeAcquireSpinLock(&extension->SpinLock, &irql);
  7302. if (VspAreBitsSet(extension, Irp)) {
  7303. KeReleaseSpinLock(&extension->SpinLock, irql);
  7304. IoCopyCurrentIrpStackLocationToNext(Irp);
  7305. IoSetCompletionRoutine(Irp, VspRefCountCompletionRoutine, filter,
  7306. TRUE, TRUE, TRUE);
  7307. IoCallDriver(filter->TargetObject, Irp);
  7308. return STATUS_PENDING;
  7309. }
  7310. KeReleaseSpinLock(&extension->SpinLock, irql);
  7311. context = VspAllocateContext(extension->Root);
  7312. if (!context) {
  7313. rootExtension = extension->Root;
  7314. KeAcquireSpinLock(&rootExtension->ESpinLock, &irql);
  7315. if (rootExtension->EmergencyContextInUse) {
  7316. InsertTailList(&rootExtension->IrpWaitingList,
  7317. &Irp->Tail.Overlay.ListEntry);
  7318. if (!rootExtension->IrpWaitingListNeedsChecking) {
  7319. InterlockedExchange(
  7320. &rootExtension->IrpWaitingListNeedsChecking, TRUE);
  7321. }
  7322. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  7323. VspDecrementRefCount(filter);
  7324. return STATUS_PENDING;
  7325. }
  7326. rootExtension->EmergencyContextInUse = TRUE;
  7327. KeReleaseSpinLock(&rootExtension->ESpinLock, irql);
  7328. context = rootExtension->EmergencyContext;
  7329. }
  7330. for (l = extension->ListOfDiffAreaFiles.Flink;
  7331. l != &extension->ListOfDiffAreaFiles; l = l->Flink) {
  7332. diffAreaFile = CONTAINING_RECORD(l, VSP_DIFF_AREA_FILE,
  7333. VolumeListEntry);
  7334. status = VspIncrementRefCount(diffAreaFile->Filter, Irp);
  7335. if (status == STATUS_PENDING) {
  7336. break;
  7337. }
  7338. }
  7339. if (l != &extension->ListOfDiffAreaFiles) {
  7340. for (ll = extension->ListOfDiffAreaFiles.Flink; ll != l;
  7341. ll = ll->Flink) {
  7342. diffAreaFile = CONTAINING_RECORD(ll, VSP_DIFF_AREA_FILE,
  7343. VolumeListEntry);
  7344. VspDecrementRefCount(diffAreaFile->Filter);
  7345. }
  7346. VspFreeContext(extension->Root, context);
  7347. VspDecrementRefCount(filter);
  7348. return STATUS_PENDING;
  7349. }
  7350. nextSp = IoGetNextIrpStackLocation(Irp);
  7351. nextSp->Parameters.Write.Length = 1; // Use this for a ref count.
  7352. context->Type = VSP_CONTEXT_TYPE_WRITE_VOLUME;
  7353. context->WriteVolume.Extension = extension;
  7354. context->WriteVolume.Irp = Irp;
  7355. context->WriteVolume.RoundedStart = 0;
  7356. ExInitializeWorkItem(&context->WorkItem, VspWriteVolume, context);
  7357. VspAcquireNonPagedResource(extension, &context->WorkItem);
  7358. return STATUS_PENDING;
  7359. }
  7360. NTSTATUS
  7361. VolSnapCleanup(
  7362. IN PDEVICE_OBJECT DeviceObject,
  7363. IN PIRP Irp
  7364. )
  7365. /*++
  7366. Routine Description:
  7367. This routine is the dispatch for IRP_MJ_CLEANUP.
  7368. Arguments:
  7369. DeviceObject - Supplies the device object.
  7370. Irp - Supplies the IO request packet.
  7371. Return Value:
  7372. NTSTATUS
  7373. --*/
  7374. {
  7375. PFILTER_EXTENSION filter = (PFILTER_EXTENSION) DeviceObject->DeviceExtension;
  7376. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  7377. KEVENT event;
  7378. KIRQL irql;
  7379. PIRP irp;
  7380. PVSP_CONTEXT context;
  7381. if (filter->DeviceExtensionType == DEVICE_EXTENSION_VOLUME) {
  7382. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  7383. Irp->IoStatus.Information = 0;
  7384. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7385. return STATUS_INVALID_DEVICE_REQUEST;
  7386. }
  7387. ASSERT(filter->DeviceExtensionType == DEVICE_EXTENSION_FILTER);
  7388. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7389. IoCopyCurrentIrpStackLocationToNext(Irp);
  7390. IoSetCompletionRoutine(Irp, VspSignalCompletion, &event, TRUE, TRUE, TRUE);
  7391. IoCallDriver(filter->TargetObject, Irp);
  7392. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  7393. IoAcquireCancelSpinLock(&irql);
  7394. if (filter->FlushAndHoldIrp) {
  7395. irp = filter->FlushAndHoldIrp;
  7396. if (IoGetCurrentIrpStackLocation(irp)->FileObject ==
  7397. irpSp->FileObject) {
  7398. irp->CancelIrql = irql;
  7399. IoSetCancelRoutine(irp, NULL);
  7400. VspCancelRoutine(DeviceObject, irp);
  7401. } else {
  7402. IoReleaseCancelSpinLock(irql);
  7403. }
  7404. } else {
  7405. IoReleaseCancelSpinLock(irql);
  7406. }
  7407. IoAcquireCancelSpinLock(&irql);
  7408. if (filter->AutoCleanupFileObject == irpSp->FileObject) {
  7409. filter->AutoCleanupFileObject = NULL;
  7410. IoReleaseCancelSpinLock(irql);
  7411. if (!InterlockedExchange(&filter->DestroyAllSnapshotsPending, TRUE)) {
  7412. context = &filter->DestroyContext;
  7413. context->Type = VSP_CONTEXT_TYPE_FILTER;
  7414. context->Filter.Filter = filter;
  7415. ObReferenceObject(filter->DeviceObject);
  7416. ExInitializeWorkItem(&context->WorkItem,
  7417. VspDestroyAllSnapshotsWorker, context);
  7418. ExQueueWorkItem(&context->WorkItem, DelayedWorkQueue);
  7419. }
  7420. } else {
  7421. IoReleaseCancelSpinLock(irql);
  7422. }
  7423. Irp->IoStatus.Status = STATUS_SUCCESS;
  7424. Irp->IoStatus.Information = 0;
  7425. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7426. return STATUS_SUCCESS;
  7427. }
  7428. NTSTATUS
  7429. DriverEntry(
  7430. IN PDRIVER_OBJECT DriverObject,
  7431. IN PUNICODE_STRING RegistryPath
  7432. )
  7433. /*++
  7434. Routine Description:
  7435. This routine is called when the driver loads loads.
  7436. Arguments:
  7437. DriverObject - Supplies the driver object.
  7438. RegistryPath - Supplies the registry path.
  7439. Return Value:
  7440. NTSTATUS
  7441. --*/
  7442. {
  7443. ULONG i;
  7444. PDEVICE_OBJECT deviceObject;
  7445. NTSTATUS status;
  7446. PDO_EXTENSION rootExtension;
  7447. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  7448. DriverObject->MajorFunction[i] = VolSnapDefaultDispatch;
  7449. }
  7450. DriverObject->DriverExtension->AddDevice = VolSnapAddDevice;
  7451. DriverObject->MajorFunction[IRP_MJ_CREATE] = VolSnapCreate;
  7452. DriverObject->MajorFunction[IRP_MJ_READ] = VolSnapRead;
  7453. DriverObject->MajorFunction[IRP_MJ_WRITE] = VolSnapWrite;
  7454. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VolSnapDeviceControl;
  7455. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = VolSnapCleanup;
  7456. DriverObject->MajorFunction[IRP_MJ_PNP] = VolSnapPnp;
  7457. DriverObject->MajorFunction[IRP_MJ_POWER] = VolSnapPower;
  7458. status = IoAllocateDriverObjectExtension(DriverObject, VolSnapAddDevice,
  7459. sizeof(DO_EXTENSION),
  7460. (PVOID*) &rootExtension);
  7461. if (!NT_SUCCESS(status)) {
  7462. return status;
  7463. }
  7464. RtlZeroMemory(rootExtension, sizeof(DO_EXTENSION));
  7465. rootExtension->DriverObject = DriverObject;
  7466. InitializeListHead(&rootExtension->FilterList);
  7467. InitializeListHead(&rootExtension->HoldIrps);
  7468. KeInitializeTimer(&rootExtension->HoldTimer);
  7469. KeInitializeDpc(&rootExtension->HoldTimerDpc, VspFsTimerDpc,
  7470. rootExtension);
  7471. KeInitializeSemaphore(&rootExtension->Semaphore, 1, 1);
  7472. for (i = 0; i < NUMBER_OF_THREAD_POOLS; i++) {
  7473. InitializeListHead(&rootExtension->WorkerQueue[i]);
  7474. KeInitializeSemaphore(&rootExtension->WorkerSemaphore[i], 0, MAXLONG);
  7475. KeInitializeSpinLock(&rootExtension->SpinLock[i]);
  7476. }
  7477. KeInitializeSemaphore(&rootExtension->ThreadsRefCountSemaphore, 1, 1);
  7478. IoRegisterDriverReinitialization(DriverObject, VspDriverReinit,
  7479. rootExtension);
  7480. ExInitializeNPagedLookasideList(&rootExtension->ContextLookasideList,
  7481. NULL, NULL, 0, sizeof(VSP_CONTEXT),
  7482. VOLSNAP_TAG_CONTEXT, 32);
  7483. rootExtension->EmergencyContext = VspAllocateContext(rootExtension);
  7484. if (!rootExtension->EmergencyContext) {
  7485. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  7486. return STATUS_INSUFFICIENT_RESOURCES;
  7487. }
  7488. InitializeListHead(&rootExtension->IrpWaitingList);
  7489. KeInitializeSpinLock(&rootExtension->ESpinLock);
  7490. ExInitializeNPagedLookasideList(&rootExtension->TempTableEntryLookasideList,
  7491. NULL, NULL, 0, sizeof(RTL_BALANCED_LINKS) +
  7492. sizeof(TEMP_TRANSLATION_TABLE_ENTRY),
  7493. VOLSNAP_TAG_TEMP_TABLE, 32);
  7494. rootExtension->EmergencyTableEntry =
  7495. VspAllocateTempTableEntry(rootExtension);
  7496. if (!rootExtension->EmergencyTableEntry) {
  7497. ExFreeToNPagedLookasideList(&rootExtension->ContextLookasideList,
  7498. rootExtension->EmergencyContext);
  7499. ExDeleteNPagedLookasideList(
  7500. &rootExtension->TempTableEntryLookasideList);
  7501. ExDeleteNPagedLookasideList(&rootExtension->ContextLookasideList);
  7502. return STATUS_INSUFFICIENT_RESOURCES;
  7503. }
  7504. InitializeListHead(&rootExtension->WorkItemWaitingList);
  7505. rootExtension->RegistryPath.Length = RegistryPath->Length;
  7506. rootExtension->RegistryPath.MaximumLength =
  7507. rootExtension->RegistryPath.Length + sizeof(WCHAR);
  7508. rootExtension->RegistryPath.Buffer = (PWSTR)
  7509. ExAllocatePoolWithTag(PagedPool,
  7510. rootExtension->RegistryPath.MaximumLength,
  7511. VOLSNAP_TAG_SHORT_TERM);
  7512. if (rootExtension->RegistryPath.Buffer) {
  7513. RtlCopyMemory(rootExtension->RegistryPath.Buffer,
  7514. RegistryPath->Buffer, RegistryPath->Length);
  7515. rootExtension->RegistryPath.Buffer[RegistryPath->Length/
  7516. sizeof(WCHAR)] = 0;
  7517. }
  7518. InitializeListHead(&rootExtension->AdjustBitmapQueue);
  7519. return STATUS_SUCCESS;
  7520. }