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.

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