Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1035 lines
25 KiB

  1. /*++
  2. Copyright (c) 1997, 1998 Microsoft Corporation
  3. Module Name:
  4. silog.c
  5. Abstract:
  6. Logging support for the single instance store
  7. Authors:
  8. Bill Bolosky, Summer, 1997
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "sip.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, SipComputeChecksum)
  16. #pragma alloc_text(PAGE, SipDrainLogFile)
  17. #endif // ALLOC_PRAGMA
  18. #if DBG
  19. VOID
  20. SipDBGDumpLogRecord(
  21. PSIS_LOG_HEADER header)
  22. {
  23. DbgPrint("log record: type %d, size %d, index 0x%x.0x%x\n",
  24. header->Type,
  25. header->Size,
  26. header->Index.HighPart,
  27. header->Index.LowPart);
  28. switch (header->Type) {
  29. }
  30. }
  31. #endif // DBG
  32. NTSTATUS
  33. SipMakeLogEntry(
  34. IN OUT PDEVICE_EXTENSION deviceExtension,
  35. IN USHORT type,
  36. IN USHORT size,
  37. IN PVOID record)
  38. /*++
  39. Routine Description:
  40. Make an entry in the SIS log. Creates the header, computes the
  41. checksum and then writes the log entry to the log file for this
  42. volume. A successful return guarantees that the log record is
  43. flushed to disk. This routine blocks.
  44. Arguments:
  45. deviceExtension - the device extension for the volume onto which we're
  46. logging.
  47. type - the type of the record we're writing.
  48. size - the size of the record we're writing (not counting the header)
  49. record - the log record data to write to the file.
  50. Return Value:
  51. Returns STATUS_SUCCESS or an error returned from the actual disk write.
  52. --*/
  53. {
  54. #if ENABLE_LOGGING
  55. PSIS_LOG_HEADER header = NULL;
  56. NTSTATUS status;
  57. PIRP irp;
  58. KEVENT event[1];
  59. PIO_STACK_LOCATION irpSp;
  60. BOOLEAN mutantAcquired = FALSE;
  61. IO_STATUS_BLOCK Iosb[1];
  62. if (deviceExtension->LogFileHandle == NULL) {
  63. SIS_MARK_POINT();
  64. return STATUS_DRIVER_INTERNAL_ERROR;
  65. }
  66. header = ExAllocatePoolWithTag(PagedPool, size + sizeof(SIS_LOG_HEADER), ' siS');
  67. if (!header) {
  68. SIS_MARK_POINT();
  69. status = STATUS_INSUFFICIENT_RESOURCES;
  70. goto done;
  71. }
  72. ASSERT(size % 4 == 0); // The log drain code relies on this
  73. header->Magic = SIS_LOG_HEADER_MAGIC;
  74. header->Type = type;
  75. header->Size = size + sizeof(SIS_LOG_HEADER);
  76. status = SipAllocateIndex(deviceExtension, &header->Index);
  77. if (!NT_SUCCESS(status)) {
  78. SIS_MARK_POINT_ULONG(status);
  79. return status;
  80. }
  81. //
  82. // Copy the log record into the newly alloated header+record area.
  83. //
  84. RtlMoveMemory(header + 1, record, size);
  85. //
  86. // Compute the checksum. We need to set the checksum field in the header
  87. // to 0 before we do the computation so that whatever's there isn't
  88. // part of the checksum (and then overwritten with the real checksum).
  89. //
  90. header->Checksum.QuadPart = 0;
  91. SipComputeChecksum(header, header->Size, &header->Checksum.QuadPart);
  92. //
  93. // Acquire the log mutant to serialize writing to the log file.
  94. //
  95. status = KeWaitForSingleObject(deviceExtension->LogFileMutant, Executive, KernelMode, FALSE, NULL);
  96. ASSERT(status == STATUS_SUCCESS);
  97. mutantAcquired = TRUE;
  98. ASSERT(deviceExtension->LogFileHandle != NULL && deviceExtension->LogFileObject != NULL); // Should have happened in phase 2 initialization
  99. //
  100. // Create an irp to do the write. We don't want to just use ZwWriteFile because we want to
  101. // avoid the context switch to the process where we hold the log handle.
  102. //
  103. irp = IoBuildAsynchronousFsdRequest(
  104. IRP_MJ_WRITE,
  105. deviceExtension->FileSystemDeviceObject,
  106. header,
  107. header->Size,
  108. &deviceExtension->LogWriteOffset,
  109. Iosb);
  110. if (!irp) {
  111. SIS_MARK_POINT();
  112. status = STATUS_INSUFFICIENT_RESOURCES;
  113. goto done;
  114. }
  115. irpSp = IoGetNextIrpStackLocation(irp);
  116. irpSp->FileObject = deviceExtension->LogFileObject;
  117. //
  118. // Initialize the event on which we'll wait for the write to complete.
  119. //
  120. KeInitializeEvent(event,NotificationEvent,FALSE);
  121. IoSetCompletionRoutine(
  122. irp,
  123. SiDeleteAndSetCompletion,
  124. event,
  125. TRUE,
  126. TRUE,
  127. TRUE);
  128. //
  129. // Make sure that this request is really write through all the way to the disk
  130. // medium.
  131. //
  132. irpSp->Flags |= SL_WRITE_THROUGH;
  133. status = IoCallDriver(deviceExtension->FileSystemDeviceObject, irp);
  134. // At this point, we have released the mutant in the complete
  135. // routine.
  136. #if DBG
  137. irp = NULL; irpSp = NULL; // The completion routine may have already deallocated the irp.
  138. #endif // DBG
  139. if (STATUS_PENDING == status) {
  140. status = KeWaitForSingleObject(event,Executive,KernelMode,FALSE,NULL);
  141. ASSERT(status == STATUS_SUCCESS);
  142. status = Iosb->Status;
  143. }
  144. if (!NT_SUCCESS(status)) {
  145. #if DBG
  146. DbgPrint("SiMakeLogEntry: Log entry failed after write wait, 0x%x\n",status);
  147. #endif // DBG
  148. SIS_MARK_POINT_ULONG(status);
  149. goto done;
  150. } else {
  151. ASSERT(Iosb->Information == header->Size);
  152. deviceExtension->LogWriteOffset.QuadPart += header->Size;
  153. }
  154. done:
  155. if (header != NULL) {
  156. ExFreePool(header);
  157. }
  158. if (mutantAcquired) {
  159. KeReleaseMutant(
  160. deviceExtension->LogFileMutant,
  161. IO_NO_INCREMENT,
  162. FALSE,
  163. FALSE);
  164. }
  165. return status;
  166. #else // ENABLE_LOGGING
  167. UNREFERENCED_PARAMETER( deviceExtension );
  168. UNREFERENCED_PARAMETER( type );
  169. UNREFERENCED_PARAMETER( size );
  170. UNREFERENCED_PARAMETER( record );
  171. return STATUS_SUCCESS;
  172. #endif // ENABLE_LOGGING
  173. }
  174. VOID
  175. SipComputeChecksum(
  176. IN PVOID buffer,
  177. IN ULONG size,
  178. IN OUT PLONGLONG checksum)
  179. /*++
  180. Routine Description:
  181. Compute a checksum for a buffer. We use the "131 hash," which
  182. work by keeping a 64 bit running total, and for each 32 bits of
  183. data multiplying the 64 bits by 131 and adding in the next 32
  184. bits. Must be called at PASSIVE_LEVEL, and all aruments
  185. may be pagable.
  186. Arguments:
  187. buffer - pointer to the data to be checksummed
  188. size - size of the data to be checksummed
  189. checksum - pointer to large integer to receive the checksum. This
  190. may be within the buffer, and SipComputeChecksum guarantees that
  191. the initial value will be used in computing the checksum.
  192. Return Value:
  193. void
  194. --*/
  195. {
  196. LONGLONG runningTotal;
  197. ULONG *ptr = (unsigned *)buffer;
  198. ULONG bytesRemaining = size;
  199. PAGED_CODE();
  200. //
  201. // NB: code in volume check assumes that the checksum of the empty bit string is
  202. // 0. If this is ceases to be true, be sure to fix the code there.
  203. //
  204. runningTotal = *checksum;
  205. while (bytesRemaining >= sizeof(*ptr)) {
  206. runningTotal = runningTotal * 131 + *ptr;
  207. bytesRemaining -= sizeof(*ptr);
  208. ptr++;
  209. }
  210. if (bytesRemaining > 0) {
  211. ULONG extra;
  212. ASSERT(bytesRemaining < sizeof (ULONG));
  213. extra = 0;
  214. RtlMoveMemory(&extra, ptr, bytesRemaining);
  215. runningTotal = runningTotal * 131 + extra;
  216. }
  217. *checksum = runningTotal;
  218. }
  219. NTSTATUS
  220. SipOpenLogFile(
  221. IN OUT PDEVICE_EXTENSION deviceExtension)
  222. /*++
  223. Routine Description:
  224. Open the log file for this volume. Must not already be opened. Must be called
  225. exactly once per volume, and must be called on a worker thread.
  226. Arguments:
  227. deviceExtension - the device extension for the volume for which we're
  228. to open the log file.
  229. Return Value:
  230. Returns status of the open.
  231. --*/
  232. {
  233. #if ENABLE_LOGGING
  234. NTSTATUS status;
  235. OBJECT_ATTRIBUTES Obja[1];
  236. UNICODE_STRING fileName;
  237. IO_STATUS_BLOCK Iosb[1];
  238. SIS_MARK_POINT();
  239. ASSERT(deviceExtension->LogFileHandle == NULL);
  240. ASSERT(deviceExtension->LogFileObject == NULL);
  241. fileName.Length = 0;
  242. fileName.MaximumLength = deviceExtension->CommonStorePathname.Length + LOG_FILE_NAME_LEN;
  243. fileName.Buffer = ExAllocatePoolWithTag(PagedPool, fileName.MaximumLength, ' siS');
  244. if (!fileName.Buffer) {
  245. #if DBG
  246. DbgPrint("SIS: SipOpenLogFile: unable to allocate filename buffer. We're toast.\n");
  247. #endif // DBG
  248. SIS_MARK_POINT();
  249. status = STATUS_INSUFFICIENT_RESOURCES;
  250. goto done;
  251. }
  252. RtlCopyUnicodeString(
  253. &fileName,
  254. &deviceExtension->CommonStorePathname);
  255. ASSERT(fileName.Length == deviceExtension->CommonStorePathname.Length);
  256. status = RtlAppendUnicodeToString(
  257. &fileName,
  258. LOG_FILE_NAME);
  259. ASSERT(status == STATUS_SUCCESS);
  260. ASSERT(fileName.Length == deviceExtension->CommonStorePathname.Length + LOG_FILE_NAME_LEN); // or else you changed LOG_FILE_NAME without changing LOG_FILE_NAME_LEN
  261. InitializeObjectAttributes(
  262. Obja,
  263. &fileName,
  264. OBJ_CASE_INSENSITIVE,
  265. NULL,
  266. NULL);
  267. status = NtCreateFile(
  268. &deviceExtension->LogFileHandle,
  269. GENERIC_READ | GENERIC_WRITE,
  270. Obja,
  271. Iosb,
  272. NULL, // allocation size
  273. FILE_ATTRIBUTE_NORMAL,
  274. FILE_SHARE_READ, // share access
  275. FILE_OPEN_IF,
  276. FILE_WRITE_THROUGH,
  277. NULL, // EA buffer
  278. 0); // EA length
  279. if (!NT_SUCCESS(status)) {
  280. #if DBG
  281. DbgPrint("SipOpenLogFile: ZwCreate failed, 0x%x\n",status);
  282. #endif // DBG
  283. SIS_MARK_POINT_ULONG(status);
  284. goto done;
  285. } else {
  286. status = ObReferenceObjectByHandle(
  287. deviceExtension->LogFileHandle,
  288. FILE_READ_DATA | FILE_WRITE_DATA,
  289. *IoFileObjectType,
  290. KernelMode,
  291. &deviceExtension->LogFileObject,
  292. NULL);
  293. if (!NT_SUCCESS(status)) {
  294. SIS_MARK_POINT_ULONG(status);
  295. #if DBG
  296. DbgPrint("SipOpenLogFile: ObReferenceObjectByHandle failed, 0x%x\n",status);
  297. #endif // DBG
  298. NtClose(deviceExtension->LogFileHandle);
  299. deviceExtension->LogFileHandle = NULL;
  300. goto done;
  301. }
  302. }
  303. SipDrainLogFile(deviceExtension);
  304. SIS_MARK_POINT();
  305. done:
  306. if (fileName.Buffer) {
  307. ExFreePool(fileName.Buffer);
  308. #if DBG
  309. fileName.Buffer = NULL;
  310. #endif // DBG
  311. }
  312. return status;
  313. #undef LOG_FILE_NAME
  314. #undef LOG_FILE_NAME_LEN
  315. #else // ENABLE_LOGGING
  316. UNREFERENCED_PARAMETER( deviceExtension );
  317. return STATUS_SUCCESS;
  318. #endif // ENABLE_LOGGING
  319. }
  320. VOID
  321. SipDrainLogFile(
  322. PDEVICE_EXTENSION deviceExtension)
  323. /*++
  324. Routine Description:
  325. Drain the log file for this volume and assure that all of the operations in it
  326. have happened or not happened atomically.
  327. Arguments:
  328. deviceExtension - the device extension for the volume for which we're
  329. to drain the log file.
  330. Return Value:
  331. VOID
  332. --*/
  333. {
  334. #if ENABLE_LOGGING
  335. FILE_ALLOCATED_RANGE_BUFFER inArb[1];
  336. FILE_ALLOCATED_RANGE_BUFFER outArb[1];
  337. NTSTATUS status;
  338. HANDLE eventHandle = NULL;
  339. PKEVENT event = NULL;
  340. IO_STATUS_BLOCK Iosb[1];
  341. LARGE_INTEGER fileOffset;
  342. PCHAR buffer = NULL;
  343. #define BUFFER_SIZE 16384
  344. PULONG bufferPointer;
  345. PSIS_LOG_HEADER logHeader;
  346. LARGE_INTEGER stashedChecksum, computedChecksum;
  347. BOOLEAN clearLog = FALSE;
  348. PAGED_CODE();
  349. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  350. buffer = ExAllocatePoolWithTag(PagedPool, BUFFER_SIZE, ' siS');
  351. if (NULL == buffer) {
  352. SIS_MARK_POINT();
  353. goto done;
  354. }
  355. status = SipCreateEvent(
  356. NotificationEvent,
  357. &eventHandle,
  358. &event);
  359. if (!NT_SUCCESS(status)) {
  360. SIS_MARK_POINT_ULONG(status);
  361. goto done;
  362. }
  363. #if DBG
  364. deviceExtension->LogWriteOffset.QuadPart = -1;
  365. #endif // DBG
  366. //
  367. // Figure out where the log file starts.
  368. //
  369. inArb->FileOffset.QuadPart = 0;
  370. inArb->Length.QuadPart = MAXLONGLONG;
  371. status = NtFsControlFile(
  372. deviceExtension->LogFileHandle,
  373. eventHandle,
  374. NULL, // APC routine
  375. NULL, // ApcContext
  376. Iosb,
  377. FSCTL_QUERY_ALLOCATED_RANGES,
  378. inArb,
  379. sizeof(FILE_ALLOCATED_RANGE_BUFFER),
  380. outArb,
  381. sizeof(FILE_ALLOCATED_RANGE_BUFFER));
  382. if (STATUS_PENDING == status) {
  383. status = KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  384. ASSERT(STATUS_SUCCESS == status); // must succeed because Iosb is on the stack
  385. status = Iosb->Status;
  386. }
  387. if (!NT_SUCCESS(status)) {
  388. SIS_MARK_POINT_ULONG(status);
  389. clearLog = TRUE;
  390. goto done;
  391. }
  392. if (0 == Iosb->Information) {
  393. //
  394. // The file is empty. We're done.
  395. //
  396. SIS_MARK_POINT_ULONG(deviceExtension);
  397. clearLog = TRUE;
  398. goto done;
  399. }
  400. //
  401. // Skip over any leading unallocated range, starting at the beginning of the first allocated range.
  402. //
  403. fileOffset = outArb->FileOffset;
  404. //
  405. // Find the first log entry by searching for the first occurance of the magic number.
  406. //
  407. for (;;) {
  408. KeClearEvent(event);
  409. status = ZwReadFile(
  410. deviceExtension->LogFileHandle,
  411. eventHandle,
  412. NULL, // APC routine
  413. NULL, // APC context
  414. Iosb,
  415. buffer,
  416. BUFFER_SIZE,
  417. &fileOffset,
  418. NULL); // key
  419. if (STATUS_PENDING == status) {
  420. status = KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  421. ASSERT(STATUS_SUCCESS == status); // must succeed because Iosb is on the stack
  422. status = Iosb->Status;
  423. }
  424. if (!NT_SUCCESS(status)) {
  425. SIS_MARK_POINT_ULONG(status);
  426. clearLog = TRUE;
  427. goto done;
  428. }
  429. if (0 == Iosb->Information) {
  430. SIS_MARK_POINT();
  431. clearLog = TRUE;
  432. goto done;
  433. }
  434. //
  435. // Cruise through the buffer looking for the magic number
  436. //
  437. for (bufferPointer = (PULONG)buffer; bufferPointer < ((PULONG)buffer) + BUFFER_SIZE/sizeof(ULONG); bufferPointer++) {
  438. if (SIS_LOG_HEADER_MAGIC == *bufferPointer) {
  439. fileOffset.QuadPart += (bufferPointer - ((PULONG)buffer)) * sizeof(ULONG);
  440. goto startLogReading;
  441. }
  442. }
  443. //
  444. // We didn't find it, read in the next chunk.
  445. //
  446. fileOffset.QuadPart += BUFFER_SIZE;
  447. }
  448. startLogReading:
  449. for (;;) {
  450. KeClearEvent(event);
  451. status = ZwReadFile(
  452. deviceExtension->LogFileHandle,
  453. eventHandle,
  454. NULL, // APC routine
  455. NULL, // APC context
  456. Iosb,
  457. buffer,
  458. BUFFER_SIZE,
  459. &fileOffset,
  460. NULL); // key
  461. if (STATUS_PENDING == status) {
  462. status = KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  463. ASSERT(STATUS_SUCCESS == status); // must succeed because Iosb is on the stack
  464. status = Iosb->Status;
  465. }
  466. if (!NT_SUCCESS(status)) {
  467. SIS_MARK_POINT_ULONG(status);
  468. deviceExtension->LogWriteOffset = fileOffset;
  469. goto done;
  470. }
  471. if (0 == Iosb->Information) {
  472. SIS_MARK_POINT();
  473. deviceExtension->LogWriteOffset = fileOffset;
  474. goto done;
  475. }
  476. ASSERT(Iosb->Information <= BUFFER_SIZE);
  477. logHeader = (PSIS_LOG_HEADER)buffer;
  478. while ((((PCHAR)logHeader) - buffer) + sizeof(SIS_LOG_HEADER) <= Iosb->Information) {
  479. //
  480. // We know that we've got enough space for the log header.
  481. //
  482. //
  483. // Check the header to see if it looks valid (ie., if it's got a good magic
  484. // number).
  485. //
  486. if (SIS_LOG_HEADER_MAGIC != logHeader->Magic) {
  487. //
  488. // This log record is corrupt. Start writing the new log records here, and
  489. // punt the readback.
  490. //
  491. SIS_MARK_POINT();
  492. deviceExtension->LogWriteOffset.QuadPart = fileOffset.QuadPart + (((PCHAR)logHeader) - buffer);
  493. goto done;
  494. }
  495. //
  496. // See if we have enough space for the whole record.
  497. //
  498. if (((ULONG)(((PCHAR)logHeader - buffer) + logHeader->Size)) > Iosb->Information) {
  499. if (logHeader->Size > BUFFER_SIZE) {
  500. //
  501. // The log is corrupt. Punt reading it.
  502. //
  503. SIS_MARK_POINT();
  504. deviceExtension->LogWriteOffset.QuadPart = fileOffset.QuadPart + (((PCHAR)logHeader) - buffer);
  505. goto done;
  506. }
  507. //
  508. // The log record isn't contained entirely within the buffer we've read. Advance the buffer.
  509. //
  510. break;
  511. }
  512. //
  513. // We've got a whole log record. Process it.
  514. //
  515. //
  516. // Make sure that the log record checkum matches. First, we have to stash the checksum out of
  517. // the header and then set the header space to 0, because that's what it was when the checksum
  518. // was computed in the first place.
  519. //
  520. stashedChecksum = logHeader->Checksum;
  521. logHeader->Checksum.QuadPart = 0;
  522. computedChecksum.QuadPart = 0;
  523. SipComputeChecksum(logHeader, logHeader->Size, &computedChecksum.QuadPart);
  524. if (computedChecksum.QuadPart != stashedChecksum.QuadPart) {
  525. //
  526. // eventlog an error.
  527. //
  528. #if DBG
  529. DbgPrint("SIS: SipDrainLogFile: log record checksum doesn't match, 0x%x.0x%x != 0x%x.0x%x\n",
  530. computedChecksum.HighPart,computedChecksum.LowPart,
  531. stashedChecksum.HighPart,stashedChecksum.LowPart);
  532. #endif // DBG
  533. deviceExtension->LogWriteOffset.QuadPart = fileOffset.QuadPart + (((PCHAR)logHeader) - buffer);
  534. goto done;
  535. }
  536. //
  537. // The log record looks good. Process it.
  538. //
  539. switch (logHeader->Type) {
  540. case SIS_LOG_TYPE_REFCOUNT_UPDATE: {
  541. PSIS_LOG_REFCOUNT_UPDATE refcountLogRecord = (PSIS_LOG_REFCOUNT_UPDATE)(logHeader + 1);
  542. SipProcessRefcountUpdateLogRecord(deviceExtension,refcountLogRecord);
  543. /*BJB*/ DbgPrint("SIS: SipDrainLog: RC update UT %d, LF NTFS id 0x%x.0x%x, LI 0x%x.0x%x, CSid <whatever>\n",
  544. refcountLogRecord->UpdateType,refcountLogRecord->LinkFileNtfsId.HighPart,
  545. refcountLogRecord->LinkFileNtfsId.LowPart,refcountLogRecord->LinkIndex.HighPart,
  546. refcountLogRecord->LinkIndex.LowPart);
  547. break;
  548. }
  549. default: {
  550. #if DBG
  551. DbgPrint("SIS: SipDrainLog: Unknown log record type %d, ignoring.\n",logHeader->Type);
  552. #endif // DBG
  553. break;
  554. }
  555. }
  556. logHeader = (PSIS_LOG_HEADER)(((PCHAR)logHeader) + logHeader->Size);
  557. }
  558. //
  559. // Advance within the file to the beginning of the next record, loop around and reread the buffer.
  560. //
  561. fileOffset.QuadPart += ((PCHAR)logHeader) - buffer;
  562. }
  563. done:
  564. if (clearLog) {
  565. SipClearLogFile(deviceExtension);
  566. }
  567. if (NULL != event) {
  568. ObDereferenceObject(event);
  569. event = NULL;
  570. }
  571. if (NULL != eventHandle) {
  572. NtClose(eventHandle);
  573. eventHandle = NULL;
  574. }
  575. if (NULL != buffer) {
  576. ExFreePool(buffer);
  577. }
  578. ASSERT(-1 != deviceExtension->LogWriteOffset.QuadPart); // This should have been reset somewhere here.
  579. #undef BUFFER_SIZE
  580. #else
  581. UNREFERENCED_PARAMETER( deviceExtension );
  582. #endif // ENABLE_LOGGING
  583. }
  584. VOID
  585. SipClearLogFile(
  586. PDEVICE_EXTENSION deviceExtension)
  587. /*++
  588. Routine Description:
  589. Clear out the contents of the log file. Must be called during initialization
  590. when we're guaranteed to be serialized. Also sets the log file sparse.
  591. Arguments:
  592. deviceExtension - the device extension for the volume for which we're
  593. to clear the log file.
  594. Return Value:
  595. VOID
  596. --*/
  597. {
  598. #if ENABLE_LOGGING
  599. FILE_END_OF_FILE_INFORMATION eofInfo[1];
  600. LARGE_INTEGER byteOffset;
  601. NTSTATUS status;
  602. IO_STATUS_BLOCK Iosb[1];
  603. ASSERT(NULL != deviceExtension->LogFileObject);
  604. eofInfo->EndOfFile.QuadPart = 0;
  605. status = SipSetInformationFile(
  606. deviceExtension->LogFileObject,
  607. deviceExtension->DeviceObject,
  608. FileEndOfFileInformation,
  609. sizeof(FILE_END_OF_FILE_INFORMATION),
  610. eofInfo);
  611. if (!NT_SUCCESS(status)) {
  612. SIS_MARK_POINT_ULONG(status);
  613. #if DBG
  614. DbgPrint("SipClearLogFile: unable to set EOF to 0, status 0x%x\n",status);
  615. #endif // DBG
  616. return;
  617. }
  618. deviceExtension->LogWriteOffset.QuadPart = 0;
  619. status = SipFsControlFile(
  620. deviceExtension->LogFileObject,
  621. deviceExtension->DeviceObject,
  622. FSCTL_SET_SPARSE,
  623. NULL, // input buffer
  624. 0, // input buffer length
  625. NULL, // output buffer
  626. 0, // output buffer length
  627. NULL); // returned output buffer length
  628. #if DBG
  629. if (!NT_SUCCESS(status)) {
  630. SIS_MARK_POINT_ULONG(status);
  631. DbgPrint("SIS: SipClearLogFile: set sparse failed 0x%x\n",status);
  632. }
  633. #endif // DBG
  634. #else
  635. UNREFERENCED_PARAMETER( deviceExtension );
  636. #endif // ENABLE_LOGGING
  637. }
  638. #if ENABLE_LOGGING
  639. VOID
  640. SipAcquireLog(
  641. IN OUT PDEVICE_EXTENSION deviceExtension)
  642. {
  643. NTSTATUS status;
  644. status = KeWaitForSingleObject(deviceExtension->LogFileMutant, Executive, KernelMode, FALSE, NULL);
  645. ASSERT(status == STATUS_SUCCESS || status == STATUS_ABANDONED);
  646. }
  647. VOID
  648. SipReleaseLog(
  649. IN OUT PDEVICE_EXTENSION deviceExtension)
  650. {
  651. KeReleaseMutant(deviceExtension->LogFileMutant, IO_NO_INCREMENT, TRUE, FALSE);
  652. }
  653. typedef struct _TRIM_ENTRY {
  654. HANDLE logHandle;
  655. LARGE_INTEGER firstValidAddress;
  656. struct _TRIM_ENTRY *next;
  657. } TRIM_ENTRY, *PTRIM_ENTRY;
  658. HANDLE trimEventHandle = NULL;
  659. PKEVENT trimEvent = NULL;
  660. #endif // ENABLE_LOGGING
  661. VOID
  662. SiTrimLogs(
  663. IN PVOID parameter)
  664. /*++
  665. Routine Description:
  666. Run through the list of SIS volumes on this system, and trim the log files
  667. for each of them. This function should be called with a period greater than
  668. the longest time we expect log entries to be meaningful.
  669. Note: this routine is NOT thread safe; it can only be called once at a time.
  670. Since it reschedules itself, this should not be an issue.
  671. Arguments:
  672. the parameter is ignored
  673. Return Value:
  674. none
  675. --*/
  676. {
  677. #if ENABLE_LOGGING
  678. KIRQL OldIrql;
  679. PTRIM_ENTRY trimEntries = NULL;
  680. PDEVICE_EXTENSION deviceExtension;
  681. NTSTATUS status;
  682. FILE_ZERO_DATA_INFORMATION zeroDataInfo[1];
  683. IO_STATUS_BLOCK Iosb[1];
  684. LARGE_INTEGER dueTime;
  685. UNREFERENCED_PARAMETER(parameter);
  686. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  687. SIS_MARK_POINT();
  688. if (NULL == trimEventHandle) {
  689. status = SipCreateEvent(
  690. SynchronizationEvent,
  691. &trimEventHandle,
  692. &trimEvent);
  693. if (!NT_SUCCESS(status)) {
  694. SIS_MARK_POINT_ULONG(status);
  695. #if DBG
  696. DbgPrint("SIS: SipTrimLogs: can't allocate event, 0x%x\n",status);
  697. #endif // DBG
  698. goto done;
  699. }
  700. }
  701. //
  702. // First cruise the device extensions and build up a list of trim entries for them.
  703. // We need to do it this way (rather than running the list of device extensions directly)
  704. // because we need to handle the case where a volume is dismounted while we're in progress.
  705. // If it happens, then we'll have an invalid LogFileHandle, which will cause an error return
  706. // from the fsctl, which we'll ignore.
  707. //
  708. KeAcquireSpinLock(deviceExtensionListLock, &OldIrql);
  709. for (deviceExtension = deviceExtensionListHead->Next;
  710. deviceExtension != deviceExtensionListHead;
  711. deviceExtension = deviceExtension->Next) {
  712. if (deviceExtension->Phase2InitializationComplete && (NULL != deviceExtension->LogFileHandle)) {
  713. //
  714. // This is a device with a log file. Make a new trim entry for it.
  715. //
  716. PTRIM_ENTRY newEntry = ExAllocatePoolWithTag(NonPagedPool, sizeof(TRIM_ENTRY), ' siS');
  717. if (NULL == newEntry) {
  718. //
  719. // Just punt the rest of the volumes.
  720. //
  721. break;
  722. }
  723. newEntry->next = trimEntries;
  724. trimEntries = newEntry;
  725. newEntry->firstValidAddress = deviceExtension->PreviousLogWriteOffset;
  726. newEntry->logHandle = deviceExtension->LogFileHandle;
  727. //
  728. // Now update the device extension so that we'll trim to the current pointer on the
  729. // next pass.
  730. //
  731. deviceExtension->PreviousLogWriteOffset = deviceExtension->LogWriteOffset;
  732. }
  733. }
  734. KeReleaseSpinLock(deviceExtensionListLock, OldIrql);
  735. //
  736. // Now we're back at PASSIVE_LEVEL. Cruise the trim entries and truncate each log file as appropriate.
  737. //
  738. zeroDataInfo->FileOffset.QuadPart = 0;
  739. while (NULL != trimEntries) {
  740. PTRIM_ENTRY thisEntry;
  741. #if DBG
  742. if (BJBDebug & 0x20000) {
  743. DbgPrint("SIS: SipTrimLogs: trimming log with LFH 0x%x.\n",trimEntries->logHandle);
  744. }
  745. #endif // DBG
  746. zeroDataInfo->BeyondFinalZero = trimEntries->firstValidAddress;
  747. status = ZwFsControlFile(
  748. trimEntries->logHandle,
  749. trimEventHandle,
  750. NULL, // APC routine
  751. NULL, // APC context
  752. Iosb,
  753. FSCTL_SET_ZERO_DATA,
  754. zeroDataInfo,
  755. sizeof(FILE_ZERO_DATA_INFORMATION),
  756. NULL,
  757. 0);
  758. if (STATUS_PENDING == status) {
  759. status = KeWaitForSingleObject(trimEvent, Executive, KernelMode, FALSE, NULL);
  760. ASSERT(STATUS_SUCCESS == status); // Iosb is on the stack, so we can't let this fail
  761. status = Iosb->Status;
  762. }
  763. #if DBG
  764. if (!NT_SUCCESS(status)) {
  765. SIS_MARK_POINT_ULONG(status);
  766. DbgPrint("SIS: SipTrimLogs: FSCTL_ZERO_DATA failed, 0x%x\n",status);
  767. }
  768. #endif // DBG
  769. thisEntry = trimEntries;
  770. trimEntries = thisEntry->next;
  771. ExFreePool(thisEntry);
  772. }
  773. //
  774. // We've trimmed every log file in the system. Rechedule ourselves.
  775. //
  776. done:
  777. dueTime.QuadPart = LOG_TRIM_TIMER_INTERVAL;
  778. KeSetTimerEx(
  779. LogTrimTimer,
  780. dueTime,
  781. 0,
  782. LogTrimDpc);
  783. return;
  784. #else // ENABLE_LOGGING
  785. UNREFERENCED_PARAMETER( parameter );
  786. #endif // ENABLE_LOGGING
  787. }
  788. VOID
  789. SiLogTrimDpcRoutine(
  790. IN PKDPC dpc,
  791. IN PVOID context,
  792. IN PVOID systemArg1,
  793. IN PVOID systemArg2)
  794. {
  795. #if ENABLE_LOGGING
  796. ExQueueWorkItem(LogTrimWorkItem,DelayedWorkQueue);
  797. #if DBG
  798. if (BJBDebug & 0x20000) {
  799. DbgPrint("SIS: LogTrimDpcRoutine: queued up log trim.\n");
  800. }
  801. #endif // DBG
  802. #else // ENABLE_LOGGING
  803. UNREFERENCED_PARAMETER( dpc );
  804. UNREFERENCED_PARAMETER( context );
  805. UNREFERENCED_PARAMETER( systemArg1 );
  806. UNREFERENCED_PARAMETER( systemArg2 );
  807. #endif // ENABLE_LOGGING
  808. }