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.

1349 lines
33 KiB

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