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.

679 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. cleanup.c
  5. Abstract:
  6. This module implements the file cleanup routine for MSFS called by the
  7. dispatch driver.
  8. Author:
  9. Manny Weiser (mannyw) 23-Jan-1991
  10. Revision History:
  11. --*/
  12. #include "mailslot.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CLEANUP)
  17. //
  18. // local procedure prototypes
  19. //
  20. NTSTATUS
  21. MsCommonCleanup (
  22. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  23. IN PIRP Irp
  24. );
  25. NTSTATUS
  26. MsCleanupCcb (
  27. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  28. IN PIRP Irp,
  29. IN PCCB Ccb
  30. );
  31. NTSTATUS
  32. MsCleanupFcb (
  33. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  34. IN PIRP Irp,
  35. IN PFCB Fcb
  36. );
  37. NTSTATUS
  38. MsCleanupRootDcb (
  39. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  40. IN PIRP Irp,
  41. IN PROOT_DCB RootDcb,
  42. IN PROOT_DCB_CCB Ccb
  43. );
  44. NTSTATUS
  45. MsCleanupVcb (
  46. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  47. IN PIRP Irp,
  48. IN PVCB Vcb
  49. );
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text( PAGE, MsCleanupCcb )
  52. #pragma alloc_text( PAGE, MsCleanupFcb )
  53. #pragma alloc_text( PAGE, MsCleanupRootDcb )
  54. #pragma alloc_text( PAGE, MsCleanupVcb )
  55. #pragma alloc_text( PAGE, MsCommonCleanup )
  56. #pragma alloc_text( PAGE, MsFsdCleanup )
  57. #pragma alloc_text( PAGE, MsCancelTimer )
  58. #endif
  59. NTSTATUS
  60. MsFsdCleanup (
  61. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  62. IN PIRP Irp
  63. )
  64. /*++
  65. Routine Description:
  66. This routine implements the FSD part of the NtCleanupFile API calls.
  67. Arguments:
  68. MsfsDeviceObject - Supplies the device object to use.
  69. Irp - Supplies the Irp being processed
  70. Return Value:
  71. NTSTATUS - The Fsd status for the Irp
  72. --*/
  73. {
  74. NTSTATUS status;
  75. PAGED_CODE();
  76. DebugTrace(+1, Dbg, "MsFsdCleanup\n", 0);
  77. //
  78. // Call the common cleanup routine.
  79. //
  80. FsRtlEnterFileSystem();
  81. status = MsCommonCleanup( MsfsDeviceObject, Irp );
  82. FsRtlExitFileSystem();
  83. //
  84. // Return to our caller.
  85. //
  86. DebugTrace(-1, Dbg, "MsFsdCleanup -> %08lx\n", status );
  87. return status;
  88. }
  89. NTSTATUS
  90. MsCommonCleanup (
  91. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  92. IN PIRP Irp
  93. )
  94. /*++
  95. Routine Description:
  96. This is the common routine for cleaning up a file.
  97. Arguments:
  98. Irp - Supplies the Irp to process
  99. Return Value:
  100. NTSTATUS - the return status for the operation
  101. --*/
  102. {
  103. PIO_STACK_LOCATION irpSp;
  104. NTSTATUS status;
  105. NODE_TYPE_CODE nodeTypeCode;
  106. PVOID fsContext, fsContext2;
  107. PVCB vcb;
  108. PAGED_CODE();
  109. irpSp = IoGetCurrentIrpStackLocation( Irp );
  110. DebugTrace(+1, Dbg, "MsFsdCleanup\n", 0);
  111. DebugTrace( 0, Dbg, "MsfsDeviceObject = %08lx\n", (ULONG)MsfsDeviceObject);
  112. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp);
  113. DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)irpSp->FileObject);
  114. //
  115. // Get the a referenced pointer to the node. If this is a CCB close and the FCB is already closed
  116. // then the node type comes back as undefined. We still want to cleanup in this case.
  117. // Cleanup for the CCB in this case is removing it from the FCB chain and removing share options. We
  118. // could do without this cleanup but it would look stange to have a corrupted chain in this case
  119. // (it does not harm as its never traversed again).
  120. //
  121. if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject,
  122. &fsContext,
  123. &fsContext2 )) == NTC_UNDEFINED) {
  124. MsReferenceNode( ((PNODE_HEADER)(fsContext)) );
  125. }
  126. //
  127. // Get the VCB we are trying to access.
  128. //
  129. vcb = &MsfsDeviceObject->Vcb;
  130. //
  131. // Acquire exclusive access to the VCB.
  132. //
  133. MsAcquireExclusiveVcb( vcb );
  134. try {
  135. //
  136. // Decide how to handle this IRP.
  137. //
  138. switch (NodeType( fsContext ) ) {
  139. case MSFS_NTC_FCB: // Cleanup a server handle to a mailslot file
  140. status = MsCleanupFcb( MsfsDeviceObject,
  141. Irp,
  142. (PFCB)fsContext);
  143. MsDereferenceFcb( (PFCB)fsContext );
  144. break;
  145. case MSFS_NTC_CCB: // Cleanup a client handle to a mailslot file
  146. status = MsCleanupCcb( MsfsDeviceObject,
  147. Irp,
  148. (PCCB)fsContext);
  149. MsDereferenceCcb( (PCCB)fsContext );
  150. break;
  151. case MSFS_NTC_VCB: // Cleanup MSFS
  152. status = MsCleanupVcb( MsfsDeviceObject,
  153. Irp,
  154. (PVCB)fsContext);
  155. MsDereferenceVcb( (PVCB)fsContext );
  156. break;
  157. case MSFS_NTC_ROOT_DCB: // Cleanup root directory
  158. status = MsCleanupRootDcb( MsfsDeviceObject,
  159. Irp,
  160. (PROOT_DCB)fsContext,
  161. (PROOT_DCB_CCB)fsContext2);
  162. MsDereferenceRootDcb( (PROOT_DCB)fsContext );
  163. break;
  164. #ifdef MSDBG
  165. default:
  166. //
  167. // This is not one of ours.
  168. //
  169. KeBugCheck( MAILSLOT_FILE_SYSTEM );
  170. break;
  171. #endif
  172. }
  173. } finally {
  174. MsReleaseVcb( vcb );
  175. status = STATUS_SUCCESS;
  176. MsCompleteRequest( Irp, status );
  177. DebugTrace(-1, Dbg, "MsCommonCleanup -> %08lx\n", status);
  178. }
  179. DebugTrace(-1, Dbg, "MsCommonCleanup -> %08lx\n", status);
  180. return status;
  181. }
  182. NTSTATUS
  183. MsCleanupCcb (
  184. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  185. IN PIRP Irp,
  186. IN PCCB Ccb
  187. )
  188. /*++
  189. Routine Description:
  190. The routine cleans up a CCB.
  191. Arguments:
  192. MsfsDeviceObject - A pointer the the mailslot file system device object.
  193. Irp - Supplies the IRP associated with the cleanup.
  194. Ccb - Supplies the CCB for the mailslot to clean up.
  195. Return Value:
  196. NTSTATUS - An appropriate completion status
  197. --*/
  198. {
  199. NTSTATUS status;
  200. PFCB fcb;
  201. PAGED_CODE();
  202. DebugTrace(+1, Dbg, "MsCleanupCcb...\n", 0);
  203. //
  204. // Get a pointer to the FCB.
  205. //
  206. fcb = Ccb->Fcb;
  207. //
  208. // Acquire exclusive access to the FCB
  209. //
  210. MsAcquireExclusiveFcb( fcb );
  211. //
  212. // Set the CCB to closing and remove this CCB from the active list. This CCB may already be
  213. // closed if the FCB was closed first so don't check this. We still want the chain maintained.
  214. //
  215. Ccb->Header.NodeState = NodeStateClosing;
  216. RemoveEntryList( &Ccb->CcbLinks ); // Protected by the FCB lock since this is the FCB CCB chain
  217. MsReleaseFcb( fcb );
  218. //
  219. // Cleanup the share access.
  220. //
  221. ASSERT (MsIsAcquiredExclusiveVcb(fcb->Vcb));
  222. IoRemoveShareAccess( Ccb->FileObject, &fcb->ShareAccess );
  223. //
  224. // And return to our caller
  225. //
  226. status = STATUS_SUCCESS;
  227. return status;
  228. }
  229. VOID
  230. MsCancelTimer (
  231. IN PDATA_ENTRY DataEntry
  232. )
  233. /*++
  234. Routine Description:
  235. The routine cancels the timer and if possible frees up a work block
  236. Arguments:
  237. DataEntry - Block that needs to be checked for a timer
  238. Return Value:
  239. None
  240. --*/
  241. {
  242. PWORK_CONTEXT WorkContext;
  243. //
  244. // There was a timer on this read operation. Attempt
  245. // to cancel the operation. If the cancel operation
  246. // is successful, then we must cleanup after the operation.
  247. // If it was unsuccessful the timer DPC will run, and
  248. // will eventually cleanup.
  249. //
  250. WorkContext = DataEntry->TimeoutWorkContext;
  251. if (WorkContext == NULL) {
  252. //
  253. // No timeout for this request, its already been canceled or its running
  254. //
  255. return;
  256. }
  257. //
  258. // Nobody else should touch this now. either this routine will free this memory or the
  259. // timer is running at it will free the memory.
  260. //
  261. DataEntry->TimeoutWorkContext = NULL;
  262. if (KeCancelTimer( &WorkContext->Timer ) ) {
  263. //
  264. // Release the reference to the FCB.
  265. //
  266. MsDereferenceFcb( WorkContext->Fcb );
  267. //
  268. // Free the memory from the work context, the time
  269. // and the DPC.
  270. //
  271. IoFreeWorkItem (WorkContext->WorkItem);
  272. ExFreePool( WorkContext );
  273. } else {
  274. //
  275. // Time code is active. Break the link between the timer block and the IRP
  276. //
  277. WorkContext->Irp = NULL;
  278. }
  279. }
  280. NTSTATUS
  281. MsCleanupFcb (
  282. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  283. IN PIRP Irp,
  284. IN PFCB Fcb
  285. )
  286. /*++
  287. Routine Description:
  288. This routine cleans up an FCB. All outstanding i/o on the file
  289. object are completed with an error status.
  290. Arguments:
  291. MsfsDeviceObject - A pointer the the mailslot file system device object.
  292. Irp - Supplies the IRP associated with the cleanup.
  293. Fcb - Supplies the FCB for the mailslot to clean up.
  294. Return Value:
  295. NTSTATUS - An appropriate completion status
  296. --*/
  297. {
  298. NTSTATUS status;
  299. PDATA_QUEUE dataQueue;
  300. PDATA_ENTRY dataEntry;
  301. PLIST_ENTRY listEntry;
  302. PIRP oldIrp;
  303. PCCB ccb;
  304. PWORK_CONTEXT workContext;
  305. PKTIMER timer;
  306. PAGED_CODE();
  307. DebugTrace(+1, Dbg, "MsCleanupFcb, Fcb = %08lx\n", (ULONG)Fcb);
  308. status = STATUS_SUCCESS;
  309. //
  310. // Wipe out the name of the FCB from the prefix table and the parent DCB.
  311. //
  312. MsRemoveFcbName( Fcb );
  313. //
  314. // Acquire exclusive access to the FCB.
  315. //
  316. MsAcquireExclusiveFcb( Fcb );
  317. try {
  318. //
  319. // Complete all outstanding I/O on this FCB.
  320. //
  321. dataQueue = &Fcb->DataQueue;
  322. dataQueue->QueueState = -1;
  323. for (listEntry = MsGetNextDataQueueEntry( dataQueue );
  324. !MsIsDataQueueEmpty(dataQueue);
  325. listEntry = MsGetNextDataQueueEntry( dataQueue ) ) {
  326. //
  327. // This is an outstanding I/O request on this FCB.
  328. // Remove it from our queue and complete the request
  329. // if one is outstanding.
  330. //
  331. dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
  332. oldIrp = MsRemoveDataQueueEntry( dataQueue, dataEntry );
  333. if (oldIrp != NULL) {
  334. DebugTrace(0, Dbg, "Completing IRP %08lx\n", (ULONG)oldIrp );
  335. MsCompleteRequest( oldIrp, STATUS_FILE_FORCED_CLOSED );
  336. }
  337. }
  338. //
  339. // Now cleanup all the CCB's on this FCB, to ensure that new
  340. // write IRP will not be processed.
  341. //
  342. listEntry = Fcb->Specific.Fcb.CcbQueue.Flink;
  343. while( listEntry != &Fcb->Specific.Fcb.CcbQueue ) {
  344. ccb = (PCCB)CONTAINING_RECORD( listEntry, CCB, CcbLinks );
  345. ccb->Header.NodeState = NodeStateClosing;
  346. //
  347. // Get the next CCB on this FCB.
  348. //
  349. listEntry = listEntry->Flink;
  350. }
  351. //
  352. // Cleanup the share access.
  353. //
  354. ASSERT (MsIsAcquiredExclusiveVcb(Fcb->Vcb));
  355. IoRemoveShareAccess( Fcb->FileObject, &Fcb->ShareAccess);
  356. //
  357. // Mark the FCB closing.
  358. //
  359. Fcb->Header.NodeState = NodeStateClosing;
  360. } finally {
  361. MsReleaseFcb( Fcb );
  362. DebugTrace(-1, Dbg, "MsCloseFcb -> %08lx\n", status);
  363. }
  364. //
  365. // Return to the caller.
  366. //
  367. return status;
  368. }
  369. NTSTATUS
  370. MsCleanupRootDcb (
  371. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  372. IN PIRP Irp,
  373. IN PROOT_DCB RootDcb,
  374. IN PROOT_DCB_CCB Ccb
  375. )
  376. /*++
  377. Routine Description:
  378. This routine cleans up a Root DCB.
  379. Arguments:
  380. MsfsDeviceObject - A pointer the the mailslot file system device object.
  381. Irp - Supplies the IRP associated with the cleanup.
  382. RootDcb - Supplies the root dcb for MSFS.
  383. Return Value:
  384. NTSTATUS - An appropriate completion status
  385. --*/
  386. {
  387. NTSTATUS status;
  388. PIO_STACK_LOCATION irpSp;
  389. PAGED_CODE();
  390. DebugTrace(+1, Dbg, "MsCleanupRootDcb...\n", 0);
  391. status = STATUS_SUCCESS;
  392. irpSp = IoGetCurrentIrpStackLocation( Irp );
  393. //
  394. // Now acquire exclusive access to the Vcb.
  395. //
  396. MsAcquireExclusiveVcb( RootDcb->Vcb );
  397. //
  398. // clear any active notify requests
  399. //
  400. MsFlushNotifyForFile (RootDcb, irpSp->FileObject);
  401. //
  402. // Remove share access
  403. //
  404. IoRemoveShareAccess( irpSp->FileObject,
  405. &RootDcb->ShareAccess );
  406. //
  407. // Mark the DCB CCB closing.
  408. //
  409. Ccb->Header.NodeState = NodeStateClosing;
  410. MsReleaseVcb( RootDcb->Vcb );
  411. DebugTrace(-1, Dbg, "MsCleanupRootDcb -> %08lx\n", status);
  412. //
  413. // Return to the caller.
  414. //
  415. return status;
  416. }
  417. NTSTATUS
  418. MsCleanupVcb (
  419. IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
  420. IN PIRP Irp,
  421. IN PVCB Vcb
  422. )
  423. /*++
  424. Routine Description:
  425. The routine cleans up a VCB.
  426. Arguments:
  427. MsfsDeviceObject - A pointer the the mailslot file system device object.
  428. Irp - Supplies the IRP associated with the cleanup.
  429. Vcb - Supplies the VCB for MSFS.
  430. Return Value:
  431. NTSTATUS - An appropriate completion status
  432. --*/
  433. {
  434. NTSTATUS status;
  435. PIO_STACK_LOCATION irpSp;
  436. PAGED_CODE();
  437. DebugTrace(+1, Dbg, "MsCleanupVcb...\n", 0);
  438. status = STATUS_SUCCESS;
  439. irpSp = IoGetCurrentIrpStackLocation( Irp );
  440. //
  441. // Now acquire exclusive access to the Vcb
  442. //
  443. MsAcquireExclusiveVcb( Vcb );
  444. IoRemoveShareAccess( irpSp->FileObject,
  445. &Vcb->ShareAccess );
  446. MsReleaseVcb( Vcb );
  447. DebugTrace(-1, Dbg, "MsCleanupVcb -> %08lx\n", status);
  448. //
  449. // And return to our caller
  450. //
  451. return status;
  452. }
  453.