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.

2055 lines
54 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. oplock.c
  5. Abstract:
  6. This module contains the routines used to support oppurtunistic
  7. locking in the server.
  8. Details:
  9. Oplock activity is controlled by information contained in the
  10. connection block. In particular oplocks must be synchronized
  11. with the read block raw SMB, since the oplock request SMB is
  12. indistinguishable from raw data.
  13. RawReadsInProgress -
  14. Is incremented when a read raw request is accepted. It is
  15. decremented after the raw data has been sent. An oplock break
  16. request is never sent when RawReadsInProgress is nonzero.
  17. OplockBreaksInProgess -
  18. Is incremented when the server determines that it must send
  19. an oplock break SMB. It is decremented when the oplock break
  20. response arrives.
  21. OplockBreakRequestsPending -
  22. Is the number of oplock break requests that could not be sent
  23. due the lack of a WCBs. It is incremented when WCB allocation
  24. fails. It is decremented when the WCB is successfully allocated
  25. and the oplock break request is sent.
  26. OplockWorkItemList -
  27. Is a list of oplock context blocks for oplock break that could
  28. not be sent due to (1) a read raw in progress or (2) a resource
  29. shortage.
  30. It is possible for an oplock break request from the server and a
  31. read raw request from the client to "cross on the wire". In this
  32. case the client is expected to examine the raw data. If the data
  33. may be an oplock break request, the client must break the oplock
  34. then reissue the read request.
  35. If the server receives the read raw request after having sent an
  36. oplock break request (but before the reply arrives), it must return
  37. zero bytes read, since the oplock break request may have completed
  38. the raw request, and the client is unprepared to receives a larger
  39. than negotiated size response.
  40. Author:
  41. Manny Weiser (mannyw) 16-Apr-1991
  42. Revision History:
  43. --*/
  44. #include "precomp.h"
  45. #include "oplock.tmh"
  46. #pragma hdrstop
  47. #define BugCheckFileId SRV_FILE_OPLOCK
  48. //
  49. // Local definitions
  50. //
  51. PWORK_CONTEXT
  52. GenerateOplockBreakRequest(
  53. IN PRFCB Rfcb
  54. );
  55. #ifdef ALLOC_PRAGMA
  56. #pragma alloc_text( PAGE, SrvFillOplockBreakRequest )
  57. #pragma alloc_text( PAGE, SrvRestartOplockBreakSend )
  58. #pragma alloc_text( PAGE, SrvAllocateWaitForOplockBreak )
  59. #pragma alloc_text( PAGE, SrvDereferenceWaitForOplockBreak )
  60. #pragma alloc_text( PAGE, SrvFreeWaitForOplockBreak )
  61. #pragma alloc_text( PAGE, SrvGetOplockBreakTimeout )
  62. #pragma alloc_text( PAGE, SrvRequestOplock )
  63. #pragma alloc_text( PAGE, SrvStartWaitForOplockBreak )
  64. #pragma alloc_text( PAGE, SrvWaitForOplockBreak )
  65. #pragma alloc_text( PAGE, SrvCheckOplockWaitState )
  66. #pragma alloc_text( PAGE8FIL, SrvOplockBreakNotification )
  67. #pragma alloc_text( PAGE8FIL, GenerateOplockBreakRequest )
  68. #pragma alloc_text( PAGE8FIL, SrvSendOplockRequest )
  69. #pragma alloc_text( PAGE8FIL, SrvCheckDeferredOpenOplockBreak )
  70. #endif
  71. #if 0
  72. #pragma alloc_text( PAGECONN, SrvSendDelayedOplockBreak )
  73. #endif
  74. #if SRVDBG
  75. //
  76. // Unfortunately, when KdPrint is given a %wZ conversion, it calls a
  77. // pageable Rtl routine to convert. This is bad if we're calling
  78. // KdPrint from DPC level, as we are below. So we've introduced
  79. // SrvPrintwZ() here to get around the problem. This is only for
  80. // debugging anyway....
  81. //
  82. #ifdef ALLOC_PRAGMA
  83. #pragma alloc_text( PAGE8FIL, SrvCheckDeferredOpenOplockBreak )
  84. #endif
  85. #define SrvPrintwZ( x ) if( KeGetCurrentIrql() == 0 ){ DbgPrint( "%wZ", x ); } else { DbgPrint( "??" ); }
  86. #else
  87. #define SrvPrintwZ( x )
  88. #endif
  89. VOID
  90. DereferenceRfcbInternal (
  91. IN PRFCB Rfcb,
  92. IN KIRQL OldIrql
  93. );
  94. VOID SRVFASTCALL
  95. SrvOplockBreakNotification(
  96. IN PWORK_CONTEXT WorkContext
  97. )
  98. /*++
  99. Routine Description:
  100. This function receives the oplock break notification from a file
  101. system. It must send the oplock break SMB to the oplock owner.
  102. Arguments:
  103. OplockContext - A pointer to the oplock context for this oplock break.
  104. Return Value:
  105. --*/
  106. {
  107. ULONG information;
  108. NTSTATUS status;
  109. PCONNECTION connection;
  110. KIRQL oldIrql;
  111. PRFCB Rfcb = (PRFCB)WorkContext;
  112. PPAGED_RFCB pagedRfcb = Rfcb->PagedRfcb;
  113. UNLOCKABLE_CODE( 8FIL );
  114. //
  115. // Check the status of the oplock request.
  116. //
  117. UpdateRfcbHistory( Rfcb, 'tnpo' );
  118. status = Rfcb->Irp->IoStatus.Status;
  119. information = (ULONG)Rfcb->Irp->IoStatus.Information;
  120. connection = Rfcb->Connection;
  121. IF_DEBUG( OPLOCK ) {
  122. KdPrint(( "SrvOplockBreakNotification: Received notification for " ));
  123. SrvPrintwZ( &Rfcb->Mfcb->FileName );
  124. KdPrint(( "\n" ));
  125. KdPrint(( " status 0x%x, information %X, connection %p\n",
  126. status, information, connection ));
  127. KdPrint(( " Rfcb->OplockState = %X\n", Rfcb->OplockState ));
  128. }
  129. //
  130. // Check the oplock break request.
  131. //
  132. ACQUIRE_SPIN_LOCK( &connection->SpinLock, &oldIrql );
  133. //
  134. // Mark this rfcb as not cacheable since the oplock has been broken.
  135. // This is to close a timing window where the client closes the file
  136. // just as we are preparing to send an oplock break. We won't send the
  137. // break because the rfcb is closing and we will cache the file if
  138. // it was an opbatch. This results in the oplock never being broken.
  139. //
  140. Rfcb->IsCacheable = FALSE;
  141. if ( !NT_SUCCESS(status) ||
  142. Rfcb->OplockState == OplockStateNone ||
  143. ((GET_BLOCK_STATE( Rfcb ) == BlockStateClosing) &&
  144. (Rfcb->OplockState != OplockStateOwnServerBatch)) ) {
  145. IF_DEBUG( SMB_ERRORS ) {
  146. if( status == STATUS_INVALID_OPLOCK_PROTOCOL ) {
  147. if ( GET_BLOCK_STATE( Rfcb ) != BlockStateClosing ) {
  148. KdPrint(( "BUG: SrvOplockBreakNotification: " ));
  149. SrvPrintwZ( &Rfcb->Mfcb->FileName );
  150. KdPrint(( " is not closing.\n" ));
  151. }
  152. }
  153. }
  154. //
  155. // One of the following is true:
  156. // (1) The oplock request failed.
  157. // (2) Our oplock break to none has succeeded.
  158. // (3) We are in the process of closing the file.
  159. //
  160. // Note that if a level I oplock request fails when a retry at
  161. // level II is desired, SrvFsdOplockCompletionRoutine handles
  162. // setting the retry event and we do not get here at all.
  163. //
  164. IF_DEBUG( OPLOCK ) {
  165. KdPrint(( "SrvOplockBreakNotification: Breaking to none\n"));
  166. }
  167. UpdateRfcbHistory( Rfcb, 'nnso' );
  168. Rfcb->OplockState = OplockStateNone;
  169. if( Rfcb->CachedOpen ) {
  170. //
  171. // SrvCloseCachedRfcb releases the spinlock
  172. //
  173. SrvCloseCachedRfcb( Rfcb, oldIrql );
  174. } else {
  175. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  176. }
  177. //
  178. // Free the IRP we used to the oplock request.
  179. //
  180. UpdateRfcbHistory( Rfcb, 'prif' );
  181. IoFreeIrp( Rfcb->Irp );
  182. Rfcb->Irp = NULL;
  183. //
  184. // Dereference the rfcb.
  185. //
  186. SrvDereferenceRfcb( Rfcb );
  187. } else if ( Rfcb->OplockState == OplockStateOwnServerBatch ) {
  188. //
  189. // We are losing a server-initiated batch oplock. Don't send
  190. // anything to the client. If the client still has the file
  191. // open, just release the oplock. If the client has closed the
  192. // file, we have to close the file now.
  193. //
  194. IF_DEBUG(FILE_CACHE) {
  195. KdPrint(( "SrvOplockBreakNotification: server oplock broken for %p, file %wZ\n", Rfcb, &Rfcb->Mfcb->FileName ));
  196. }
  197. if ( !Rfcb->CachedOpen ) {
  198. IF_DEBUG(FILE_CACHE) {
  199. KdPrint(( "SrvOplockBreakNotification: ack close pending for " ));
  200. SrvPrintwZ( &Rfcb->Mfcb->FileName );
  201. KdPrint(( "\n" ));
  202. }
  203. UpdateRfcbHistory( Rfcb, 'pcao' );
  204. Rfcb->OplockState = OplockStateNone;
  205. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  206. Rfcb->RetryOplockRequest = NULL;
  207. SrvBuildIoControlRequest(
  208. Rfcb->Irp,
  209. Rfcb->Lfcb->FileObject,
  210. Rfcb,
  211. IRP_MJ_FILE_SYSTEM_CONTROL,
  212. FSCTL_OPLOCK_BREAK_ACK_NO_2,
  213. NULL, // Main buffer
  214. 0, // Input buffer length
  215. NULL, // Auxiliary buffer
  216. 0, // Output buffer length
  217. NULL, // MDL
  218. SrvFsdOplockCompletionRoutine
  219. );
  220. IoCallDriver( Rfcb->Lfcb->DeviceObject, Rfcb->Irp );
  221. } else {
  222. //
  223. // SrvCloseCachedRfcb releases the spin lock.
  224. //
  225. IF_DEBUG(FILE_CACHE) {
  226. KdPrint(( "SrvOplockBreakNotification: closing cached rfcb for "));
  227. SrvPrintwZ( &Rfcb->Mfcb->FileName );
  228. KdPrint(( "\n" ));
  229. }
  230. UpdateRfcbHistory( Rfcb, '$bpo' );
  231. SrvCloseCachedRfcb( Rfcb, oldIrql );
  232. SrvDereferenceRfcb( Rfcb );
  233. }
  234. } else {
  235. RELEASE_SPIN_LOCK( &connection->SpinLock, oldIrql );
  236. //
  237. // We have an oplock to break.
  238. //
  239. IF_DEBUG( OPLOCK ) {
  240. if (information == FILE_OPLOCK_BROKEN_TO_LEVEL_2) {
  241. KdPrint(( "SrvOplockBreakNotification: Breaking to level 2\n"));
  242. } else if (information == FILE_OPLOCK_BROKEN_TO_NONE) {
  243. KdPrint(( "SrvOplockBreakNotification: Breaking to level none\n"));
  244. } else {
  245. INTERNAL_ERROR(
  246. ERROR_LEVEL_UNEXPECTED,
  247. "SrvOplockBreakNotification: Unknown oplock type %d",
  248. information,
  249. NULL
  250. );
  251. }
  252. }
  253. //
  254. // Save the new oplock level, in case this oplock break is deferrred.
  255. //
  256. if ( information == FILE_OPLOCK_BROKEN_TO_LEVEL_2 &&
  257. CLIENT_CAPABLE_OF( LEVEL_II_OPLOCKS, Rfcb->Connection ) ) {
  258. Rfcb->NewOplockLevel = OPLOCK_BROKEN_TO_II;
  259. } else {
  260. Rfcb->NewOplockLevel = OPLOCK_BROKEN_TO_NONE;
  261. }
  262. //
  263. // Do not send the oplock break notification if a read raw is
  264. // in progress (and the client is expecting raw data on the VC).
  265. //
  266. // The oplock break notification will be sent after the raw
  267. // data.
  268. //
  269. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  270. //
  271. // Do not send the oplock break if we have not yet sent the
  272. // open response (i.e. the client does not yet know that it
  273. // owns the oplock).
  274. //
  275. if ( !Rfcb->OpenResponseSent ) {
  276. Rfcb->DeferredOplockBreak = TRUE;
  277. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  278. } else {
  279. //
  280. // EndpointSpinLock will be released in this routine.
  281. //
  282. SrvSendOplockRequest( connection, Rfcb, oldIrql );
  283. }
  284. }
  285. return;
  286. } // SrvOplockBreakNotification
  287. PWORK_CONTEXT
  288. GenerateOplockBreakRequest(
  289. IN PRFCB Rfcb
  290. )
  291. /*++
  292. Routine Description:
  293. This function creates an oplock break request SMB.
  294. Arguments:
  295. Rfcb - A pointer to the RFCB. Rfcb->NewOplockLevel contains
  296. the oplock level to break to.
  297. Return Value:
  298. None.
  299. --*/
  300. {
  301. PWORK_CONTEXT workContext;
  302. PCONNECTION connection = Rfcb->Connection;
  303. BOOLEAN success;
  304. KIRQL oldIrql;
  305. UNLOCKABLE_CODE( 8FIL );
  306. //
  307. // Attempt to allocate a work context block for the oplock break.
  308. //
  309. ALLOCATE_WORK_CONTEXT( connection->CurrentWorkQueue, &workContext );
  310. if ( workContext == NULL ) {
  311. INTERNAL_ERROR(
  312. ERROR_LEVEL_EXPECTED,
  313. "GenerateOplockBreakRequest: no receive work items available",
  314. NULL,
  315. NULL
  316. );
  317. //
  318. // If the rfcb is closing, forget about the oplock break.
  319. // Acquire the lock that guards the RFCB's state field.
  320. //
  321. if ( GET_BLOCK_STATE( Rfcb ) == BlockStateClosing ) {
  322. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  323. connection->OplockBreaksInProgress--;
  324. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  325. SrvDereferenceRfcb( Rfcb );
  326. return NULL;
  327. }
  328. //
  329. // Mark this connection as waiting to send an oplock break.
  330. //
  331. success = SrvAddToNeedResourceQueue(
  332. connection,
  333. OplockSendPending,
  334. Rfcb
  335. );
  336. if ( !success ) {
  337. //
  338. // Failed to queue the RFCB, so the connection must be going
  339. // away. Simply dereference the RFCB and forget about the
  340. // oplock break.
  341. //
  342. SrvDereferenceRfcb( Rfcb );
  343. }
  344. return NULL;
  345. }
  346. //
  347. // If the rfcb is closing, forget about the oplock break.
  348. // Acquire the lock that guards the RFCB's state field.
  349. //
  350. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  351. if ( GET_BLOCK_STATE( Rfcb ) == BlockStateClosing ) {
  352. connection->OplockBreaksInProgress--;
  353. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  354. SrvDereferenceRfcb( Rfcb );
  355. workContext->BlockHeader.ReferenceCount = 0;
  356. RETURN_FREE_WORKITEM( workContext );
  357. return NULL;
  358. }
  359. //
  360. // Put the work item on the in-progress list.
  361. //
  362. SrvInsertTailList(
  363. &connection->InProgressWorkItemList,
  364. &workContext->InProgressListEntry
  365. );
  366. connection->InProgressWorkContextCount++;
  367. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  368. //
  369. // Return a pointer to the work context block to the caller.
  370. //
  371. return workContext;
  372. } // GenerateOplockBreakRequest
  373. VOID
  374. SrvFillOplockBreakRequest (
  375. IN PWORK_CONTEXT WorkContext,
  376. IN PRFCB Rfcb
  377. )
  378. /*++
  379. Routine Description:
  380. This function fills the request buffer of a work context block with
  381. an oplock break request for the file specified by the RFCB.
  382. Arguments:
  383. WorkContext - The work context block to fill
  384. Rfcb - The file whose oplock is being broken. Rfcb->NewOplockLevel contains
  385. the level to break to.
  386. Return Value:
  387. None.
  388. --*/
  389. {
  390. PNT_SMB_HEADER requestHeader;
  391. PREQ_LOCKING_ANDX requestParameters;
  392. ULONG sendLength;
  393. PAGED_CODE( );
  394. requestHeader = (PNT_SMB_HEADER)WorkContext->RequestBuffer->Buffer;
  395. requestParameters = (PREQ_LOCKING_ANDX)(requestHeader + 1);
  396. //
  397. // Fill in the SMB header.
  398. // Zero the unused part of the header for safety.
  399. //
  400. RtlZeroMemory(
  401. (PVOID)&requestHeader->Status,
  402. FIELD_OFFSET(SMB_HEADER, Mid) - FIELD_OFFSET(NT_SMB_HEADER, Status)
  403. );
  404. *(PULONG)requestHeader->Protocol = SMB_HEADER_PROTOCOL;
  405. requestHeader->Command = SMB_COM_LOCKING_ANDX;
  406. SmbPutAlignedUshort( &requestHeader->Tid, Rfcb->Tid );
  407. SmbPutAlignedUshort( &requestHeader->Mid, 0xFFFF );
  408. SmbPutAlignedUshort( &requestHeader->Pid, 0xFFFF );
  409. //
  410. // Fill in the SMB parameters.
  411. //
  412. requestParameters->WordCount = 8;
  413. requestParameters->AndXCommand = 0xFF;
  414. requestParameters->AndXReserved = 0;
  415. SmbPutUshort( &requestParameters->AndXOffset, 0 );
  416. SmbPutUshort( &requestParameters->Fid, Rfcb->Fid );
  417. requestParameters->LockType = LOCKING_ANDX_OPLOCK_RELEASE;
  418. requestParameters->OplockLevel = Rfcb->NewOplockLevel;
  419. SmbPutUlong ( &requestParameters->Timeout, 0 );
  420. SmbPutUshort( &requestParameters->NumberOfUnlocks, 0 );
  421. SmbPutUshort( &requestParameters->NumberOfLocks, 0 );
  422. SmbPutUshort( &requestParameters->ByteCount, 0 );
  423. sendLength = LOCK_BROKEN_SIZE;
  424. WorkContext->RequestBuffer->DataLength = sendLength;
  425. return;
  426. } // SrvFillOplockBreakRequest
  427. VOID SRVFASTCALL
  428. SrvRestartOplockBreakSend(
  429. IN PWORK_CONTEXT WorkContext
  430. )
  431. /*++
  432. Routine Description:
  433. This routine is used to send the break request smb during servicing
  434. of the need resource queue if SrvFsdServiceNeedResourceQueue is called
  435. at Dpc.
  436. Arguments:
  437. WorkContext - A pointer to the work context block.
  438. Return Value:
  439. None.
  440. --*/
  441. {
  442. //
  443. // The rfcb is being referenced by the work item.
  444. //
  445. PRFCB rfcb = WorkContext->Rfcb;
  446. PPAGED_RFCB pagedRfcb = rfcb->PagedRfcb;
  447. PAGED_CODE( );
  448. IF_DEBUG(OPLOCK) {
  449. KdPrint(("SrvRestartOplockBreakSend entered.\n"));
  450. }
  451. pagedRfcb->OplockBreakTimeoutTime =
  452. SrvGetOplockBreakTimeout( WorkContext );
  453. WorkContext->ResponseHeader =
  454. WorkContext->ResponseBuffer->Buffer;
  455. //
  456. // Generate the oplock break request SMB.
  457. //
  458. SrvFillOplockBreakRequest( WorkContext, rfcb );
  459. //
  460. // If this is a break from level 2 to none, send the
  461. // oplock break but don't queue this. No response from the
  462. // client is expected.
  463. //
  464. if ( rfcb->NewOplockLevel == OPLOCK_BROKEN_TO_NONE &&
  465. rfcb->OplockState == OplockStateOwnLevelII ) {
  466. IF_DEBUG(OPLOCK) {
  467. KdPrint(("SrvRestartOplockBreakSend: Oplock break from "
  468. " II to none sent.\n"));
  469. }
  470. rfcb->OplockState = OplockStateNone;
  471. } else {
  472. //
  473. // Reference the RFCB so it cannot be freed while it is on
  474. // the list.
  475. //
  476. SrvReferenceRfcb( rfcb );
  477. //
  478. // Insert the RFCB on the list of oplock breaks in progress.
  479. //
  480. ACQUIRE_LOCK( &SrvOplockBreakListLock );
  481. //
  482. // Check if the rfcb is closing.
  483. //
  484. if ( GET_BLOCK_STATE( rfcb ) == BlockStateClosing ) {
  485. //
  486. // The file is closing, forget about this break.
  487. // Cleanup and exit.
  488. //
  489. RELEASE_LOCK( &SrvOplockBreakListLock );
  490. IF_DEBUG(OPLOCK) {
  491. KdPrint(("SrvRestartOplockBreakSend: Rfcb %p closing.\n",
  492. rfcb));
  493. }
  494. ExInterlockedAddUlong(
  495. &WorkContext->Connection->OplockBreaksInProgress,
  496. (ULONG)-1,
  497. WorkContext->Connection->EndpointSpinLock
  498. );
  499. //
  500. // Remove the queue reference.
  501. //
  502. SrvDereferenceRfcb( rfcb );
  503. //
  504. // Remove the pointer reference here since we know we are
  505. // not in the fsd. The rfcb may be cleaned up safely here.
  506. //
  507. SrvDereferenceRfcb( rfcb );
  508. WorkContext->Rfcb = NULL;
  509. SrvRestartFsdComplete( WorkContext );
  510. return;
  511. }
  512. SrvInsertTailList( &SrvOplockBreaksInProgressList, &rfcb->ListEntry );
  513. rfcb->OnOplockBreaksInProgressList = TRUE;
  514. RELEASE_LOCK( &SrvOplockBreakListLock );
  515. IF_DEBUG(OPLOCK) {
  516. KdPrint(("SrvRestartOplockBreakSend: Oplock sent.\n"));
  517. }
  518. }
  519. //
  520. // Since this is an out-of-order transmission to the client, we do not
  521. // stamp a security signatue on it.
  522. //
  523. WorkContext->NoResponseSmbSecuritySignature = TRUE;
  524. //
  525. // Update statistics for the broken oplock.
  526. //
  527. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOplocksBroken );
  528. SRV_START_SEND_2(
  529. WorkContext,
  530. (rfcb->OplockState == OplockStateNone) ?
  531. SrvFsdRestartSendOplockIItoNone :
  532. SrvFsdRestartSmbAtSendCompletion,
  533. NULL,
  534. NULL
  535. );
  536. } // SrvRestartOplockBreakSend
  537. VOID
  538. SrvAllocateWaitForOplockBreak (
  539. OUT PWAIT_FOR_OPLOCK_BREAK *WaitForOplockBreak
  540. )
  541. /*++
  542. Routine Description:
  543. This routine allocates an wait for oplock break item. It also
  544. allocates extra space for a kernel timer and a kernel DPC object.
  545. Arguments:
  546. WaitForOplockBreak - Returns a pointer to the wait for oplock break
  547. item, or NULL if no space was available. The oplock context
  548. block has a pointer to the IRP.
  549. Return Value:
  550. None.
  551. --*/
  552. {
  553. PAGED_CODE( );
  554. //
  555. // Attempt to allocate the memory.
  556. //
  557. *WaitForOplockBreak = (PWAIT_FOR_OPLOCK_BREAK)ALLOCATE_NONPAGED_POOL(
  558. sizeof(WAIT_FOR_OPLOCK_BREAK),
  559. BlockTypeWaitForOplockBreak
  560. );
  561. if ( *WaitForOplockBreak == NULL ) {
  562. INTERNAL_ERROR(
  563. ERROR_LEVEL_EXPECTED,
  564. "SrvAllocateWaitForOplockBreak: Unable to allocate %d bytes "
  565. "from paged pool.",
  566. sizeof(WAIT_FOR_OPLOCK_BREAK),
  567. NULL
  568. );
  569. *WaitForOplockBreak = NULL;
  570. return;
  571. }
  572. //
  573. // Zero the item.
  574. //
  575. RtlZeroMemory( (PVOID)*WaitForOplockBreak, sizeof(WAIT_FOR_OPLOCK_BREAK) );
  576. //
  577. // Initialize the header
  578. //
  579. SET_BLOCK_TYPE_STATE_SIZE( *WaitForOplockBreak,
  580. BlockTypeWaitForOplockBreak,
  581. BlockStateActive,
  582. sizeof( WAIT_FOR_OPLOCK_BREAK ));
  583. //
  584. // Set the reference count to 2 to account for the workcontext
  585. // and the oplock wait for oplock break list reference to the structure.
  586. //
  587. (*WaitForOplockBreak)->BlockHeader.ReferenceCount = 2;
  588. INITIALIZE_REFERENCE_HISTORY( *WaitForOplockBreak );
  589. //
  590. // Return a pointer to the wait for oplock break item
  591. //
  592. INCREMENT_DEBUG_STAT( SrvDbgStatistics.WaitForOplockBreakInfo.Allocations );
  593. return;
  594. } // SrvAllocateWaitForOplockBreak
  595. VOID
  596. SrvDereferenceWaitForOplockBreak (
  597. IN PWAIT_FOR_OPLOCK_BREAK WaitForOplockBreak
  598. )
  599. /*++
  600. Routine Description:
  601. This routine dereferences an wait for oplock break item.
  602. Arguments:
  603. WaitForOplockBreak - A pointer to the item to dereference.
  604. Return Value:
  605. None.
  606. --*/
  607. {
  608. ULONG oldCount;
  609. PAGED_CODE( );
  610. ASSERT( GET_BLOCK_TYPE( WaitForOplockBreak ) == BlockTypeWaitForOplockBreak );
  611. ASSERT( (LONG)WaitForOplockBreak->BlockHeader.ReferenceCount > 0 );
  612. UPDATE_REFERENCE_HISTORY( WaitForOplockBreak, TRUE );
  613. oldCount = ExInterlockedAddUlong(
  614. &WaitForOplockBreak->BlockHeader.ReferenceCount,
  615. (ULONG)-1,
  616. &GLOBAL_SPIN_LOCK(Fsd)
  617. );
  618. IF_DEBUG(REFCNT) {
  619. KdPrint(( "Dereferencing WaitForOplockBreak %p; old refcnt %lx\n",
  620. WaitForOplockBreak, oldCount ));
  621. }
  622. if ( oldCount == 1 ) {
  623. //
  624. // The new reference count is 0. Delete the block.
  625. //
  626. SrvFreeWaitForOplockBreak( WaitForOplockBreak );
  627. }
  628. return;
  629. } // SrvDereferenceWaitForOplockBreak
  630. VOID
  631. SrvFreeWaitForOplockBreak (
  632. IN PWAIT_FOR_OPLOCK_BREAK WaitForOplockBreak
  633. )
  634. /*++
  635. Routine Description:
  636. This routine deallocates an wait for oplock break item.
  637. Arguments:
  638. WaitForOplockBreak - A pointer to the item to free.
  639. Return Value:
  640. None.
  641. --*/
  642. {
  643. PAGED_CODE( );
  644. TERMINATE_REFERENCE_HISTORY( WaitForOplockBreak );
  645. DEALLOCATE_NONPAGED_POOL( WaitForOplockBreak );
  646. INCREMENT_DEBUG_STAT( SrvDbgStatistics.WaitForOplockBreakInfo.Frees );
  647. return;
  648. } // SrvFreeWaitForOplockBreak
  649. BOOLEAN
  650. SrvRequestOplock (
  651. IN PWORK_CONTEXT WorkContext,
  652. IN POPLOCK_TYPE OplockType,
  653. IN BOOLEAN RequestIIOnFailure
  654. )
  655. /*++
  656. Routine Description:
  657. This function will attempt to request an oplock if the oplock was
  658. requested.
  659. Arguments:
  660. WorkContext - Pointer to the workitem containing the rfcb.
  661. OplockType - Pointer to the oplock type being requested. If the
  662. request was successful, this will contain the type of oplock
  663. that was obtained.
  664. RequestIIOfFailure - If TRUE, a level II oplock will be requested in
  665. case the original request was denied.
  666. Return Value:
  667. TRUE - The oplock was obtained.
  668. FALSE - The oplock was not obtained.
  669. --*/
  670. {
  671. NTSTATUS status;
  672. ULONG ioControlCode;
  673. PRFCB rfcb;
  674. PLFCB lfcb;
  675. PPAGED_RFCB pagedRfcb;
  676. KEVENT oplockRetryEvent;
  677. UNICODE_STRING fileName;
  678. PAGED_CODE( );
  679. if ( !SrvEnableOplocks && (*OplockType != OplockTypeServerBatch) ) {
  680. return FALSE;
  681. }
  682. rfcb = WorkContext->Rfcb;
  683. pagedRfcb = rfcb->PagedRfcb;
  684. lfcb = rfcb->Lfcb;
  685. //
  686. // If this is an FCB open, return TRUE if the RFCB already owns an
  687. // oplock, FALSE otherwise. Since we're folding multiple FCB opens
  688. // into a single FID, they are logically one open. Hence, the oplock
  689. // state of all open instances is identical.
  690. //
  691. if ( pagedRfcb->FcbOpenCount > 1 ) {
  692. return (BOOLEAN)(rfcb->OplockState != OplockStateNone);
  693. }
  694. //
  695. // If we already have an oplock, because this is a reclaiming of a
  696. // cached open, then we don't need to request one now.
  697. //
  698. if ( rfcb->OplockState != OplockStateNone ) {
  699. UpdateRfcbHistory( rfcb, 'poer' );
  700. IF_DEBUG(FILE_CACHE) {
  701. KdPrint(( "SrvRequestOplock: already own server oplock for "));
  702. SrvPrintwZ( &rfcb->Mfcb->FileName );
  703. KdPrint(( "\n" ));
  704. }
  705. ASSERT( ((rfcb->OplockState == OplockStateOwnBatch) &&
  706. (*OplockType == OplockTypeBatch)) ||
  707. ((rfcb->OplockState == OplockStateOwnServerBatch) &&
  708. (*OplockType == OplockTypeServerBatch)) );
  709. return (BOOLEAN)(*OplockType != OplockTypeServerBatch);
  710. }
  711. //
  712. // Check to see if connection is reliable. If not, reject oplock request.
  713. //
  714. SrvUpdateVcQualityOfService( WorkContext->Connection, NULL );
  715. if ( !WorkContext->Connection->EnableOplocks &&
  716. (*OplockType != OplockTypeServerBatch) ) {
  717. return FALSE;
  718. }
  719. //
  720. // Do not give oplocks to system files, otherwise deadlock can occur. This
  721. // can happen, for instance, if the LSA is needing to open a system file to handle
  722. // an AcceptSecurityContext request. If a client has this system file open, we may
  723. // need to send a break to the client, which may require us to take a resource already
  724. // held during this open operation.
  725. //
  726. // Another way to look at it is to assert that we can't allow operation of the local
  727. // operating system to depend on timely interactions with clients on the network.
  728. //
  729. if( WorkContext->TreeConnect != NULL &&
  730. WorkContext->TreeConnect->Share->PotentialSystemFile == TRUE &&
  731. rfcb->Mfcb->FileName.Length > SrvSystemRoot.Length ) {
  732. UNICODE_STRING tmpString;
  733. tmpString = rfcb->Mfcb->FileName;
  734. tmpString.Length = SrvSystemRoot.Length;
  735. if( RtlCompareUnicodeString( &SrvSystemRoot, &tmpString, TRUE ) == 0 &&
  736. tmpString.Buffer[ tmpString.Length / sizeof( WCHAR ) ] == OBJ_NAME_PATH_SEPARATOR ) {
  737. IF_DEBUG( OPLOCK ) {
  738. KdPrint(("Oplock request REJECTED for system file: <%wZ>!\n",
  739. &rfcb->Mfcb->FileName ));
  740. }
  741. return FALSE;
  742. }
  743. }
  744. //
  745. // Do not give batch oplocks on substreams of files
  746. //
  747. if( *OplockType == OplockTypeBatch || *OplockType == OplockTypeServerBatch ) {
  748. PWCHAR s, es;
  749. SrvGetBaseFileName( &rfcb->Mfcb->FileName, &fileName );
  750. for( s = fileName.Buffer; fileName.Length; s++, fileName.Length -= sizeof(WCHAR) ) {
  751. if( *s == L':' ) {
  752. IF_DEBUG( OPLOCK ) {
  753. KdPrint(("Oplock request REJECTED for substream: <%wZ>!\n",
  754. &rfcb->Mfcb->FileName ));
  755. }
  756. return FALSE;
  757. }
  758. }
  759. }
  760. IF_DEBUG(OPLOCK) {
  761. KdPrint(("SrvRequestOplock: Attempting to obtain oplock for RFCB %p ", rfcb ));
  762. SrvPrintwZ( &rfcb->Mfcb->FileName );
  763. KdPrint(( "\n" ));
  764. }
  765. //
  766. // Set the RFCB oplock to the type of oplock we are requesting.
  767. //
  768. if ( *OplockType == OplockTypeExclusive ) {
  769. rfcb->OplockState = OplockStateOwnExclusive;
  770. ioControlCode = FSCTL_REQUEST_OPLOCK_LEVEL_1;
  771. } else if ( *OplockType == OplockTypeBatch ) {
  772. rfcb->OplockState = OplockStateOwnBatch;
  773. ioControlCode = FSCTL_REQUEST_BATCH_OPLOCK;
  774. } else if ( *OplockType == OplockTypeServerBatch ) {
  775. IF_DEBUG(FILE_CACHE) {
  776. KdPrint(( "SrvRequestOplock: requesting server oplock for " ));
  777. SrvPrintwZ( &rfcb->Mfcb->FileName );
  778. KdPrint(( "\n" ));
  779. }
  780. UpdateRfcbHistory( rfcb, 'osqr' );
  781. rfcb->OplockState = OplockStateOwnServerBatch;
  782. ioControlCode = FSCTL_REQUEST_BATCH_OPLOCK;
  783. } else {
  784. ASSERT(0);
  785. return(FALSE);
  786. }
  787. //
  788. // Generate and issue the oplock request IRP.
  789. //
  790. if (rfcb->Irp != NULL) {
  791. //DbgPrint( "ACK! Would have allocated second IRP for RFCB %x\n", rfcb );
  792. UpdateRfcbHistory( rfcb, '2pri' );
  793. //
  794. // This RFCB previously owned an oplock, and that oplock has been broken, but
  795. // the rundown of the oplock is not yet complete. We can't start a new one,
  796. // because then there would be two oplock IRPs associated with the RFCB, and
  797. // the RFCB could be queued twice to the work queue. (Even if it didn't get
  798. // queued twice, the completion of the first one would clear Rfcb->Irp.)
  799. //
  800. // We could come up with some delay scheme to wait for the previous oplock to
  801. // rundown, but since the oplock has been broken, it doesn't seem like we want
  802. // to try again anyway.
  803. //
  804. return FALSE;
  805. }
  806. UpdateRfcbHistory( rfcb, 'pria' );
  807. //
  808. // Reference the RFCB to account for the IRP we are about to submit.
  809. //
  810. SrvReferenceRfcb( rfcb );
  811. rfcb->Irp = SrvBuildIoControlRequest(
  812. NULL,
  813. lfcb->FileObject,
  814. rfcb,
  815. IRP_MJ_FILE_SYSTEM_CONTROL,
  816. ioControlCode,
  817. NULL, // Main buffer
  818. 0, // Input buffer length
  819. NULL, // Auxiliary buffer
  820. 0, // Output buffer length
  821. NULL, // MDL
  822. SrvFsdOplockCompletionRoutine
  823. );
  824. if ( rfcb->Irp == NULL ) {
  825. IF_DEBUG(OPLOCK) {
  826. KdPrint(("SrvRequestOplock: oplock attempt failed, could not allocate IRP" ));
  827. }
  828. rfcb->OplockState = OplockStateNone;
  829. SrvDereferenceRfcb( rfcb );
  830. return FALSE;
  831. }
  832. //
  833. // Clear this flag to indicate that this has not caused an oplock
  834. // break to occur.
  835. //
  836. rfcb->DeferredOplockBreak = FALSE;
  837. //
  838. // Initialize this event that we use to do an oplock request retry
  839. // in case the original request fails. This will prevent the completion
  840. // routine from cleaning up the irp.
  841. //
  842. if ( RequestIIOnFailure ) {
  843. KeInitializeEvent( &oplockRetryEvent, SynchronizationEvent, FALSE );
  844. rfcb->RetryOplockRequest = &oplockRetryEvent;
  845. } else {
  846. rfcb->RetryOplockRequest = NULL;
  847. }
  848. //
  849. // Make the actual request.
  850. //
  851. status = IoCallDriver(
  852. lfcb->DeviceObject,
  853. rfcb->Irp
  854. );
  855. //
  856. // If the driver returns STATUS_PENDING, the oplock was granted.
  857. // The IRP will complete when (1) The driver wants to break to
  858. // oplock or (2) The file is being closed.
  859. //
  860. if ( status == STATUS_PENDING ) {
  861. //
  862. // Remember that this work item caused us to generate an oplock
  863. // request.
  864. //
  865. WorkContext->OplockOpen = TRUE;
  866. IF_DEBUG(OPLOCK) {
  867. KdPrint(("RequestOplock: oplock attempt successful\n" ));
  868. }
  869. UpdateRfcbHistory( rfcb, 'rgpo' );
  870. return (BOOLEAN)(*OplockType != OplockTypeServerBatch);
  871. } else if ( RequestIIOnFailure ) {
  872. //
  873. // The caller wants us to attempt a level II oplock request.
  874. //
  875. ASSERT( *OplockType != OplockTypeServerBatch );
  876. IF_DEBUG(OPLOCK) {
  877. KdPrint(("SrvRequestOplock: Oplock request failed. "
  878. "OplockII being attempted.\n" ));
  879. }
  880. //
  881. // Wait for the completion routine to be run. It will set
  882. // an event that will signal us to go on.
  883. //
  884. KeWaitForSingleObject(
  885. &oplockRetryEvent,
  886. WaitAny,
  887. KernelMode, // don't let stack be paged -- event is on stack!
  888. FALSE,
  889. NULL
  890. );
  891. //
  892. // The Oplock Retry event was signaled. Proceed with the retry.
  893. //
  894. IF_DEBUG(OPLOCK) {
  895. KdPrint(("SrvRequestOplock: Oplock retry event signalled.\n"));
  896. }
  897. //
  898. // Generate and issue the wait for oplock IRP. Clear the
  899. // Retry event pointer so that the completion routine can clean up
  900. // the irp in case of failure.
  901. //
  902. rfcb->RetryOplockRequest = NULL;
  903. (VOID) SrvBuildIoControlRequest(
  904. rfcb->Irp,
  905. lfcb->FileObject,
  906. rfcb,
  907. IRP_MJ_FILE_SYSTEM_CONTROL,
  908. FSCTL_REQUEST_OPLOCK_LEVEL_2,
  909. NULL, // Main buffer
  910. 0, // Input buffer length
  911. NULL, // Auxiliary buffer
  912. 0, // Output buffer length
  913. NULL, // MDL
  914. SrvFsdOplockCompletionRoutine
  915. );
  916. //
  917. // Set the RFCB oplock to the type of oplock we are requesting.
  918. //
  919. rfcb->OplockState = OplockStateOwnLevelII;
  920. status = IoCallDriver(
  921. lfcb->DeviceObject,
  922. rfcb->Irp
  923. );
  924. //
  925. // If the driver returns STATUS_PENDING, the oplock was granted.
  926. // The IRP will complete when (1) The driver wants to break to
  927. // oplock or (2) The file is being closed.
  928. //
  929. if ( status == STATUS_PENDING ) {
  930. //
  931. // Remember that this work item caused us to generate an oplock
  932. // request.
  933. //
  934. WorkContext->OplockOpen = TRUE;
  935. IF_DEBUG(OPLOCK) {
  936. KdPrint(("SrvRequestOplock: OplockII attempt successful\n" ));
  937. }
  938. *OplockType = OplockTypeShareRead;
  939. return TRUE;
  940. }
  941. } else {
  942. UpdateRfcbHistory( rfcb, 'gnpo' );
  943. }
  944. IF_DEBUG(OPLOCK) {
  945. KdPrint(("SrvRequestOplock: oplock attempt unsuccessful\n" ));
  946. }
  947. //
  948. // Oplock was denied.
  949. //
  950. return FALSE;
  951. } // SrvRequestOplock
  952. NTSTATUS
  953. SrvStartWaitForOplockBreak (
  954. IN PWORK_CONTEXT WorkContext,
  955. IN PRESTART_ROUTINE RestartRoutine,
  956. IN HANDLE Handle OPTIONAL,
  957. IN PFILE_OBJECT FileObject OPTIONAL
  958. )
  959. /*++
  960. Routine Description:
  961. This function builds and issues an oplock break notify file system
  962. control IRP.
  963. Arguments:
  964. WorkContext - A pointer to the work context block for this request.
  965. RestartRoutine - The restart routine for this IRP.
  966. Additional one of the following must be supplied:
  967. Handle - A handle to the oplocked file.
  968. FileObject - A pointer to the file object of the oplocked file.
  969. Return Value:
  970. NTSTATUS.
  971. --*/
  972. {
  973. PFILE_OBJECT fileObject;
  974. NTSTATUS status;
  975. PWAIT_FOR_OPLOCK_BREAK waitForOplockBreak;
  976. PAGED_CODE( );
  977. //
  978. // Allocate memory, so that we can track this wait for oplock break.
  979. //
  980. SrvAllocateWaitForOplockBreak( &waitForOplockBreak );
  981. if (waitForOplockBreak == NULL) {
  982. return STATUS_INSUFF_SERVER_RESOURCES;
  983. }
  984. IF_DEBUG( OPLOCK ) {
  985. KdPrint(("Starting wait for oplock break. Context = %p\n", waitForOplockBreak));
  986. }
  987. //
  988. // Get a pointer to the file object, so that we can directly
  989. // build a wait for oplock IRP for asynchronous operations.
  990. //
  991. if (ARGUMENT_PRESENT( FileObject ) ) {
  992. fileObject = FileObject;
  993. } else {
  994. status = ObReferenceObjectByHandle(
  995. Handle,
  996. 0,
  997. NULL,
  998. KernelMode,
  999. (PVOID *)&fileObject,
  1000. NULL // handle information
  1001. );
  1002. if ( !NT_SUCCESS(status) ) {
  1003. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  1004. //
  1005. // This internal error bugchecks the system.
  1006. //
  1007. INTERNAL_ERROR(
  1008. ERROR_LEVEL_IMPOSSIBLE,
  1009. "SrvStartWaitForOplock: unable to reference file handle 0x%lx",
  1010. Handle,
  1011. NULL
  1012. );
  1013. return STATUS_UNSUCCESSFUL;
  1014. }
  1015. }
  1016. //
  1017. // Set the restart routine.
  1018. //
  1019. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1020. WorkContext->FspRestartRoutine = RestartRoutine;
  1021. //
  1022. // Generate and send the wait for oplock break IRP.
  1023. //
  1024. SrvBuildIoControlRequest(
  1025. WorkContext->Irp,
  1026. fileObject,
  1027. WorkContext,
  1028. IRP_MJ_FILE_SYSTEM_CONTROL,
  1029. FSCTL_OPLOCK_BREAK_NOTIFY,
  1030. NULL, // Main buffer
  1031. 0, // Input buffer length
  1032. NULL, // Auxiliary buffer
  1033. 0, // Output buffer length
  1034. NULL, // MDL
  1035. NULL
  1036. );
  1037. //
  1038. // Set the timeout time for the oplock wait to complete.
  1039. //
  1040. WorkContext->WaitForOplockBreak = waitForOplockBreak;
  1041. waitForOplockBreak->WaitState = WaitStateWaitForOplockBreak;
  1042. waitForOplockBreak->Irp = WorkContext->Irp;
  1043. KeQuerySystemTime( (PLARGE_INTEGER)&waitForOplockBreak->TimeoutTime );
  1044. waitForOplockBreak->TimeoutTime.QuadPart += SrvWaitForOplockBreakTime.QuadPart;
  1045. ACQUIRE_LOCK( &SrvOplockBreakListLock );
  1046. SrvInsertTailList(
  1047. &SrvWaitForOplockBreakList,
  1048. &waitForOplockBreak->ListEntry
  1049. );
  1050. RELEASE_LOCK( &SrvOplockBreakListLock );
  1051. //
  1052. // Submit the IRP.
  1053. //
  1054. (VOID)IoCallDriver(
  1055. IoGetRelatedDeviceObject( fileObject ),
  1056. WorkContext->Irp
  1057. );
  1058. //
  1059. // We no longer need a reference to the file object. Dereference
  1060. // it now.
  1061. //
  1062. if ( !ARGUMENT_PRESENT( FileObject ) ) {
  1063. ObDereferenceObject( fileObject );
  1064. }
  1065. return STATUS_SUCCESS;
  1066. } // SrvStartWaitForOplockBreak
  1067. NTSTATUS
  1068. SrvWaitForOplockBreak (
  1069. IN PWORK_CONTEXT WorkContext,
  1070. IN HANDLE FileHandle
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. This function waits synchrounsly for an oplock to be broken.
  1075. !!! When cancel is available. This function will also start timer.
  1076. If the timer expires before the oplock is broken, the wait is
  1077. cancelled.
  1078. Arguments:
  1079. FileHandle - A handle to an oplocked file.
  1080. Return Value:
  1081. NTSTATUS - The status of the wait for oplock break.
  1082. --*/
  1083. {
  1084. PWAIT_FOR_OPLOCK_BREAK waitForOplockBreak;
  1085. PAGED_CODE( );
  1086. //
  1087. // Allocate memory, so that we can track this wait for oplock break.
  1088. //
  1089. SrvAllocateWaitForOplockBreak( &waitForOplockBreak );
  1090. if (waitForOplockBreak == NULL) {
  1091. return STATUS_INSUFF_SERVER_RESOURCES;
  1092. }
  1093. IF_DEBUG( OPLOCK ) {
  1094. KdPrint(("Starting wait for oplock break. Context = %p\n", waitForOplockBreak));
  1095. }
  1096. //
  1097. // Set the timeout time for the oplock wait to complete.
  1098. //
  1099. waitForOplockBreak->WaitState = WaitStateWaitForOplockBreak;
  1100. waitForOplockBreak->Irp = NULL;
  1101. KeQuerySystemTime( (PLARGE_INTEGER)&waitForOplockBreak->TimeoutTime );
  1102. waitForOplockBreak->TimeoutTime.QuadPart += SrvWaitForOplockBreakTime.QuadPart;
  1103. //
  1104. // SrvIssueWaitForOplockBreakRequest will queue the waitForOplockBreak
  1105. // structure on the global list of oplock breaks.
  1106. //
  1107. return SrvIssueWaitForOplockBreak(
  1108. FileHandle,
  1109. waitForOplockBreak
  1110. );
  1111. } // SrvWaitForOplockBreak
  1112. VOID
  1113. SrvSendDelayedOplockBreak (
  1114. IN PCONNECTION Connection
  1115. )
  1116. /*++
  1117. Routine Description:
  1118. This function sends outstanding oplock breaks on a connection that
  1119. were held back because a read raw operation was in progress.
  1120. Arguments:
  1121. Connection - A pointer to the connection block that has completed
  1122. a read raw operation.
  1123. Return Value:
  1124. None
  1125. --*/
  1126. {
  1127. KIRQL oldIrql;
  1128. PLIST_ENTRY listEntry;
  1129. PWORK_CONTEXT workContext;
  1130. PRFCB rfcb;
  1131. #if SRVDBG
  1132. ULONG oplockBreaksSent = 0;
  1133. #endif
  1134. //UNLOCKABLE_CODE( CONN );
  1135. //
  1136. // Acquire the lock that protects the connection's oplock list and
  1137. // raw read status.
  1138. //
  1139. ACQUIRE_SPIN_LOCK( Connection->EndpointSpinLock, &oldIrql );
  1140. //
  1141. // Indicate that the read raw operation is complete. If the count
  1142. // goes to zero, oplock breaks can proceed.
  1143. //
  1144. Connection->RawReadsInProgress--;
  1145. while ( (Connection->RawReadsInProgress == 0) &&
  1146. !IsListEmpty( &Connection->OplockWorkList ) ) {
  1147. //
  1148. // There is an outstanding oplock break request. Send
  1149. // the request now.
  1150. //
  1151. listEntry = Connection->OplockWorkList.Flink;
  1152. RemoveHeadList( &Connection->OplockWorkList );
  1153. //
  1154. // Note that releasing the spin lock here is safe. If a new
  1155. // raw read request comes in, it will be rejected, because the
  1156. // OplockBreaksInProgress count is not zero. Also, if the
  1157. // oplock break count manages to go to zero, and a raw read
  1158. // comes in, we'll catch this back at the top of the loop.
  1159. //
  1160. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, oldIrql );
  1161. rfcb = (PRFCB)CONTAINING_RECORD( listEntry, RFCB, ListEntry );
  1162. #if DBG
  1163. rfcb->ListEntry.Flink = rfcb->ListEntry.Blink = NULL;
  1164. #endif
  1165. workContext = GenerateOplockBreakRequest( rfcb );
  1166. if ( workContext != NULL ) {
  1167. //
  1168. // Copy the RFCB reference to the work context block.
  1169. //
  1170. workContext->Rfcb = rfcb;
  1171. //
  1172. // !!! Is the init of share, session, tree connect
  1173. // necessary?
  1174. //
  1175. workContext->Share = NULL;
  1176. workContext->Session = NULL;
  1177. workContext->TreeConnect = NULL;
  1178. workContext->SecurityContext = NULL;
  1179. workContext->Connection = rfcb->Connection;
  1180. SrvReferenceConnection( workContext->Connection );
  1181. workContext->Endpoint = workContext->Connection->Endpoint;
  1182. SrvRestartOplockBreakSend( workContext );
  1183. #if SRVDBG
  1184. oplockBreaksSent++;
  1185. #endif
  1186. } else {
  1187. //
  1188. // We are out of resources. GenerateOplockRequest, has
  1189. // added this connection to the needs resource queue. The
  1190. // scavenger will finish processing the remainder of the
  1191. // oplock break requests when resources become available.
  1192. //
  1193. #if SRVDBG
  1194. IF_DEBUG(OPLOCK) {
  1195. KdPrint(("SrvSendDelayedOplockBreak: sent %d\n", oplockBreaksSent ));
  1196. }
  1197. #endif
  1198. return;
  1199. }
  1200. ACQUIRE_SPIN_LOCK( Connection->EndpointSpinLock, &oldIrql );
  1201. }
  1202. //
  1203. // We have stopped trying to send oplock break requests. The
  1204. // scavenger will attempt to send the rest.
  1205. //
  1206. #if SRVDBG
  1207. IF_DEBUG(OPLOCK) {
  1208. KdPrint(("SrvSendDelayedOplockBreak: sent %d\n", oplockBreaksSent ));
  1209. }
  1210. #endif
  1211. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, oldIrql );
  1212. return;
  1213. } // SrvSendDelayedOplockBreak
  1214. NTSTATUS
  1215. SrvCheckOplockWaitState (
  1216. IN PWAIT_FOR_OPLOCK_BREAK WaitForOplockBreak
  1217. )
  1218. /*++
  1219. Routine Description:
  1220. This function checks the state of a wait for oplock break, and
  1221. takes action.
  1222. Arguments:
  1223. WaitForOplockBreak
  1224. Return Value:
  1225. NTSTATUS -
  1226. STATUS_SUCCESS - The oplock was successfully broken.
  1227. STATUS_SHARING_VIOLATION - The oplock could not be broken.
  1228. --*/
  1229. {
  1230. PAGED_CODE( );
  1231. if ( WaitForOplockBreak == NULL ) {
  1232. return STATUS_SUCCESS;
  1233. }
  1234. ACQUIRE_LOCK( &SrvOplockBreakListLock );
  1235. if ( WaitForOplockBreak->WaitState == WaitStateOplockWaitTimedOut ) {
  1236. IF_DEBUG( OPLOCK ) {
  1237. KdPrint(("SrvCheckOplockWaitState: Oplock wait timed out\n"));
  1238. }
  1239. RELEASE_LOCK( &SrvOplockBreakListLock );
  1240. return STATUS_SHARING_VIOLATION;
  1241. } else {
  1242. IF_DEBUG( OPLOCK ) {
  1243. KdPrint(("SrvCheckOplockWaitState: Oplock wait succeeded\n"));
  1244. }
  1245. WaitForOplockBreak->WaitState = WaitStateOplockWaitSucceeded;
  1246. SrvRemoveEntryList(
  1247. &SrvWaitForOplockBreakList,
  1248. &WaitForOplockBreak->ListEntry
  1249. );
  1250. RELEASE_LOCK( &SrvOplockBreakListLock );
  1251. //
  1252. // The WaitForOplockBreak has been taken off of the wait for oplock
  1253. // break list. Decrement the reference count.
  1254. //
  1255. SrvDereferenceWaitForOplockBreak( WaitForOplockBreak );
  1256. return STATUS_SUCCESS;
  1257. }
  1258. } // SrvCheckOplockWaitState
  1259. LARGE_INTEGER
  1260. SrvGetOplockBreakTimeout (
  1261. IN PWORK_CONTEXT WorkContext
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. This function computes the timeout to wait for an oplock break response
  1266. from the client. This is based on the formula:
  1267. new timeout = current time + default timeout +
  1268. link delay + requestSize / throughput +
  1269. link delay + responseSize / thoughput
  1270. Arguments:
  1271. WorkContext - Pointer to the work context block that points to the
  1272. connection that owns this oplock.
  1273. Return Value:
  1274. The timeout value.
  1275. --*/
  1276. {
  1277. LARGE_INTEGER timeoutTime;
  1278. LARGE_INTEGER currentTime;
  1279. LARGE_INTEGER throughput;
  1280. LARGE_INTEGER additionalTimeoutTime;
  1281. LARGE_INTEGER propagationDelay;
  1282. PCONNECTION connection = WorkContext->Connection;
  1283. PAGED_CODE( );
  1284. //
  1285. // Get current time.
  1286. //
  1287. KeQuerySystemTime( &currentTime );
  1288. //
  1289. // Add default timeout
  1290. //
  1291. timeoutTime.QuadPart = currentTime.QuadPart +
  1292. SrvWaitForOplockBreakRequestTime.QuadPart;
  1293. //
  1294. // Update link QOS.
  1295. //
  1296. SrvUpdateVcQualityOfService(
  1297. connection,
  1298. &currentTime
  1299. );
  1300. //
  1301. // Access connection QOS fields using a spin lock.
  1302. //
  1303. ACQUIRE_LOCK( &connection->Lock );
  1304. throughput = connection->PagedConnection->Throughput;
  1305. additionalTimeoutTime = connection->PagedConnection->Delay;
  1306. RELEASE_LOCK( &connection->Lock );
  1307. //
  1308. // Calculate the actual timeout.
  1309. //
  1310. if ( throughput.QuadPart == 0 ) {
  1311. throughput = SrvMinLinkThroughput;
  1312. }
  1313. //
  1314. // Add link delay + link delay to account for round trip.
  1315. //
  1316. additionalTimeoutTime.QuadPart *= 2;
  1317. if ( throughput.QuadPart != 0 ) {
  1318. //
  1319. // Compute the propagation delay. Convert throughput from bytes/s
  1320. // to bytes/100ns.
  1321. //
  1322. propagationDelay.QuadPart =
  1323. Int32x32To64( SRV_PROPAGATION_DELAY_SIZE, 10*1000*1000 );
  1324. propagationDelay.QuadPart /= throughput.QuadPart;
  1325. additionalTimeoutTime.QuadPart += propagationDelay.QuadPart;
  1326. }
  1327. timeoutTime.QuadPart += additionalTimeoutTime.QuadPart;
  1328. return timeoutTime;
  1329. } // SrvGetOplockBreakTimeout
  1330. VOID
  1331. SrvSendOplockRequest(
  1332. IN PCONNECTION Connection,
  1333. IN PRFCB Rfcb,
  1334. IN KIRQL OldIrql
  1335. )
  1336. /*++
  1337. Routine Description:
  1338. This function tries to send an oplock break request to the owner of
  1339. an oplock.
  1340. *** Must be called with the EndpointSpinLock held. Released on exit ***
  1341. Arguments:
  1342. Connection - The connection on which to send the oplock break.
  1343. Rfcb - The RFCB of the oplocked file. Rfcb->NewOplockLevel contains the
  1344. oplock level to break to. The rfcb has an extra reference
  1345. from the irp used to make the oplock request.
  1346. OldIrql - The previous IRQL value obtained when the spin lock was
  1347. acquired.
  1348. Return Value:
  1349. None.
  1350. --*/
  1351. {
  1352. PWORK_CONTEXT workContext;
  1353. UNLOCKABLE_CODE( 8FIL );
  1354. //
  1355. // Indicate that we are about to send an oplock break request
  1356. // and queue this request to the oplocks in progress list.
  1357. //
  1358. Connection->OplockBreaksInProgress++;
  1359. //
  1360. // If there is a read raw in progress we will defer the oplock
  1361. // break request and send it only after the read raw has
  1362. // completed.
  1363. //
  1364. if ( Connection->RawReadsInProgress != 0 ) {
  1365. IF_DEBUG( OPLOCK ) {
  1366. KdPrint(( "SrvOplockBreakNotification: Read raw in progress; "
  1367. "oplock break deferred\n"));
  1368. }
  1369. //
  1370. // if the connection is closing, forget about this.
  1371. //
  1372. if ( GET_BLOCK_STATE(Connection) != BlockStateActive ) {
  1373. Connection->OplockBreaksInProgress--;
  1374. //
  1375. // Dereference the rfcb.
  1376. //
  1377. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, OldIrql );
  1378. SrvDereferenceRfcb( Rfcb );
  1379. } else {
  1380. //
  1381. // Save the RFCB on the list for this connection. It will be
  1382. // used when the read raw has completed.
  1383. //
  1384. InsertTailList( &Connection->OplockWorkList, &Rfcb->ListEntry );
  1385. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, OldIrql );
  1386. }
  1387. return;
  1388. }
  1389. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, OldIrql );
  1390. workContext = GenerateOplockBreakRequest( Rfcb );
  1391. //
  1392. // If we were able to generate the oplock break request SMB
  1393. // prepare and send it. Otherwise this connection has
  1394. // been inserted in the need resource queue and the
  1395. // scavenger will have to send the SMB.
  1396. //
  1397. if ( workContext != NULL ) {
  1398. //
  1399. // Copy the RFCB reference to the work context block.
  1400. // Do not re-reference the RFCB.
  1401. //
  1402. workContext->Rfcb = Rfcb;
  1403. //
  1404. // !!! Is the init of share, session, tree connect
  1405. // necessary?
  1406. //
  1407. workContext->Share = NULL;
  1408. workContext->Session = NULL;
  1409. workContext->TreeConnect = NULL;
  1410. workContext->SecurityContext = NULL;
  1411. workContext->Connection = Connection;
  1412. SrvReferenceConnection( Connection );
  1413. workContext->Endpoint = Connection->Endpoint;
  1414. SrvRestartOplockBreakSend( workContext );
  1415. }
  1416. } // SrvSendOplockRequest
  1417. VOID SRVFASTCALL
  1418. SrvCheckDeferredOpenOplockBreak(
  1419. IN PWORK_CONTEXT WorkContext
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This routine checks to see if there an oplock break was deferred
  1424. pending the completion of the open request. If there is, try to
  1425. send it.
  1426. Arguments:
  1427. WorkContext - Pointer to the work item that contains the rfcb
  1428. and the connection block of the open request that just finished.
  1429. Return Value:
  1430. None.
  1431. --*/
  1432. {
  1433. KIRQL oldIrql;
  1434. PRFCB rfcb;
  1435. PCONNECTION connection;
  1436. UNLOCKABLE_CODE( 8FIL );
  1437. //
  1438. // This work item contained an open and oplock request. Now that
  1439. // the response has been sent, see if there is a deferred oplock
  1440. // break request to send.
  1441. //
  1442. rfcb = WorkContext->Rfcb;
  1443. connection = WorkContext->Connection;
  1444. ASSERT( rfcb != NULL );
  1445. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  1446. rfcb->OpenResponseSent = TRUE;
  1447. if ( rfcb->DeferredOplockBreak ) {
  1448. //
  1449. // EndpointSpinLock will be released in this routine.
  1450. //
  1451. SrvSendOplockRequest( connection, rfcb, oldIrql );
  1452. } else {
  1453. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1454. }
  1455. return;
  1456. } // SrvCheckDeferredOpenOplockBreak