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.

566 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Close.c
  5. Abstract:
  6. This module implements the File Close routine for Rx called by the
  7. dispatch driver.
  8. Author:
  9. Joe Linn [JoeLinn] sep-9-1994
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (RDBSS_BUG_CHECK_CLOSE)
  18. //
  19. // The local debug trace level
  20. //
  21. #define Dbg (DEBUG_TRACE_CLOSE)
  22. enum _CLOSE_DEBUG_BREAKPOINTS {
  23. CloseBreakPoint_BeforeCloseFakeFcb = 1,
  24. CloseBreakPoint_AfterCloseFakeFcb
  25. };
  26. VOID
  27. RxCloseFcbSection (
  28. IN OUT PRX_CONTEXT RxContext,
  29. IN OUT PFCB Fcb
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(PAGE, RxCommonClose)
  33. #pragma alloc_text(PAGE, RxCloseFcbSection)
  34. #pragma alloc_text(PAGE, RxCloseAssociatedSrvOpen)
  35. #endif
  36. NTSTATUS
  37. RxCommonClose (
  38. IN PRX_CONTEXT RxContext,
  39. IN PIRP Irp
  40. )
  41. /*++
  42. Routine Description:
  43. Close is invoked whenever the last reference to a file object is deleted.
  44. Cleanup is invoked when the last handle to a file object is closed, and
  45. is called before close.
  46. Arguments:
  47. Return Value:
  48. RXSTATUS - The return status for the operation
  49. Notes:
  50. The CLOSE handling strategy in RDBSS is predicated upon the axiom that the
  51. workload on the server should be minimized as and when possible.
  52. There are a number of applications which repeatedly close and open the same
  53. file, e.g., batch file processing. In these cases the same file is opened,
  54. a line/buffer is read, the file is closed and the same set of operations are
  55. repeated over and over again.
  56. This is handled in RDBSS by a delayed processing of the CLOSE request. There
  57. is a delay ( of about 10 seconds ) between completing the request and initiating
  58. processing on the request. This opens up a window during which a subsequent
  59. OPEN can be collapsed onto an existing SRV_OPEN. The time interval can be tuned
  60. to meet these requirements.
  61. --*/
  62. {
  63. NTSTATUS Status;
  64. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  65. PFILE_OBJECT FileObject = IrpSp->FileObject;
  66. PFCB Fcb;
  67. PFOBX Fobx;
  68. TYPE_OF_OPEN TypeOfOpen;
  69. BOOLEAN AcquiredFcb = FALSE;
  70. PAGED_CODE();
  71. TypeOfOpen = RxDecodeFileObject( FileObject, &Fcb, &Fobx );
  72. RxDbgTrace( +1, Dbg, ("RxCommonClose IrpC/Fobx/Fcb = %08lx %08lx %08lx\n",
  73. RxContext, Fobx, Fcb) );
  74. RxLog(( "CClose %lx %lx %lx %lx\n", RxContext, Fobx, Fcb, FileObject ));
  75. RxWmiLog( LOG,
  76. RxCommonClose_1,
  77. LOGPTR( RxContext )
  78. LOGPTR( Fobx )
  79. LOGPTR( Fcb )
  80. LOGPTR( FileObject ) );
  81. Status = RxAcquireExclusiveFcb( RxContext, Fcb );
  82. if (Status != STATUS_SUCCESS) {
  83. RxDbgTrace( -1, Dbg, ("RxCommonClose Cannot acquire FCB(%lx) %lx\n", Fcb, Status ));
  84. return Status;
  85. }
  86. AcquiredFcb = TRUE;
  87. try {
  88. PSRV_OPEN SrvOpen = NULL;
  89. BOOLEAN DelayClose = FALSE;
  90. switch (TypeOfOpen) {
  91. case RDBSS_NTC_STORAGE_TYPE_UNKNOWN:
  92. case RDBSS_NTC_STORAGE_TYPE_FILE:
  93. case RDBSS_NTC_STORAGE_TYPE_DIRECTORY:
  94. case RDBSS_NTC_OPENTARGETDIR_FCB:
  95. case RDBSS_NTC_IPC_SHARE:
  96. case RDBSS_NTC_MAILSLOT:
  97. case RDBSS_NTC_SPOOLFILE:
  98. RxDbgTrace( 0, Dbg, ("Close UserFileOpen/UserDirectoryOpen/OpenTargetDir %04lx\n", TypeOfOpen ));
  99. RxReferenceNetFcb( Fcb );
  100. if (Fobx) {
  101. SrvOpen = Fobx->SrvOpen;
  102. if ((NodeType( Fcb ) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) &&
  103. (!FlagOn( Fcb->FcbState, FCB_STATE_ORPHANED )) &&
  104. (!FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) &&
  105. (FlagOn( Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED ))) {
  106. PSRV_CALL SrvCall = Fcb->NetRoot->SrvCall;
  107. RxLog(( "@@@@DelayCls FOBX %lx SrvOpen %lx@@\n", Fobx, SrvOpen ));
  108. RxWmiLog( LOG,
  109. RxCommonClose_2,
  110. LOGPTR( Fobx )
  111. LOGPTR( SrvOpen ) );
  112. //
  113. // If this is the last open instance and the close is being delayed
  114. // mark the SRV_OPEN. This will enable us to respond to buffering
  115. // state change requests with a close operation as opposed to
  116. // the regular flush/purge response.
  117. //
  118. // We also check the COLLAPSING_DISABLED flag to determine whether its even necessary to delay
  119. // close the file. If we cannot collapse the open, no reason to delay its closure. Delaying here
  120. // caused us to stall for 10 seconds on an oplock break to a delay closed file because the final close
  121. // caused by the break was delay-closed again, resulting in a delay before the oplock break is satisfied.
  122. //
  123. if ( (SrvOpen->OpenCount == 1) && !FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED )) {
  124. if (InterlockedIncrement( &SrvCall->NumberOfCloseDelayedFiles ) <
  125. SrvCall->MaximumNumberOfCloseDelayedFiles) {
  126. DelayClose = TRUE;
  127. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED );
  128. } else {
  129. RxDbgTrace( 0, Dbg, ("Not delaying files because count exceeded limit\n") );
  130. InterlockedDecrement( &SrvCall->NumberOfCloseDelayedFiles );
  131. }
  132. }
  133. }
  134. if (!DelayClose) {
  135. PNET_ROOT NetRoot = (PNET_ROOT)Fcb->NetRoot;
  136. if ((NetRoot->Type != NET_ROOT_PRINT) &&
  137. FlagOn( Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE )) {
  138. RxScavengeRelatedFobxs( Fcb );
  139. RxSynchronizeWithScavenger( RxContext, Fcb );
  140. RxReleaseFcb( NULL, Fcb );
  141. RxAcquireFcbTableLockExclusive( &NetRoot->FcbTable, TRUE);
  142. RxOrphanThisFcb( Fcb );
  143. RxReleaseFcbTableLock( &NetRoot->FcbTable );
  144. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  145. ASSERT( Status == STATUS_SUCCESS );
  146. }
  147. }
  148. RxMarkFobxOnClose( Fobx );
  149. }
  150. if (!DelayClose) {
  151. Status = RxCloseAssociatedSrvOpen( RxContext, Fobx );
  152. if (Fobx != NULL) {
  153. RxDereferenceNetFobx( Fobx, LHS_ExclusiveLockHeld );
  154. }
  155. } else {
  156. ASSERT(Fobx != NULL);
  157. RxDereferenceNetFobx( Fobx, LHS_SharedLockHeld );
  158. }
  159. AcquiredFcb = !RxDereferenceAndFinalizeNetFcb( Fcb, RxContext, FALSE, FALSE );
  160. FileObject->FsContext = IntToPtr( 0xffffffff );
  161. if (AcquiredFcb) {
  162. AcquiredFcb = FALSE;
  163. RxReleaseFcb( RxContext, Fcb );
  164. } else {
  165. //
  166. // the tracker gets very unhappy if you don't do this!
  167. //
  168. RxTrackerUpdateHistory( RxContext, NULL, 'rrCr', __LINE__, __FILE__, 0 );
  169. }
  170. break;
  171. default:
  172. RxBugCheck( TypeOfOpen, 0, 0 );
  173. break;
  174. }
  175. } finally {
  176. if (AbnormalTermination()) {
  177. if (AcquiredFcb) {
  178. RxReleaseFcb( RxContext, Fcb );
  179. }
  180. } else {
  181. ASSERT( !AcquiredFcb );
  182. }
  183. RxDbgTrace(-1, Dbg, ("RxCommonClose -> %08lx\n", Status));
  184. }
  185. return Status;
  186. }
  187. VOID
  188. RxCloseFcbSection (
  189. IN OUT PRX_CONTEXT RxContext,
  190. IN OUT PFCB Fcb
  191. )
  192. /*++
  193. Routine Description:
  194. This routine initiates the flush and close of the image secton associated
  195. with an FCB instance
  196. Arguments:
  197. RxContext - the context
  198. Fcb - the fcb instance for which close processing is to be initiated
  199. Return Value:
  200. Notes:
  201. On entry to this routine the FCB must have been accquired exclusive.
  202. On exit there is no change in resource ownership
  203. --*/
  204. {
  205. NTSTATUS Status;
  206. PAGED_CODE();
  207. RxDbgTrace(0, Dbg, ("CleanupPurge:MmFlushImage\n", 0));
  208. MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite );
  209. //
  210. // we don't pass in the context here because it is not necessary to track this
  211. // release because of the subsequent acquire...........
  212. //
  213. RxReleaseFcb( NULL, Fcb );
  214. MmForceSectionClosed( &Fcb->NonPaged->SectionObjectPointers, TRUE );
  215. Status = RxAcquireExclusiveFcb( NULL, Fcb );
  216. ASSERT( Status == STATUS_SUCCESS );
  217. }
  218. NTSTATUS
  219. RxCloseAssociatedSrvOpen (
  220. IN OUT PRX_CONTEXT RxContext OPTIONAL,
  221. IN OUT PFOBX Fobx
  222. )
  223. /*++
  224. Routine Description:
  225. This routine initiates the close processing for an FOBX. The FOBX close
  226. processing can be trigerred in one of three ways ....
  227. 1) Regular close processing on receipt of the IRP_MJ_CLOSE for the associated
  228. file object.
  229. 2) Delayed close processing while scavenging the FOBX. This happens when the
  230. close processing was delayed in anticipation of an open and no opens are
  231. forthcoming.
  232. 3) Delayed close processing on receipt of a buffering state change request
  233. for a close that was delayed.
  234. Arguments:
  235. RxContext - the context parameter is NULL for case (2).
  236. Fobx - the FOBX instance for which close processing is to be initiated.
  237. It is NULL for MAILSLOT files.
  238. Return Value:
  239. Notes:
  240. On entry to this routine the FCB must have been accquired exclusive.
  241. On exit there is no change in resource ownership
  242. --*/
  243. {
  244. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  245. PFCB Fcb;
  246. PSRV_OPEN SrvOpen;
  247. PRX_CONTEXT LocalRxContext = RxContext;
  248. PAGED_CODE();
  249. //
  250. // Distinguish between those cases where there is a real SRV_OPEN instance
  251. // from those that do not have one, e.g., mailslot files.
  252. //
  253. if (Fobx == NULL) {
  254. if (RxContext != NULL) {
  255. Fcb = (PFCB)(RxContext->pFcb);
  256. SrvOpen = NULL;
  257. } else {
  258. Status = STATUS_SUCCESS;
  259. }
  260. } else {
  261. if (FlagOn( Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED )) {
  262. RxMarkFobxOnClose( Fobx );
  263. Status = STATUS_SUCCESS;
  264. } else {
  265. SrvOpen = Fobx->SrvOpen;
  266. if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_CLOSED )) {
  267. Fcb = SrvOpen->Fcb;
  268. ASSERT( RxIsFcbAcquiredExclusive( Fcb ) );
  269. SetFlag( Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED );
  270. if (SrvOpen->OpenCount > 0) {
  271. SrvOpen->OpenCount -= 1;
  272. }
  273. RxMarkFobxOnClose( Fobx );
  274. Status = STATUS_SUCCESS;
  275. } else {
  276. Fcb = SrvOpen->Fcb;
  277. }
  278. ASSERT( (RxContext == NULL) || (Fcb == (PFCB)RxContext->pFcb) );
  279. }
  280. }
  281. //
  282. // If there is no corresponding open on the server side or if the close
  283. // processing has already been accomplished there is no further processing
  284. // required. In other cases w.r.t scavenged close processing a new
  285. // context might have to be created.
  286. //
  287. if ((Status == STATUS_MORE_PROCESSING_REQUIRED) && (RxContext == NULL)) {
  288. LocalRxContext = RxCreateRxContext( NULL,
  289. SrvOpen->Fcb->RxDeviceObject,
  290. RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING );
  291. if (LocalRxContext != NULL) {
  292. LocalRxContext->MajorFunction = IRP_MJ_CLOSE;
  293. LocalRxContext->pFcb = (PMRX_FCB)Fcb;
  294. LocalRxContext->pFobx = (PMRX_FOBX)Fobx;
  295. if (Fobx != NULL) {
  296. LocalRxContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)(Fobx->SrvOpen);
  297. }
  298. Status = STATUS_MORE_PROCESSING_REQUIRED;
  299. } else {
  300. Status = STATUS_INSUFFICIENT_RESOURCES;
  301. }
  302. }
  303. //
  304. // if the context creation was successful and the close processing for
  305. // the SRV_OPEN instance needs to be initiated with the mini rdr
  306. // proceed.
  307. //
  308. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  309. ASSERT( RxIsFcbAcquiredExclusive( Fcb ) );
  310. ///
  311. // Mark the Fobx instance on the initiation of the close operation. This
  312. // is the complement to the action taken on cleanup. It ensures
  313. // that the infrastructure setup for delayed close processing is undone.
  314. // For those instances in which the FOBS is NULL the FCB is manipulated
  315. // directly
  316. //
  317. if (Fobx != NULL) {
  318. RxMarkFobxOnClose( Fobx );
  319. } else {
  320. InterlockedDecrement( &Fcb->OpenCount );
  321. }
  322. if (SrvOpen != NULL) {
  323. if (SrvOpen->Condition == Condition_Good) {
  324. if (SrvOpen->OpenCount > 0) {
  325. SrvOpen->OpenCount -= 1;
  326. }
  327. if (SrvOpen->OpenCount == 1) {
  328. if (!IsListEmpty( &SrvOpen->FobxList )) {
  329. PFOBX RemainingFobx;
  330. RemainingFobx = CONTAINING_RECORD( SrvOpen->FobxList.Flink,
  331. FOBX,
  332. FobxQLinks );
  333. if (!IsListEmpty( &RemainingFobx->ScavengerFinalizationList )) {
  334. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED );
  335. }
  336. }
  337. }
  338. //
  339. // Purge the FCB before initiating the close processing with
  340. // the mini redirectors
  341. //
  342. if ((SrvOpen->OpenCount == 0) &&
  343. (Status == STATUS_MORE_PROCESSING_REQUIRED) &&
  344. (RxContext == NULL)) {
  345. RxCloseFcbSection( LocalRxContext, Fcb );
  346. }
  347. //
  348. // Since RxCloseFcbSections drops and reacquires the resource, ensure that
  349. // the SrvOpen is still valid before proceeding with the
  350. // finalization.
  351. //
  352. SrvOpen = Fobx->SrvOpen;
  353. if ((SrvOpen != NULL) &&
  354. ((SrvOpen->OpenCount == 0) ||
  355. (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED ))) &&
  356. !FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_CLOSED ) &&
  357. (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
  358. ASSERT( RxIsFcbAcquiredExclusive( Fcb ) );
  359. MINIRDR_CALL( Status,
  360. LocalRxContext,
  361. Fcb->MRxDispatch,
  362. MRxCloseSrvOpen,
  363. (LocalRxContext) );
  364. RxLog(( "MRXClose %lx %lx %lx %lx %lx\n", RxContext, Fcb, SrvOpen, Fobx, Status ));
  365. RxWmiLog( LOG,
  366. RxCloseAssociatedSrvOpen,
  367. LOGPTR( RxContext )
  368. LOGPTR( Fcb )
  369. LOGPTR( SrvOpen )
  370. LOGPTR( Fobx )
  371. LOGULONG( Status ) );
  372. SetFlag( SrvOpen->Flags, SRVOPEN_FLAG_CLOSED );
  373. //
  374. // Since the SrvOpen has been closed (the close for the
  375. // Fid was sent to the server above) we need to reset
  376. // the Key.
  377. //
  378. SrvOpen->Key = (PVOID) (ULONG_PTR) 0xffffffff;
  379. if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED )) {
  380. InterlockedDecrement( &Fcb->NetRoot->SrvCall->NumberOfCloseDelayedFiles );
  381. }
  382. RxRemoveShareAccessPerSrvOpens( SrvOpen );
  383. //
  384. // Ensure that any buffering state change requests for this
  385. // SRV_OPEN instance which was closed is purged from the
  386. // buffering manager data structures.
  387. //
  388. RxPurgeChangeBufferingStateRequestsForSrvOpen( SrvOpen );
  389. RxDereferenceSrvOpen( SrvOpen, LHS_ExclusiveLockHeld );
  390. } else {
  391. Status = STATUS_SUCCESS;
  392. }
  393. SetFlag( Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED );
  394. } else {
  395. Status = STATUS_SUCCESS;
  396. }
  397. } else {
  398. ASSERT( (NodeType( Fcb ) == RDBSS_NTC_OPENTARGETDIR_FCB) ||
  399. (NodeType( Fcb ) == RDBSS_NTC_IPC_SHARE) ||
  400. (NodeType( Fcb ) == RDBSS_NTC_MAILSLOT) );
  401. RxDereferenceNetFcb( Fcb );
  402. Status = STATUS_SUCCESS;
  403. }
  404. if (LocalRxContext != RxContext) {
  405. RxDereferenceAndDeleteRxContext( LocalRxContext );
  406. }
  407. }
  408. return Status;
  409. }