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.

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