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.

451 lines
12 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: CLOSE.C
  6. //
  7. // Contents: This module implements the File Close and Cleanup routines for
  8. // Dsfs called by the dispatch driver.
  9. //
  10. // Functions: DfsFsdClose - FSD entry point for Close IRP
  11. // DfsFsdCleanup - FSD entry point for Cleanup IRP
  12. // DfsFspClose - FSP entry point for Close IRP
  13. // DfsCommonClose - Common close IRP handler
  14. //
  15. // History: 12 Nov 1991 AlanW Created from CDFS souce.
  16. //-----------------------------------------------------------------------------
  17. #include "dfsprocs.h"
  18. #include "fcbsup.h"
  19. #include "mupwml.h"
  20. //
  21. // The local debug trace level
  22. //
  23. #define Dbg (DEBUG_TRACE_CLOSE)
  24. //
  25. // Local procedure prototypes
  26. //
  27. NTSTATUS
  28. DfsCommonClose (
  29. IN PIRP_CONTEXT IrpContext,
  30. IN PIRP Irp
  31. );
  32. VOID
  33. DfsCloseWorkInSystemContext (
  34. PDFS_FCB pDfsFcb );
  35. VOID
  36. DfsClosePostSystemWork(
  37. PDFS_FCB pDfsFcb );
  38. #ifdef ALLOC_PRAGMA
  39. #pragma alloc_text( PAGE, DfsFsdClose )
  40. #pragma alloc_text( PAGE, DfsFsdCleanup )
  41. #pragma alloc_text( PAGE, DfsFspClose )
  42. #pragma alloc_text( PAGE, DfsCommonClose )
  43. #endif // ALLOC_PRAGMA
  44. //+-------------------------------------------------------------------
  45. //
  46. // Function: DfsFsdClose, public
  47. //
  48. // Synopsis: This routine implements the FSD part of closing down the
  49. // last reference to a file object.
  50. //
  51. // Arguments: [DeviceObject] -- Supplies the device object where the
  52. // file being closed exists
  53. // [Irp] - Supplies the Irp being processed
  54. //
  55. // Returns: NTSTATUS - The FSD status for the IRP
  56. //
  57. // Notes: Even when the close is through the attached device
  58. // object, we need to check if the file is one of ours,
  59. // since files opened via the logical root device
  60. // object get switched over to the attached device for
  61. // local volumes.
  62. //
  63. //--------------------------------------------------------------------
  64. NTSTATUS
  65. DfsFsdClose (
  66. IN PDEVICE_OBJECT DeviceObject,
  67. IN PIRP Irp
  68. ) {
  69. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  70. PFILE_OBJECT FileObject = IrpSp->FileObject;
  71. NTSTATUS Status;
  72. PIRP_CONTEXT IrpContext;
  73. MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Entry,
  74. LOGPTR(DeviceObject)
  75. LOGPTR(Irp)
  76. LOGPTR(FileObject));
  77. DfsDbgTrace(+1, Dbg, "DfsFsdClose: Entered\n", 0);
  78. ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
  79. if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
  80. if (DfsLookupFcb(IrpSp->FileObject) == NULL) {
  81. Status = DfsVolumePassThrough(DeviceObject, Irp);
  82. DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status) );
  83. return Status;
  84. }
  85. }
  86. //
  87. // Call the common close routine, with blocking allowed if synchronous
  88. //
  89. FsRtlEnterFileSystem();
  90. try {
  91. IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
  92. if (IrpContext == NULL)
  93. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  94. Status = DfsCommonClose( IrpContext, Irp );
  95. } except(DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) {
  96. //
  97. // We had some trouble trying to perform the requested
  98. // operation, so we'll abort the I/O request with
  99. // the error status that we get back from the
  100. // execption code
  101. //
  102. Status = DfsProcessException( IrpContext, Irp, GetExceptionCode() );
  103. }
  104. FsRtlExitFileSystem();
  105. //
  106. // And return to our caller
  107. //
  108. DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status));
  109. MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Exit,
  110. LOGSTATUS(Status)
  111. LOGPTR(DeviceObject)
  112. LOGPTR(Irp)
  113. LOGPTR(FileObject));
  114. return Status;
  115. }
  116. //+-------------------------------------------------------------------
  117. //
  118. // Function: DfsFsdCleanup, public
  119. //
  120. // Synopsis: This routine implements the FSD part of closing down the
  121. // last user handle to a file object.
  122. //
  123. // Arguments: [DeviceObject] -- Supplies the device object where the
  124. // file being closed exists
  125. // [Irp] - Supplies the Irp being processed
  126. //
  127. // Returns: NTSTATUS - The FSD status for the IRP
  128. //
  129. //--------------------------------------------------------------------
  130. NTSTATUS
  131. DfsFsdCleanup (
  132. IN PDEVICE_OBJECT DeviceObject,
  133. IN PIRP Irp
  134. ) {
  135. NTSTATUS Status;
  136. PIRP_CONTEXT IrpContext;
  137. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  138. PFILE_OBJECT FileObject = IrpSp->FileObject;
  139. TYPE_OF_OPEN TypeOfOpen;
  140. PDFS_VCB Vcb;
  141. PDFS_FCB Fcb;
  142. DfsDbgTrace(+1, Dbg, "DfsFsdCleanup: Entered\n", 0);
  143. MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Entry,
  144. LOGPTR(DeviceObject)
  145. LOGPTR(FileObject)
  146. LOGPTR(Irp));
  147. ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
  148. //
  149. // Now, pass through to the device that opened the file for us if the
  150. // file was a redirected open of some kind.
  151. //
  152. if (DeviceObject->DeviceType == FILE_DEVICE_DFS) {
  153. TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
  154. if (TypeOfOpen == RedirectedFileOpen) {
  155. Status = DfsVolumePassThrough(DeviceObject, Irp);
  156. DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: RedirectedOpen.Exit -> %08lx\n", ULongToPtr(Status) );
  157. return Status;
  158. }
  159. }
  160. //
  161. // TypeOfOpen != RedirectedFileOpen. We do nothing special for cleanup;
  162. // everything is done in the close routine.
  163. //
  164. FsRtlEnterFileSystem();
  165. Status = STATUS_SUCCESS;
  166. DfsCompleteRequest( NULL, Irp, Status );
  167. FsRtlExitFileSystem();
  168. //
  169. // And return to our caller
  170. //
  171. DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: Exit -> %08lx\n", ULongToPtr(Status));
  172. MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Exit,
  173. LOGSTATUS(Status)
  174. LOGPTR(DeviceObject)
  175. LOGPTR(FileObject)
  176. LOGPTR(Irp));
  177. return Status;
  178. }
  179. //+-------------------------------------------------------------------
  180. //
  181. // Function: DfsFspClose, public
  182. //
  183. // Synopsis: This routine implements the FSP part of closing down the
  184. // last reference to a file object.
  185. //
  186. // Arguments: [IrpContext] -- Supplies the IRP context for the request
  187. // being processed.
  188. // [Irp] - Supplies the Irp being processed
  189. //
  190. // Returns: PDEVICE_OBJECT - Returns the volume device object
  191. // of the volume just processed by this operation.
  192. // This value is used by the Fsp dispatcher to examine
  193. // the device object's overflow queue
  194. //
  195. //--------------------------------------------------------------------
  196. VOID
  197. DfsFspClose (
  198. IN PIRP_CONTEXT IrpContext,
  199. IN PIRP Irp
  200. ) {
  201. DfsDbgTrace(+1, Dbg, "DfsFspClose: Entered\n", 0);
  202. //
  203. // Call the common close routine.
  204. //
  205. (VOID)DfsCommonClose( IrpContext, Irp );
  206. //
  207. // And return to our caller
  208. //
  209. DfsDbgTrace(-1, Dbg, "DfsFspClose: Exit -> VOID\n", 0);
  210. }
  211. //+-------------------------------------------------------------------
  212. //
  213. // Function: DfsCommonClose, local
  214. //
  215. // Synopsis: This is the common routine for closing a file/directory
  216. // called by both the fsd and fsp threads.
  217. //
  218. // Close is invoked whenever the last reference to a file
  219. // object is deleted. Cleanup is invoked when the last handle
  220. // to a file object is closed, and is called before close.
  221. //
  222. // The function of close is to completely tear down and
  223. // remove the DFS_FCB structures associated with the
  224. // file object.
  225. //
  226. // Arguments: [Irp] -- Supplies the Irp to process
  227. //
  228. // Returns: NTSTATUS - The return status for the operation
  229. //
  230. //--------------------------------------------------------------------
  231. NTSTATUS
  232. DfsCommonClose (
  233. IN PIRP_CONTEXT IrpContext,
  234. IN PIRP Irp
  235. ) {
  236. NTSTATUS Status = STATUS_SUCCESS;
  237. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  238. PFILE_OBJECT FileObject = IrpSp->FileObject;
  239. TYPE_OF_OPEN TypeOfOpen;
  240. PDFS_VCB Vcb;
  241. PDFS_FCB Fcb;
  242. BOOLEAN DontComplete = FALSE;
  243. BOOLEAN pktLocked;
  244. DfsDbgTrace(+1, Dbg, "DfsCommonClose: Entered\n", 0);
  245. DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  246. DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject);
  247. //
  248. // This action is a noop for unopened file objects. Nothing needs
  249. // to be done for FS device opens, either.
  250. //
  251. TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
  252. if (TypeOfOpen == UnopenedFileObject ||
  253. TypeOfOpen == FilesystemDeviceOpen ) {
  254. DfsDbgTrace(-1, Dbg, "DfsCommonClose: Filesystem file object\n", 0);
  255. DfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  256. return STATUS_SUCCESS;
  257. }
  258. try {
  259. //
  260. // Case on the type of open that we are trying to close.
  261. //
  262. switch (TypeOfOpen) {
  263. case LogicalRootDeviceOpen:
  264. DfsDbgTrace(0, Dbg, "DfsCommonClose: Close LogicalRootDevice\n", 0);
  265. InterlockedDecrement(&Vcb->DirectAccessOpenCount);
  266. InterlockedDecrement(&Vcb->OpenFileCount);
  267. if (Vcb->VcbState & VCB_STATE_FLAG_LOCKED) {
  268. ASSERT (Vcb->FileObjectWithVcbLocked == FileObject);
  269. Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
  270. Vcb->FileObjectWithVcbLocked = NULL;
  271. }
  272. try_return( Status = STATUS_SUCCESS );
  273. case RedirectedFileOpen:
  274. DfsDbgTrace(0, Dbg, "DfsCommonClose: File -> %wZ\n", &Fcb->FullFileName);
  275. //
  276. // Decrement the OpenFileCount for the Vcb through which this
  277. // file was opened.
  278. //
  279. InterlockedDecrement(&Vcb->OpenFileCount);
  280. //
  281. // Close the redirected file by simply passing through
  282. // to the redirected device. We detach the DFS_FCB from the
  283. // file object before the close so it cannot be looked
  284. // up in some other thread.
  285. //
  286. DfsDetachFcb( FileObject, Fcb);
  287. Status = DfsFilePassThrough(Fcb, Irp);
  288. DontComplete = TRUE;
  289. //
  290. // Post to system work here, to avoid deadlocks with RDR.
  291. // workaround for bug 20642.
  292. //
  293. DfsClosePostSystemWork( Fcb );
  294. break;
  295. default:
  296. BugCheck("Dfs close, unexpected open type");
  297. }
  298. try_exit: NOTHING;
  299. } finally {
  300. //
  301. // If this is a normal termination, then complete the request.
  302. // Even if we're not to complete the IRP, we still need to
  303. // delete the IRP_CONTEXT.
  304. //
  305. if (!AbnormalTermination()) {
  306. if (DontComplete) {
  307. DfsCompleteRequest( IrpContext, NULL, 0 );
  308. } else {
  309. DfsCompleteRequest( IrpContext, Irp, Status );
  310. }
  311. }
  312. DfsDbgTrace(-1, Dbg, "DfsCommonClose: Exit -> %08lx\n", ULongToPtr(Status));
  313. }
  314. return Status;
  315. }
  316. VOID
  317. DfsClosePostSystemWork(
  318. PDFS_FCB pDfsFcb )
  319. {
  320. ExInitializeWorkItem( &pDfsFcb->WorkQueueItem,
  321. DfsCloseWorkInSystemContext,
  322. pDfsFcb );
  323. ExQueueWorkItem( &pDfsFcb->WorkQueueItem, CriticalWorkQueue );
  324. return;
  325. }
  326. //
  327. //work around for bug 20642.
  328. //
  329. VOID
  330. DfsCloseWorkInSystemContext (
  331. PDFS_FCB pDfsFcb )
  332. {
  333. BOOLEAN pktLocked;
  334. //
  335. // Decrement the RefCount on the DFS_MACHINE_ENTRY through which
  336. // this file was opened
  337. //
  338. PktAcquireExclusive( TRUE, &pktLocked );
  339. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  340. DfsDecrementMachEntryCount(pDfsFcb->DfsMachineEntry, TRUE);
  341. ExReleaseResourceLite( &DfsData.Resource );
  342. PktRelease();
  343. DfsDeleteFcb( NULL, pDfsFcb );
  344. }