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.

943 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. LowIo.c
  5. Abstract:
  6. This module implements buffer locking and mapping; also synchronous waiting for a lowlevelIO.
  7. Author:
  8. JoeLinn [JoeLinn] 12-Oct-94
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_LOWIO)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, RxLockUserBuffer)
  19. #pragma alloc_text(PAGE, RxNewMapUserBuffer)
  20. #pragma alloc_text(PAGE, RxMapSystemBuffer)
  21. #pragma alloc_text(PAGE, RxInitializeLowIoContext)
  22. #pragma alloc_text(PAGE, RxLowIoGetBufferAddress)
  23. #pragma alloc_text(PAGE, RxLowIoSubmitRETRY)
  24. #pragma alloc_text(PAGE, RxLowIoCompletionTail)
  25. #pragma alloc_text(PAGE, RxLowIoCompletion)
  26. #pragma alloc_text(PAGE, RxLowIoPopulateFsctlInfo)
  27. #pragma alloc_text(PAGE, RxLowIoSubmit)
  28. #pragma alloc_text(PAGE, RxInitializeLowIoPerFcbInfo)
  29. #pragma alloc_text(PAGE, RxInitializeLowIoPerFcbInfo)
  30. #endif
  31. //this is a crude implementation of the insertion, deletion, and coverup operations for wimp lowio
  32. //we'll just use a linked list for now.........
  33. #define RxInsertIntoOutStandingPagingOperationsList(RxContext,Operation) { \
  34. PLIST_ENTRY WhichList = (Operation==LOWIO_OP_READ) \
  35. ?&capFcb->Specific.Fcb.PagingIoReadsOutstanding \
  36. :&capFcb->Specific.Fcb.PagingIoWritesOutstanding;\
  37. InsertTailList(WhichList,&RxContext->RxContextSerializationQLinks); \
  38. }
  39. #define RxRemoveFromOutStandingPagingOperationsList(RxContext) { \
  40. RemoveEntryList(&RxContext->RxContextSerializationQLinks); \
  41. RxContext->RxContextSerializationQLinks.Flink = NULL; \
  42. RxContext->RxContextSerializationQLinks.Blink = NULL; \
  43. }
  44. #ifndef WIN9X
  45. FAST_MUTEX RxLowIoPagingIoSyncMutex;
  46. //here we hiding the IO access flags
  47. #define RxLockAndMapUserBufferForLowIo(RXCONTEXT,LOWIOCONTEXT,OPERATION) {\
  48. RxLockUserBuffer( RXCONTEXT, \
  49. (OPERATION==LOWIO_OP_READ)?IoWriteAccess:IoReadAccess,\
  50. LOWIOCONTEXT->ParamsFor.ReadWrite.ByteCount ); \
  51. if (RxNewMapUserBuffer(RXCONTEXT) == NULL) Status = STATUS_INSUFFICIENT_RESOURCES; \
  52. LOWIOCONTEXT->ParamsFor.ReadWrite.Buffer = RxUserBufferFromContext(RXCONTEXT); \
  53. }
  54. //these next macros are a bit strange. the macro parameter is the RxContext.....people who have
  55. // not defined appropriate capture macros can access out from there. on NT, we will just use the
  56. // captured entities but we hide the actual field designators
  57. #define RxIsPagingIo(RXCONTEXT) (FlagOn(capReqPacket->Flags,IRP_PAGING_IO))
  58. #define RxUserBufferFromContext(RXCONTEXT) (capReqPacket->MdlAddress)
  59. #if 0
  60. //if capFcb->NetRoot is NULL, then this must be the device FCB!
  61. #define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
  62. if (capFcb->VNetRoot != NULL) { \
  63. pMiniRdrDispatch = capFcb->MRxDispatch; \
  64. } else { \
  65. PV_NET_ROOT pVirtualNetRoot = (PV_NET_ROOT)capFileObject->FsContext2; \
  66. pMiniRdrDispatch = pVirtualNetRoot->NetRoot->Dispatch; \
  67. } \
  68. }
  69. #endif 0
  70. #define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
  71. pMiniRdrDispatch = RxContext->RxDeviceObject->Dispatch; \
  72. }
  73. #define RxMarkPendingForLowIo(RXCONTEXT) IoMarkIrpPending(capReqPacket)
  74. #define RxUnmarkPendingForLowIo(RXCONTEXT) {\
  75. capPARAMS->Control &= ~SL_PENDING_RETURNED; \
  76. }
  77. #define RxGetCurrentResourceThreadForLowIo(RXCONTEXT) \
  78. (ExGetCurrentResourceThread())
  79. //NT specific routines
  80. VOID
  81. RxLockUserBuffer (
  82. IN PRX_CONTEXT RxContext,
  83. IN LOCK_OPERATION Operation,
  84. IN ULONG BufferLength
  85. )
  86. /*++
  87. Routine Description:
  88. This routine locks the specified buffer for the specified type of
  89. access. The file system requires this routine since it does not
  90. ask the I/O system to lock its buffers for direct I/O. This routine
  91. may only be called from the Fsd while still in the user context.
  92. Arguments:
  93. RxContext - Pointer to the pointer Irp for which the buffer is to be locked.
  94. Operation - IoWriteAccess for read operations, or IoReadAccess for
  95. write operations.
  96. BufferLength - Length of user buffer.
  97. Return Value:
  98. None
  99. --*/
  100. {
  101. RxCaptureRequestPacket;
  102. PMDL Mdl = NULL;
  103. PAGED_CODE();
  104. if (capReqPacket->MdlAddress == NULL) {
  105. ASSERT(!(capReqPacket->Flags & IRP_INPUT_OPERATION));
  106. // Allocate the Mdl, and Raise if we fail.
  107. if (BufferLength > 0) {
  108. Mdl = IoAllocateMdl(
  109. capReqPacket->UserBuffer,
  110. BufferLength,
  111. FALSE,
  112. FALSE,
  113. capReqPacket );
  114. if (Mdl == NULL) {
  115. RxRaiseStatus(
  116. RxContext,
  117. STATUS_INSUFFICIENT_RESOURCES );
  118. } else {
  119. // Now probe the buffer described by the Irp. If we get an exception,
  120. // deallocate the Mdl and return the appropriate "expected" status.
  121. try {
  122. MmProbeAndLockPages(
  123. Mdl,
  124. capReqPacket->RequestorMode,
  125. Operation );
  126. } except(EXCEPTION_EXECUTE_HANDLER) {
  127. NTSTATUS Status;
  128. Status = GetExceptionCode();
  129. IoFreeMdl( Mdl );
  130. capReqPacket->MdlAddress = NULL;
  131. SetFlag(
  132. RxContext->Flags,
  133. RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
  134. RxRaiseStatus(
  135. RxContext,
  136. (FsRtlIsNtstatusExpected(Status) ?
  137. Status :
  138. STATUS_INVALID_USER_BUFFER));
  139. }
  140. }
  141. }
  142. } else {
  143. Mdl = capReqPacket->MdlAddress;
  144. ASSERT(RxLowIoIsMdlLocked(Mdl));
  145. }
  146. }
  147. NTSTATUS
  148. RxLockBuffer (
  149. IN PRX_CONTEXT RxContext,
  150. IN PVOID pBuffer,
  151. IN ULONG BufferLength,
  152. IN LOCK_OPERATION Operation,
  153. OUT PMDL *pBufferMdlPtr
  154. )
  155. /*++
  156. Routine Description:
  157. This routine locks the input buffer for the specified type of
  158. access. The file system requires this routine since it does not
  159. ask the I/O system to lock its buffers for direct I/O.
  160. Arguments:
  161. RxContext - Pointer to the pointer Irp for which the buffer is to be locked.
  162. Operation - IoWriteAccess for read operations, or IoReadAccess for
  163. write operations.
  164. pBufferMdl - a placeholder for a pointer to the locked down MDL
  165. Return Value:
  166. RxStatus(SUCCESS) - if the operation was successful
  167. --*/
  168. {
  169. NTSTATUS Status = STATUS_SUCCESS;
  170. RxCaptureRequestPacket;
  171. *pBufferMdlPtr = NULL;
  172. // Allocate the Mdl, and Raise if we fail.
  173. *pBufferMdlPtr = IoAllocateMdl(
  174. pBuffer,
  175. BufferLength,
  176. FALSE,
  177. FALSE,
  178. capReqPacket);
  179. if (*pBufferMdlPtr == NULL) {
  180. Status = STATUS_INSUFFICIENT_RESOURCES;
  181. } else {
  182. // probe and lock down the buffer
  183. try {
  184. MmProbeAndLockPages(
  185. *pBufferMdlPtr,
  186. capReqPacket->RequestorMode,
  187. Operation );
  188. RxProtectMdlFromFree(*pBufferMdlPtr);
  189. } except(EXCEPTION_EXECUTE_HANDLER) {
  190. NTSTATUS Status;
  191. Status = GetExceptionCode();
  192. IoFreeMdl(*pBufferMdlPtr);
  193. Status = FsRtlIsNtstatusExpected(Status) ?
  194. Status :
  195. STATUS_INVALID_USER_BUFFER;
  196. }
  197. }
  198. return Status;
  199. }
  200. PVOID
  201. RxMapSystemBuffer (
  202. IN PRX_CONTEXT RxContext
  203. )
  204. /*++
  205. Routine Description:
  206. This routine returns the system buffer address from the irp. the way that the code is written
  207. it may also decide to get the buffer address from the mdl. that is wrong because the systembuffer is
  208. always nonpaged so no locking/mapping is needed. thus, the mdl path now contains an assert.
  209. Arguments:
  210. RxContext - Pointer to the IrpC for the request.
  211. Return Value:
  212. Mapped address
  213. --*/
  214. {
  215. RxCaptureRequestPacket;
  216. PAGED_CODE();
  217. if (capReqPacket->MdlAddress == NULL) {
  218. return capReqPacket->AssociatedIrp.SystemBuffer;
  219. } else {
  220. ASSERT (!"there should not be an MDL in this irp!!!!!");
  221. return MmGetSystemAddressForMdlSafe(
  222. capReqPacket->MdlAddress, NormalPagePriority );
  223. }
  224. }
  225. PVOID
  226. RxNewMapUserBuffer (
  227. IN PRX_CONTEXT RxContext
  228. )
  229. /*++
  230. Routine Description:
  231. This routine returns the address of the userbuffer. if an MDL exists then the assumption is that
  232. the mdl describes the userbuffer and the system address for the mdl is returned. otherwise, the userbuffer
  233. is returned directly.
  234. Arguments:
  235. RxContext - Pointer to the IrpC for the request.
  236. Return Value:
  237. Mapped address
  238. --*/
  239. {
  240. RxCaptureRequestPacket;
  241. PAGED_CODE();
  242. if (capReqPacket->MdlAddress == NULL) {
  243. return capReqPacket->UserBuffer;
  244. } else {
  245. return MmGetSystemAddressForMdlSafe(
  246. capReqPacket->MdlAddress,
  247. NormalPagePriority );
  248. }
  249. }
  250. #else
  251. #define RxMarkPendingForLowIo(RXCONTEXT)
  252. #define RxUnmarkPendingForLowIo(RXCONTEXT)
  253. //CIA figure out how paging io works on win9x
  254. #define RxIsPagingIo(RXCONTEXT) FALSE
  255. #define RxGetCurrentResourceThreadForLowIo(RXCONTEXT) 11
  256. #define RxLockAndMapUserBufferForLowIo(RXCONTEXT,LOWIOCONTEXT,OPERATION) {\
  257. if(((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer = \
  258. RxAllocateMdl(capReqPacket->ir_data, capReqPacket->ir_length)) \
  259. != NULL) {\
  260. NTSTATUS __Status = _RxProbeAndLockPages((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer, \
  261. KernelMode,\
  262. (OPERATION==LOWIO_OP_READ)?IoWriteAccess:IoReadAccess\
  263. ); \
  264. if (__Status != STATUS_SUCCESS) { \
  265. IoFreeMdl((LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer); \
  266. (LOWIOCONTEXT)->ParamsFor.ReadWrite.Buffer = NULL; \
  267. } \
  268. }\
  269. }
  270. #define RxGetMiniRdrDispatchForLowIo(RXCONTEXT) {\
  271. PV_NET_ROOT pVirtualNetRoot = (PV_NET_ROOT)capReqPacket->ir_rh; \
  272. pMiniRdrDispatch = pVirtualNetRoot->NetRoot->Dispatch; \
  273. }
  274. #endif //#ifndef WIN9X
  275. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. //
  277. // from here down (except for fsctl buffer determination), everything is available for either wrapper. we may
  278. // decide that the fsctl stuff should be moved as well
  279. //
  280. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  281. VOID
  282. RxInitializeLowIoContext(
  283. PLOWIO_CONTEXT LowIoContext,
  284. ULONG Operation
  285. )
  286. /*++
  287. Routine Description:
  288. This routine initializes the LowIO context in the RxContext.
  289. Arguments:
  290. RxContext - context of irp being processed.
  291. Return Value:
  292. none
  293. --*/
  294. {
  295. PRX_CONTEXT RxContext = CONTAINING_RECORD(LowIoContext,RX_CONTEXT,LowIoContext);
  296. RxCaptureRequestPacket; RxCaptureParamBlock;
  297. PAGED_CODE();
  298. ASSERT (LowIoContext = &RxContext->LowIoContext);
  299. KeInitializeEvent(
  300. &RxContext->SyncEvent,
  301. NotificationEvent,
  302. FALSE );
  303. //this ID is used to release the resource on behalf of another thread....
  304. // e.g. it is used when an async routine completes to release the thread
  305. // acquired by the first acquirer.
  306. LowIoContext->ResourceThreadId = RxGetCurrentResourceThreadForLowIo(RxContext);
  307. LowIoContext->Operation = (USHORT)Operation;
  308. switch (Operation) {
  309. case LOWIO_OP_READ:
  310. case LOWIO_OP_WRITE:
  311. IF_DEBUG {
  312. LowIoContext->ParamsFor.ReadWrite.ByteOffset = 0xffffffee; //no operation should start there!
  313. LowIoContext->ParamsFor.ReadWrite.ByteCount = 0xeeeeeeee; //no operation should start there!
  314. }
  315. ASSERT (&capPARAMS->Parameters.Read.Length == &capPARAMS->Parameters.Write.Length);
  316. ASSERT (&capPARAMS->Parameters.Read.Key == &capPARAMS->Parameters.Write.Key);
  317. LowIoContext->ParamsFor.ReadWrite.Key = capPARAMS->Parameters.Read.Key;
  318. LowIoContext->ParamsFor.ReadWrite.Flags = 0
  319. | (RxIsPagingIo(RxContext)?LOWIO_READWRITEFLAG_PAGING_IO:0)
  320. ;
  321. break;
  322. case LOWIO_OP_FSCTL:
  323. case LOWIO_OP_IOCTL:
  324. LowIoContext->ParamsFor.FsCtl.Flags = 0;
  325. LowIoContext->ParamsFor.FsCtl.InputBufferLength = 0;
  326. LowIoContext->ParamsFor.FsCtl.pInputBuffer = NULL;
  327. LowIoContext->ParamsFor.FsCtl.OutputBufferLength = 0;
  328. LowIoContext->ParamsFor.FsCtl.pOutputBuffer = NULL;
  329. LowIoContext->ParamsFor.FsCtl.MinorFunction = 0;
  330. break;
  331. case LOWIO_OP_SHAREDLOCK:
  332. case LOWIO_OP_EXCLUSIVELOCK:
  333. case LOWIO_OP_UNLOCK:
  334. case LOWIO_OP_UNLOCK_MULTIPLE:
  335. case LOWIO_OP_CLEAROUT:
  336. case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
  337. break;
  338. default:
  339. ASSERT(FALSE);
  340. }
  341. }
  342. PVOID
  343. RxLowIoGetBufferAddress (
  344. IN PRX_CONTEXT RxContext
  345. )
  346. /*++
  347. Routine Description:
  348. This routine gets the buffer corresponding to the Mdl in the LowIoContext.
  349. Arguments:
  350. RxContext - context for the request.
  351. Return Value:
  352. Mapped address
  353. --*/
  354. {
  355. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  356. PAGED_CODE();
  357. if (LowIoContext->ParamsFor.ReadWrite.ByteCount > 0) {
  358. ASSERT(LowIoContext->ParamsFor.ReadWrite.Buffer);
  359. return MmGetSystemAddressForMdlSafe(
  360. LowIoContext->ParamsFor.ReadWrite.Buffer,
  361. NormalPagePriority);
  362. } else {
  363. return NULL;
  364. }
  365. }
  366. NTSTATUS
  367. RxLowIoSubmitRETRY (
  368. IN PRX_CONTEXT RxContext
  369. )
  370. /*++
  371. Routine Description:
  372. This routine just calls LowIoSubmit; the completion routine was previously
  373. stored so we just extract it and pass it in. This is called out of the Fsp
  374. dispatcher for retrying at the low level.
  375. Arguments:
  376. RxContext - the usual
  377. Return Value:
  378. whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
  379. --*/
  380. {
  381. PAGED_CODE();
  382. return(RxLowIoSubmit(RxContext,RxContext->LowIoContext.CompletionRoutine));
  383. }
  384. NTSTATUS
  385. RxLowIoCompletionTail (
  386. IN PRX_CONTEXT RxContext
  387. )
  388. /*++
  389. Routine Description:
  390. This routine is called by lowio routines at the very end...i.e. after the individual completion
  391. routines are called.
  392. Arguments:
  393. RxContext - the RDBSS context
  394. Return Value:
  395. whatever value supplied by the caller.
  396. --*/
  397. {
  398. NTSTATUS Status;
  399. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  400. ULONG Operation = LowIoContext->Operation;
  401. BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
  402. PAGED_CODE();
  403. RxDbgTrace(+1, Dbg, ("RxLowIoCompletionTail, Operation=%08lx\n",LowIoContext->Operation));
  404. if (( KeGetCurrentIrql() < DISPATCH_LEVEL )
  405. || (FlagOn(LowIoContext->Flags,LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL)) ) {
  406. Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
  407. } else {
  408. Status = STATUS_MORE_PROCESSING_REQUIRED;
  409. }
  410. if ( (Status == STATUS_MORE_PROCESSING_REQUIRED) || (Status == STATUS_RETRY) ) {
  411. RxDbgTrace(-1, Dbg, ("RxLowIoCompletionTail wierdstatus, Status=%08lx\n",Status));
  412. return(Status);
  413. }
  414. switch (Operation) {
  415. case LOWIO_OP_READ:
  416. case LOWIO_OP_WRITE:
  417. if (FlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO)) {
  418. RxDbgTrace(0, Dbg, ("RxLowIoCompletionTail pagingio unblock\n"));
  419. ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
  420. RxRemoveFromOutStandingPagingOperationsList(RxContext);
  421. ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
  422. RxResumeBlockedOperations_ALL(RxContext);
  423. }
  424. break;
  425. case LOWIO_OP_SHAREDLOCK:
  426. case LOWIO_OP_EXCLUSIVELOCK:
  427. case LOWIO_OP_UNLOCK:
  428. case LOWIO_OP_UNLOCK_MULTIPLE:
  429. case LOWIO_OP_CLEAROUT:
  430. break;
  431. case LOWIO_OP_FSCTL:
  432. case LOWIO_OP_IOCTL:
  433. case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
  434. break;
  435. default:
  436. ASSERT(!"Valid Low Io Op Code");
  437. }
  438. if (!FlagOn(LowIoContext->Flags,LOWIO_CONTEXT_FLAG_SYNCCALL)){
  439. //if we're being called from lowiosubmit then just get out otherwise...do the completion
  440. RxCompleteAsynchronousRequest( RxContext, Status );
  441. }
  442. RxDbgTrace(-1, Dbg, ("RxLowIoCompletionTail, Status=%08lx\n",Status));
  443. return(Status);
  444. }
  445. NTSTATUS
  446. RxLowIoCompletion (
  447. IN PRX_CONTEXT RxContext
  448. )
  449. /*++
  450. Routine Description:
  451. This routine must be called by the minirdr lowio routines when they
  452. complete IF THEY HAVE INITIALLY RETURNED PENDING.
  453. It behaves a bit differently depending on whether it's sync or
  454. async IO. for sync, we just get back into the user's thread. for async,
  455. we first try the completion routine directly....if we get MORE_PROCESSING...
  456. then we flip to a thread and the routine will be recalled.
  457. Arguments:
  458. RxContext - the RDBSS context
  459. Return Value:
  460. whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED). the value M_P_R is very handy
  461. if this is being called for a Irp completion; M_P_R causes the Irp completion guy to stop processing....which
  462. is good since the called completion routine may complete the packet!
  463. --*/
  464. {
  465. RxCaptureParamBlock;
  466. #ifndef WIN9X
  467. NTSTATUS Status;
  468. #endif
  469. BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
  470. PAGED_CODE();
  471. if (SynchronousIo) {
  472. RxSignalSynchronousWaiter(RxContext);
  473. return(STATUS_MORE_PROCESSING_REQUIRED);
  474. }
  475. #ifdef WIN9X
  476. RxDbgTrace(0, Dbg, ("We SHOULD NEVER GET HERE\n"));
  477. ASSERT(FALSE);
  478. #else
  479. RxDbgTrace(0, Dbg, ("RxLowIoCompletion ASYNC\n"));
  480. ASSERT (RxLowIoIsBufferLocked(&RxContext->LowIoContext));
  481. Status = RxLowIoCompletionTail(RxContext);
  482. //the called routine makes the decision as to whether it can continue.....many will ask for
  483. //a post if we're at DPC level.....some will not.
  484. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  485. RxFsdPostRequestWithResume(RxContext,RxLowIoCompletion);
  486. return(STATUS_MORE_PROCESSING_REQUIRED);
  487. }
  488. //i'm not too sure about this
  489. if (Status == STATUS_RETRY) {
  490. RxFsdPostRequestWithResume(RxContext,RxLowIoSubmitRETRY);
  491. return(STATUS_MORE_PROCESSING_REQUIRED);
  492. }
  493. return(Status);
  494. #endif
  495. }
  496. #if DBG
  497. VOID
  498. RxAssertFsctlIsLikeIoctl ()
  499. {
  500. ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.OutputBufferLength)
  501. == FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.OutputBufferLength) );
  502. ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.InputBufferLength)
  503. == FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.InputBufferLength) );
  504. ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.FsControlCode)
  505. == FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.IoControlCode) );
  506. ASSERT(FIELD_OFFSET(IO_STACK_LOCATION,Parameters.FileSystemControl.Type3InputBuffer)
  507. == FIELD_OFFSET(IO_STACK_LOCATION,Parameters.DeviceIoControl.Type3InputBuffer) );
  508. }
  509. #else
  510. #define RxAssertFsctlIsLikeIoctl()
  511. #endif //if DBG
  512. NTSTATUS
  513. NTAPI
  514. RxLowIoPopulateFsctlInfo (
  515. IN PRX_CONTEXT RxContext
  516. )
  517. {
  518. NTSTATUS Status = STATUS_SUCCESS;
  519. RxCaptureRequestPacket;
  520. RxCaptureParamBlock;
  521. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  522. PAGED_CODE();
  523. RxAssertFsctlIsLikeIoctl();
  524. LowIoContext->ParamsFor.FsCtl.FsControlCode =
  525. capPARAMS->Parameters.FileSystemControl.FsControlCode;
  526. LowIoContext->ParamsFor.FsCtl.InputBufferLength =
  527. capPARAMS->Parameters.FileSystemControl.InputBufferLength;
  528. LowIoContext->ParamsFor.FsCtl.OutputBufferLength =
  529. capPARAMS->Parameters.FileSystemControl.OutputBufferLength;
  530. LowIoContext->ParamsFor.FsCtl.MinorFunction = capPARAMS->MinorFunction;
  531. switch (LowIoContext->ParamsFor.FsCtl.FsControlCode & 3) {
  532. case METHOD_BUFFERED:
  533. {
  534. LowIoContext->ParamsFor.FsCtl.pInputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
  535. LowIoContext->ParamsFor.FsCtl.pOutputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
  536. }
  537. break;
  538. case METHOD_IN_DIRECT:
  539. case METHOD_OUT_DIRECT:
  540. {
  541. LowIoContext->ParamsFor.FsCtl.pInputBuffer = capReqPacket->AssociatedIrp.SystemBuffer;
  542. if (capReqPacket->MdlAddress!=NULL) {
  543. LowIoContext->ParamsFor.FsCtl.pOutputBuffer =
  544. MmGetSystemAddressForMdlSafe(
  545. capReqPacket->MdlAddress,
  546. NormalPagePriority);
  547. if (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL) {
  548. Status = STATUS_INSUFFICIENT_RESOURCES;
  549. }
  550. } else {
  551. LowIoContext->ParamsFor.FsCtl.pOutputBuffer = NULL;
  552. }
  553. }
  554. break;
  555. case METHOD_NEITHER:
  556. {
  557. LowIoContext->ParamsFor.FsCtl.pInputBuffer = capPARAMS->Parameters.FileSystemControl.Type3InputBuffer;
  558. LowIoContext->ParamsFor.FsCtl.pOutputBuffer = capReqPacket->UserBuffer;
  559. }
  560. break;
  561. default:
  562. ASSERT(!"Valid Method for Fs Control");
  563. break;
  564. }
  565. return Status;
  566. }
  567. NTSTATUS
  568. RxLowIoSubmit (
  569. IN PRX_CONTEXT RxContext,
  570. PLOWIO_COMPLETION_ROUTINE CompletionRoutine
  571. )
  572. /*++
  573. Routine Description:
  574. This routine passes the request to the minirdr after setting up for completion. it then waits
  575. or pends as appropriate.
  576. Arguments:
  577. RxContext - the usual
  578. Return Value:
  579. whatever value is returned by a callout....or by LowIoCompletion.
  580. --*/
  581. {
  582. RxCaptureRequestPacket;
  583. RxCaptureFcb;
  584. RxCaptureFobx;
  585. RxCaptureParamBlock;
  586. RxCaptureFileObject;
  587. NTSTATUS Status = STATUS_SUCCESS;
  588. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  589. ULONG Operation = LowIoContext->Operation;
  590. BOOLEAN SynchronousIo = !BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION);
  591. PAGED_CODE();
  592. LowIoContext->CompletionRoutine = CompletionRoutine;
  593. RxDbgTrace(+1, Dbg, ("RxLowIoSubmit, Operation=%08lx\n",LowIoContext->Operation));
  594. switch (Operation) {
  595. case LOWIO_OP_READ:
  596. case LOWIO_OP_WRITE:
  597. ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xffffffee);
  598. ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xeeeeeeee);
  599. RxLockAndMapUserBufferForLowIo(RxContext,LowIoContext,Operation);
  600. #ifndef WIN9X
  601. // NT paging IO is different from WIN9X so this may be different
  602. if (FlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,LOWIO_READWRITEFLAG_PAGING_IO)) {
  603. ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
  604. RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
  605. RxInsertIntoOutStandingPagingOperationsList(RxContext,Operation);
  606. ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
  607. }
  608. #else
  609. if (!LowIoContext->ParamsFor.ReadWrite.Buffer) {
  610. //
  611. // Couldn't get mdl for data!
  612. //
  613. return(STATUS_INSUFFICIENT_RESOURCES);
  614. }
  615. #endif //ifndef WIN9X
  616. break;
  617. //can't do much to make this OS independent
  618. case LOWIO_OP_FSCTL:
  619. case LOWIO_OP_IOCTL:
  620. Status = RxLowIoPopulateFsctlInfo(RxContext);
  621. if (Status == STATUS_SUCCESS) {
  622. if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0) &&
  623. (LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL)) {
  624. Status = STATUS_INVALID_PARAMETER;
  625. }
  626. if ((LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0) &&
  627. (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) {
  628. Status = STATUS_INVALID_PARAMETER;
  629. }
  630. }
  631. break;
  632. case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
  633. case LOWIO_OP_SHAREDLOCK:
  634. case LOWIO_OP_EXCLUSIVELOCK:
  635. case LOWIO_OP_UNLOCK:
  636. case LOWIO_OP_UNLOCK_MULTIPLE:
  637. case LOWIO_OP_CLEAROUT:
  638. break;
  639. default:
  640. ASSERT(!"Valid Low Io Op Code");
  641. Status = STATUS_INVALID_PARAMETER;
  642. }
  643. SetFlag(RxContext->Flags,RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
  644. if (Status==STATUS_SUCCESS) {
  645. PMINIRDR_DISPATCH pMiniRdrDispatch;
  646. if (!SynchronousIo) {
  647. //get ready for any arbitrary finish order...assume return of pending
  648. InterlockedIncrement(&RxContext->ReferenceCount);
  649. if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)) {
  650. RxMarkPendingForLowIo(RxContext);
  651. }
  652. RxDbgTrace( 0, Dbg, ("RxLowIoSubmit, Operation is ASYNC!\n"));
  653. }
  654. pMiniRdrDispatch = NULL;
  655. RxGetMiniRdrDispatchForLowIo(RxContext);
  656. if (pMiniRdrDispatch != NULL) {
  657. do {
  658. RxContext->InformationToReturn = 0;
  659. MINIRDR_CALL(
  660. Status,
  661. RxContext,
  662. pMiniRdrDispatch,
  663. MRxLowIOSubmit[LowIoContext->Operation],
  664. (RxContext));
  665. if (Status == STATUS_PENDING){
  666. if (!SynchronousIo) {
  667. goto FINALLY;
  668. }
  669. RxWaitSync(RxContext);
  670. Status = RxContext->StoredStatus;
  671. } else {
  672. if (!SynchronousIo && Status != STATUS_RETRY) {
  673. //we were wrong about pending..so clear the bit and deref
  674. if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)) {
  675. RxUnmarkPendingForLowIo(RxContext);
  676. }
  677. InterlockedDecrement(&RxContext->ReferenceCount);
  678. }
  679. }
  680. } while (Status == STATUS_RETRY);
  681. } else {
  682. Status = STATUS_INVALID_PARAMETER;
  683. }
  684. }
  685. //you do not come here for pended,async IO
  686. RxContext->StoredStatus = Status;
  687. SetFlag(LowIoContext->Flags,LOWIO_CONTEXT_FLAG_SYNCCALL);
  688. Status = RxLowIoCompletionTail(RxContext);
  689. FINALLY:
  690. RxDbgTrace(-1, Dbg, ("RxLowIoSubmit, Status=%08lx\n",Status));
  691. return(Status);
  692. }
  693. VOID
  694. RxInitializeLowIoPerFcbInfo(
  695. PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
  696. )
  697. /*++
  698. Routine Description:
  699. This routine is called in FcbInitialization to initialize the LowIo part of the structure.
  700. Arguments:
  701. LowIoPerFcbInfo - the struct to be initialized
  702. Return Value:
  703. --*/
  704. {
  705. PAGED_CODE();
  706. InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
  707. InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
  708. }
  709.