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.

1353 lines
35 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. filecache.c
  5. Abstract:
  6. This module implements the open file handle cache.
  7. Author:
  8. Keith Moore (keithmo) 21-Aug-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Private constants.
  14. //
  15. //
  16. // Private types.
  17. //
  18. //
  19. // Private prototypes.
  20. //
  21. NTSTATUS
  22. UlpRestartReadFileEntry(
  23. IN PDEVICE_OBJECT pDeviceObject,
  24. IN PIRP pIrp,
  25. IN PVOID pContext
  26. );
  27. NTSTATUS
  28. UlpRestartReadCompleteFileEntry(
  29. IN PDEVICE_OBJECT pDeviceObject,
  30. IN PIRP pIrp,
  31. IN PVOID pContext
  32. );
  33. //
  34. // Private globals.
  35. //
  36. #ifdef ALLOC_PRAGMA
  37. #pragma alloc_text( INIT, InitializeFileCache )
  38. #pragma alloc_text( PAGE, TerminateFileCache )
  39. #pragma alloc_text( PAGE, UlCreateFileEntry )
  40. #pragma alloc_text( PAGE, UlFailMdlReadDev )
  41. #pragma alloc_text( PAGE, UlFailMdlReadCompleteDev )
  42. #pragma alloc_text( PAGE, UlReadFileEntry )
  43. #pragma alloc_text( PAGE, UlReadFileEntryFast )
  44. #pragma alloc_text( PAGE, UlReadCompleteFileEntry )
  45. #pragma alloc_text( PAGE, UlReadCompleteFileEntryFast )
  46. #endif // ALLOC_PRAGMA
  47. #if 0
  48. NOT PAGEABLE -- UlpRestartReadFileEntry
  49. NOT PAGEABLE -- UlpRestartReadCompleteFileEntry
  50. #endif
  51. //
  52. // Public functions.
  53. //
  54. /***************************************************************************++
  55. Routine Description:
  56. Performs global initialization of the open file cache.
  57. Arguments:
  58. None.
  59. Return Value:
  60. NTSTATUS - Completion status.
  61. --***************************************************************************/
  62. NTSTATUS
  63. InitializeFileCache(
  64. VOID
  65. )
  66. {
  67. return STATUS_SUCCESS; // NYI
  68. } // InitializeFileCache
  69. /***************************************************************************++
  70. Routine Description:
  71. Performs global termination of the open file cache.
  72. Arguments:
  73. None.
  74. Return Value:
  75. None.
  76. --***************************************************************************/
  77. VOID
  78. TerminateFileCache(
  79. VOID
  80. )
  81. {
  82. } // TerminateFileCache
  83. /***************************************************************************++
  84. Routine Description:
  85. Creates a new file entry for the specified file.
  86. Arguments:
  87. FileHandle - The file handle.
  88. pFileCacheEntry - Receives the newly created file cache entry if
  89. successful.
  90. Return Value:
  91. NTSTATUS - Completion status.
  92. --***************************************************************************/
  93. NTSTATUS
  94. UlCreateFileEntry(
  95. IN HANDLE FileHandle,
  96. IN OUT PUL_FILE_CACHE_ENTRY pFileCacheEntry
  97. )
  98. {
  99. NTSTATUS Status;
  100. PFILE_OBJECT pFileObject;
  101. IO_STATUS_BLOCK IoStatusBlock;
  102. PFAST_IO_DISPATCH pFastIoDispatch;
  103. FILE_STANDARD_INFORMATION FileInfo;
  104. FILE_FS_SIZE_INFORMATION SizeInfo;
  105. //
  106. // Sanity check.
  107. //
  108. PAGED_CODE();
  109. //
  110. // Setup locals so we know how to cleanup on exit.
  111. //
  112. pFileObject = NULL;
  113. Status = STATUS_SUCCESS;
  114. RtlZeroMemory( pFileCacheEntry, sizeof(*pFileCacheEntry) );
  115. pFileCacheEntry->Signature = UL_FILE_CACHE_ENTRY_SIGNATURE;
  116. UlTrace(FILE_CACHE, (
  117. "UlCreateFileEntry: handle %p\n",
  118. (PVOID) FileHandle
  119. ));
  120. //
  121. // Get a referenced pointer to the file object.
  122. //
  123. Status = ObReferenceObjectByHandle(
  124. FileHandle, // Handle
  125. FILE_READ_ACCESS, // DesiredAccess
  126. *IoFileObjectType, // ObjectType
  127. UserMode, // AccessMode
  128. (PVOID *) &pFileObject, // Object
  129. NULL // HandleInformation
  130. );
  131. if (NT_SUCCESS(Status) == FALSE)
  132. goto end;
  133. pFileCacheEntry->pFileObject = pFileObject;
  134. //
  135. // Snag the device object from the file object, then fill in the
  136. // fast I/O routines. The code here was shamelessly stolen from
  137. // the NT SMB server.
  138. //
  139. pFileCacheEntry->pDeviceObject = IoGetRelatedDeviceObject( pFileObject );
  140. //
  141. // Assume no fast I/O, and then query the fast I/O dispath routines.
  142. //
  143. pFileCacheEntry->pMdlRead = &UlFailMdlReadDev;
  144. pFileCacheEntry->pMdlReadComplete = &UlFailMdlReadCompleteDev;
  145. pFastIoDispatch =
  146. pFileCacheEntry->pDeviceObject->DriverObject->FastIoDispatch;
  147. //
  148. // Query MdlRead.
  149. //
  150. if (pFastIoDispatch != NULL &&
  151. pFastIoDispatch->SizeOfFastIoDispatch >
  152. FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead) &&
  153. pFastIoDispatch->MdlRead != NULL)
  154. {
  155. //
  156. // Fill in MdlRead call if the file system's vector is large
  157. // enough. We still need to check if the routines is specified.
  158. //
  159. pFileCacheEntry->pMdlRead = pFastIoDispatch->MdlRead;
  160. }
  161. //
  162. // Query MdlReadComplete.
  163. //
  164. if (pFastIoDispatch != NULL &&
  165. pFastIoDispatch->SizeOfFastIoDispatch >
  166. FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete) &&
  167. pFastIoDispatch->MdlReadComplete != NULL)
  168. {
  169. //
  170. // Fill in MdlReadComplete call if the file system's vector is large
  171. // enough. We still need to check if the routines is specified.
  172. //
  173. pFileCacheEntry->pMdlReadComplete = pFastIoDispatch->MdlReadComplete;
  174. }
  175. //
  176. // Get the file size, etc from the file. Note that, since we *may*
  177. // be running in the context of a user-mode thread, we need to
  178. // use the Zw form of the API rather than the Nt form.
  179. //
  180. if (!pFastIoDispatch ||
  181. pFastIoDispatch->SizeOfFastIoDispatch <=
  182. FIELD_OFFSET(FAST_IO_DISPATCH, FastIoQueryStandardInfo) ||
  183. !pFastIoDispatch->FastIoQueryStandardInfo ||
  184. !pFastIoDispatch->FastIoQueryStandardInfo(
  185. pFileObject,
  186. TRUE,
  187. &FileInfo,
  188. &IoStatusBlock,
  189. pFileCacheEntry->pDeviceObject
  190. ))
  191. {
  192. Status = ZwQueryInformationFile(
  193. FileHandle, // FileHandle
  194. &IoStatusBlock, // IoStatusBlock,
  195. &FileInfo, // FileInformation,
  196. sizeof(FileInfo), // Length
  197. FileStandardInformation // FileInformationClass
  198. );
  199. if (NT_SUCCESS(Status) == FALSE)
  200. goto end;
  201. }
  202. pFileCacheEntry->EndOfFile = FileInfo.EndOfFile;
  203. //
  204. // Get the file size information for the SectorSize.
  205. //
  206. if (!(pFileObject->Flags & FO_CACHE_SUPPORTED))
  207. {
  208. if (pFileCacheEntry->pDeviceObject->SectorSize)
  209. {
  210. pFileCacheEntry->BytesPerSector =
  211. pFileCacheEntry->pDeviceObject->SectorSize;
  212. }
  213. else
  214. {
  215. Status = ZwQueryVolumeInformationFile(
  216. FileHandle,
  217. &IoStatusBlock,
  218. &SizeInfo,
  219. sizeof(SizeInfo),
  220. FileFsSizeInformation
  221. );
  222. if (NT_SUCCESS(Status) == FALSE)
  223. goto end;
  224. pFileCacheEntry->BytesPerSector = SizeInfo.BytesPerSector;
  225. }
  226. }
  227. //
  228. // Success!
  229. //
  230. UlTrace(FILE_CACHE, (
  231. "UlCreateFileEntry: entry %p, handle %lx [%p]\n",
  232. pFileCacheEntry,
  233. FileHandle,
  234. pFileObject
  235. ));
  236. end:
  237. if (NT_SUCCESS(Status) == FALSE)
  238. {
  239. //
  240. // If we made it to this point, then the open has failed.
  241. //
  242. UlTrace(FILE_CACHE, (
  243. "UlCreateFileEntry: handle %p, failure %08lx\n",
  244. FileHandle,
  245. Status
  246. ));
  247. UlDestroyFileCacheEntry( pFileCacheEntry );
  248. }
  249. return Status;
  250. } // UlCreateFileEntry
  251. /***************************************************************************++
  252. Routine Description:
  253. Reads data from a file. Does a MDL read for filesystems that support
  254. MDL reads. If the fs doesn't support MDL reads, this function
  255. allocates a buffer to hold the data.
  256. Arguments:
  257. pFileBuffer - Contains all the info about the read, and the data
  258. once that's been read.
  259. pIrp - This IRP is used to issue the read.
  260. Return Value:
  261. NTSTATUS - Completion status.
  262. --***************************************************************************/
  263. NTSTATUS
  264. UlReadFileEntry(
  265. IN OUT PUL_FILE_BUFFER pFileBuffer,
  266. IN PIRP pIrp
  267. )
  268. {
  269. NTSTATUS Status;
  270. PIO_STACK_LOCATION pIrpSp;
  271. PUL_FILE_CACHE_ENTRY pFile;
  272. PUCHAR pFileData;
  273. PMDL pMdl;
  274. ULONG ReadLength;
  275. ULONG SectorSize;
  276. ULONG RelativeOffset;
  277. ULONGLONG ReadOffset;
  278. //
  279. // Sanity check.
  280. //
  281. PAGED_CODE();
  282. ASSERT( pFileBuffer );
  283. ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
  284. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
  285. ASSERT( IS_VALID_IRP( pIrp ) );
  286. pFile = pFileBuffer->pFileCacheEntry;
  287. if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
  288. {
  289. UlTrace(FILE_CACHE, (
  290. "UlReadFileEntry(Buffer = %p, pFile = %p, pIrp = %p) MDL Read\n",
  291. pFileBuffer,
  292. pFile,
  293. pIrp
  294. ));
  295. //
  296. // Caching file system. Do a MDL read.
  297. //
  298. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  299. pIrpSp->MajorFunction = IRP_MJ_READ;
  300. pIrpSp->MinorFunction = IRP_MN_MDL;
  301. pIrpSp->FileObject = pFile->pFileObject;
  302. pIrpSp->DeviceObject = pFile->pDeviceObject;
  303. //
  304. // Initialize the IRP.
  305. //
  306. pIrp->MdlAddress = NULL;
  307. pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
  308. //
  309. // Indicate to the file system that this operation can be handled
  310. // synchronously. Basically, this means that the file system can
  311. // use our thread to fault pages in, etc. This avoids
  312. // having to context switch to a file system thread.
  313. //
  314. pIrp->Flags = IRP_SYNCHRONOUS_API;
  315. //
  316. // Set the number of bytes to read and the offset.
  317. //
  318. pIrpSp->Parameters.Read.Length = pFileBuffer->Length;
  319. pIrpSp->Parameters.Read.ByteOffset.QuadPart =
  320. pFileBuffer->FileOffset.QuadPart;
  321. ASSERT( pIrpSp->Parameters.Read.Key == 0 );
  322. //
  323. // Set up the completion routine.
  324. //
  325. IoSetCompletionRoutine(
  326. pIrp, // Irp
  327. UlpRestartReadFileEntry, // CompletionRoutine
  328. pFileBuffer, // Context
  329. TRUE, // InvokeOnSuccess
  330. TRUE, // InvokeOnError
  331. TRUE // InvokeOnCancel
  332. );
  333. //
  334. // Call the driver. Note that we always set status to
  335. // STATUS_PENDING, since we set the IRP completion routine
  336. // to *always* be called.
  337. //
  338. UlCallDriver( pFile->pDeviceObject, pIrp );
  339. Status = STATUS_PENDING;
  340. }
  341. else
  342. {
  343. UlTrace(FILE_CACHE, (
  344. "UlReadFileEntry(Buffer = %p, pFile = %p, pIrp = %p) NoCache Read\n",
  345. pFileBuffer,
  346. pFile,
  347. pIrp
  348. ));
  349. //
  350. // Non-caching file system. Allocate a buffer and issue a
  351. // normal read. The buffer needs to be aligned on the sector
  352. // size to make the read truely async.
  353. //
  354. SectorSize = pFile->BytesPerSector;
  355. ASSERT( SectorSize > 0 );
  356. ASSERT( 0 == (SectorSize & (SectorSize - 1)) );
  357. ReadLength = (pFileBuffer->Length + SectorSize - 1) & ~(SectorSize - 1);
  358. //
  359. // Align down the offset as well on SectorSize - this is required
  360. // for NOCACHE read.
  361. //
  362. ReadOffset = pFileBuffer->FileOffset.QuadPart;
  363. ReadOffset &= ~((ULONGLONG) SectorSize - 1);
  364. ASSERT( ReadOffset <= pFileBuffer->FileOffset.QuadPart );
  365. RelativeOffset = pFileBuffer->RelativeOffset =
  366. (ULONG) (pFileBuffer->FileOffset.QuadPart - ReadOffset);
  367. //
  368. // We may have to allocate an extra SectorSize of bytes.
  369. //
  370. if ((pFileBuffer->Length + RelativeOffset) > ReadLength)
  371. {
  372. ReadLength += SectorSize;
  373. }
  374. pFileData = (PUCHAR) UL_ALLOCATE_POOL(
  375. NonPagedPool,
  376. ReadLength,
  377. UL_NONCACHED_FILE_DATA_POOL_TAG
  378. );
  379. if (!pFileData)
  380. {
  381. Status = STATUS_INSUFFICIENT_RESOURCES;
  382. goto end;
  383. }
  384. //
  385. // Get a MDL for our buffer.
  386. //
  387. pMdl = UlAllocateMdl(
  388. pFileData,
  389. ReadLength,
  390. FALSE,
  391. FALSE,
  392. NULL
  393. );
  394. if (!pMdl)
  395. {
  396. UL_FREE_POOL(
  397. pFileData,
  398. UL_NONCACHED_FILE_DATA_POOL_TAG
  399. );
  400. Status = STATUS_INSUFFICIENT_RESOURCES;
  401. goto end;
  402. }
  403. MmBuildMdlForNonPagedPool( pMdl );
  404. pFileBuffer->pMdl = pMdl;
  405. //
  406. // Remember where the data is.
  407. //
  408. pFileBuffer->pFileData = pFileData;
  409. //
  410. // Set up the read information.
  411. //
  412. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  413. pIrpSp->MajorFunction = IRP_MJ_READ;
  414. pIrpSp->MinorFunction = IRP_MN_NORMAL;
  415. pIrpSp->FileObject = pFile->pFileObject;
  416. pIrpSp->DeviceObject = pFile->pDeviceObject;
  417. //
  418. // Initialize the IRP.
  419. //
  420. pIrp->MdlAddress = NULL;
  421. pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
  422. //
  423. // Indicate to the file system that this operation can be handled
  424. // synchronously. Basically, this means that the file system can
  425. // use the server's thread to fault pages in, etc. This avoids
  426. // having to context switch to a file system thread.
  427. //
  428. pIrp->Flags = IRP_NOCACHE;
  429. //
  430. // Set the number of bytes to read and the offset.
  431. //
  432. pIrpSp->Parameters.Read.Length = ReadLength;
  433. pIrpSp->Parameters.Read.ByteOffset.QuadPart = ReadOffset;
  434. ASSERT( pIrpSp->Parameters.Read.Key == 0 );
  435. //
  436. // If the target device does buffered I/O, load the address of the
  437. // caller's buffer as the "system buffered I/O buffer". If the
  438. // target device does direct I/O, load the MDL address. If it does
  439. // neither, load both the user buffer address and the MDL address.
  440. // (This is necessary to support file systems, such as HPFS, that
  441. // sometimes treat the I/O as buffered and sometimes treat it as
  442. // direct.)
  443. //
  444. if (pFileBuffer->pFileCacheEntry->pDeviceObject->Flags & DO_BUFFERED_IO)
  445. {
  446. pIrp->AssociatedIrp.SystemBuffer = pFileData;
  447. pIrp->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
  448. }
  449. else
  450. if (pFileBuffer->pFileCacheEntry->pDeviceObject->Flags & DO_DIRECT_IO)
  451. {
  452. pIrp->MdlAddress = pMdl;
  453. }
  454. else
  455. {
  456. pIrp->UserBuffer = pFileData;
  457. pIrp->MdlAddress = pMdl;
  458. }
  459. //
  460. // Set up the completion routine.
  461. //
  462. IoSetCompletionRoutine(
  463. pIrp, // Irp
  464. UlpRestartReadFileEntry, // CompletionRoutine
  465. pFileBuffer, // Context
  466. TRUE, // InvokeOnSuccess
  467. TRUE, // InvokeOnError
  468. TRUE // InvokeOnCancel
  469. );
  470. //
  471. // Call the driver. Note that we always set status to
  472. // STATUS_PENDING, since we set the IRP completion routine
  473. // to *always* be called.
  474. //
  475. UlCallDriver( pFile->pDeviceObject, pIrp );
  476. Status = STATUS_PENDING;
  477. }
  478. end:
  479. return Status;
  480. } // UlReadFileEntry
  481. /***************************************************************************++
  482. Routine Description:
  483. Reads data from a file. Does a MDL read for filesystems that support
  484. MDL reads and Fast I/O. If the FS doesn't support fast i/o and MDL
  485. reads, the function returns with a failure status.
  486. Arguments:
  487. pFileBuffer - Contains all the info about the read, and the data
  488. once that's been read.
  489. Return Value:
  490. NTSTATUS - Completion status.
  491. --***************************************************************************/
  492. NTSTATUS
  493. UlReadFileEntryFast(
  494. IN OUT PUL_FILE_BUFFER pFileBuffer
  495. )
  496. {
  497. NTSTATUS Status;
  498. IO_STATUS_BLOCK IoStatus;
  499. PUL_FILE_CACHE_ENTRY pFile;
  500. //
  501. // Sanity check.
  502. //
  503. PAGED_CODE();
  504. ASSERT( pFileBuffer );
  505. ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
  506. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
  507. pFile = pFileBuffer->pFileCacheEntry;
  508. if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
  509. {
  510. UlTrace(FILE_CACHE, (
  511. "UlReadFileEntryFast(Buffer = %p, pFile = %p) MDL Read\n",
  512. pFileBuffer,
  513. pFile
  514. ));
  515. //
  516. // Cached filesystem. Try to use the fast path for the MDL read
  517. // complete.
  518. //
  519. if (pFileBuffer->pFileCacheEntry->pMdlRead(
  520. pFileBuffer->pFileCacheEntry->pFileObject,
  521. (PLARGE_INTEGER) &pFileBuffer->FileOffset,
  522. pFileBuffer->Length,
  523. 0,
  524. &pFileBuffer->pMdl,
  525. &IoStatus,
  526. pFileBuffer->pFileCacheEntry->pDeviceObject
  527. ))
  528. {
  529. Status = STATUS_SUCCESS;
  530. }
  531. else
  532. {
  533. //
  534. // It didn't work. The caller must now use the IRP path
  535. // by calling UlReadFileEntry.
  536. //
  537. Status = STATUS_UNSUCCESSFUL;
  538. }
  539. }
  540. else
  541. {
  542. UlTrace(FILE_CACHE, (
  543. "UlReadFileEntryFast(Buffer = %p, pFile = %p) NoCache Read\n",
  544. pFileBuffer,
  545. pFile
  546. ));
  547. //
  548. // Non-caching file system. No fast i/o. The caller should
  549. // use the IRP path by calling UlReadFileEntry.
  550. //
  551. Status = STATUS_UNSUCCESSFUL;
  552. }
  553. return Status;
  554. } // UlReadFileEntryFast
  555. /***************************************************************************++
  556. Routine Description:
  557. Frees up resources allocated by UlReadFileEntry (or UlReadFileEntryFast).
  558. Should be called when the file data read is no longer in use.
  559. Arguments:
  560. pFileBuffer - Contains all the info about the read, and the data
  561. that was read.
  562. pIrp - This IRP is used to issue the read completion.
  563. Return Value:
  564. NTSTATUS - Completion status.
  565. --***************************************************************************/
  566. NTSTATUS
  567. UlReadCompleteFileEntry(
  568. IN PUL_FILE_BUFFER pFileBuffer,
  569. IN PIRP pIrp
  570. )
  571. {
  572. NTSTATUS Status;
  573. PIO_STACK_LOCATION pIrpSp;
  574. PUL_FILE_CACHE_ENTRY pFile;
  575. UL_STATUS_BLOCK UlStatus;
  576. //
  577. // Sanity check.
  578. //
  579. PAGED_CODE();
  580. ASSERT( pFileBuffer );
  581. ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
  582. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
  583. ASSERT( IS_VALID_IRP( pIrp ) );
  584. pFile = pFileBuffer->pFileCacheEntry;
  585. if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
  586. {
  587. UlTrace(FILE_CACHE, (
  588. "UlReadCompleteFileEntry(Buffer = %p, pFile = %p, pIrp = %p) MDL Read\n",
  589. pFileBuffer,
  590. pFile,
  591. pIrp
  592. ));
  593. //
  594. // Caching file system. Do a MDL read completion.
  595. //
  596. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  597. pIrpSp->MajorFunction = IRP_MJ_READ;
  598. pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
  599. pIrpSp->FileObject = pFile->pFileObject;
  600. pIrpSp->DeviceObject = pFile->pDeviceObject;
  601. //
  602. // Initialize the IRP.
  603. //
  604. pIrp->MdlAddress = pFileBuffer->pMdl;
  605. pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
  606. pFileBuffer->pMdl = NULL;
  607. //
  608. // MDL functions are inherently synchronous.
  609. //
  610. pIrp->Flags = IRP_SYNCHRONOUS_API;
  611. //
  612. // Set the number of bytes to read and the offset.
  613. //
  614. pIrpSp->Parameters.Read.Length = pFileBuffer->Length;
  615. pIrpSp->Parameters.Read.ByteOffset.QuadPart =
  616. pFileBuffer->FileOffset.QuadPart;
  617. ASSERT(pIrpSp->Parameters.Read.Key == 0);
  618. if (pFileBuffer->pCompletionRoutine)
  619. {
  620. //
  621. // Set up the completion routine. We don't need to do anything
  622. // on the completion, so we'll just have the I/O manager call
  623. // our callers routine directly.
  624. //
  625. IoSetCompletionRoutine(
  626. pIrp, // Irp
  627. pFileBuffer->pCompletionRoutine, // CompletionRoutine
  628. pFileBuffer->pContext, // Context
  629. TRUE, // InvokeOnSuccess
  630. TRUE, // InvokeOnError
  631. TRUE // InvokeOnCancel
  632. );
  633. //
  634. // Call the driver. Note that we always set status to
  635. // STATUS_PENDING, since we set the IRP completion routine
  636. // to *always* be called.
  637. //
  638. UlCallDriver( pFile->pDeviceObject, pIrp );
  639. Status = STATUS_PENDING;
  640. }
  641. else
  642. {
  643. //
  644. // Caller has asked us to perform a synchronous operation by
  645. // passing in a NULL completion routine. Initialize the UlStatus
  646. // and wait for it to get signaled after calling UlCallDriver.
  647. //
  648. UlInitializeStatusBlock( &UlStatus );
  649. IoSetCompletionRoutine(
  650. pIrp, // Irp
  651. UlpRestartReadCompleteFileEntry, // CompletionRoutine
  652. &UlStatus, // Context
  653. TRUE, // InvokeOnSuccess
  654. TRUE, // InvokeOnError
  655. TRUE // InvokeOnCancel
  656. );
  657. Status = UlCallDriver( pFile->pDeviceObject, pIrp );
  658. if (STATUS_PENDING == Status)
  659. {
  660. //
  661. // Wait for it to finish.
  662. //
  663. UlWaitForStatusBlockEvent( &UlStatus );
  664. //
  665. // Retrieve the updated status.
  666. //
  667. Status = UlStatus.IoStatus.Status;
  668. }
  669. }
  670. }
  671. else
  672. {
  673. UlTrace(FILE_CACHE, (
  674. "UlReadCompleteFileEntry(Buffer = %p, pFile = %p) NoCache Read\n",
  675. pFileBuffer,
  676. pFile
  677. ));
  678. //
  679. // Non-caching file system. We allocated this buffer. Just
  680. // free it and call the completion routine.
  681. //
  682. ASSERT( pFileBuffer->pMdl );
  683. UlFreeMdl( pFileBuffer->pMdl );
  684. pFileBuffer->pMdl = NULL;
  685. ASSERT( pFileBuffer->pFileData );
  686. UL_FREE_POOL(
  687. pFileBuffer->pFileData,
  688. UL_NONCACHED_FILE_DATA_POOL_TAG
  689. );
  690. pFileBuffer->pFileData = NULL;
  691. //
  692. // Fake the completion here.
  693. //
  694. if (pFileBuffer->pCompletionRoutine)
  695. {
  696. pFileBuffer->pCompletionRoutine(
  697. pFileBuffer->pFileCacheEntry->pDeviceObject,
  698. pIrp,
  699. pFileBuffer->pContext
  700. );
  701. //
  702. // Return pending, since we called their completion routine.
  703. //
  704. Status = STATUS_PENDING;
  705. }
  706. else
  707. {
  708. Status = STATUS_SUCCESS;
  709. }
  710. }
  711. if (!NT_SUCCESS(Status))
  712. {
  713. UlTrace(FILE_CACHE, (
  714. "UlReadCompleteFileEntry(Buffer = %p, pFile = %p) FAILED! %x\n",
  715. pFileBuffer,
  716. pFile,
  717. Status
  718. ));
  719. }
  720. return Status;
  721. } // UlReadCompleteFileEntry
  722. /***************************************************************************++
  723. Routine Description:
  724. Frees up resources allocated by UlReadFileEntry (or UlReadFileEntryFast).
  725. Should be called when the file data read is no longer in use.
  726. Arguments:
  727. pFileBuffer - Contains all the info about the read, and the data
  728. that was read.
  729. Return Value:
  730. NTSTATUS - Completion status.
  731. --***************************************************************************/
  732. NTSTATUS
  733. UlReadCompleteFileEntryFast(
  734. IN PUL_FILE_BUFFER pFileBuffer
  735. )
  736. {
  737. NTSTATUS Status;
  738. PUL_FILE_CACHE_ENTRY pFile;
  739. //
  740. // Sanity check.
  741. //
  742. PAGED_CODE();
  743. ASSERT( pFileBuffer );
  744. ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
  745. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
  746. pFile = pFileBuffer->pFileCacheEntry;
  747. if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
  748. {
  749. UlTrace(FILE_CACHE, (
  750. "UlReadCompleteFileEntryFast(Buffer = %p, pFile = %p) MDL Read\n",
  751. pFileBuffer,
  752. pFile
  753. ));
  754. //
  755. // Cached filesystem. Try to use the fast path for the MDL read
  756. // complete.
  757. //
  758. if (pFileBuffer->pFileCacheEntry->pMdlReadComplete(
  759. pFileBuffer->pFileCacheEntry->pFileObject,
  760. pFileBuffer->pMdl,
  761. pFileBuffer->pFileCacheEntry->pDeviceObject
  762. ))
  763. {
  764. pFileBuffer->pMdl = NULL;
  765. Status = STATUS_SUCCESS;
  766. }
  767. else
  768. {
  769. //
  770. // It didn't work. The caller must now use the IRP path
  771. // by calling UlReadCompleteFileEntry.
  772. //
  773. Status = STATUS_UNSUCCESSFUL;
  774. }
  775. }
  776. else
  777. {
  778. UlTrace(FILE_CACHE, (
  779. "UlReadCompleteFileEntryFast(Buffer = %p, pFile = %p) NoCache Read\n",
  780. pFileBuffer,
  781. pFile
  782. ));
  783. //
  784. // Non-caching file system. We allocated this buffer. Just
  785. // free it.
  786. //
  787. ASSERT( pFileBuffer->pMdl );
  788. UlFreeMdl( pFileBuffer->pMdl );
  789. pFileBuffer->pMdl = NULL;
  790. ASSERT( pFileBuffer->pFileData );
  791. UL_FREE_POOL(
  792. pFileBuffer->pFileData,
  793. UL_NONCACHED_FILE_DATA_POOL_TAG
  794. );
  795. pFileBuffer->pFileData = NULL;
  796. Status = STATUS_SUCCESS;
  797. }
  798. return Status;
  799. } // UlReadCompleteFileEntryFast
  800. /***************************************************************************++
  801. Routine Description:
  802. Helper function to destroy a file cache entry.
  803. Arguments:
  804. pWorkItem - Supplies a pointer to the work item queued. This should
  805. point to the WORK_ITEM structure embedded in a UL_FILE_CACHE_ENTRY.
  806. Return Value:
  807. None.
  808. --***************************************************************************/
  809. VOID
  810. UlDestroyFileCacheEntry(
  811. PUL_FILE_CACHE_ENTRY pFileCacheEntry
  812. )
  813. {
  814. //
  815. // Sanity check.
  816. //
  817. PAGED_CODE();
  818. UlTrace(FILE_CACHE, (
  819. "UlDestroyFileCacheEntry: entry %p\n",
  820. pFileCacheEntry
  821. ));
  822. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileCacheEntry ) );
  823. //
  824. // Cleanup the file system stuff.
  825. //
  826. if (pFileCacheEntry->pFileObject != NULL)
  827. {
  828. ObDereferenceObject( pFileCacheEntry->pFileObject );
  829. pFileCacheEntry->pFileObject = NULL;
  830. }
  831. //
  832. // Now release the entry's resources.
  833. //
  834. pFileCacheEntry->Signature = UL_FILE_CACHE_ENTRY_SIGNATURE_X;
  835. } // UlDestroyFileCacheEntry
  836. /***************************************************************************++
  837. Routine Description:
  838. Dummy function to fail MDL reads.
  839. Arguments:
  840. Same as FsRtlMdlReadDev().
  841. Return Value:
  842. BOOLEAN - Always FALSE (failure).
  843. --***************************************************************************/
  844. BOOLEAN
  845. UlFailMdlReadDev(
  846. IN PFILE_OBJECT FileObject,
  847. IN PLARGE_INTEGER FileOffset,
  848. IN ULONG Length,
  849. IN ULONG LockKey,
  850. OUT PMDL *MdlChain,
  851. OUT PIO_STATUS_BLOCK IoStatus,
  852. IN PDEVICE_OBJECT DeviceObject
  853. )
  854. {
  855. UNREFERENCED_PARAMETER( FileObject );
  856. UNREFERENCED_PARAMETER( FileOffset );
  857. UNREFERENCED_PARAMETER( Length );
  858. UNREFERENCED_PARAMETER( LockKey );
  859. UNREFERENCED_PARAMETER( MdlChain );
  860. UNREFERENCED_PARAMETER( IoStatus );
  861. UNREFERENCED_PARAMETER( DeviceObject );
  862. PAGED_CODE();
  863. return FALSE;
  864. } // UlFailMdlReadDev
  865. /***************************************************************************++
  866. Routine Description:
  867. Dummy function to fail MDL read completes.
  868. Arguments:
  869. Same as FsRtlMdlReadCompleteDev().
  870. Return Value:
  871. BOOLEAN - Always FALSE (failure).
  872. --***************************************************************************/
  873. BOOLEAN
  874. UlFailMdlReadCompleteDev(
  875. IN PFILE_OBJECT FileObject,
  876. IN PMDL MdlChain,
  877. IN PDEVICE_OBJECT DeviceObject
  878. )
  879. {
  880. UNREFERENCED_PARAMETER( FileObject );
  881. UNREFERENCED_PARAMETER( MdlChain );
  882. UNREFERENCED_PARAMETER( DeviceObject );
  883. PAGED_CODE();
  884. return FALSE;
  885. } // UlFailMdlReadCompleteDev
  886. //
  887. // Private functions.
  888. //
  889. /***************************************************************************++
  890. Routine Description:
  891. Completion routine for UlReadFileEntry. Sets the data fields in
  892. the UL_FILE_BUFFER and calls the completion routine passed to
  893. UlReadFileEntry.
  894. Arguments:
  895. pDeviceObject - the file system device object (not used)
  896. pIrp - the IRP used to do the read
  897. pContext - pointer to the UL_FILE_BUFFER
  898. Return Value:
  899. NTSTATUS - Completion status.
  900. --***************************************************************************/
  901. NTSTATUS
  902. UlpRestartReadFileEntry(
  903. IN PDEVICE_OBJECT pDeviceObject,
  904. IN PIRP pIrp,
  905. IN PVOID pContext
  906. )
  907. {
  908. NTSTATUS Status;
  909. PUL_FILE_BUFFER pFileBuffer = (PUL_FILE_BUFFER)pContext;
  910. PUL_FILE_CACHE_ENTRY pFile;
  911. PUCHAR pFileData;
  912. ULONGLONG EffetiveLength;
  913. //
  914. // Sanity check.
  915. //
  916. ASSERT( pFileBuffer );
  917. ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
  918. ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
  919. pFile = pFileBuffer->pFileCacheEntry;
  920. if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
  921. {
  922. //
  923. // This was a MDL read.
  924. //
  925. if (NT_SUCCESS(pIrp->IoStatus.Status))
  926. {
  927. pFileBuffer->pMdl = pIrp->MdlAddress;
  928. }
  929. }
  930. else
  931. {
  932. //
  933. // This was a NoCache Read. pFileBuffer->pMdl
  934. // was already set by UlReadFileEntry.
  935. //
  936. ASSERT( pFileBuffer->pMdl );
  937. if (NT_SUCCESS(pIrp->IoStatus.Status))
  938. {
  939. //
  940. // Set the byte count of the MDL to the true bytes we asked for
  941. // and adjust the offset to skip the possible extra bytes we
  942. // have read.
  943. //
  944. EffetiveLength =
  945. pIrp->IoStatus.Information - pFileBuffer->RelativeOffset;
  946. //
  947. // Re-initialize the MDL if we have read at least what we have
  948. // requested, otherwise, fail the read.
  949. //
  950. if (pIrp->IoStatus.Information >= pFileBuffer->RelativeOffset &&
  951. EffetiveLength >= pFileBuffer->Length)
  952. {
  953. pFileData = pFileBuffer->pFileData +
  954. pFileBuffer->RelativeOffset;
  955. MmInitializeMdl(
  956. pFileBuffer->pMdl,
  957. pFileData,
  958. pFileBuffer->Length
  959. );
  960. MmBuildMdlForNonPagedPool( pFileBuffer->pMdl );
  961. pIrp->IoStatus.Information = pFileBuffer->Length;
  962. }
  963. else
  964. {
  965. pIrp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
  966. pIrp->IoStatus.Information = 0;
  967. }
  968. }
  969. }
  970. if (pFileBuffer->pCompletionRoutine)
  971. {
  972. Status = (pFileBuffer->pCompletionRoutine)(
  973. pDeviceObject,
  974. pIrp,
  975. pFileBuffer->pContext
  976. );
  977. }
  978. else
  979. {
  980. Status = STATUS_MORE_PROCESSING_REQUIRED;
  981. }
  982. return Status;
  983. } // UlpRestartReadFileEntry
  984. /***************************************************************************++
  985. Routine Description:
  986. Completion routine for UlReadCompleteFileEntry. Simply call
  987. UlSignalStatusBlock to unblock the waiting thread.
  988. Arguments:
  989. pDeviceObject - the file system device object (not used)
  990. pIrp - the IRP used to do the read completion
  991. pContext - pointer to the UL_STATUS_BLOCK
  992. Return Value:
  993. NTSTATUS - Completion status.
  994. --***************************************************************************/
  995. NTSTATUS
  996. UlpRestartReadCompleteFileEntry(
  997. IN PDEVICE_OBJECT pDeviceObject,
  998. IN PIRP pIrp,
  999. IN PVOID pContext
  1000. )
  1001. {
  1002. PUL_STATUS_BLOCK pStatus = (PUL_STATUS_BLOCK) pContext;
  1003. UNREFERENCED_PARAMETER( pDeviceObject );
  1004. //
  1005. // Signal the read completion has been completed.
  1006. //
  1007. UlSignalStatusBlock(
  1008. pStatus,
  1009. pIrp->IoStatus.Status,
  1010. pIrp->IoStatus.Information
  1011. );
  1012. return STATUS_MORE_PROCESSING_REQUIRED;
  1013. } // UlpRestartReadCompleteFileEntry