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.

707 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. fscontrl.c
  5. Abstract:
  6. This module implements the forwarding of all broadcast requests
  7. to UNC providers.
  8. Author:
  9. Manny Weiser (mannyw) 6-Jan-1992
  10. Revision History:
  11. --*/
  12. #include "mup.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_FORWARD)
  17. //
  18. // local procedure prototypes
  19. //
  20. NTSTATUS
  21. BuildAndSubmitIrp (
  22. IN PIRP OriginalIrp,
  23. IN PCCB Ccb,
  24. IN PMASTER_FORWARDED_IO_CONTEXT MasterContext
  25. );
  26. NTSTATUS
  27. ForwardedIoCompletionRoutine (
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp,
  30. IN PVOID Context
  31. );
  32. VOID
  33. DeferredForwardedIoCompletionRoutine(
  34. PVOID Context);
  35. NTSTATUS
  36. CommonForwardedIoCompletionRoutine(
  37. IN PDEVICE_OBJECT DeviceObject,
  38. IN PIRP Irp,
  39. IN PVOID Context);
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text( PAGE, BuildAndSubmitIrp )
  42. #pragma alloc_text( PAGE, MupForwardIoRequest )
  43. #endif
  44. NTSTATUS
  45. MupForwardIoRequest (
  46. IN PMUP_DEVICE_OBJECT MupDeviceObject,
  47. IN PIRP Irp
  48. )
  49. /*++
  50. Routine Description:
  51. This routine forwards an I/O Request Packet to all redirectors for
  52. a broadcast request.
  53. Arguments:
  54. MupDeviceObject - Supplies the device object to use.
  55. Irp - Supplies the Irp being processed
  56. Return Value:
  57. NTSTATUS - The status for the IRP
  58. --*/
  59. {
  60. NTSTATUS status;
  61. PIO_STACK_LOCATION irpSp;
  62. PFCB fcb;
  63. PVOID fscontext2;
  64. PLIST_ENTRY listEntry;
  65. PCCB ccb;
  66. PMASTER_FORWARDED_IO_CONTEXT masterContext;
  67. BOOLEAN ownLock = FALSE;
  68. MupDeviceObject;
  69. PAGED_CODE();
  70. DebugTrace(+1, Dbg, "MupForwardIrp\n", 0);
  71. if (MupEnableDfs &&
  72. MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) {
  73. status = DfsVolumePassThrough((PDEVICE_OBJECT)MupDeviceObject, Irp);
  74. return( status );
  75. }
  76. irpSp = IoGetCurrentIrpStackLocation( Irp );
  77. //
  78. // Find the FCB for this file object
  79. //
  80. FsRtlEnterFileSystem();
  81. MupDecodeFileObject(
  82. irpSp->FileObject,
  83. (PVOID *)&fcb,
  84. &fscontext2
  85. );
  86. if ( fcb == NULL || BlockType( fcb ) != BlockTypeFcb ) {
  87. //
  88. // This is not an FCB.
  89. //
  90. DebugTrace(0, Dbg, "The fail is closing\n", 0);
  91. FsRtlExitFileSystem();
  92. MupCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST );
  93. status = STATUS_INVALID_DEVICE_REQUEST;
  94. DebugTrace(-1, Dbg, "MupForwardRequest -> %08lx\n", status );
  95. return status;
  96. }
  97. //
  98. // Allocate a context structure
  99. //
  100. masterContext = MupAllocateMasterIoContext();
  101. if (masterContext == NULL) {
  102. //
  103. // We ran out of resources. Clean up and return the error.
  104. //
  105. DebugTrace(0, Dbg, "Couldn't allc masterContect\n", 0);
  106. FsRtlExitFileSystem();
  107. MupCompleteRequest( Irp, STATUS_INSUFFICIENT_RESOURCES );
  108. status = STATUS_INSUFFICIENT_RESOURCES;
  109. DebugTrace(-1, Dbg, "MupForwardRequest -> %08lx\n", status );
  110. return status;
  111. }
  112. DebugTrace( 0, Dbg, "Allocated MasterContext 0x%08lx\n", masterContext );
  113. IoMarkIrpPending(Irp);
  114. //
  115. // At this point, we're committed to returning STATUS_PENDING
  116. //
  117. masterContext->OriginalIrp = Irp;
  118. //
  119. // set status for MupDereferenceMasterIoContext. If this is still
  120. // an error when the context is freed then masterContext->ErrorStatus
  121. // will be used to complete the request.
  122. //
  123. masterContext->SuccessStatus = STATUS_UNSUCCESSFUL;
  124. masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
  125. //
  126. // Copy the referenced pointer to the FCB.
  127. //
  128. masterContext->Fcb = fcb;
  129. try {
  130. //
  131. // Submit the forwarded IRPs. Note that we can not hold the lock
  132. // across calls to BuildAndSubmitIrp as it calls IoCallDriver().
  133. //
  134. ACQUIRE_LOCK( &MupCcbListLock );
  135. ownLock = TRUE;
  136. listEntry = fcb->CcbList.Flink;
  137. while ( listEntry != &fcb->CcbList ) {
  138. RELEASE_LOCK( &MupCcbListLock );
  139. ownLock = FALSE;
  140. ccb = CONTAINING_RECORD( listEntry, CCB, ListEntry );
  141. MupAcquireGlobalLock();
  142. MupReferenceBlock( ccb );
  143. MupReleaseGlobalLock();
  144. BuildAndSubmitIrp( Irp, ccb, masterContext );
  145. ACQUIRE_LOCK( &MupCcbListLock );
  146. ownLock = TRUE;
  147. listEntry = listEntry->Flink;
  148. }
  149. RELEASE_LOCK( &MupCcbListLock );
  150. ownLock = FALSE;
  151. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  152. masterContext->ErrorStatus = GetExceptionCode();
  153. }
  154. //
  155. // If BuildAndSubmitIrp threw an exception, the lock might still be
  156. // held. Drop it if so.
  157. //
  158. if (ownLock == TRUE) {
  159. RELEASE_LOCK( &MupCcbListLock );
  160. }
  161. //
  162. // Release our reference to the master IO context block.
  163. //
  164. MupDereferenceMasterIoContext( masterContext, NULL );
  165. //
  166. // Return to the caller.
  167. //
  168. FsRtlExitFileSystem();
  169. DebugTrace(-1, Dbg, "MupForwardIrp -> %08lx\n", status);
  170. return STATUS_PENDING;
  171. }
  172. NTSTATUS
  173. BuildAndSubmitIrp (
  174. IN PIRP OriginalIrp,
  175. IN PCCB Ccb,
  176. IN PMASTER_FORWARDED_IO_CONTEXT MasterContext
  177. )
  178. /*++
  179. Routine Description:
  180. This routine takes the original IRP and forwards it to the
  181. the UNC provider described by the CCB.
  182. Arguments:
  183. OriginalIrp - Supplies the Irp being processed
  184. Ccb - A pointer the the ccb.
  185. MasterContext - A pointer to the master context block for this
  186. forwarded request.
  187. Return Value:
  188. NTSTATUS - The status for the Irp
  189. --*/
  190. {
  191. PIRP irp = NULL;
  192. PIO_STACK_LOCATION irpSp;
  193. PFORWARDED_IO_CONTEXT forwardedIoContext = NULL;
  194. NTSTATUS status = STATUS_SUCCESS;
  195. PDEVICE_OBJECT deviceObject;
  196. ULONG bufferLength;
  197. KPROCESSOR_MODE requestorMode;
  198. PMDL mdl = NULL;
  199. PAGED_CODE();
  200. DebugTrace(+1, Dbg, "BuildAndSubmitIrp\n", 0);
  201. try {
  202. // make this NonPagedPool, since we could free this up in the
  203. // io completion routine.
  204. forwardedIoContext = ExAllocatePoolWithTag(
  205. NonPagedPool,
  206. sizeof( FORWARDED_IO_CONTEXT ),
  207. ' puM');
  208. if (forwardedIoContext == NULL) {
  209. try_return(status = STATUS_INSUFFICIENT_RESOURCES);
  210. }
  211. forwardedIoContext->pIrp = NULL;
  212. forwardedIoContext->DeviceObject = NULL;
  213. DebugTrace( 0, Dbg, "Allocated work context 0x%08lx\n", forwardedIoContext );
  214. //
  215. // Get the address of the target device object. Note that this was
  216. // already done for the no intermediate buffering case, but is done
  217. // here again to speed up the turbo write path.
  218. //
  219. deviceObject = IoGetRelatedDeviceObject( Ccb->FileObject );
  220. //
  221. // Allocate and initialize the I/O Request Packet (IRP) for this
  222. // operation. The allocation is performed with an exception handler
  223. // in case the caller does not have enough quota to allocate the
  224. // packet.
  225. //
  226. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  227. if (irp == NULL) {
  228. //
  229. // An IRP could not be allocated. Return an appropriate
  230. // error status code.
  231. //
  232. try_return(status = STATUS_INSUFFICIENT_RESOURCES);
  233. }
  234. irp->Tail.Overlay.OriginalFileObject = Ccb->FileObject;
  235. irp->Tail.Overlay.Thread = OriginalIrp->Tail.Overlay.Thread;
  236. irp->RequestorMode = KernelMode;
  237. //
  238. // Get a pointer to the stack location for the first driver. This will be
  239. // used to pass the original function codes and parameters.
  240. //
  241. irpSp = IoGetNextIrpStackLocation( irp );
  242. //
  243. // Copy the parameters from the original request.
  244. //
  245. RtlMoveMemory(
  246. irpSp,
  247. IoGetCurrentIrpStackLocation( OriginalIrp ),
  248. sizeof( *irpSp )
  249. );
  250. bufferLength = irpSp->Parameters.Write.Length;
  251. irpSp->FileObject = Ccb->FileObject;
  252. //
  253. // Even though this is probably meaningless to a remote mailslot
  254. // write, pass it though obediently.
  255. //
  256. if (Ccb->FileObject->Flags & FO_WRITE_THROUGH) {
  257. irpSp->Flags = SL_WRITE_THROUGH;
  258. }
  259. requestorMode = OriginalIrp->RequestorMode;
  260. //
  261. // Now determine whether this device expects to have data buffered
  262. // to it or whether it performs direct I/O. This is based on the
  263. // DO_BUFFERED_IO flag in the device object. If the flag is set,
  264. // then a system buffer is allocated and the caller's data is copied
  265. // into it. Otherwise, a Memory Descriptor List (MDL) is allocated
  266. // and the caller's buffer is locked down using it.
  267. //
  268. if (deviceObject->Flags & DO_BUFFERED_IO) {
  269. //
  270. // The device does not support direct I/O. Allocate a system
  271. // buffer, and copy the caller's data into it. This is done
  272. // using an exception handler that will perform cleanup if the
  273. // operation fails. Note that this is only done if the operation
  274. // has a non-zero length.
  275. //
  276. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  277. if ( bufferLength != 0 ) {
  278. //
  279. // If the request was made from a mode other than kernel,
  280. // presumably user, probe the entire buffer to determine
  281. // whether or not the caller has write access to it.
  282. //
  283. if (requestorMode != KernelMode) {
  284. ProbeForRead(
  285. OriginalIrp->UserBuffer,
  286. bufferLength,
  287. sizeof( UCHAR )
  288. );
  289. }
  290. //
  291. // Allocate the intermediary system buffer from paged
  292. // pool and charge quota for it.
  293. //
  294. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(
  295. PagedPoolCacheAligned,
  296. bufferLength,
  297. ' puM');
  298. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  299. try_return(status = STATUS_INSUFFICIENT_RESOURCES);
  300. }
  301. RtlMoveMemory(
  302. irp->AssociatedIrp.SystemBuffer,
  303. OriginalIrp->UserBuffer,
  304. bufferLength);
  305. //
  306. // Set the IRP_BUFFERED_IO flag in the IRP so that I/O
  307. // completion will know that this is not a direct I/O
  308. // operation. Also set the IRP_DEALLOCATE_BUFFER flag
  309. // so it will deallocate the buffer.
  310. //
  311. irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  312. } else {
  313. //
  314. // This is a zero-length write. Simply indicate that this is
  315. // buffered I/O, and pass along the request. The buffer will
  316. // not be set to deallocate so the completion path does not
  317. // have to special-case the length.
  318. //
  319. irp->Flags = IRP_BUFFERED_IO;
  320. }
  321. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  322. //
  323. // This is a direct I/O operation. Allocate an MDL and invoke the
  324. // memory management routine to lock the buffer into memory.
  325. // Note that no MDL is allocated, nor is any memory probed or
  326. // locked if the length of the request was zero.
  327. //
  328. if ( bufferLength != 0 ) {
  329. //
  330. // Allocate an MDL, charging quota for it, and hang it
  331. // off of the IRP. Probe and lock the pages associated
  332. // with the caller's buffer for read access and fill in
  333. // the MDL with the PFNs of those pages.
  334. //
  335. mdl = IoAllocateMdl(
  336. OriginalIrp->UserBuffer,
  337. bufferLength,
  338. FALSE,
  339. TRUE,
  340. irp
  341. );
  342. if (mdl == NULL) {
  343. try_return(status = STATUS_INSUFFICIENT_RESOURCES);
  344. }
  345. MmProbeAndLockPages( mdl, requestorMode, IoReadAccess );
  346. }
  347. } else {
  348. //
  349. // Pass the address of the caller's buffer to the device driver.
  350. // It is now up to the driver to do everything.
  351. //
  352. irp->UserBuffer = OriginalIrp->UserBuffer;
  353. }
  354. //
  355. // If this write operation is to be performed without any caching,
  356. // set the appropriate flag in the IRP so no caching is performed.
  357. //
  358. if (Ccb->FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
  359. irp->Flags |= IRP_NOCACHE | IRP_WRITE_OPERATION;
  360. } else {
  361. irp->Flags |= IRP_WRITE_OPERATION;
  362. }
  363. //
  364. // Setup the context block
  365. //
  366. forwardedIoContext->Ccb = Ccb;
  367. forwardedIoContext->MasterContext = MasterContext;
  368. MupAcquireGlobalLock();
  369. MupReferenceBlock( MasterContext );
  370. MupReleaseGlobalLock();
  371. //
  372. // Set up the completion routine.
  373. //
  374. IoSetCompletionRoutine(
  375. irp,
  376. (PIO_COMPLETION_ROUTINE)ForwardedIoCompletionRoutine,
  377. forwardedIoContext,
  378. TRUE,
  379. TRUE,
  380. TRUE
  381. );
  382. //
  383. // Pass the request to the provider.
  384. //
  385. IoCallDriver( Ccb->DeviceObject, irp );
  386. //
  387. // At this point it is up to the completion routine to free things
  388. //
  389. irp = NULL;
  390. forwardedIoContext = NULL;
  391. mdl = NULL;
  392. try_exit:
  393. NOTHING;
  394. } except(EXCEPTION_EXECUTE_HANDLER) {
  395. status = GetExceptionCode();
  396. }
  397. //
  398. // Clean up everything if we are returning an error
  399. //
  400. if (!NT_SUCCESS(status)) {
  401. if ( forwardedIoContext != NULL )
  402. ExFreePool( forwardedIoContext );
  403. if ( irp != NULL ) {
  404. if (irp->AssociatedIrp.SystemBuffer != NULL)
  405. ExFreePool(irp->AssociatedIrp.SystemBuffer);
  406. IoFreeIrp( irp );
  407. }
  408. if ( mdl != NULL )
  409. IoFreeMdl( mdl );
  410. }
  411. DebugTrace(-1, Dbg, "BuildAndSubmitIrp -> 0x%08lx\n", status);
  412. return status;
  413. }
  414. NTSTATUS
  415. ForwardedIoCompletionRoutine (
  416. IN PDEVICE_OBJECT DeviceObject,
  417. IN PIRP Irp,
  418. IN PVOID Context
  419. )
  420. /*++
  421. Routine Description:
  422. This routines cleans up after a forwarded IRP has completed.
  423. Arguments:
  424. DeviceObject - A pointer to the MUP device object.
  425. IRP - A pointer to the IRP being processed.
  426. Context - A pointer to a block containing the context of a forward IRP.
  427. Return Value:
  428. None.
  429. --*/
  430. {
  431. PFORWARDED_IO_CONTEXT ioContext = Context;
  432. NTSTATUS status = Irp->IoStatus.Status;
  433. DebugTrace( +1, Dbg, "ForwardedIoCompletionRoutine\n", 0 );
  434. DebugTrace( 0, Dbg, "Irp = 0x%08lx\n", Irp );
  435. DebugTrace( 0, Dbg, "Context = 0x%08lx\n", Context );
  436. DebugTrace( 0, Dbg, "status = 0x%08lx\n", status );
  437. //
  438. // Give this to a worker thread if we are at too high an Irq level
  439. //
  440. if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
  441. ioContext->DeviceObject = DeviceObject;
  442. ioContext->pIrp = Irp;
  443. ExInitializeWorkItem(
  444. &ioContext->WorkQueueItem,
  445. DeferredForwardedIoCompletionRoutine,
  446. Context);
  447. ExQueueWorkItem(&ioContext->WorkQueueItem, CriticalWorkQueue);
  448. } else {
  449. CommonForwardedIoCompletionRoutine(
  450. DeviceObject,
  451. Irp,
  452. Context);
  453. }
  454. //
  455. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  456. // will stop working on the IRP.
  457. //
  458. DebugTrace( -1, Dbg, "ForwardedIoCompletionRoutine exit\n", 0 );
  459. return STATUS_MORE_PROCESSING_REQUIRED;
  460. }
  461. VOID
  462. DeferredForwardedIoCompletionRoutine(
  463. PVOID Context)
  464. {
  465. PFORWARDED_IO_CONTEXT ioContext = Context;
  466. CommonForwardedIoCompletionRoutine(
  467. ioContext->DeviceObject,
  468. ioContext->pIrp,
  469. Context);
  470. }
  471. NTSTATUS
  472. CommonForwardedIoCompletionRoutine(
  473. IN PDEVICE_OBJECT DeviceObject,
  474. IN PIRP Irp,
  475. IN PVOID Context)
  476. {
  477. PFORWARDED_IO_CONTEXT ioContext = Context;
  478. NTSTATUS status = Irp->IoStatus.Status;
  479. DeviceObject;
  480. //
  481. // Free the Irp, and any additional structures we may have allocated.
  482. //
  483. if ( Irp->MdlAddress ) {
  484. MmUnlockPages( Irp->MdlAddress );
  485. IoFreeMdl( Irp->MdlAddress );
  486. }
  487. if ( Irp->Flags & IRP_DEALLOCATE_BUFFER ) {
  488. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  489. }
  490. IoFreeIrp( Irp );
  491. //
  492. // Release the our referenced blocks.
  493. //
  494. MupDereferenceCcb( ioContext->Ccb );
  495. MupDereferenceMasterIoContext( ioContext->MasterContext, &status );
  496. //
  497. // Free the slave forwarded IO context block
  498. //
  499. ExFreePool( ioContext );
  500. return STATUS_MORE_PROCESSING_REQUIRED;
  501. }