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.

2222 lines
69 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effects
  2. Copyright (c) 1987-1993 Microsoft Corporation
  3. Module Name:
  4. buffring.c
  5. Abstract:
  6. This module defines the implementation for changing buffering states in the RDBSS
  7. Author:
  8. Balan Sethu Raman (SethuR) 11-Nov-95 Created
  9. Notes:
  10. The RDBSS provides a mechanism for providing distributed cache coherency in conjunction with
  11. the various mini redirectors. This service is encapsulated in the BUFFERING_MANAGER which
  12. processes CHANGE_BUFFERING_STATE_REQUESTS.
  13. In the SMB protocol OPLOCK's ( Oppurtunistic Locks ) provide the necessary infrastructure for
  14. cache coherency.
  15. There are three components in the implementation of cache coherency protocol's in any mini
  16. redirector.
  17. 1) The first constitutes the modifications to the CREATE/OPEN path. In this path the
  18. type of buffering to be requested is determined and the appropriate request is made to the
  19. server. On the return path the buffering state associated with the FCB is updated based
  20. on the result of the CREATE/OPEN.
  21. 2) The receive indication code needs to modified to handle change buffering state notifications
  22. from the server. If such a request is detected then the local mechanism to coordinate the
  23. buffering states needs to be triggered.
  24. 3) The mechanism for changing the buffering state which is implemented as part of the
  25. RDBSS.
  26. Any change buffering state request must identify the SRV_OPEN to which the request applies.
  27. The amount of computational effort involved in identifying the SRV_OPEN depends upon the
  28. protocol. In the SMB protocol the Server gets to pick the id's used for identifying files
  29. opened at the server. These are relative to the NET_ROOT(share) on which they are opened.
  30. Thus every change buffering state request is identified by two keys, the NetRootKey and the
  31. SrvOpenKey which need to be translated to the appropriate NET_ROOT and SRV_OPEN instance
  32. respectively. In order to provide better integration with the resource acquisition/release
  33. mechanism and to avoid duplication of this effort in the various mini redirectors the RDBSS
  34. provides this service.
  35. There are two mechanisms provided in the wrapper for indicating buffering state
  36. changes to SRV_OPEN's. They are
  37. 1) RxIndicateChangeOfBufferingState
  38. 2) RxIndicateChangeOfBufferingStateForSrvOpen.
  39. The mini rediretors that need an auxillary mechanism for establishing the mapping
  40. from the id's to the SRV_OPEN instance employ (1) while the mini redirectors that
  41. do not require this assistance employ (2).
  42. The buffering manager processes these requests in different stages. It maintains the
  43. requests received from the various underlying mini redirectors in one of three lists.
  44. The Dispatcher list contains all the requests for which the appropriate mapping to a
  45. SRV_OPEN instance has not been established. The Handler list contains all the requests
  46. for which the appropriate mapping has been established and have not yet been processed.
  47. The LastChanceHandlerList contains all the requests for which the initial processing was
  48. unsuccessful.
  49. This typically happens when the FCB was accquired in a SHARED mode at the time the
  50. change buffering state request was received. In such cases the Oplock break request
  51. can only be processed by a delayed worker thread.
  52. The Change buffering state request processing in the redirector is intertwined with
  53. the FCB accqusition/release protocol. This helps in ensuring shorter turn around times.
  54. --*/
  55. #include "precomp.h"
  56. #pragma hdrstop
  57. #ifdef ALLOC_PRAGMA
  58. #pragma alloc_text(PAGE, RxTearDownBufferingManager)
  59. #pragma alloc_text(PAGE, RxIndicateChangeOfBufferingStateForSrvOpen)
  60. #pragma alloc_text(PAGE, RxPrepareRequestForHandling)
  61. #pragma alloc_text(PAGE, RxPrepareRequestForReuse)
  62. #pragma alloc_text(PAGE, RxpDiscardChangeBufferingStateRequests)
  63. #pragma alloc_text(PAGE, RxProcessFcbChangeBufferingStateRequest)
  64. #pragma alloc_text(PAGE, RxPurgeChangeBufferingStateRequestsForSrvOpen)
  65. #pragma alloc_text(PAGE, RxProcessChangeBufferingStateRequestsForSrvOpen)
  66. #pragma alloc_text(PAGE, RxInitiateSrvOpenKeyAssociation)
  67. #pragma alloc_text(PAGE, RxpLookupSrvOpenForRequestLite)
  68. #pragma alloc_text(PAGE, RxChangeBufferingState)
  69. #pragma alloc_text(PAGE, RxFlushFcbInSystemCache)
  70. #pragma alloc_text(PAGE, RxPurgeFcbInSystemCache)
  71. #endif
  72. //
  73. // The Bug check file id for this module
  74. //
  75. #define BugCheckFileId (RDBSS_BUG_CHECK_CACHESUP)
  76. //
  77. // The local debug trace level
  78. //
  79. #define Dbg (DEBUG_TRACE_CACHESUP)
  80. //
  81. // Forward declarations
  82. //
  83. extern NTSTATUS
  84. RxRegisterChangeBufferingStateRequest(
  85. PSRV_CALL pSrvCall,
  86. PSRV_OPEN pSrvOpen,
  87. PVOID SrvOpenKey,
  88. PVOID pMRxContext);
  89. extern VOID
  90. RxDispatchChangeBufferingStateRequests(
  91. PSRV_CALL pSrvCall);
  92. extern VOID
  93. RxpDispatchChangeBufferingStateRequests(
  94. IN OUT PSRV_CALL pSrvCall,
  95. IN OUT PSRV_OPEN pSrvOpen,
  96. OUT PLIST_ENTRY pDiscardedRequests);
  97. extern VOID
  98. RxpDiscardChangeBufferingStateRequests(
  99. IN OUT PLIST_ENTRY pDiscardedRequests);
  100. extern VOID
  101. RxLastChanceHandlerForChangeBufferingStateRequests(
  102. PSRV_CALL pSrvCall);
  103. extern NTSTATUS
  104. RxpLookupSrvOpenForRequestLite(
  105. IN PSRV_CALL pSrvCall,
  106. IN OUT PCHANGE_BUFFERING_STATE_REQUEST pRequest);
  107. extern VOID
  108. RxGatherRequestsForSrvOpen(
  109. IN OUT PSRV_CALL pSrvCall,
  110. IN PSRV_OPEN pSrvOpen,
  111. IN OUT PLIST_ENTRY pRequestsListHead);
  112. NTSTATUS
  113. RxInitializeBufferingManager(
  114. PSRV_CALL pSrvCall)
  115. /*++
  116. Routine Description:
  117. This routine initializes the buffering manager associated with a SRV_CALL
  118. instance.
  119. Arguments:
  120. pSrvCall - the SRV_CALL instance
  121. Return Value:
  122. STATUS_SUCCESS if successful
  123. Notes:
  124. The buffering manager consists of three lists .....
  125. 1) the dispatcher list which contains all the requests that need to be
  126. processed.
  127. 2) the handler list contains all the requests for which the SRV_OPEN
  128. instance has been found and referenced.
  129. 3) the last chance handler list contains all the requests for which
  130. an unsuccessful attempt to process the request was made, i.e., the
  131. FCB could not be acquired exclusively.
  132. The manipulation of these lists are done under the control of the spin lock
  133. associated with the buffering manager. A Mutex will not suffice since these
  134. lists are manipulated at DPC level.
  135. All buffering manager operations at non DPC level are serialized using the
  136. Mutex associated with the buffering manager.
  137. --*/
  138. {
  139. PRX_BUFFERING_MANAGER pBufferingManager;
  140. pBufferingManager = &pSrvCall->BufferingManager;
  141. KeInitializeSpinLock( &pBufferingManager->SpinLock );
  142. InitializeListHead(&pBufferingManager->HandlerList);
  143. InitializeListHead(&pBufferingManager->LastChanceHandlerList);
  144. InitializeListHead(&pBufferingManager->DispatcherList);
  145. pBufferingManager->fNoWaitHandlerActive = FALSE;
  146. pBufferingManager->fLastChanceHandlerActive = FALSE;
  147. pBufferingManager->fDispatcherActive = FALSE;
  148. pBufferingManager->NumberOfOutstandingOpens = 0;
  149. InitializeListHead(&pBufferingManager->SrvOpenLists[0]);
  150. ExInitializeFastMutex(&pBufferingManager->Mutex);
  151. return STATUS_SUCCESS;
  152. }
  153. NTSTATUS
  154. RxTearDownBufferingManager(
  155. PSRV_CALL pSrvCall)
  156. /*++
  157. Routine Description:
  158. This routine tears down the buffering manager associated with a SRV_CALL
  159. instance.
  160. Arguments:
  161. pSrvCall - the SRV_CALL instance
  162. Return Value:
  163. STATUS_SUCCESS if successful
  164. --*/
  165. {
  166. PRX_BUFFERING_MANAGER pBufferingManager;
  167. PAGED_CODE();
  168. pBufferingManager = &pSrvCall->BufferingManager;
  169. // Ensure that all the work items in the buffering manager are not in use.
  170. if (pBufferingManager->DispatcherWorkItem.List.Flink != NULL) {
  171. //DbgBreakPoint();
  172. }
  173. if (pBufferingManager->HandlerWorkItem.List.Flink != NULL) {
  174. //DbgBreakPoint();
  175. }
  176. if (pBufferingManager->LastChanceHandlerWorkItem.List.Flink != NULL) {
  177. //DbgBreakPoint();
  178. }
  179. return STATUS_SUCCESS;
  180. }
  181. VOID
  182. RxIndicateChangeOfBufferingState(
  183. PMRX_SRV_CALL pSrvCall,
  184. PVOID SrvOpenKey,
  185. PVOID pMRxContext)
  186. /*++
  187. Routine Description:
  188. This routine registers an oplock break indication.
  189. Arguments:
  190. pSrvCall - the SRV_CALL instance
  191. SrvOpenKey - the key for the SRV_OPEN instance.
  192. pMRxContext - the context to be passed back to the mini rdr during callbacks for
  193. processing the oplock break.
  194. Return Value:
  195. none.
  196. Notes:
  197. This is an instance in which the buffering state change request from the
  198. server identifies the SRV_OPEN instance using the key generated by the server
  199. This implies that the key needs to be mapped onto the SRV_OPEN instance locally.
  200. --*/
  201. {
  202. RxRegisterChangeBufferingStateRequest(
  203. (PSRV_CALL)pSrvCall,
  204. NULL,
  205. SrvOpenKey,
  206. pMRxContext);
  207. }
  208. VOID
  209. RxIndicateChangeOfBufferingStateForSrvOpen(
  210. PMRX_SRV_CALL pSrvCall,
  211. PMRX_SRV_OPEN pMRxSrvOpen,
  212. PVOID SrvOpenKey,
  213. PVOID pMRxContext)
  214. /*++
  215. Routine Description:
  216. This routine registers an oplock break indication. If the necessary preconditions
  217. are satisfied the oplock is processed further.
  218. Arguments:
  219. pSrvCall - the SRV_CALL instance
  220. pMRxSrvOpen - the SRV_OPEN instance.
  221. pMRxContext - the context to be passed back to the mini rdr during callbacks for
  222. processing the oplock break.
  223. Return Value:
  224. none.
  225. Notes:
  226. This is an instance where in the buffering state change indications from the server
  227. use the key generated by the client. ( the SRV_OPEN address in itself is the best
  228. key that can be used ). This implies that no further lookup is required.
  229. However if this routine is called at DPC level, the indication is processed as if
  230. the lookup needs to be done.
  231. --*/
  232. {
  233. PAGED_CODE();
  234. if (KeGetCurrentIrql() <= APC_LEVEL) {
  235. PSRV_OPEN pSrvOpen = (PSRV_OPEN)pMRxSrvOpen;
  236. // If the resource for the FCB has already been accquired by this thread
  237. // the buffering state change indication can be processed immediately
  238. // without further delay.
  239. if (ExIsResourceAcquiredExclusiveLite(pSrvOpen->pFcb->Header.Resource)) {
  240. RxChangeBufferingState(pSrvOpen,pMRxContext,TRUE);
  241. } else {
  242. RxRegisterChangeBufferingStateRequest(
  243. (PSRV_CALL)pSrvCall,
  244. pSrvOpen,
  245. pSrvOpen->Key,
  246. pMRxContext);
  247. }
  248. } else {
  249. RxRegisterChangeBufferingStateRequest(
  250. (PSRV_CALL)pSrvCall,
  251. NULL,
  252. SrvOpenKey,
  253. pMRxContext);
  254. }
  255. }
  256. NTSTATUS
  257. RxRegisterChangeBufferingStateRequest(
  258. PSRV_CALL pSrvCall,
  259. PSRV_OPEN pSrvOpen,
  260. PVOID SrvOpenKey,
  261. PVOID pMRxContext)
  262. /*++
  263. Routine Description:
  264. This routine registers a change buffering state requests. If necessary the worker thread
  265. routines for further processing are activated.
  266. Arguments:
  267. pRequest -- change buffering state request to be regsitered
  268. Return Value:
  269. STATUS_SUCCESS if successful.
  270. Notes:
  271. This routine registers the change buffering state request by either inserting it in the
  272. registration list (DPC Level processing ) or the appropriate(dispatcher/handler list).
  273. This is the common routine for processing both kinds of callbacks, i.e, the ones in
  274. which the SRV_OPEN instance has been located and the ones in which only the SRV_OPEN
  275. key is available.
  276. --*/
  277. {
  278. NTSTATUS Status;
  279. KIRQL SavedIrql;
  280. PCHANGE_BUFFERING_STATE_REQUEST pRequest;
  281. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  282. // Ensure that either the SRV_OPEN instance for this request has not been
  283. // passed in or the call is not at DPC level.
  284. ASSERT((pSrvOpen == NULL) ||
  285. (KeGetCurrentIrql() <= APC_LEVEL));
  286. pRequest = RxAllocatePoolWithTag(
  287. NonPagedPool,
  288. sizeof(CHANGE_BUFFERING_STATE_REQUEST),
  289. RX_BUFFERING_MANAGER_POOLTAG);
  290. if (pRequest != NULL) {
  291. BOOLEAN ActivateHandler = FALSE;
  292. BOOLEAN ActivateDispatcher = FALSE;
  293. pRequest->Flags = 0;
  294. pRequest->pSrvCall = pSrvCall;
  295. pRequest->pSrvOpen = pSrvOpen;
  296. pRequest->SrvOpenKey = SrvOpenKey;
  297. pRequest->pMRxContext = pMRxContext;
  298. // If the SRV_OPEN instance for the request is known apriori the request can
  299. // be directly inserted into the buffering manager's HandlerList as opposed
  300. // to the DispatcherList for those instances in which only the SRV_OPEN key
  301. // is available. The insertion into the HandlerList ust be accompanied by an
  302. // additional reference to prevent finalization of the instance while a request
  303. // is still active.
  304. if (pSrvOpen != NULL) {
  305. RxReferenceSrvOpen((PSRV_OPEN)pSrvOpen);
  306. }
  307. KeAcquireSpinLock(
  308. &pSrvCall->BufferingManager.SpinLock,
  309. &SavedIrql);
  310. if (pRequest->pSrvOpen != NULL) {
  311. InsertTailList(&pBufferingManager->HandlerList,&pRequest->ListEntry);
  312. if (!pBufferingManager->fNoWaitHandlerActive) {
  313. pBufferingManager->fNoWaitHandlerActive = TRUE;
  314. ActivateHandler = TRUE;
  315. }
  316. RxLog(("Req %lx SrvOpenKey %lx in Handler List\n",pRequest,pRequest->pSrvOpen));
  317. RxWmiLog(LOG,
  318. RxRegisterChangeBufferingStateRequest_1,
  319. LOGPTR(pRequest)
  320. LOGPTR(pRequest->pSrvOpen));
  321. } else {
  322. InsertTailList(&pBufferingManager->DispatcherList,&pRequest->ListEntry);
  323. if (!pBufferingManager->fDispatcherActive) {
  324. pBufferingManager->fDispatcherActive = TRUE;
  325. ActivateDispatcher = TRUE;
  326. }
  327. RxDbgTrace(0,Dbg,("Request %lx SrvOpenKey %lx in Registartion List\n",pRequest,pRequest->SrvOpenKey));
  328. RxLog(("Req %lx SrvOpenKey %lx in Reg. List\n",pRequest,pRequest->SrvOpenKey));
  329. RxWmiLog(LOG,
  330. RxRegisterChangeBufferingStateRequest_2,
  331. LOGPTR(pRequest)
  332. LOGPTR(pRequest->SrvOpenKey));
  333. }
  334. KeReleaseSpinLock(
  335. &pSrvCall->BufferingManager.SpinLock,
  336. SavedIrql);
  337. InterlockedIncrement(&pSrvCall->BufferingManager.CumulativeNumberOfBufferingChangeRequests);
  338. if (ActivateHandler) {
  339. // Reference the SRV_CALL instance to ensure that it will not be
  340. // finalized while the worker thread request is in the scheduler
  341. RxReferenceSrvCallAtDpc(pSrvCall);
  342. RxPostToWorkerThread(
  343. RxFileSystemDeviceObject,
  344. HyperCriticalWorkQueue,
  345. &pBufferingManager->HandlerWorkItem,
  346. RxProcessChangeBufferingStateRequests,
  347. pSrvCall);
  348. }
  349. if (ActivateDispatcher) {
  350. // Reference the SRV_CALL instance to ensure that it will not be
  351. // finalized while the worker thread request is in the scheduler
  352. RxReferenceSrvCallAtDpc(pSrvCall);
  353. RxPostToWorkerThread(
  354. RxFileSystemDeviceObject,
  355. HyperCriticalWorkQueue,
  356. &pBufferingManager->DispatcherWorkItem,
  357. RxDispatchChangeBufferingStateRequests,
  358. pSrvCall);
  359. }
  360. Status = STATUS_SUCCESS;
  361. } else {
  362. Status = STATUS_INSUFFICIENT_RESOURCES;
  363. RxLog(("!!CBSReq. %lx %lx %lx %lx %lx\n", pSrvCall,pSrvOpen,SrvOpenKey,pMRxContext,Status));
  364. RxWmiLogError(Status,
  365. LOG,
  366. RxRegisterChangeBufferingStateRequest_3,
  367. LOGPTR(pSrvCall)
  368. LOGPTR(pSrvOpen)
  369. LOGPTR(SrvOpenKey)
  370. LOGPTR(pMRxContext)
  371. LOGULONG(Status));
  372. RxDbgTrace(0, Dbg, ("Change Buffering State Request Ignored %lx %lx %lx\n", pSrvCall,pSrvOpen,SrvOpenKey,pMRxContext,Status));
  373. }
  374. RxDbgTrace(0,
  375. Dbg,
  376. ("Register SrvCall(%lx) SrvOpen (%lx) Key(%lx) Status(%lx)\n",
  377. pSrvCall,pSrvOpen,SrvOpenKey,Status));
  378. return Status;
  379. }
  380. NTSTATUS
  381. RxPrepareRequestForHandling(
  382. PCHANGE_BUFFERING_STATE_REQUEST pRequest)
  383. /*++
  384. Routine Description:
  385. This routine preprocesses the request before initiating buffering state change
  386. processing. In addition to obtaining the references on the FCB abd the associated
  387. SRV_OPEN, an event is allocated as part of the FCB. This helps establish a priority
  388. mechanism for servicing buffering state change requests.
  389. The FCB accquisition is a two step process, i.e, wait for this event to be set followed
  390. by a wait for the resource.
  391. Arguments:
  392. pRequest - the buffering state change request
  393. Return Value:
  394. STATUS_SUCCESS
  395. STATUS_INSUFFICIENT_RESOURCES
  396. Notes:
  397. Not all the FCB's have the space for the buffering state change event allocated when the
  398. FCB instance is created. The upside is that space is conserved and the downside is that
  399. a separate allocation needs to be made when it is required.
  400. This event associated with the FCB provides a two step mechanism for accelerating the
  401. processing of buffering state change requests. Ordinary operations get delayed in favour
  402. of the buffering state change requests. The details are in resrcsup.c
  403. --*/
  404. {
  405. NTSTATUS Status = STATUS_SUCCESS;
  406. PKEVENT pEvent;
  407. PSRV_OPEN pSrvOpen = pRequest->pSrvOpen;
  408. PAGED_CODE();
  409. if (!FlagOn(pRequest->Flags,RX_REQUEST_PREPARED_FOR_HANDLING)) {
  410. SetFlag(pRequest->Flags,RX_REQUEST_PREPARED_FOR_HANDLING);
  411. RxAcquireSerializationMutex();
  412. if ((pEvent = pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent) == NULL) {
  413. pEvent = RxAllocatePoolWithTag(
  414. NonPagedPool,
  415. sizeof(KEVENT),
  416. RX_BUFFERING_MANAGER_POOLTAG);
  417. if (pEvent != NULL) {
  418. pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent = pEvent;
  419. KeInitializeEvent(
  420. pEvent,
  421. NotificationEvent,
  422. FALSE );
  423. }
  424. } else {
  425. KeResetEvent(pEvent);
  426. }
  427. if (pEvent != NULL) {
  428. SetFlag(pSrvOpen->Fcb->FcbState,FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
  429. SetFlag(pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING);
  430. SetFlag(pSrvOpen->Flags,SRVOPEN_FLAG_COLLAPSING_DISABLED);
  431. RxDbgTrace(0,Dbg,("3333 Request %lx SrvOpenKey %lx in Handler List\n",pRequest,pRequest->SrvOpenKey));
  432. RxLog(("3333 Req %lx SrvOpenKey %lx in Hndlr List\n",pRequest,pRequest->SrvOpenKey));
  433. RxWmiLog(LOG,
  434. RxPrepareRequestForHandling_1,
  435. LOGPTR(pRequest)
  436. LOGPTR(pRequest->SrvOpenKey));
  437. } else {
  438. RxDbgTrace(0,Dbg,("4444 Ignoring Request %lx SrvOpenKey %lx \n",pRequest,pRequest->SrvOpenKey));
  439. RxLog(("Chg. Buf. State Ignored %lx %lx %lx\n",
  440. pRequest->SrvOpenKey,
  441. pRequest->pMRxContext,STATUS_INSUFFICIENT_RESOURCES));
  442. RxWmiLog(LOG,
  443. RxPrepareRequestForHandling_2,
  444. LOGPTR(pRequest->SrvOpenKey)
  445. LOGPTR(pRequest->pMRxContext));
  446. Status = STATUS_INSUFFICIENT_RESOURCES;
  447. }
  448. RxReleaseSerializationMutex();
  449. }
  450. return Status;
  451. }
  452. VOID
  453. RxPrepareRequestForReuse(
  454. PCHANGE_BUFFERING_STATE_REQUEST pRequest)
  455. /*++
  456. Routine Description:
  457. This routine postprocesses the request before destroying it. This involves
  458. dereferencing and setting the appropriate state flags.
  459. Arguments:
  460. pRequest - the buffering state change request
  461. Notes:
  462. --*/
  463. {
  464. PAGED_CODE();
  465. if (FlagOn(pRequest->Flags,RX_REQUEST_PREPARED_FOR_HANDLING)) {
  466. PFCB pFcb = pRequest->pSrvOpen->Fcb;
  467. // We should never clear the SrvOpen flag unless we are also clearing the FCB flag
  468. // and setting the event!
  469. //ClearFlag(pRequest->pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING);
  470. if (RxIsFcbAcquiredExclusive(pFcb)) {
  471. RxDereferenceSrvOpen(pRequest->pSrvOpen,LHS_ExclusiveLockHeld);
  472. } else {
  473. RxDereferenceSrvOpen(pRequest->pSrvOpen,LHS_LockNotHeld);
  474. }
  475. } else if (pRequest->pSrvOpen != NULL) {
  476. RxDereferenceSrvOpen(pRequest->pSrvOpen,LHS_LockNotHeld);
  477. }
  478. pRequest->pSrvOpen = NULL;
  479. }
  480. VOID
  481. RxpDiscardChangeBufferingStateRequests(
  482. PLIST_ENTRY pDiscardedRequests)
  483. /*++
  484. Routine Description:
  485. This routine discards a list of change buffering state requests one at a time
  486. Arguments:
  487. pDiscardedRequests - the requests to be discarded
  488. Notes:
  489. --*/
  490. {
  491. PAGED_CODE();
  492. // Process the discarded requests,i.e, free the memory
  493. while (!IsListEmpty(pDiscardedRequests)) {
  494. PLIST_ENTRY pListEntry;
  495. PCHANGE_BUFFERING_STATE_REQUEST pRequest;
  496. pListEntry = RemoveHeadList(pDiscardedRequests);
  497. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  498. CONTAINING_RECORD(
  499. pListEntry,
  500. CHANGE_BUFFERING_STATE_REQUEST,
  501. ListEntry);
  502. RxDbgTrace(0,Dbg,("**** (2)Discarding Request(%lx) SrvOpenKey(%lx) \n",
  503. pRequest,pRequest->SrvOpenKey));
  504. RxLog(("**** (2)Disc Req(%lx) SOKey(%lx) \n",
  505. pRequest,pRequest->SrvOpenKey));
  506. RxWmiLog(LOG,
  507. RxpDiscardChangeBufferingStateRequests,
  508. LOGPTR(pRequest)
  509. LOGPTR(pRequest->SrvOpenKey));
  510. RxPrepareRequestForReuse(pRequest);
  511. RxFreePool(pRequest);
  512. }
  513. }
  514. VOID
  515. RxpDispatchChangeBufferingStateRequests(
  516. PSRV_CALL pSrvCall,
  517. PSRV_OPEN pSrvOpen,
  518. PLIST_ENTRY pDiscardedRequests)
  519. /*++
  520. Routine Description:
  521. This routine dispatches the request before destroying it. This involves looking up
  522. the SRV_OPEN instance associated with a given SrvOpenKey.
  523. Arguments:
  524. pSrvCall - the associated SRV_CALL instance
  525. pSrvOpen - the associated SRV_OPEN instance.
  526. Notes:
  527. There are two flavours of this routine. When pSrvOpen is NULL this routine walks
  528. through the list of outstanding requests and establishes the mapping between the
  529. SrvOpenKey and the SRV_OPEN instance. On the other hand when pSrvOpen is a valid
  530. SRV_OPEN instance it merely traverses the list to gather together the requests
  531. corresponding to the given SRV_OPEN and transfer them enmasse to to the handler
  532. list.
  533. The buffering manager mutex must have been accquired on entry to this routine
  534. and the mutex ownership will remain invariant on exit.
  535. --*/
  536. {
  537. NTSTATUS Status;
  538. KIRQL SavedIrql;
  539. PLIST_ENTRY pListEntry;
  540. LIST_ENTRY DispatcherList;
  541. LIST_ENTRY HandlerList;
  542. BOOLEAN ActivateDispatcher;
  543. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  544. PCHANGE_BUFFERING_STATE_REQUEST pRequest;
  545. InitializeListHead(pDiscardedRequests);
  546. InitializeListHead(&HandlerList);
  547. ActivateDispatcher = FALSE;
  548. // Since the buffering manager lists are subject to modifications while
  549. // the requests on the list are being processed, the requests are transferred
  550. // enmasse onto a temporary list. This prevents multiple acquisition/release of
  551. // the spinlock for each individual request.
  552. KeAcquireSpinLock(&pBufferingManager->SpinLock,&SavedIrql);
  553. RxTransferList(&DispatcherList,&pBufferingManager->DispatcherList);
  554. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  555. // Process the list of requests.
  556. pListEntry = DispatcherList.Flink;
  557. while (pListEntry != &DispatcherList) {
  558. PLIST_ENTRY pListHead;
  559. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  560. CONTAINING_RECORD(
  561. pListEntry,
  562. CHANGE_BUFFERING_STATE_REQUEST,
  563. ListEntry);
  564. pListEntry = pListEntry->Flink;
  565. if (pSrvOpen == NULL) {
  566. Status = RxpLookupSrvOpenForRequestLite(
  567. pSrvCall,
  568. pRequest);
  569. } else {
  570. if (pRequest->SrvOpenKey == pSrvOpen->Key) {
  571. pRequest->pSrvOpen = pSrvOpen;
  572. RxReferenceSrvOpen(pSrvOpen);
  573. Status = STATUS_SUCCESS;
  574. } else {
  575. Status = STATUS_PENDING;
  576. }
  577. }
  578. // The result of a lookup for a SRV_OPEN instance can yield
  579. // either STATUS_PENDING, STATUS_SUCCESS or STATUS_NOT_FOUND.
  580. switch (Status) {
  581. case STATUS_SUCCESS:
  582. {
  583. RemoveEntryList(&pRequest->ListEntry);
  584. InsertTailList(
  585. &HandlerList,
  586. &pRequest->ListEntry);
  587. }
  588. break;
  589. default:
  590. ASSERT(!"Valid Status Code from RxpLookupSrvOpenForRequestLite");
  591. case STATUS_NOT_FOUND:
  592. {
  593. RemoveEntryList(&pRequest->ListEntry);
  594. InsertTailList(
  595. pDiscardedRequests,
  596. &pRequest->ListEntry);
  597. }
  598. break;
  599. case STATUS_PENDING:
  600. break;
  601. }
  602. }
  603. // Splice back the list of requests that cannot be dispatched onto the
  604. // buffering manager's list and prepare for posting to another thread
  605. // to resume processing later.
  606. KeAcquireSpinLock(
  607. &pBufferingManager->SpinLock,
  608. &SavedIrql);
  609. if (!IsListEmpty(&DispatcherList)) {
  610. DispatcherList.Flink->Blink = pBufferingManager->DispatcherList.Blink;
  611. pBufferingManager->DispatcherList.Blink->Flink = DispatcherList.Flink;
  612. DispatcherList.Blink->Flink = &pBufferingManager->DispatcherList;
  613. pBufferingManager->DispatcherList.Blink = DispatcherList.Blink;
  614. if (ActivateDispatcher = !pBufferingManager->fDispatcherActive) {
  615. pBufferingManager->fDispatcherActive = ActivateDispatcher;
  616. }
  617. }
  618. if (!IsListEmpty(&HandlerList)) {
  619. HandlerList.Flink->Blink = pBufferingManager->HandlerList.Blink;
  620. pBufferingManager->HandlerList.Blink->Flink = HandlerList.Flink;
  621. HandlerList.Blink->Flink = &pBufferingManager->HandlerList;
  622. pBufferingManager->HandlerList.Blink = HandlerList.Blink;
  623. }
  624. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  625. // if resumption at a later time is desired because of unprocessed requests
  626. // post to a worker thread.
  627. if (ActivateDispatcher) {
  628. // Reference the SRV_CALL to ensure that finalization will not occur
  629. // while the worker thread request is in the scheduler.
  630. RxReferenceSrvCall(pSrvCall);
  631. RxLog(("***** Activating Dispatcher\n"));
  632. RxWmiLog(LOG,
  633. RxpDispatchChangeBufferingStateRequests,
  634. LOGPTR(pSrvCall));
  635. RxPostToWorkerThread(
  636. RxFileSystemDeviceObject,
  637. HyperCriticalWorkQueue,
  638. &pBufferingManager->DispatcherWorkItem,
  639. RxDispatchChangeBufferingStateRequests,
  640. pSrvCall);
  641. }
  642. }
  643. VOID
  644. RxDispatchChangeBufferingStateRequests(
  645. PSRV_CALL pSrvCall)
  646. /*++
  647. Routine Description:
  648. This routine dispatches the request. This involves looking up
  649. the SRV_OPEN instance associated with a given SrvOpenKey.
  650. Arguments:
  651. pSrvCall - the associated SRV_CALL instance
  652. --*/
  653. {
  654. KIRQL SavedIrql;
  655. BOOLEAN ActivateHandler = FALSE;
  656. LIST_ENTRY DiscardedRequests;
  657. PRX_BUFFERING_MANAGER pBufferingManager;
  658. RxUndoScavengerFinalizationMarking(
  659. pSrvCall);
  660. pBufferingManager = &pSrvCall->BufferingManager;
  661. RxAcquireBufferingManagerMutex(pBufferingManager);
  662. KeAcquireSpinLock(&pBufferingManager->SpinLock,&SavedIrql);
  663. pBufferingManager->fDispatcherActive = FALSE;
  664. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  665. RxpDispatchChangeBufferingStateRequests(pSrvCall,NULL,&DiscardedRequests);
  666. RxReleaseBufferingManagerMutex(pBufferingManager);
  667. // If requests have been transferred from the dispatcher list to the handler
  668. // list ensure that the handler is activated.
  669. KeAcquireSpinLock(&pBufferingManager->SpinLock,&SavedIrql);
  670. if (!IsListEmpty(&pBufferingManager->HandlerList) &&
  671. (ActivateHandler = !pBufferingManager->fNoWaitHandlerActive)) {
  672. pBufferingManager->fNoWaitHandlerActive = ActivateHandler;
  673. }
  674. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  675. // Note that in this case we have a continuation of processing, from the
  676. // dispatcher to the handler. The reference that was taken to protect the
  677. // dispatcher is transferred to the handling routine. If continuation
  678. // is not required the SRV_CALL instance is dereferenced.
  679. if (ActivateHandler) {
  680. RxProcessChangeBufferingStateRequests(pSrvCall);
  681. } else {
  682. RxDereferenceSrvCall(pSrvCall,LHS_LockNotHeld);
  683. }
  684. // Discard the requests for which the SRV_OPEN instance cannot be located.
  685. // This will cover all the instances for which a buffering change request
  686. // and a close crossed on the wire.
  687. RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
  688. }
  689. VOID
  690. RxpProcessChangeBufferingStateRequests(
  691. PSRV_CALL pSrvCall,
  692. BOOLEAN UpdateHandlerState)
  693. /*++
  694. Routine Description:
  695. This routine initiates the actual processing of change buffering state requests.
  696. Arguments:
  697. pSrvCall - the SRV_CALL instance
  698. Return Value:
  699. none.
  700. Notes:
  701. The change buffering requests are received for different FCB's. If the attempt
  702. is made to handle these requests in the order they are received teh average
  703. response time for completing a change buffering state request can be arbitratily
  704. high. This is because the FCB needs to be acquired exclusively to complete
  705. processing the request. In order to avoid this case the buffering manager
  706. adopts a two pronged strategy -- a first attempt is made to acquire the FCB
  707. exclusively without waiting. If this attempt fails the requests are transferred
  708. to a last chance handler list. This combined with the processing of change
  709. buffering state requests on FCB acquisition/release ensures that most requests
  710. are processed with a very short turn around time.
  711. --*/
  712. {
  713. KIRQL SavedIrql;
  714. PLIST_ENTRY pLastChanceHandlerListEntry;
  715. PLIST_ENTRY pListEntry;
  716. PCHANGE_BUFFERING_STATE_REQUEST pRequest = NULL;
  717. PRX_BUFFERING_MANAGER pBufferingManager;
  718. PSRV_OPEN pSrvOpen;
  719. BOOLEAN ActivateLastChanceHandler;
  720. RxLog(("RPCBSR Entry SrvCall(%lx) \n", pSrvCall));
  721. RxWmiLog(LOG,
  722. RxpProcessChangeBufferingStateRequests_1,
  723. LOGPTR(pSrvCall));
  724. pBufferingManager = &pSrvCall->BufferingManager;
  725. pLastChanceHandlerListEntry = pListEntry = NULL;
  726. for (;;) {
  727. pListEntry = NULL;
  728. ActivateLastChanceHandler = FALSE;
  729. RxAcquireBufferingManagerMutex(pBufferingManager);
  730. KeAcquireSpinLock(&pBufferingManager->SpinLock,&SavedIrql);
  731. // Pick a request from the handler list for change buffering state
  732. // processing.
  733. if (!IsListEmpty(&pBufferingManager->HandlerList)) {
  734. pListEntry = RemoveHeadList(&pBufferingManager->HandlerList);
  735. }
  736. // If the FCB fro the previously picked request could not be acquired
  737. // exclusively without waiting it needs to be transferred to the last
  738. // chance handler list and the last chance handler activated if
  739. // required.
  740. if (pLastChanceHandlerListEntry != NULL) {
  741. // Insert the entry into the last chance handler list.
  742. InsertTailList(
  743. &pBufferingManager->LastChanceHandlerList,
  744. pLastChanceHandlerListEntry);
  745. // reinitialize for the next pass.
  746. pLastChanceHandlerListEntry = NULL;
  747. // prepare for spinning up the last chance handler.
  748. if (!pBufferingManager->fLastChanceHandlerActive &&
  749. !IsListEmpty(&pBufferingManager->LastChanceHandlerList)) {
  750. pBufferingManager->fLastChanceHandlerActive = TRUE;
  751. ActivateLastChanceHandler = TRUE;
  752. }
  753. }
  754. // No more requests to be handled. Prepare for wind down.
  755. if ((pListEntry == NULL) &&
  756. UpdateHandlerState) {
  757. pBufferingManager->fNoWaitHandlerActive = FALSE;
  758. }
  759. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  760. RxReleaseBufferingManagerMutex(pBufferingManager);
  761. // spin up the last chance handler for processing the requests if required.
  762. if (ActivateLastChanceHandler) {
  763. // Reference the SRV_CALL instance to ensure that it will not be
  764. // finalized while the worker thread request is in the scheduler
  765. RxReferenceSrvCall(pSrvCall);
  766. RxPostToWorkerThread(
  767. RxFileSystemDeviceObject,
  768. DelayedWorkQueue,
  769. &pBufferingManager->LastChanceHandlerWorkItem,
  770. RxLastChanceHandlerForChangeBufferingStateRequests,
  771. pSrvCall);
  772. ActivateLastChanceHandler = FALSE;
  773. }
  774. if (pListEntry == NULL) {
  775. break;
  776. }
  777. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  778. CONTAINING_RECORD(
  779. pListEntry,
  780. CHANGE_BUFFERING_STATE_REQUEST,
  781. ListEntry);
  782. RxLog(("Proc. Req. SrvOpen (%lx) \n",pRequest->pSrvOpen));
  783. RxWmiLog(LOG,
  784. RxpProcessChangeBufferingStateRequests_2,
  785. LOGPTR(pRequest->pSrvOpen));
  786. if (RxPrepareRequestForHandling(pRequest) == STATUS_SUCCESS) {
  787. // Try to acquire the FCB without waiting. If the FCB is currently unavailable
  788. // then it is guaranteed that this request will be processed when the FCB
  789. // resource is released.
  790. ASSERT(pRequest->pSrvOpen != NULL);
  791. if (RxAcquireExclusiveFcb(
  792. CHANGE_BUFFERING_STATE_CONTEXT,
  793. pRequest->pSrvOpen->Fcb) == STATUS_SUCCESS) {
  794. BOOLEAN FcbFinalized;
  795. PFCB pFcb;
  796. RxLog(("Proc. Req. SrvOpen FCB (%lx) \n",pRequest->pSrvOpen->Fcb));
  797. RxWmiLog(LOG,
  798. RxpProcessChangeBufferingStateRequests_3,
  799. LOGPTR(pRequest->pSrvOpen->Fcb));
  800. pSrvOpen = pRequest->pSrvOpen;
  801. pFcb = pSrvOpen->Fcb;
  802. RxReferenceNetFcb(pFcb);
  803. if (!FlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_CLOSED)) {
  804. RxDbgTrace(0,Dbg,("SrvOpenKey(%lx) being processed(Last Resort)\n",pRequest->SrvOpenKey));
  805. RxLog(("SOKey(%lx) processed(Last Resort)\n",pRequest->SrvOpenKey));
  806. RxWmiLog(LOG,
  807. RxpProcessChangeBufferingStateRequests_4,
  808. LOGPTR(pRequest->SrvOpenKey));
  809. RxChangeBufferingState(pSrvOpen,pRequest->pMRxContext,TRUE);
  810. }
  811. RxAcquireSerializationMutex();
  812. ClearFlag(pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING);
  813. ClearFlag(pSrvOpen->Fcb->FcbState,FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
  814. KeSetEvent(pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent,IO_NETWORK_INCREMENT,FALSE);
  815. RxReleaseSerializationMutex();
  816. RxPrepareRequestForReuse(pRequest);
  817. FcbFinalized = RxDereferenceAndFinalizeNetFcb(
  818. pFcb,
  819. CHANGE_BUFFERING_STATE_CONTEXT_WAIT,
  820. FALSE,
  821. FALSE);
  822. if (!FcbFinalized) {
  823. RxReleaseFcb(CHANGE_BUFFERING_STATE_CONTEXT,pFcb);
  824. }
  825. RxFreePool(pRequest);
  826. } else {
  827. // The FCB has been currently accquired. Transfer the change buffering state
  828. // request to the last chance handler list. This will ensure that the
  829. // change buffering state request is processed in all cases, i.e.,
  830. // accquisition of the resource in shared mode as well as the acquistion
  831. // of the FCB resource by other components ( cache manager/memory manager )
  832. // without going through the wrapper.
  833. pLastChanceHandlerListEntry = &pRequest->ListEntry;
  834. }
  835. } else {
  836. RxPrepareRequestForReuse(pRequest);
  837. RxFreePool(pRequest);
  838. }
  839. }
  840. // Dereference the SRV_CALL instance.
  841. RxDereferenceSrvCall(pSrvCall,LHS_LockNotHeld);
  842. RxLog(("RPCBSR Exit SrvCall(%lx)\n",pSrvCall));
  843. RxWmiLog(LOG,
  844. RxpProcessChangeBufferingStateRequests_5,
  845. LOGPTR(pSrvCall));
  846. }
  847. VOID
  848. RxProcessChangeBufferingStateRequests(
  849. PSRV_CALL pSrvCall)
  850. /*++
  851. Routine Description:
  852. This routine is the last chance handler for processing change buffering state
  853. requests
  854. Arguments:
  855. pSrvCall -- the SrvCall instance
  856. Notes:
  857. Since the reference for the srv call instance was accquired at DPC undo
  858. the scavenger marking if required.
  859. --*/
  860. {
  861. RxUndoScavengerFinalizationMarking(
  862. pSrvCall);
  863. RxpProcessChangeBufferingStateRequests(
  864. pSrvCall,
  865. TRUE);
  866. }
  867. VOID
  868. RxLastChanceHandlerForChangeBufferingStateRequests(
  869. PSRV_CALL pSrvCall)
  870. /*++
  871. Routine Description:
  872. This routine is the last chance handler for processing change buffering state
  873. requests
  874. Arguments:
  875. Return Value:
  876. none.
  877. Notes:
  878. This routine exists because Mm/Cache manager manipulate the header resource
  879. associated with the FCB directly in some cases. In such cases it is not possible
  880. to determine whether the release is done through the wrapper. In such cases it
  881. is important to have a thread actually wait on the FCB resource to be released
  882. and subsequently process the buffering state request as a last resort mechanism.
  883. This also handles the case when the FCB is accquired shared. In such cases the
  884. change buffering state has to be completed in the context of a thread which can
  885. accquire it exclusively.
  886. The filtering of the requests must be further optimized by marking the FCB state
  887. during resource accquisition by the wrapper so that requests do not get downgraded
  888. easily. ( TO BE IMPLEMENTED )
  889. --*/
  890. {
  891. KIRQL SavedIrql;
  892. PLIST_ENTRY pListEntry;
  893. LIST_ENTRY FinalizationList;
  894. PRX_BUFFERING_MANAGER pBufferingManager;
  895. PCHANGE_BUFFERING_STATE_REQUEST pRequest = NULL;
  896. PSRV_OPEN pSrvOpen;
  897. BOOLEAN FcbFinalized,FcbAcquired;
  898. PFCB pFcb;
  899. RxLog(("RLCHCBSR Entry SrvCall(%lx)\n",pSrvCall));
  900. RxWmiLog(LOG,
  901. RxLastChanceHandlerForChangeBufferingStateRequests_1,
  902. LOGPTR(pSrvCall));
  903. InitializeListHead(&FinalizationList);
  904. pBufferingManager = &pSrvCall->BufferingManager;
  905. for (;;) {
  906. RxAcquireBufferingManagerMutex(pBufferingManager);
  907. KeAcquireSpinLock(&pBufferingManager->SpinLock,&SavedIrql);
  908. if (!IsListEmpty(&pBufferingManager->LastChanceHandlerList)) {
  909. pListEntry = RemoveHeadList(&pBufferingManager->LastChanceHandlerList);
  910. } else {
  911. pListEntry = NULL;
  912. pBufferingManager->fLastChanceHandlerActive = FALSE;
  913. }
  914. KeReleaseSpinLock(&pBufferingManager->SpinLock,SavedIrql);
  915. RxReleaseBufferingManagerMutex(pBufferingManager);
  916. if (pListEntry == NULL) {
  917. break;
  918. }
  919. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  920. CONTAINING_RECORD(
  921. pListEntry,
  922. CHANGE_BUFFERING_STATE_REQUEST,
  923. ListEntry);
  924. pSrvOpen = pRequest->pSrvOpen;
  925. pFcb = pSrvOpen->Fcb;
  926. RxReferenceNetFcb(pFcb);
  927. FcbAcquired = (RxAcquireExclusiveFcb(
  928. CHANGE_BUFFERING_STATE_CONTEXT_WAIT,
  929. pRequest->pSrvOpen->Fcb) == STATUS_SUCCESS);
  930. if (FcbAcquired && !FlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_CLOSED)) {
  931. RxDbgTrace(0,Dbg,("SrvOpenKey(%lx) being processed(Last Resort)\n",pRequest->SrvOpenKey));
  932. RxLog(("SOKey(%lx) processed(Last Resort)\n",pRequest->SrvOpenKey));
  933. RxWmiLog(LOG,
  934. RxLastChanceHandlerForChangeBufferingStateRequests_2,
  935. LOGPTR(pRequest->SrvOpenKey));
  936. RxChangeBufferingState(pSrvOpen,pRequest->pMRxContext,TRUE);
  937. }
  938. RxAcquireSerializationMutex();
  939. ClearFlag(pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING);
  940. ClearFlag(pSrvOpen->Fcb->FcbState,FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
  941. KeSetEvent(pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent,IO_NETWORK_INCREMENT,FALSE);
  942. RxReleaseSerializationMutex();
  943. InsertTailList(&FinalizationList,pListEntry);
  944. if (FcbAcquired) {
  945. RxReleaseFcb(CHANGE_BUFFERING_STATE_CONTEXT,pFcb);
  946. }
  947. }
  948. while (!IsListEmpty(&FinalizationList)) {
  949. pListEntry = RemoveHeadList(&FinalizationList);
  950. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  951. CONTAINING_RECORD(
  952. pListEntry,
  953. CHANGE_BUFFERING_STATE_REQUEST,
  954. ListEntry);
  955. pSrvOpen = pRequest->pSrvOpen;
  956. pFcb = pSrvOpen->Fcb;
  957. FcbAcquired = (RxAcquireExclusiveFcb(
  958. CHANGE_BUFFERING_STATE_CONTEXT_WAIT,
  959. pRequest->pSrvOpen->Fcb) == STATUS_SUCCESS);
  960. ASSERT(FcbAcquired == TRUE);
  961. RxPrepareRequestForReuse(pRequest);
  962. FcbFinalized = RxDereferenceAndFinalizeNetFcb(
  963. pFcb,
  964. CHANGE_BUFFERING_STATE_CONTEXT_WAIT,
  965. FALSE,
  966. FALSE);
  967. if (!FcbFinalized && FcbAcquired) {
  968. RxReleaseFcb(CHANGE_BUFFERING_STATE_CONTEXT,pFcb);
  969. }
  970. RxFreePool(pRequest);
  971. }
  972. RxLog(("RLCHCBSR Exit SrvCall(%lx)\n",pSrvCall));
  973. RxWmiLog(LOG,
  974. RxLastChanceHandlerForChangeBufferingStateRequests_3,
  975. LOGPTR(pSrvCall));
  976. // Dereference the SRV_CALL instance.
  977. RxDereferenceSrvCall(pSrvCall, LHS_LockNotHeld);
  978. }
  979. VOID
  980. RxProcessFcbChangeBufferingStateRequest(
  981. PFCB pFcb)
  982. /*++
  983. Routine Description:
  984. This routine processes all the outstanding change buffering state request for a
  985. FCB.
  986. Arguments:
  987. pFcb - the FCB instance
  988. Return Value:
  989. none.
  990. Notes:
  991. The FCB instance must be acquired exclusively on entry to this routine and
  992. its ownership will remain invariant on exit.
  993. --*/
  994. {
  995. PSRV_CALL pSrvCall;
  996. LIST_ENTRY FcbRequestList;
  997. PLIST_ENTRY pListEntry;
  998. PRX_BUFFERING_MANAGER pBufferingManager;
  999. PCHANGE_BUFFERING_STATE_REQUEST pRequest = NULL;
  1000. PAGED_CODE();
  1001. RxLog(("RPFcbCBSR Entry FCB(%lx)\n",pFcb));
  1002. RxWmiLog(LOG,
  1003. RxProcessFcbChangeBufferingStateRequest_1,
  1004. LOGPTR(pFcb));
  1005. pSrvCall = (PSRV_CALL)pFcb->VNetRoot->NetRoot->SrvCall;
  1006. pBufferingManager = &pSrvCall->BufferingManager;
  1007. InitializeListHead(&FcbRequestList);
  1008. // Walk through the list of SRV_OPENS associated with this FCB and pick up
  1009. // the requests that can be dispatched.
  1010. RxAcquireBufferingManagerMutex(pBufferingManager);
  1011. pListEntry = pFcb->SrvOpenList.Flink;
  1012. while (pListEntry != &pFcb->SrvOpenList) {
  1013. PSRV_OPEN pSrvOpen;
  1014. pSrvOpen = (PSRV_OPEN)
  1015. (CONTAINING_RECORD(
  1016. pListEntry,
  1017. SRV_OPEN,
  1018. SrvOpenQLinks));
  1019. pListEntry = pListEntry->Flink;
  1020. RxGatherRequestsForSrvOpen(pSrvCall,pSrvOpen,&FcbRequestList);
  1021. }
  1022. RxReleaseBufferingManagerMutex(pBufferingManager);
  1023. if (!IsListEmpty(&FcbRequestList)) {
  1024. // Initiate buffering state change processing.
  1025. pListEntry = FcbRequestList.Flink;
  1026. while (pListEntry != &FcbRequestList) {
  1027. NTSTATUS Status = STATUS_SUCCESS;
  1028. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  1029. CONTAINING_RECORD(
  1030. pListEntry,
  1031. CHANGE_BUFFERING_STATE_REQUEST,
  1032. ListEntry);
  1033. pListEntry = pListEntry->Flink;
  1034. if (RxPrepareRequestForHandling(pRequest) == STATUS_SUCCESS) {
  1035. if (!FlagOn(pRequest->pSrvOpen->Flags,SRVOPEN_FLAG_CLOSED)) {
  1036. RxDbgTrace(0,Dbg,("****** SrvOpenKey(%lx) being processed\n",pRequest->SrvOpenKey));
  1037. RxLog(("****** SOKey(%lx) being processed\n",pRequest->SrvOpenKey));
  1038. RxWmiLog(LOG,
  1039. RxProcessFcbChangeBufferingStateRequest_2,
  1040. LOGPTR(pRequest->SrvOpenKey));
  1041. RxChangeBufferingState(pRequest->pSrvOpen,pRequest->pMRxContext,TRUE);
  1042. } else {
  1043. RxDbgTrace(0,Dbg,("****** 123 SrvOpenKey(%lx) being ignored\n",pRequest->SrvOpenKey));
  1044. RxLog(("****** 123 SOKey(%lx) ignored\n",pRequest->SrvOpenKey));
  1045. RxWmiLog(LOG,
  1046. RxProcessFcbChangeBufferingStateRequest_3,
  1047. LOGPTR(pRequest->SrvOpenKey));
  1048. }
  1049. }
  1050. }
  1051. // Discard the requests.
  1052. RxpDiscardChangeBufferingStateRequests(&FcbRequestList);
  1053. }
  1054. RxLog(("RPFcbCBSR Exit FCB(%lx)\n",pFcb));
  1055. RxWmiLog(LOG,
  1056. RxProcessFcbChangeBufferingStateRequest_4,
  1057. LOGPTR(pFcb));
  1058. // All buffering state change requests have been processed, clear the flag
  1059. // and signal the event as necessary.
  1060. RxAcquireSerializationMutex();
  1061. // update the FCB state.
  1062. ClearFlag(pFcb->FcbState,FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
  1063. if( pFcb->pBufferingStateChangeCompletedEvent )
  1064. KeSetEvent(pFcb->pBufferingStateChangeCompletedEvent,IO_NETWORK_INCREMENT,FALSE);
  1065. RxReleaseSerializationMutex();
  1066. }
  1067. VOID
  1068. RxGatherRequestsForSrvOpen(
  1069. IN OUT PSRV_CALL pSrvCall,
  1070. IN PSRV_OPEN pSrvOpen,
  1071. IN OUT PLIST_ENTRY pRequestsListHead)
  1072. /*++
  1073. Routine Description:
  1074. This routine gathers all the change buffering state requests associated with a SRV_OPEN.
  1075. This routine provides the mechanism for gathering all the requests for a SRV_OPEN which
  1076. is then used bu routines which process them
  1077. Arguments:
  1078. pSrvCall - the SRV_CALL instance
  1079. pSrvOpen - the SRV_OPEN instance
  1080. pRequestsListHead - the list of requests which is constructed by this routine
  1081. Notes:
  1082. On Entry to thir routine the buffering manager Mutex must have been acquired
  1083. and the ownership remains invariant on exit
  1084. --*/
  1085. {
  1086. PLIST_ENTRY pListEntry;
  1087. LIST_ENTRY DiscardedRequests;
  1088. PCHANGE_BUFFERING_STATE_REQUEST pRequest;
  1089. PRX_BUFFERING_MANAGER pBufferingManager;
  1090. PVOID SrvOpenKey;
  1091. KIRQL SavedIrql;
  1092. pBufferingManager = &pSrvCall->BufferingManager;
  1093. SrvOpenKey = pSrvOpen->Key;
  1094. // gather all the requests from the dispatcher list
  1095. RxpDispatchChangeBufferingStateRequests(pSrvCall,pSrvOpen,&DiscardedRequests);
  1096. KeAcquireSpinLock(
  1097. &pSrvCall->BufferingManager.SpinLock,
  1098. &SavedIrql);
  1099. // gather all the requests with the given SrvOpenKey in the handler list
  1100. pListEntry = pBufferingManager->HandlerList.Flink;
  1101. while (pListEntry != &pBufferingManager->HandlerList) {
  1102. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  1103. CONTAINING_RECORD(
  1104. pListEntry,
  1105. CHANGE_BUFFERING_STATE_REQUEST,
  1106. ListEntry);
  1107. pListEntry = pListEntry->Flink;
  1108. if (pRequest->SrvOpenKey == SrvOpenKey) {
  1109. RemoveEntryList(&pRequest->ListEntry);
  1110. InsertHeadList(pRequestsListHead,&pRequest->ListEntry);
  1111. }
  1112. }
  1113. KeReleaseSpinLock(
  1114. &pSrvCall->BufferingManager.SpinLock,
  1115. SavedIrql);
  1116. // gather all the requests from the last chance handler list
  1117. pListEntry = pBufferingManager->LastChanceHandlerList.Flink;
  1118. while (pListEntry != &pBufferingManager->LastChanceHandlerList) {
  1119. pRequest = (PCHANGE_BUFFERING_STATE_REQUEST)
  1120. CONTAINING_RECORD(
  1121. pListEntry,
  1122. CHANGE_BUFFERING_STATE_REQUEST,
  1123. ListEntry);
  1124. pListEntry = pListEntry->Flink;
  1125. if (pRequest->SrvOpenKey == pSrvOpen->Key) {
  1126. RemoveEntryList(&pRequest->ListEntry);
  1127. InsertHeadList(pRequestsListHead,&pRequest->ListEntry);
  1128. }
  1129. }
  1130. RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
  1131. }
  1132. VOID
  1133. RxPurgeChangeBufferingStateRequestsForSrvOpen(
  1134. IN PSRV_OPEN pSrvOpen)
  1135. /*++
  1136. Routine Description:
  1137. The routine purges all the requests associated with a given SRV_OPEN. This will ensure
  1138. that all buffering state change requests received while the SRV_OPEN was being closed
  1139. will be flushed out.
  1140. Arguments:
  1141. pSrvOpen - the SRV_OPEN instance
  1142. Notes:
  1143. --*/
  1144. {
  1145. PSRV_CALL pSrvCall = (PSRV_CALL)pSrvOpen->Fcb->VNetRoot->NetRoot->SrvCall;
  1146. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  1147. LIST_ENTRY DiscardedRequests;
  1148. PAGED_CODE();
  1149. ASSERT(RxIsFcbAcquiredExclusive(pSrvOpen->Fcb));
  1150. InitializeListHead(&DiscardedRequests);
  1151. RxAcquireBufferingManagerMutex(pBufferingManager);
  1152. RemoveEntryList(&pSrvOpen->SrvOpenKeyList);
  1153. InitializeListHead(&pSrvOpen->SrvOpenKeyList);
  1154. SetFlag(pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
  1155. RxGatherRequestsForSrvOpen(pSrvCall,pSrvOpen,&DiscardedRequests);
  1156. RxReleaseBufferingManagerMutex(pBufferingManager);
  1157. if (!IsListEmpty(&DiscardedRequests)) {
  1158. if (BooleanFlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) {
  1159. RxAcquireSerializationMutex();
  1160. ClearFlag(
  1161. pSrvOpen->Fcb->FcbState,
  1162. FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
  1163. if (pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL) {
  1164. KeSetEvent(
  1165. pSrvOpen->Fcb->pBufferingStateChangeCompletedEvent,
  1166. IO_NETWORK_INCREMENT,
  1167. FALSE);
  1168. }
  1169. RxReleaseSerializationMutex();
  1170. }
  1171. RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
  1172. }
  1173. }
  1174. VOID
  1175. RxProcessChangeBufferingStateRequestsForSrvOpen(
  1176. PSRV_OPEN pSrvOpen)
  1177. /*++
  1178. Routine Description:
  1179. The routine processes all the requests associated with a given SRV_OPEN.
  1180. Since this routine is called from a fastio path it tries to defer lock accquistion
  1181. till it is required
  1182. Arguments:
  1183. pSrvOpen - the SRV_OPEN instance
  1184. Notes:
  1185. --*/
  1186. {
  1187. LONG OldBufferingToken;
  1188. PSRV_CALL pSrvCall;
  1189. PFCB pFcb;
  1190. pSrvCall = (PSRV_CALL)pSrvOpen->pVNetRoot->pNetRoot->pSrvCall;
  1191. pFcb = (PFCB)pSrvOpen->pFcb;
  1192. // If change buffering state requests have been received for this srvcall
  1193. // since the last time the request was processed ensure that we process
  1194. // all these requests now.
  1195. OldBufferingToken = pSrvOpen->BufferingToken;
  1196. if (InterlockedCompareExchange(
  1197. &pSrvOpen->BufferingToken,
  1198. pSrvCall->BufferingManager.CumulativeNumberOfBufferingChangeRequests,
  1199. pSrvCall->BufferingManager.CumulativeNumberOfBufferingChangeRequests)
  1200. != OldBufferingToken) {
  1201. if (RxAcquireExclusiveFcb(NULL,pFcb) == STATUS_SUCCESS) {
  1202. RxProcessFcbChangeBufferingStateRequest(pFcb);
  1203. RxReleaseFcb(NULL,pFcb);
  1204. }
  1205. }
  1206. }
  1207. VOID
  1208. RxInitiateSrvOpenKeyAssociation(
  1209. IN OUT PSRV_OPEN pSrvOpen)
  1210. /*++
  1211. Routine Description:
  1212. This routine prepares a SRV_OPEN instance for SrvOpenKey association.
  1213. Arguments:
  1214. pSrvOpen - the SRV_OPEN instance
  1215. Notes:
  1216. The process of key association is a two phase protocol. In the initialization process
  1217. a sequence number is stowed away in the SRV_OPEN. When the
  1218. RxCompleteSrvOpenKeyAssociation routine is called the sequence number is used to
  1219. update the data structures associated with the SRV_CALL instance. This is required
  1220. because of the asynchronous nature of receiving buffering state change indications
  1221. (oplock breaks in SMB terminology ) before the open is completed.
  1222. --*/
  1223. {
  1224. KIRQL SavedIrql;
  1225. PSRV_CALL pSrvCall = (PSRV_CALL)pSrvOpen->Fcb->VNetRoot->NetRoot->SrvCall;
  1226. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  1227. PAGED_CODE();
  1228. pSrvOpen->Key = NULL;
  1229. InterlockedIncrement(&pBufferingManager->NumberOfOutstandingOpens);
  1230. InitializeListHead(&pSrvOpen->SrvOpenKeyList);
  1231. }
  1232. VOID
  1233. RxCompleteSrvOpenKeyAssociation(
  1234. IN OUT PSRV_OPEN pSrvOpen)
  1235. /*++
  1236. Routine Description:
  1237. The routine associates the given key with the SRV_OPEN instance
  1238. Arguments:
  1239. pMRxSrvOpen - the SRV_OPEN instance
  1240. SrvOpenKey - the key to be associated with the instance
  1241. Notes:
  1242. This routine in addition to establishing the mapping also ensures that any pending
  1243. buffering state change requests are handled correctly. This ensures that change
  1244. buffering state requests received during the duration of SRV_OPEN construction
  1245. will be handled immediately.
  1246. --*/
  1247. {
  1248. KIRQL SavedIrql;
  1249. BOOLEAN ActivateHandler = FALSE;
  1250. ULONG Index = 0;
  1251. PSRV_CALL pSrvCall = (PSRV_CALL)pSrvOpen->Fcb->VNetRoot->NetRoot->SrvCall;
  1252. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  1253. LIST_ENTRY DiscardedRequests;
  1254. // Associate the SrvOpenKey with the SRV_OPEN instance and also dispatch the
  1255. // associated change buffering state request if any.
  1256. InterlockedDecrement(&pBufferingManager->NumberOfOutstandingOpens);
  1257. if (pSrvOpen->Condition == Condition_Good) {
  1258. InitializeListHead(&DiscardedRequests);
  1259. RxAcquireBufferingManagerMutex(pBufferingManager);
  1260. InsertTailList(
  1261. &pBufferingManager->SrvOpenLists[Index],
  1262. &pSrvOpen->SrvOpenKeyList);
  1263. RxpDispatchChangeBufferingStateRequests(
  1264. pSrvCall,
  1265. pSrvOpen,
  1266. &DiscardedRequests);
  1267. RxReleaseBufferingManagerMutex(pBufferingManager);
  1268. KeAcquireSpinLock(
  1269. &pBufferingManager->SpinLock,
  1270. &SavedIrql);
  1271. if (!IsListEmpty(&pBufferingManager->HandlerList) &&
  1272. (ActivateHandler = !pBufferingManager->fNoWaitHandlerActive)) {
  1273. pBufferingManager->fNoWaitHandlerActive = ActivateHandler;
  1274. }
  1275. KeReleaseSpinLock(
  1276. &pBufferingManager->SpinLock,
  1277. SavedIrql);
  1278. if (ActivateHandler) {
  1279. // Reference the SRV_CALL instance to ensure that it will not be
  1280. // finalized while the worker thread request is in the scheduler
  1281. RxReferenceSrvCall(pSrvCall);
  1282. RxPostToWorkerThread(
  1283. RxFileSystemDeviceObject,
  1284. HyperCriticalWorkQueue,
  1285. &pBufferingManager->HandlerWorkItem,
  1286. RxProcessChangeBufferingStateRequests,
  1287. pSrvCall);
  1288. }
  1289. RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
  1290. }
  1291. }
  1292. NTSTATUS
  1293. RxpLookupSrvOpenForRequestLite(
  1294. IN PSRV_CALL pSrvCall,
  1295. IN PCHANGE_BUFFERING_STATE_REQUEST pRequest)
  1296. /*++
  1297. Routine Description:
  1298. The routine looks up the SRV_OPEN instance associated with a buffering state change
  1299. request.
  1300. Arguments:
  1301. pSrvCall - the SRV_CALL instance
  1302. pRequest - the buffering state change request
  1303. Return Value:
  1304. STATUS_SUCCESS - the SRV_OPEN instance was found
  1305. STATUS_PENDING - the SRV_OPEN instance was not found but there are open requests
  1306. outstanding
  1307. STATUS_NOT_FOUND - the SRV_OPEN instance was not found.
  1308. Notes:
  1309. --*/
  1310. {
  1311. NTSTATUS Status = STATUS_SUCCESS;
  1312. PRX_BUFFERING_MANAGER pBufferingManager = &pSrvCall->BufferingManager;
  1313. ULONG Index = 0;
  1314. PSRV_OPEN pSrvOpen = NULL;
  1315. PLIST_ENTRY pListHead,pListEntry;
  1316. PAGED_CODE();
  1317. pListHead = &pBufferingManager->SrvOpenLists[Index];
  1318. pListEntry = pListHead->Flink;
  1319. while (pListEntry != pListHead) {
  1320. pSrvOpen = (PSRV_OPEN)
  1321. CONTAINING_RECORD(
  1322. pListEntry,
  1323. SRV_OPEN,
  1324. SrvOpenKeyList);
  1325. if ((pSrvOpen->Key == pRequest->SrvOpenKey) &&
  1326. (!FlagOn(pSrvOpen->pFcb->FcbState,FCB_STATE_ORPHANED))) {
  1327. RxReferenceSrvOpen(pSrvOpen);
  1328. break;
  1329. }
  1330. pListEntry = pListEntry->Flink;
  1331. }
  1332. if (pListEntry == pListHead) {
  1333. pSrvOpen = NULL;
  1334. if (pBufferingManager->NumberOfOutstandingOpens == 0) {
  1335. Status = STATUS_NOT_FOUND;
  1336. } else {
  1337. Status = STATUS_PENDING;
  1338. }
  1339. }
  1340. pRequest->pSrvOpen = pSrvOpen;
  1341. return Status;
  1342. }
  1343. #define RxIsFcbOpenedExclusively(FCB) ( ((FCB)->ShareAccess.SharedRead \
  1344. + (FCB)->ShareAccess.SharedWrite \
  1345. + (FCB)->ShareAccess.SharedDelete) == 0 )
  1346. NTSTATUS
  1347. RxChangeBufferingState (
  1348. PSRV_OPEN SrvOpen,
  1349. PVOID Context,
  1350. BOOLEAN ComputeNewState)
  1351. /*++
  1352. Routine Description:
  1353. This routine is called to process a buffering state change request.
  1354. Arguments:
  1355. SrvOpen - the SrvOpen to be changed;
  1356. Context - the context parameter for mini rdr callback.
  1357. ComputeNewState - determines if the new state is to be computed.
  1358. Return Value:
  1359. Notes:
  1360. On entry to this routine the FCB must have been accquired exclusive.
  1361. On exit there is no change in resource ownership
  1362. --*/
  1363. {
  1364. ULONG NewBufferingState, OldBufferingState;
  1365. PFCB Fcb = SrvOpen->Fcb;
  1366. NTSTATUS FlushStatus = STATUS_SUCCESS;
  1367. PAGED_CODE();
  1368. #define LOSING_CAPABILITY(a) ((NewBufferingState&(a))<(OldBufferingState&(a)))
  1369. RxDbgTrace(+1, Dbg, ("RxChangeBufferingState SrvOpen=%08lx, Context=%08lx\n", SrvOpen, Context ));
  1370. RxLog(("ChangeBufferState %lx %lx\n", SrvOpen, Context ));
  1371. RxWmiLog(LOG,
  1372. RxChangeBufferingState_1,
  1373. LOGPTR(SrvOpen)
  1374. LOGPTR(Context));
  1375. ASSERT ( NodeTypeIsFcb(Fcb) );
  1376. SetFlag(Fcb->FcbState,FCB_STATE_BUFFERSTATE_CHANGING); //this is informational for error recovery
  1377. try {
  1378. if (ComputeNewState) {
  1379. NTSTATUS Status;
  1380. RxDbgTrace(0,Dbg,("RxChangeBufferingState FCB(%lx) Compute New State\n",Fcb));
  1381. // Compute the new buffering state with the help of the mini redirector
  1382. MINIRDR_CALL_THROUGH(
  1383. Status,
  1384. Fcb->MRxDispatch,
  1385. MRxComputeNewBufferingState,
  1386. ((PMRX_SRV_OPEN)SrvOpen,Context,&NewBufferingState));
  1387. if (Status != STATUS_SUCCESS) {
  1388. NewBufferingState = 0;
  1389. }
  1390. } else {
  1391. NewBufferingState = SrvOpen->BufferingFlags;
  1392. }
  1393. if (RxIsFcbOpenedExclusively(Fcb) &&
  1394. !ComputeNewState){
  1395. NewBufferingState |= (FCB_STATE_WRITECACHEING_ENABLED |
  1396. FCB_STATE_FILESIZECACHEING_ENABLED |
  1397. FCB_STATE_FILETIMECACHEING_ENABLED |
  1398. FCB_STATE_WRITEBUFFERING_ENABLED |
  1399. FCB_STATE_LOCK_BUFFERING_ENABLED |
  1400. FCB_STATE_READBUFFERING_ENABLED |
  1401. FCB_STATE_READCACHEING_ENABLED);
  1402. }
  1403. if (Fcb->OutstandingLockOperationsCount != 0) {
  1404. NewBufferingState &= ~FCB_STATE_LOCK_BUFFERING_ENABLED;
  1405. }
  1406. OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
  1407. RxDbgTrace(0, Dbg, ("--> OldBS=%08lx, NewBS=%08lx, SrvOBS = %08lx\n",
  1408. OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags ));
  1409. RxLog(("CBS-2 %lx %lx %lx\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags ));
  1410. RxWmiLog(LOG,
  1411. RxChangeBufferingState_2,
  1412. LOGULONG(OldBufferingState)
  1413. LOGULONG(NewBufferingState)
  1414. LOGULONG(SrvOpen->BufferingFlags));
  1415. RxDbgTrace(0,Dbg,("RxChangeBufferingState FCB(%lx) Old (%lx) New (%lx)\n",Fcb,OldBufferingState,NewBufferingState));
  1416. // Fcb->FcbState &= ~FCB_STATE_BUFFERING_STATE_MASK;
  1417. if(LOSING_CAPABILITY(FCB_STATE_WRITECACHEING_ENABLED)){
  1418. RxDbgTrace(0, Dbg, ("-->flush\n", 0 ));
  1419. RxLog(("CBS-Flush"));
  1420. RxWmiLog(LOG,
  1421. RxChangeBufferingState_3,
  1422. LOGPTR(Fcb));
  1423. //CcFlushCache(&Fcb->NonPaged->SectionObjectPointers,NULL,0,NULL );
  1424. FlushStatus = RxFlushFcbInSystemCache(Fcb,FALSE);
  1425. }
  1426. // If there are no handles to this file or it the read caching capability
  1427. // is lost the file needs to be purged. This will force the memory
  1428. // manager to relinquish the additional reference on the file.
  1429. if ((Fcb->UncleanCount == 0) ||
  1430. (LOSING_CAPABILITY(FCB_STATE_READCACHEING_ENABLED)
  1431. || FlagOn(NewBufferingState, MINIRDR_BUFSTATE_COMMAND_FORCEPURGE))) {
  1432. RxDbgTrace(0, Dbg, ("-->purge\n", 0 ));
  1433. RxLog(("CBS-purge\n"));
  1434. RxWmiLog(LOG,
  1435. RxChangeBufferingState_4,
  1436. LOGPTR(Fcb));
  1437. if( !NT_SUCCESS(FlushStatus) )
  1438. {
  1439. RxCcLogError( (PDEVICE_OBJECT)Fcb->RxDeviceObject,
  1440. &Fcb->PrivateAlreadyPrefixedName,
  1441. IO_LOST_DELAYED_WRITE,
  1442. FlushStatus,
  1443. IRP_MJ_WRITE,
  1444. Fcb );
  1445. }
  1446. CcPurgeCacheSection(
  1447. &Fcb->NonPaged->SectionObjectPointers,
  1448. NULL,
  1449. 0,
  1450. FALSE );
  1451. }
  1452. // the wrapper does not use these flags yet
  1453. if(LOSING_CAPABILITY(FCB_STATE_WRITEBUFFERING_ENABLED)) NOTHING;
  1454. if(LOSING_CAPABILITY(FCB_STATE_READBUFFERING_ENABLED)) NOTHING;
  1455. if(LOSING_CAPABILITY(FCB_STATE_OPENSHARING_ENABLED)) NOTHING;
  1456. if(LOSING_CAPABILITY(FCB_STATE_COLLAPSING_ENABLED)) NOTHING;
  1457. if(LOSING_CAPABILITY(FCB_STATE_FILESIZECACHEING_ENABLED)) NOTHING;
  1458. if(LOSING_CAPABILITY(FCB_STATE_FILETIMECACHEING_ENABLED)) NOTHING;
  1459. if (ComputeNewState &&
  1460. FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING) &&
  1461. !IsListEmpty(&SrvOpen->FobxList)) {
  1462. NTSTATUS Status;
  1463. PRX_CONTEXT RxContext = NULL;
  1464. RxContext = RxCreateRxContext(
  1465. NULL,
  1466. SrvOpen->Fcb->RxDeviceObject,
  1467. RX_CONTEXT_FLAG_WAIT|RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
  1468. if (RxContext != NULL) {
  1469. RxContext->pFcb = (PMRX_FCB)Fcb;
  1470. RxContext->pFobx = (PMRX_FOBX)
  1471. (CONTAINING_RECORD(
  1472. SrvOpen->FobxList.Flink,
  1473. FOBX,
  1474. FobxQLinks));
  1475. RxContext->pRelevantSrvOpen = RxContext->pFobx->pSrvOpen;
  1476. if (FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_CLOSE_DELAYED)) {
  1477. RxLog((" ##### Oplock brk close %lx\n",RxContext->pFobx));
  1478. RxWmiLog(LOG,
  1479. RxChangeBufferingState_4,
  1480. LOGPTR(RxContext->pFobx));
  1481. Status = RxCloseAssociatedSrvOpen(
  1482. (PFOBX)RxContext->pFobx,
  1483. RxContext);
  1484. } else {
  1485. MINIRDR_CALL_THROUGH(
  1486. Status,
  1487. Fcb->MRxDispatch,
  1488. MRxCompleteBufferingStateChangeRequest,
  1489. (RxContext,(PMRX_SRV_OPEN)SrvOpen,Context));
  1490. }
  1491. RxDereferenceAndDeleteRxContext(RxContext);
  1492. }
  1493. RxDbgTrace(0,Dbg,("RxChangeBuffering State FCB(%lx) Completeing buffering state change\n",Fcb));
  1494. }
  1495. Fcb->FcbState = ((Fcb->FcbState & ~(FCB_STATE_BUFFERING_STATE_MASK)) |
  1496. (FCB_STATE_BUFFERING_STATE_MASK & NewBufferingState));
  1497. } finally {
  1498. ClearFlag(Fcb->FcbState,FCB_STATE_BUFFERSTATE_CHANGING); //this is informational for error recovery
  1499. ClearFlag(Fcb->FcbState,FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
  1500. }
  1501. RxDbgTrace(-1, Dbg, ("-->exit\n"));
  1502. RxLog(("Exit-CBS\n"));
  1503. RxWmiLog(LOG,
  1504. RxChangeBufferingState_5,
  1505. LOGPTR(Fcb));
  1506. return STATUS_SUCCESS;
  1507. }
  1508. NTSTATUS
  1509. RxFlushFcbInSystemCache(
  1510. IN PFCB Fcb,
  1511. IN BOOLEAN SynchronizeWithLazyWriter
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This routine simply flushes the data section on a file.
  1516. Then, it does an acquire-release on the pagingIO resource in order to
  1517. synchronize behind any other outstanding writes if such synchronization is
  1518. desired by the caller
  1519. Arguments:
  1520. Fcb - Supplies the file being flushed
  1521. SynchronizeWithLazyWriter -- set to TRUE if the flush needs to be
  1522. synchronous
  1523. Return Value:
  1524. NTSTATUS - The Status from the flush.
  1525. --*/
  1526. {
  1527. IO_STATUS_BLOCK Iosb;
  1528. PAGED_CODE();
  1529. // Make sure that this thread owns the FCB.
  1530. // This assert is not valid because the flushing of the cache can be called from a routine
  1531. // that was posted to a worker thread. Thus the FCB is acquired exclusively, but not by the
  1532. // current thread and this will fail.
  1533. // ASSERT ( RxIsFcbAcquiredExclusive ( Fcb ) );
  1534. CcFlushCache(
  1535. &Fcb->NonPaged->SectionObjectPointers,
  1536. NULL,
  1537. 0,
  1538. &Iosb ); //ok4flush
  1539. if (SynchronizeWithLazyWriter &&
  1540. NT_SUCCESS(Iosb.Status)) {
  1541. RxAcquirePagingIoResource(Fcb,NULL);
  1542. RxReleasePagingIoResource(Fcb,NULL);
  1543. }
  1544. RxLog(("Flushing %lx Status %lx\n",Fcb,Iosb.Status));
  1545. RxWmiLogError(Iosb.Status,
  1546. LOG,
  1547. RxFlushFcbInSystemCache,
  1548. LOGPTR(Fcb)
  1549. LOGULONG(Iosb.Status));
  1550. return Iosb.Status;
  1551. }
  1552. NTSTATUS
  1553. RxPurgeFcbInSystemCache(
  1554. IN PFCB Fcb,
  1555. IN PLARGE_INTEGER FileOffset OPTIONAL,
  1556. IN ULONG Length,
  1557. IN BOOLEAN UninitializeCacheMaps,
  1558. IN BOOLEAN FlushFile )
  1559. /*++
  1560. Routine Description:
  1561. This routine purges the data section on a file. Before purging it flushes
  1562. the file and ensures that there are no outstanding writes by
  1563. Then, it does an acquire-release on the pagingIO resource in order to
  1564. synchronize behind any other outstanding writes if such synchronization is
  1565. desired by the caller
  1566. Arguments:
  1567. Fcb - Supplies the file being flushed
  1568. SynchronizeWithLazyWriter -- set to TRUE if the flush needs to be
  1569. synchronous
  1570. Return Value:
  1571. NTSTATUS - The Status from the flush.
  1572. --*/
  1573. {
  1574. BOOLEAN fResult;
  1575. NTSTATUS Status;
  1576. IO_STATUS_BLOCK Iosb;
  1577. PAGED_CODE();
  1578. // Make sure that this thread owns the FCB.
  1579. ASSERT( RxIsFcbAcquiredExclusive ( Fcb ) );
  1580. // Flush if we need to
  1581. if( FlushFile )
  1582. {
  1583. Status = RxFlushFcbInSystemCache(
  1584. Fcb,
  1585. TRUE);
  1586. if( !NT_SUCCESS(Status) )
  1587. {
  1588. PVOID p1, p2;
  1589. RtlGetCallersAddress( &p1, &p2 );
  1590. RxLogRetail(("Flush failed %x %x, Purging anyway\n", Fcb, Status ));
  1591. RxLogRetail(("Purge Caller = %x %x\n", p1, p2 ));
  1592. RxCcLogError( (PDEVICE_OBJECT)Fcb->RxDeviceObject,
  1593. &Fcb->PrivateAlreadyPrefixedName,
  1594. IO_LOST_DELAYED_WRITE,
  1595. Status,
  1596. IRP_MJ_WRITE,
  1597. Fcb );
  1598. }
  1599. }
  1600. // if (Status == STATUS_SUCCESS) {
  1601. fResult = CcPurgeCacheSection(
  1602. &Fcb->NonPaged->SectionObjectPointers,
  1603. FileOffset,
  1604. Length,
  1605. UninitializeCacheMaps);
  1606. if (!fResult) {
  1607. MmFlushImageSection(
  1608. &Fcb->NonPaged->SectionObjectPointers,
  1609. MmFlushForWrite);
  1610. RxReleaseFcb( NULL, Fcb );
  1611. fResult = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
  1612. RxAcquireExclusiveFcb(NULL,Fcb);
  1613. }
  1614. Status = (fResult ? STATUS_SUCCESS
  1615. : STATUS_UNSUCCESSFUL);
  1616. // }
  1617. RxLog(("Purging %lx Status %lx\n",Fcb,Status));
  1618. RxWmiLogError(Status,
  1619. LOG,
  1620. RxPurgeFcbInSystemCache,
  1621. LOGPTR(Fcb)
  1622. LOGULONG(Status));
  1623. return Status;
  1624. }