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.

2532 lines
74 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smblock.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Lock Byte Range
  8. Unlock Byte Range
  9. Locking and X
  10. The SMB commands "Lock and Read" and "Write and Unlock" are
  11. processed in smbrdwrt.c.
  12. Author:
  13. Chuck Lenzmeier (chuckl) 26-Apr-1990
  14. Revision History:
  15. 29-Aug-1991 mannyw
  16. --*/
  17. #include "precomp.h"
  18. #include "smblock.tmh"
  19. #pragma hdrstop
  20. #if SRVDBG_PERF
  21. UCHAR LockBypass = 0;
  22. BOOLEAN LockWaitForever = 0;
  23. ULONG LockBypassConst = 0x10000000;
  24. ULONG LockBypassMirror = 0x01000000;
  25. #endif
  26. //
  27. // Forward declarations
  28. //
  29. BOOLEAN
  30. CancelLockRequest (
  31. IN PWORK_CONTEXT WorkContext,
  32. IN USHORT TargetFid,
  33. IN USHORT TargetPid,
  34. IN LARGE_INTEGER TargetOffset,
  35. IN LARGE_INTEGER TargetLength
  36. );
  37. VOID
  38. DoLockingAndX (
  39. IN OUT PWORK_CONTEXT WorkContext,
  40. IN BOOLEAN SkipFastPath
  41. );
  42. STATIC
  43. BOOLEAN
  44. ProcessOplockBreakResponse(
  45. IN PWORK_CONTEXT WorkContext,
  46. IN PRFCB Rfcb,
  47. IN PREQ_LOCKING_ANDX Request
  48. );
  49. STATIC
  50. VOID SRVFASTCALL
  51. RestartLockByteRange (
  52. IN OUT PWORK_CONTEXT WorkContext
  53. );
  54. STATIC
  55. VOID SRVFASTCALL
  56. RestartLockingAndX (
  57. IN OUT PWORK_CONTEXT WorkContext
  58. );
  59. VOID
  60. TimeoutLockRequest (
  61. IN PKDPC Dpc,
  62. IN PVOID DeferredContext,
  63. IN PVOID SystemArgument1,
  64. IN PVOID SystemArgument2
  65. );
  66. #ifdef ALLOC_PRAGMA
  67. #pragma alloc_text( PAGE, SrvSmbLockByteRange )
  68. #pragma alloc_text( PAGE, RestartLockByteRange )
  69. #pragma alloc_text( PAGE, ProcessOplockBreakResponse )
  70. #pragma alloc_text( PAGE, SrvSmbUnlockByteRange )
  71. #pragma alloc_text( PAGE, SrvSmbLockingAndX )
  72. #pragma alloc_text( PAGE, DoLockingAndX )
  73. #pragma alloc_text( PAGE, RestartLockingAndX )
  74. #pragma alloc_text( PAGE, SrvAcknowledgeOplockBreak )
  75. #pragma alloc_text( PAGE8FIL, CancelLockRequest )
  76. #pragma alloc_text( PAGE8FIL, TimeoutLockRequest )
  77. #endif
  78. SMB_PROCESSOR_RETURN_TYPE
  79. SrvSmbLockByteRange (
  80. SMB_PROCESSOR_PARAMETERS
  81. )
  82. /*++
  83. Routine Description:
  84. Processes the Lock Byte Range SMB.
  85. Arguments:
  86. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  87. of the parameters to SMB processor routines.
  88. Return Value:
  89. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  90. --*/
  91. {
  92. PREQ_LOCK_BYTE_RANGE request;
  93. NTSTATUS status = STATUS_SUCCESS;
  94. SMB_STATUS SmbStatus = SmbStatusInProgress;
  95. USHORT fid;
  96. LARGE_INTEGER length;
  97. LARGE_INTEGER offset;
  98. ULONG key;
  99. BOOLEAN failImmediately;
  100. PRFCB rfcb;
  101. PLFCB lfcb;
  102. PSRV_TIMER timer;
  103. PAGED_CODE( );
  104. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  105. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_BYTE_RANGE;
  106. SrvWmiStartContext(WorkContext);
  107. request = (PREQ_LOCK_BYTE_RANGE)WorkContext->RequestParameters;
  108. //
  109. // Verify the FID. If verified, the RFCB block is referenced
  110. // and its addresses is stored in the WorkContext block, and the
  111. // RFCB address is returned.
  112. //
  113. fid = SmbGetUshort( &request->Fid );
  114. rfcb = SrvVerifyFid(
  115. WorkContext,
  116. fid,
  117. TRUE,
  118. SrvRestartSmbReceived, // serialize with raw write
  119. &status
  120. );
  121. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  122. if ( !NT_SUCCESS( status ) ) {
  123. //
  124. // Invalid file ID or write behind error. Reject the request.
  125. //
  126. IF_DEBUG(ERRORS) {
  127. KdPrint((
  128. "SrvSmbLockByteRange: Status %X on FID: 0x%lx\n",
  129. status,
  130. fid
  131. ));
  132. }
  133. SrvSetSmbError( WorkContext, status );
  134. SmbStatus = SmbStatusSendResponse;
  135. goto Cleanup;
  136. }
  137. //
  138. // The work item has been queued because a raw write is in
  139. // progress.
  140. //
  141. SmbStatus = SmbStatusInProgress;
  142. goto Cleanup;
  143. }
  144. //
  145. // If the session has expired, return that info
  146. //
  147. if( rfcb->Lfcb->Session->IsSessionExpired )
  148. {
  149. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  150. status = SESSION_EXPIRED_STATUS_CODE;
  151. SmbStatus = SmbStatusSendResponse;
  152. goto Cleanup;
  153. }
  154. //
  155. // Verify that the client has lock access to the file via the
  156. // specified handle.
  157. //
  158. if ( rfcb->LockAccessGranted && rfcb->ExclusiveLockGranted ) {
  159. //
  160. // Get the offset and length of the range being locked. Combine
  161. // the FID with the caller's PID to form the local lock key.
  162. //
  163. // *** The FID must be included in the key in order to account
  164. // for the folding of multiple remote compatibility mode
  165. // opens into a single local open.
  166. //
  167. offset.QuadPart = SmbGetUlong( &request->Offset );
  168. length.QuadPart = SmbGetUlong( &request->Count );
  169. key = rfcb->ShiftedFid |
  170. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  171. IF_SMB_DEBUG(LOCK1) {
  172. KdPrint(( "Lock request; FID 0x%lx, count %ld, offset %ld\n",
  173. fid, length.LowPart, offset.LowPart ));
  174. }
  175. rfcb = WorkContext->Rfcb;
  176. lfcb = rfcb->Lfcb;
  177. IF_SMB_DEBUG(LOCK2) {
  178. KdPrint(( "SrvSmbLockByteRange: Locking in file 0x%p: (%ld,%ld), key 0x%lx\n",
  179. lfcb->FileObject, offset.LowPart, length.LowPart, key ));
  180. }
  181. //
  182. // Try the turbo lock path first. If the client is retrying the
  183. // lock that just failed, or if the lock is above the
  184. // always-wait limit we want FailImmediately to be FALSE, so
  185. // that the fast path fails if there's a conflict.
  186. //
  187. failImmediately = (BOOLEAN)(
  188. (offset.QuadPart != rfcb->PagedRfcb->LastFailingLockOffset.QuadPart)
  189. &&
  190. (offset.QuadPart < SrvLockViolationOffset) );
  191. if ( lfcb->FastIoLock != NULL ) {
  192. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  193. if ( lfcb->FastIoLock(
  194. lfcb->FileObject,
  195. &offset,
  196. &length,
  197. IoGetCurrentProcess(),
  198. key,
  199. failImmediately,
  200. TRUE,
  201. &WorkContext->Irp->IoStatus,
  202. lfcb->DeviceObject
  203. ) ) {
  204. //
  205. // The turbo path worked. Call the restart routine
  206. // directly.
  207. //
  208. WorkContext->Parameters.Lock.Timer = NULL;
  209. RestartLockByteRange( WorkContext );
  210. SmbStatus = SmbStatusInProgress;
  211. goto Cleanup;
  212. }
  213. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksFailed );
  214. }
  215. //
  216. // The turbo path failed (or didn't exist). Start the lock request,
  217. // reusing the receive IRP. If the client is retrying the lock that
  218. // just failed, start a timer for the request.
  219. //
  220. timer = NULL;
  221. if ( !failImmediately ) {
  222. timer = SrvAllocateTimer( );
  223. if ( timer == NULL ) {
  224. failImmediately = TRUE;
  225. }
  226. }
  227. SrvBuildLockRequest(
  228. WorkContext->Irp, // input IRP address
  229. lfcb->FileObject, // target file object address
  230. WorkContext, // context
  231. offset, // byte offset
  232. length, // range length
  233. key, // lock key
  234. failImmediately,
  235. TRUE // exclusive lock?
  236. );
  237. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  238. WorkContext->FspRestartRoutine = RestartLockByteRange;
  239. //
  240. // Start the timer, if necessary.
  241. //
  242. WorkContext->Parameters.Lock.Timer = timer;
  243. if ( timer != NULL ) {
  244. SrvSetTimer(
  245. timer,
  246. &SrvLockViolationDelayRelative,
  247. TimeoutLockRequest,
  248. WorkContext
  249. );
  250. }
  251. //
  252. // Pass the request to the file system.
  253. //
  254. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  255. //
  256. // The lock request has been started.
  257. //
  258. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbLockByteRange complete\n" ));
  259. SmbStatus = SmbStatusInProgress;
  260. } else {
  261. SrvStatistics.GrantedAccessErrors++;
  262. IF_DEBUG(ERRORS) {
  263. KdPrint(( "SrvSmbLockByteRange: Lock access not granted.\n"));
  264. }
  265. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  266. status = STATUS_ACCESS_DENIED;
  267. SmbStatus = SmbStatusSendResponse;
  268. }
  269. Cleanup:
  270. SrvWmiEndContext(WorkContext);
  271. return SmbStatus;
  272. } // SrvSmbLockByteRange
  273. SMB_PROCESSOR_RETURN_TYPE
  274. SrvSmbLockingAndX (
  275. SMB_PROCESSOR_PARAMETERS
  276. )
  277. /*++
  278. Routine Description:
  279. Processes the Locking and X SMB. This SMB is used to unlock zero
  280. or more ranges, then lock zero or more ranges.
  281. Arguments:
  282. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  283. of the parameters to SMB processor routines.
  284. Return Value:
  285. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  286. --*/
  287. {
  288. PREQ_LOCKING_ANDX request;
  289. PRESP_LOCKING_ANDX response;
  290. PNTLOCKING_ANDX_RANGE largeRange;
  291. PLOCKING_ANDX_RANGE smallRange;
  292. NTSTATUS status = STATUS_SUCCESS;
  293. SMB_STATUS SmbStatus = SmbStatusInProgress;
  294. USHORT fid;
  295. USHORT pid;
  296. ULONG unlockCount;
  297. ULONG lockCount;
  298. ULONG maxPossible;
  299. LARGE_INTEGER length;
  300. LARGE_INTEGER offset;
  301. ULONG key;
  302. ULONG lockTimeout;
  303. BOOLEAN oplockBreakResponse = FALSE;
  304. BOOLEAN largeFileLock;
  305. BOOLEAN exclusiveLock;
  306. UCHAR nextCommand;
  307. USHORT reqAndXOffset;
  308. PRFCB rfcb;
  309. PLFCB lfcb;
  310. PPAGED_RFCB pagedRfcb;
  311. PREQ_CLOSE closeRequest;
  312. PAGED_CODE( );
  313. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  314. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCKING_AND_X;
  315. SrvWmiStartContext(WorkContext);
  316. request = (PREQ_LOCKING_ANDX)WorkContext->RequestParameters;
  317. response = (PRESP_LOCKING_ANDX)WorkContext->ResponseParameters;
  318. //
  319. // Get the FID, which is combined with the PIDs in the various
  320. // lock/unlock ranges to form the local lock key.
  321. //
  322. // *** The FID must be included in the key in order to account for
  323. // the folding of multiple remote compatibility mode opens into
  324. // a single local open.
  325. //
  326. fid = SmbGetUshort( &request->Fid );
  327. IF_SMB_DEBUG(LOCK1) {
  328. unlockCount = SmbGetUshort( &request->NumberOfUnlocks );
  329. lockCount = SmbGetUshort( &request->NumberOfLocks );
  330. KdPrint(( "Locking and X request; FID 0x%lx, Unlocks: %ld, "
  331. "Locks: %ld\n", fid, unlockCount, lockCount ));
  332. }
  333. //
  334. // Verify the FID. If verified, the RFCB block is referenced
  335. // and its addresses is stored in the WorkContext block, and the
  336. // RFCB address is returned.
  337. //
  338. rfcb = SrvVerifyFid(
  339. WorkContext,
  340. fid,
  341. TRUE,
  342. SrvRestartSmbReceived, // serialize with raw write
  343. &status
  344. );
  345. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  346. if ( !NT_SUCCESS( status ) ) {
  347. //
  348. // Invalid file ID or write behind error. Reject the request.
  349. //
  350. IF_DEBUG(ERRORS) {
  351. KdPrint((
  352. "SrvSmbLockingAndX: Status %X on FID: 0x%lx\n",
  353. status,
  354. fid
  355. ));
  356. }
  357. SrvSetSmbError( WorkContext, status );
  358. SmbStatus = SmbStatusSendResponse;
  359. goto Cleanup;
  360. }
  361. //
  362. // The work item has been queued because a raw write is in
  363. // progress.
  364. //
  365. SmbStatus = SmbStatusInProgress;
  366. goto Cleanup;
  367. }
  368. pagedRfcb = rfcb->PagedRfcb;
  369. lfcb = rfcb->Lfcb;
  370. //
  371. // If the session has expired, return that info
  372. //
  373. if( lfcb->Session->IsSessionExpired )
  374. {
  375. SrvSetSmbError( WorkContext, SESSION_EXPIRED_STATUS_CODE );
  376. status = SESSION_EXPIRED_STATUS_CODE;
  377. SmbStatus = SmbStatusSendResponse;
  378. goto Cleanup;
  379. }
  380. start_lockingAndX:
  381. //
  382. // Loop through the unlock ranges.
  383. //
  384. largeFileLock =
  385. (BOOLEAN)( (request->LockType & LOCKING_ANDX_LARGE_FILES) != 0 );
  386. //
  387. // Ensure the SMB is big enough to hold all of the requests
  388. //
  389. unlockCount = SmbGetUshort( &request->NumberOfUnlocks );
  390. lockCount = SmbGetUshort( &request->NumberOfLocks );
  391. //
  392. // Find out how many entries could possibly be in this smb
  393. //
  394. maxPossible = (ULONG)(((PCHAR)WorkContext->RequestBuffer->Buffer +
  395. WorkContext->RequestBuffer->DataLength) -
  396. (PCHAR)request->Buffer);
  397. if( largeFileLock ) {
  398. maxPossible /= sizeof( NTLOCKING_ANDX_RANGE );
  399. largeRange = (PNTLOCKING_ANDX_RANGE)request->Buffer;
  400. } else {
  401. maxPossible /= sizeof( LOCKING_ANDX_RANGE );
  402. smallRange = (PLOCKING_ANDX_RANGE)request->Buffer;
  403. }
  404. //
  405. // If the request holds more than could possibly be in this SMB, return
  406. // and error
  407. //
  408. if( unlockCount + lockCount > maxPossible ) {
  409. //
  410. // They don't all fit!
  411. //
  412. IF_DEBUG( ERRORS ) {
  413. KdPrint(( "SrvSmbLockingAndX: unlockCount %u, lockCount %u, maxPossible %u\n",
  414. unlockCount, lockCount, maxPossible ));
  415. }
  416. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  417. status = STATUS_INVALID_SMB;
  418. SmbStatus = SmbStatusSendResponse;
  419. goto Cleanup;
  420. }
  421. //
  422. // If an Unlock is being requested, verify that the client has
  423. // unlock access to the file via the specified handle.
  424. //
  425. if ( unlockCount != 0 ) {
  426. if ( rfcb->UnlockAccessGranted ) {
  427. IO_STATUS_BLOCK iosb;
  428. do {
  429. //
  430. // Form the key for this lock. Get the offset and length of the
  431. // range.
  432. //
  433. ParseLockData(
  434. largeFileLock,
  435. smallRange,
  436. largeRange,
  437. &pid,
  438. &offset,
  439. &length
  440. );
  441. key = rfcb->ShiftedFid | pid;
  442. IF_SMB_DEBUG(LOCK2) {
  443. KdPrint(( "SrvSmbLockingAndX: Unlocking in file 0x%p: ",
  444. lfcb->FileObject ));
  445. KdPrint(( "(%lx%08lx, %lx%08lx), ",
  446. offset.HighPart, offset.LowPart,
  447. length.HighPart, length.LowPart ));
  448. KdPrint(( "key 0x%lx\n", key ));
  449. }
  450. //
  451. // Issue the Unlock request.
  452. //
  453. // *** Note that we do the Unlock synchronously. Unlock is a
  454. // quick operation, so there's no point in doing it
  455. // asynchronously. In order to do this, we have to let
  456. // normal I/O completion happen (so the event is set), which
  457. // means that we have to allocate a new IRP (I/O completion
  458. // likes to deallocate an IRP). This is a little wasteful,
  459. // since we've got a perfectly good IRP hanging around.
  460. // However, we do try to use the turbo path first, so in
  461. // most cases we won't actually issue an I/O request.
  462. //
  463. //
  464. // Try the turbo unlock path first.
  465. //
  466. #if SRVDBG_PERF
  467. iosb.Status = STATUS_SUCCESS;
  468. if ( (LockBypass == 3) ||
  469. ((LockBypass == 2) && (offset.LowPart >= LockBypassMirror)) ||
  470. ((LockBypass == 1) && (offset.LowPart >= LockBypassConst)) ||
  471. #else
  472. if (
  473. #endif
  474. ((lfcb->FastIoUnlockSingle != NULL) &&
  475. lfcb->FastIoUnlockSingle(
  476. lfcb->FileObject,
  477. &offset,
  478. &length,
  479. IoGetCurrentProcess(),
  480. key,
  481. &iosb,
  482. lfcb->DeviceObject
  483. )) ) {
  484. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksAttempted );
  485. status = iosb.Status;
  486. } else {
  487. if ( lfcb->FastIoUnlockSingle != NULL ) {
  488. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksAttempted );
  489. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastUnlocksFailed );
  490. }
  491. status = SrvIssueUnlockSingleRequest(
  492. lfcb->FileObject, // target file object
  493. &lfcb->DeviceObject, // target device object
  494. offset, // byte offset
  495. length, // range length
  496. key // lock key
  497. );
  498. }
  499. //
  500. // If the unlock request failed, set an error status in the
  501. // response header and jump out.
  502. //
  503. if ( !NT_SUCCESS(status) ) {
  504. IF_DEBUG(SMB_ERRORS) {
  505. KdPrint(( "SrvSmbLockingAndX: Unlock failed: %X\n", status ));
  506. }
  507. SrvSetSmbError( WorkContext, status );
  508. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbLockingAndX complete\n" ));
  509. SmbStatus = SmbStatusSendResponse;
  510. goto Cleanup;
  511. }
  512. //
  513. // Update the count of locks on the RFCB.
  514. //
  515. InterlockedDecrement( &rfcb->NumberOfLocks );
  516. //
  517. // Update both range pointers, only one is meaningful - the
  518. // other pointer is never referenced.
  519. //
  520. ++smallRange;
  521. ++largeRange;
  522. } while ( --unlockCount > 0 );
  523. } else {
  524. IF_DEBUG(ERRORS) {
  525. KdPrint(( "SrvSmbLockByteRange: Unlock access not granted.\n"));
  526. }
  527. SrvStatistics.GrantedAccessErrors++;
  528. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  529. status = STATUS_ACCESS_DENIED;
  530. SmbStatus = SmbStatusSendResponse;
  531. goto Cleanup;
  532. }
  533. }
  534. //
  535. // We've now unlocked all of the specified ranges. We did the
  536. // unlocks synchronously, but we're not willing to do that with the
  537. // lock requests, which can take an indefinite amount of time.
  538. // Instead, we start the first lock request here and allow the
  539. // restart routine to handle the remaining lock ranges.
  540. //
  541. if ( lockCount != 0 ) {
  542. //
  543. // Does the client want an exclusive lock or a shared lock?
  544. //
  545. exclusiveLock = (BOOLEAN)( (request->LockType &
  546. LOCKING_ANDX_SHARED_LOCK) == 0 );
  547. if ( rfcb->LockAccessGranted && (!exclusiveLock || rfcb->ExclusiveLockGranted) ) {
  548. if ( !(request->LockType & LOCKING_ANDX_CANCEL_LOCK ) &&
  549. !(request->LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) ) {
  550. BOOLEAN failImmediately;
  551. //
  552. // Get the lock timeout. We will change this later if
  553. // it's 0 but we want to wait anyway.
  554. //
  555. lockTimeout = SmbGetUlong( &request->Timeout );
  556. //
  557. // Indicate that no timer has been associated with this
  558. // request.
  559. //
  560. WorkContext->Parameters.Lock.Timer = NULL;
  561. //
  562. // There is at least one lock request. Set up context
  563. // information. We use the NumberOfUnlocks field of the
  564. // request to count how many of the lock requests we've
  565. // performed. This field also tells us how many unlocks
  566. // we have to do if one of the lock attempts fails. We
  567. // use the LockRange field of WorkContext->Parameters to
  568. // point to the current lock range in the request.
  569. //
  570. // Short circuit if only one lock request.
  571. //
  572. if ( lockCount == 1 ) {
  573. //
  574. // Form the key for the lock. Get the offset and length
  575. // of the range.
  576. //
  577. ParseLockData(
  578. largeFileLock,
  579. smallRange,
  580. largeRange,
  581. &pid,
  582. &offset,
  583. &length
  584. );
  585. key = rfcb->ShiftedFid | pid;
  586. IF_SMB_DEBUG(LOCK2) {
  587. KdPrint(( "SrvSmbLockingAndX: Locking in file 0x%p: ",
  588. lfcb->FileObject ));
  589. KdPrint(( "(%lx%08lx, %lx%08lx), ",
  590. offset.HighPart, offset.LowPart,
  591. length.HighPart, length.LowPart ));
  592. KdPrint(( "key 0x%lx\n", key ));
  593. }
  594. //
  595. // Try the turbo lock path first. Set FailImmediately
  596. // based on whether we plan to wait for the lock to
  597. // become available. If the client wants to wait,
  598. // or if the client doesn't want to wait but a)
  599. // previously tried to get this lock and failed or
  600. // b) this lock is above our lock delay limit (in
  601. // which cases WE want to wait), then we set
  602. // FailImmedately to FALSE. This will cause the
  603. // fast path to fail if the range is not available,
  604. // and we will build an IRP to try again.
  605. //
  606. failImmediately = ((lockTimeout == 0) &&
  607. (offset.QuadPart != pagedRfcb->LastFailingLockOffset.QuadPart) &&
  608. (offset.QuadPart < SrvLockViolationOffset) );
  609. #if SRVDBG_PERF
  610. if ( LockWaitForever ) failImmediately = FALSE;
  611. #endif
  612. #if SRVDBG_PERF
  613. WorkContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  614. if ( (LockBypass == 3) ||
  615. ((LockBypass == 2) && (offset.LowPart >= LockBypassMirror)) ||
  616. ((LockBypass == 1) && (offset.LowPart >= LockBypassConst)) ||
  617. #else
  618. if (
  619. #endif
  620. ((lfcb->FastIoLock != NULL) &&
  621. lfcb->FastIoLock(
  622. lfcb->FileObject,
  623. &offset,
  624. &length,
  625. IoGetCurrentProcess(),
  626. key,
  627. failImmediately,
  628. exclusiveLock,
  629. &WorkContext->Irp->IoStatus,
  630. lfcb->DeviceObject
  631. )) ) {
  632. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  633. if ( NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  634. //
  635. // The lock request succeeded. Update the count
  636. // of locks on the RFCB.
  637. //
  638. InterlockedIncrement( &rfcb->NumberOfLocks );
  639. goto try_next_andx;
  640. } else {
  641. //
  642. // The lock request failed.
  643. //
  644. SmbPutUshort( &request->NumberOfUnlocks, 0 );
  645. WorkContext->Parameters.Lock.LockRange =
  646. largeFileLock ? (PVOID)largeRange :
  647. (PVOID)smallRange;
  648. RestartLockingAndX( WorkContext );
  649. SmbStatus = SmbStatusInProgress;
  650. goto Cleanup;
  651. }
  652. }
  653. //
  654. // The turbo path failed, or didn't exist.
  655. //
  656. if ( lfcb->FastIoLock != NULL ) {
  657. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  658. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksFailed );
  659. }
  660. }
  661. //
  662. // Either there is more than one lock request in the SMB,
  663. // or the fast path failed (which means that we want to
  664. // try again, with a timeout).
  665. //
  666. SmbPutUshort( &request->NumberOfUnlocks, 0 );
  667. WorkContext->Parameters.Lock.LockRange =
  668. largeFileLock ? (PVOID)largeRange : (PVOID)smallRange;
  669. DoLockingAndX(
  670. WorkContext,
  671. (BOOLEAN)(lockCount == 1) // skip fast path?
  672. );
  673. SmbStatus = SmbStatusInProgress;
  674. goto Cleanup;
  675. } else if ( request->LockType & LOCKING_ANDX_CANCEL_LOCK ) {
  676. //
  677. // This is a Cancel request. Try to cancel the first lock
  678. // range. We ignore any subsequent ranges that may be
  679. // present.
  680. //
  681. // !!! Is this right?
  682. //
  683. // Get the pid, offset, and length of the lock request
  684. //
  685. ParseLockData(
  686. largeFileLock,
  687. smallRange,
  688. largeRange,
  689. &pid,
  690. &offset,
  691. &length
  692. );
  693. WorkContext->Parameters.Lock.LockRange =
  694. largeFileLock ? (PVOID)largeRange : (PVOID)smallRange;
  695. IF_SMB_DEBUG(LOCK2) {
  696. KdPrint(( "SrvSmbLockingAndX: Locking in file 0x%p: ",
  697. lfcb->FileObject ));
  698. KdPrint(( "(%lx%08lx, %lx%08lx), ",
  699. offset.HighPart, offset.LowPart,
  700. length.HighPart, length.LowPart ));
  701. }
  702. if ( CancelLockRequest( WorkContext, fid, pid, offset, length ) ) {
  703. SrvSetSmbError( WorkContext, STATUS_SUCCESS );
  704. status = STATUS_SUCCESS;
  705. } else {
  706. SrvSetSmbError( WorkContext, STATUS_OS2_CANCEL_VIOLATION );
  707. status = STATUS_OS2_CANCEL_VIOLATION;
  708. }
  709. SmbStatus = SmbStatusSendResponse;
  710. goto Cleanup;
  711. } else if ( request->LockType & LOCKING_ANDX_CHANGE_LOCKTYPE ) {
  712. //
  713. // This is a request from a Cruiser client for us to atomically
  714. // change a lock type from exclusive to shared or vice versa.
  715. // Since we cannot do this atomically, and would risk losing
  716. // the lock entirely if we tried this as a two step operation,
  717. // reject the request.
  718. //
  719. SrvSetSmbError( WorkContext, STATUS_OS2_ATOMIC_LOCKS_NOT_SUPPORTED );
  720. status = STATUS_OS2_ATOMIC_LOCKS_NOT_SUPPORTED;
  721. SmbStatus = SmbStatusSendResponse;
  722. goto Cleanup;
  723. }
  724. } else {
  725. //
  726. // We can't do locks.
  727. //
  728. IF_DEBUG(ERRORS) {
  729. KdPrint(( "SrvSmbLockByteRange: Lock access not granted.\n"));
  730. }
  731. SrvStatistics.GrantedAccessErrors++;
  732. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  733. status = STATUS_ACCESS_DENIED;
  734. SmbStatus = SmbStatusSendResponse;
  735. goto Cleanup;
  736. }
  737. }
  738. try_next_andx:
  739. //
  740. // Check for the Oplock Release flag.
  741. //
  742. nextCommand = request->AndXCommand;
  743. if ( (request->LockType & LOCKING_ANDX_OPLOCK_RELEASE) != 0 ) {
  744. oplockBreakResponse = ProcessOplockBreakResponse(
  745. WorkContext,
  746. rfcb,
  747. request
  748. );
  749. //
  750. // We have (synchronously) completed processing this SMB. If this
  751. // was an oplock break response, with no lock request, and no And X
  752. // command, do not send a reply.
  753. //
  754. if( lockCount == 0 && nextCommand == SMB_COM_NO_ANDX_COMMAND ) {
  755. if( oplockBreakResponse || unlockCount == 0 ) {
  756. SmbStatus = SmbStatusNoResponse;
  757. goto Cleanup;
  758. }
  759. }
  760. }
  761. //
  762. //
  763. // Set up the response, then check for an AndX command.
  764. //
  765. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  766. response->AndXCommand = nextCommand;
  767. response->AndXReserved = 0;
  768. SmbPutUshort(
  769. &response->AndXOffset,
  770. GET_ANDX_OFFSET(
  771. WorkContext->ResponseHeader,
  772. WorkContext->ResponseParameters,
  773. RESP_LOCKING_ANDX,
  774. 0
  775. )
  776. );
  777. response->WordCount = 2;
  778. SmbPutUshort( &response->ByteCount, 0 );
  779. WorkContext->ResponseParameters = (PCHAR)WorkContext->ResponseHeader +
  780. SmbGetUshort( &response->AndXOffset );
  781. //
  782. // Test for legal followon command.
  783. //
  784. if ( nextCommand == SMB_COM_NO_ANDX_COMMAND ) {
  785. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbLockingAndX complete.\n" ));
  786. SmbStatus = SmbStatusSendResponse;
  787. goto Cleanup;
  788. }
  789. //
  790. // Make sure the AndX command is still within the received SMB
  791. //
  792. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset >= END_OF_REQUEST_SMB( WorkContext ) ) {
  793. IF_DEBUG(SMB_ERRORS) {
  794. KdPrint(( "SrvSmbLockingAndX: Illegal followon offset: %u\n", reqAndXOffset ));
  795. }
  796. SrvLogInvalidSmb( WorkContext );
  797. //
  798. // Return an error indicating that the followon command was bad.
  799. //
  800. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  801. status = STATUS_INVALID_SMB;
  802. SmbStatus = SmbStatusSendResponse;
  803. goto Cleanup;
  804. }
  805. if ( nextCommand == SMB_COM_LOCKING_ANDX ) {
  806. UCHAR wordCount;
  807. PSMB_USHORT byteCount;
  808. ULONG availableSpaceForSmb;
  809. WorkContext->NextCommand = nextCommand;
  810. WorkContext->RequestParameters = (PCHAR)WorkContext->RequestHeader +
  811. reqAndXOffset;
  812. //
  813. // Validate the next locking and x chain
  814. //
  815. //
  816. // Get the WordCount and ByteCount values to make sure that there
  817. // was enough information sent to satisfy the specifications.
  818. //
  819. wordCount = *((PUCHAR)WorkContext->RequestParameters);
  820. byteCount = (PSMB_USHORT)( (PCHAR)WorkContext->RequestParameters +
  821. sizeof(UCHAR) + (8 * sizeof(USHORT)) );
  822. availableSpaceForSmb = (ULONG)(WorkContext->RequestBuffer->DataLength -
  823. ( (PCHAR)WorkContext->ResponseParameters -
  824. (PCHAR)WorkContext->RequestBuffer->Buffer ));
  825. if ( (wordCount == 8)
  826. &&
  827. ((PCHAR)byteCount <= (PCHAR)WorkContext->RequestBuffer->Buffer +
  828. WorkContext->RequestBuffer->DataLength -
  829. sizeof(USHORT))
  830. &&
  831. (8*sizeof(USHORT) + sizeof(UCHAR) + sizeof(USHORT) +
  832. SmbGetUshort( byteCount ) <= availableSpaceForSmb) ) {
  833. //
  834. // Update the request/response pointers
  835. //
  836. request = (PREQ_LOCKING_ANDX)WorkContext->RequestParameters;
  837. response = (PRESP_LOCKING_ANDX)WorkContext->ResponseParameters;
  838. goto start_lockingAndX;
  839. } else {
  840. //
  841. // Let the regular check fail this.
  842. //
  843. SmbStatus = SmbStatusMoreCommands;
  844. goto Cleanup;
  845. }
  846. }
  847. switch ( nextCommand ) {
  848. case SMB_COM_READ:
  849. case SMB_COM_READ_ANDX:
  850. case SMB_COM_WRITE:
  851. case SMB_COM_WRITE_ANDX:
  852. case SMB_COM_FLUSH:
  853. break;
  854. case SMB_COM_CLOSE:
  855. //
  856. // Call SrvRestartChainedClose to get the file time set and the
  857. // file closed.
  858. //
  859. closeRequest = (PREQ_CLOSE)((PUCHAR)WorkContext->RequestHeader + reqAndXOffset);
  860. //
  861. // Make sure we stay within the SMB buffer
  862. //
  863. if( (PCHAR)closeRequest + FIELD_OFFSET(REQ_CLOSE,ByteCount) <=
  864. END_OF_REQUEST_SMB( WorkContext ) ) {
  865. WorkContext->Parameters.LastWriteTime = closeRequest->LastWriteTimeInSeconds;
  866. SrvRestartChainedClose( WorkContext );
  867. SmbStatus = SmbStatusInProgress;
  868. goto Cleanup;
  869. }
  870. /* Falls Through! */
  871. default: // Illegal followon command
  872. IF_DEBUG(SMB_ERRORS) {
  873. KdPrint(( "SrvSmbLockingAndX: Illegal followon command: 0x%lx\n",
  874. nextCommand ));
  875. }
  876. SrvLogInvalidSmb( WorkContext );
  877. //
  878. // Return an error indicating that the followon command was bad.
  879. //
  880. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  881. status = STATUS_INVALID_SMB;
  882. SmbStatus = SmbStatusSendResponse;
  883. goto Cleanup;
  884. }
  885. //
  886. // If there is an AndX command, set up to process it. Otherwise,
  887. // indicate completion to the caller.
  888. //
  889. WorkContext->NextCommand = nextCommand;
  890. WorkContext->RequestParameters = (PCHAR)WorkContext->RequestHeader +
  891. reqAndXOffset;
  892. SmbStatus = SmbStatusMoreCommands;
  893. Cleanup:
  894. SrvWmiEndContext(WorkContext);
  895. return SmbStatus;
  896. } // SrvSmbLockingAndX
  897. SMB_PROCESSOR_RETURN_TYPE
  898. SrvSmbUnlockByteRange (
  899. SMB_PROCESSOR_PARAMETERS
  900. )
  901. /*++
  902. Routine Description:
  903. Processes the Unlock SMB.
  904. Arguments:
  905. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  906. of the parameters to SMB processor routines.
  907. Return Value:
  908. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  909. --*/
  910. {
  911. PREQ_UNLOCK_BYTE_RANGE request;
  912. PRESP_UNLOCK_BYTE_RANGE response;
  913. NTSTATUS status = STATUS_SUCCESS;
  914. SMB_STATUS SmbStatus = SmbStatusInProgress;
  915. USHORT fid;
  916. LARGE_INTEGER length;
  917. LARGE_INTEGER offset;
  918. ULONG key;
  919. PRFCB rfcb;
  920. PLFCB lfcb;
  921. PAGED_CODE( );
  922. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  923. WorkContext->PreviousSMB = EVENT_TYPE_SMB_UNLOCK_BYTE_RANGE;
  924. SrvWmiStartContext(WorkContext);
  925. request = (PREQ_UNLOCK_BYTE_RANGE)WorkContext->RequestParameters;
  926. response = (PRESP_UNLOCK_BYTE_RANGE)WorkContext->ResponseParameters;
  927. //
  928. // Get the offset and length of the range being locked. Combine the
  929. // FID with the caller's PID to form the local lock key.
  930. //
  931. // *** The FID must be included in the key in order to account for
  932. // the folding of multiple remote compatibility mode opens into
  933. // a single local open.
  934. //
  935. offset.QuadPart = SmbGetUlong( &request->Offset );
  936. length.QuadPart = SmbGetUlong( &request->Count );
  937. fid = SmbGetUshort( &request->Fid );
  938. IF_SMB_DEBUG(LOCK1) {
  939. KdPrint(( "Unlock request; FID 0x%lx, count %ld, offset %ld\n",
  940. fid, length.LowPart, offset.LowPart ));
  941. }
  942. //
  943. // Verify the FID. If verified, the RFCB block is referenced
  944. // and its addresses is stored in the WorkContext block, and the
  945. // RFCB address is returned.
  946. //
  947. rfcb = SrvVerifyFid(
  948. WorkContext,
  949. fid,
  950. TRUE,
  951. SrvRestartSmbReceived, // serialize with raw write
  952. &status
  953. );
  954. if ( rfcb == SRV_INVALID_RFCB_POINTER ) {
  955. if ( !NT_SUCCESS( status ) ) {
  956. //
  957. // Invalid file ID or write behind error. Reject the request.
  958. //
  959. IF_DEBUG(ERRORS) {
  960. KdPrint((
  961. "SrvSmbUnlockByteRange: Status %X on FID: 0x%lx\n",
  962. status,
  963. fid
  964. ));
  965. }
  966. SrvSetSmbError( WorkContext, status );
  967. SmbStatus = SmbStatusSendResponse;
  968. goto Cleanup;
  969. }
  970. //
  971. // The work item has been queued because a raw write is in
  972. // progress.
  973. //
  974. SmbStatus = SmbStatusInProgress;
  975. goto Cleanup;
  976. }
  977. lfcb = rfcb->Lfcb;
  978. //
  979. // Verify that the client has unlock access to the file via the
  980. // specified handle.
  981. //
  982. if ( !rfcb->UnlockAccessGranted) {
  983. SrvStatistics.GrantedAccessErrors++;
  984. IF_DEBUG(ERRORS) {
  985. KdPrint(( "SrvSmbLockByteRange: Unlock access not granted.\n"));
  986. }
  987. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  988. status = STATUS_ACCESS_DENIED;
  989. SmbStatus = SmbStatusSendResponse;
  990. goto Cleanup;
  991. }
  992. //
  993. // Issue the Unlock request.
  994. //
  995. // *** Note that we do the Unlock synchronously. Unlock is a quick
  996. // operation, so there's no point in doing it asynchronously.
  997. // In order to do this, we have to let normal I/O completion
  998. // happen (so the event is set), which means that we have to
  999. // allocate a new IRP (I/O completion likes to deallocate an
  1000. // IRP). This is a little wasteful, since we've got a perfectly
  1001. // good IRP hanging around. However, we do try to use the turbo
  1002. // path first, so in most cases we won't actually issue an I/O
  1003. // request.
  1004. //
  1005. key = rfcb->ShiftedFid |
  1006. SmbGetAlignedUshort( &WorkContext->RequestHeader->Pid );
  1007. IF_SMB_DEBUG(LOCK2) {
  1008. KdPrint(( "SrvSmbUnlockByteRange: Unlocking in file 0x%p: ",
  1009. lfcb->FileObject ));
  1010. KdPrint(( "(%lx%08lx,%lx%08lx), ",
  1011. offset.HighPart, offset.LowPart,
  1012. length.HighPart, length.LowPart ));
  1013. KdPrint(( "key 0x%lx\n", key ));
  1014. }
  1015. status = SrvIssueUnlockRequest(
  1016. lfcb->FileObject, // target file object
  1017. &lfcb->DeviceObject, // target device object
  1018. IRP_MN_UNLOCK_SINGLE, // unlock operation
  1019. offset, // byte offset
  1020. length, // range length
  1021. key // lock key
  1022. );
  1023. //
  1024. // If the unlock request failed, set an error status in the response
  1025. // header; otherwise, build a normal response message.
  1026. //
  1027. if ( !NT_SUCCESS(status) ) {
  1028. IF_DEBUG(ERRORS) {
  1029. KdPrint(( "SrvSmbUnlockByteRange: Unlock failed: %X\n", status ));
  1030. }
  1031. SrvSetSmbError( WorkContext, status );
  1032. } else {
  1033. response->WordCount = 0;
  1034. SmbPutUshort( &response->ByteCount, 0 );
  1035. InterlockedDecrement( &rfcb->NumberOfLocks );
  1036. WorkContext->ResponseParameters = NEXT_LOCATION(
  1037. response,
  1038. RESP_UNLOCK_BYTE_RANGE,
  1039. 0
  1040. );
  1041. }
  1042. //
  1043. // Processing of the SMB is complete.
  1044. //
  1045. SmbStatus = SmbStatusSendResponse;
  1046. IF_DEBUG(TRACE2) KdPrint(( "SrvSmbUnlockByteRange complete\n" ));
  1047. Cleanup:
  1048. SrvWmiEndContext(WorkContext);
  1049. return SmbStatus;
  1050. } // SrvSmbUnlockByteRange
  1051. BOOLEAN
  1052. CancelLockRequest (
  1053. IN PWORK_CONTEXT WorkContext,
  1054. IN USHORT TargetFid,
  1055. IN USHORT TargetPid,
  1056. IN LARGE_INTEGER TargetOffset,
  1057. IN LARGE_INTEGER TargetLength
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. This function searches for a lock request in progress. If the request
  1062. is found, the request IRP is cancelled.
  1063. Arguments:
  1064. WorkContext - A pointer to the work information for this request.
  1065. TargetFid - The server supplied FID of the file for the original lock
  1066. request
  1067. TargetPid - The server supplied PID of the file for the original lock
  1068. request
  1069. TargetOffset - The offset in the file of the original lock request
  1070. TargetLength - The length of the byte range of the original lock request
  1071. Return Value:
  1072. TRUE - The lock request was cancelled.
  1073. FALSE - The lock request could not be cancelled.
  1074. --*/
  1075. {
  1076. BOOLEAN match;
  1077. USHORT targetTid, targetUid;
  1078. PWORK_CONTEXT workContext;
  1079. PCONNECTION connection;
  1080. PSMB_HEADER header;
  1081. PREQ_LOCKING_ANDX request;
  1082. BOOLEAN success;
  1083. PNTLOCKING_ANDX_RANGE largeRange;
  1084. PLOCKING_ANDX_RANGE smallRange;
  1085. BOOLEAN largeFileLock;
  1086. USHORT pid;
  1087. LARGE_INTEGER offset;
  1088. LARGE_INTEGER length;
  1089. KIRQL oldIrql;
  1090. PLIST_ENTRY listHead;
  1091. PLIST_ENTRY listEntry;
  1092. UNLOCKABLE_CODE( 8FIL );
  1093. match = FALSE;
  1094. targetTid = WorkContext->RequestHeader->Tid;
  1095. targetUid = WorkContext->RequestHeader->Uid;
  1096. connection = WorkContext->Connection;
  1097. ACQUIRE_SPIN_LOCK( connection->EndpointSpinLock, &oldIrql );
  1098. //
  1099. // Scan the list of SMBs in progress looking for a locking and X SMB
  1100. // that exactly matches the one we are trying to cancel.
  1101. //
  1102. listHead = &WorkContext->Connection->InProgressWorkItemList;
  1103. listEntry = listHead;
  1104. while ( listEntry->Flink != listHead ) {
  1105. listEntry = listEntry->Flink;
  1106. workContext = CONTAINING_RECORD(
  1107. listEntry,
  1108. WORK_CONTEXT,
  1109. InProgressListEntry
  1110. );
  1111. header = workContext->RequestHeader;
  1112. request = (PREQ_LOCKING_ANDX) workContext->RequestParameters;
  1113. //
  1114. // Some workitems in the inprogressworkitemlist are added
  1115. // during a receive indication and the requestheader field
  1116. // has not been set yet. We can probably set it at that time
  1117. // but this seems to be the safest fix.
  1118. //
  1119. if ( header != NULL && request != NULL ) {
  1120. smallRange = WorkContext->Parameters.Lock.LockRange;
  1121. largeRange = WorkContext->Parameters.Lock.LockRange;
  1122. largeFileLock =
  1123. (BOOLEAN)( (request->LockType & LOCKING_ANDX_LARGE_FILES) != 0 );
  1124. ParseLockData(
  1125. largeFileLock,
  1126. smallRange,
  1127. largeRange,
  1128. &pid,
  1129. &offset,
  1130. &length
  1131. );
  1132. ACQUIRE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1133. if ( (workContext->BlockHeader.ReferenceCount != 0) &&
  1134. (workContext->ProcessingCount != 0) &&
  1135. header->Command == SMB_COM_LOCKING_ANDX &&
  1136. request->Fid == TargetFid &&
  1137. SmbGetAlignedUshort( &header->Tid ) == targetTid &&
  1138. SmbGetAlignedUshort( &header->Uid ) == targetUid &&
  1139. pid == TargetPid &&
  1140. offset.QuadPart == TargetOffset.QuadPart &&
  1141. length.QuadPart == TargetLength.QuadPart ) {
  1142. match = TRUE;
  1143. break;
  1144. }
  1145. RELEASE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1146. }
  1147. }
  1148. if ( match ) {
  1149. //
  1150. // Reference the work item, so that it cannot get used to process
  1151. // a new SMB while we are trying to cancel the old one.
  1152. //
  1153. SrvReferenceWorkItem( workContext );
  1154. RELEASE_DPC_SPIN_LOCK( &workContext->SpinLock );
  1155. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1156. success = IoCancelIrp( workContext->Irp );
  1157. SrvDereferenceWorkItem( workContext );
  1158. } else {
  1159. RELEASE_SPIN_LOCK( connection->EndpointSpinLock, oldIrql );
  1160. success = FALSE;
  1161. }
  1162. return success;
  1163. } // CancelLockRequest
  1164. VOID
  1165. DoLockingAndX (
  1166. IN OUT PWORK_CONTEXT WorkContext,
  1167. IN BOOLEAN SkipFastPath
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Processes the LockingAndX SMB, using the fast lock path. As long
  1172. as the fast lock path works, we continue to loop through the locks
  1173. specified in the LockingAndX request. As soon as the fast path
  1174. fails, however, we jump into the slow IRP-based path.
  1175. Arguments:
  1176. WorkContext - Supplies a pointer to the work context block
  1177. describing server-specific context for the request.
  1178. SkipFastPath - Indicates whether this routine should try the fast
  1179. lock path before submitting an IRP.
  1180. Return Value:
  1181. None.
  1182. --*/
  1183. {
  1184. PREQ_LOCKING_ANDX request;
  1185. PLOCKING_ANDX_RANGE smallRange;
  1186. PNTLOCKING_ANDX_RANGE largeRange;
  1187. PRFCB rfcb;
  1188. PLFCB lfcb;
  1189. USHORT pid;
  1190. CLONG lockCount;
  1191. CLONG count;
  1192. LARGE_INTEGER length;
  1193. LARGE_INTEGER offset;
  1194. ULONG key;
  1195. BOOLEAN largeFileLock;
  1196. BOOLEAN failImmediately;
  1197. BOOLEAN exclusiveLock;
  1198. ULONG lockTimeout;
  1199. PSRV_TIMER timer;
  1200. PAGED_CODE( );
  1201. //
  1202. // Get the request parameter pointer.
  1203. //
  1204. request = (PREQ_LOCKING_ANDX)WorkContext->RequestParameters;
  1205. //
  1206. // Get the file pointer, the count of locks requested, the count of
  1207. // locks already performed, and a pointer to the current lock range.
  1208. //
  1209. rfcb = WorkContext->Rfcb;
  1210. lfcb = rfcb->Lfcb;
  1211. lockCount = SmbGetUshort( &request->NumberOfLocks );
  1212. count = SmbGetUshort( &request->NumberOfUnlocks );
  1213. largeFileLock =
  1214. (BOOLEAN)( (request->LockType & LOCKING_ANDX_LARGE_FILES) != 0 );
  1215. //
  1216. // Only one of the two pointers below is actually ever referenced.
  1217. //
  1218. smallRange = WorkContext->Parameters.Lock.LockRange;
  1219. largeRange = WorkContext->Parameters.Lock.LockRange;
  1220. //
  1221. // Does the client want an exclusive lock or a shared lock?
  1222. //
  1223. exclusiveLock = (BOOLEAN)( (request->LockType &
  1224. LOCKING_ANDX_SHARED_LOCK) == 0 );
  1225. //
  1226. // Loop through the lock requests. We exit this loop when either
  1227. // we have processed all of the lock ranges or the fast lock path
  1228. // fails.
  1229. //
  1230. ASSERT ( count < lockCount );
  1231. while ( TRUE ) {
  1232. //
  1233. // Form the key for the lock. Get the offset and length
  1234. // of the range.
  1235. //
  1236. ParseLockData(
  1237. largeFileLock,
  1238. smallRange,
  1239. largeRange,
  1240. &pid,
  1241. &offset,
  1242. &length
  1243. );
  1244. key = rfcb->ShiftedFid | pid;
  1245. IF_SMB_DEBUG(LOCK2) {
  1246. KdPrint(( "DoLockingAndX: Locking in file 0x%p: ",
  1247. lfcb->FileObject ));
  1248. KdPrint(( "(%lx%08lx, %lx%08lx), ",
  1249. offset.HighPart, offset.LowPart,
  1250. length.HighPart, length.LowPart ));
  1251. KdPrint(( "key 0x%lx\n", key ));
  1252. }
  1253. lockTimeout = SmbGetUlong( &request->Timeout );
  1254. if ( (lockTimeout < SrvLockViolationDelay) &&
  1255. ((offset.QuadPart == rfcb->PagedRfcb->LastFailingLockOffset.QuadPart) ||
  1256. (offset.QuadPart >= SrvLockViolationOffset)) ) {
  1257. lockTimeout = SrvLockViolationDelay;
  1258. }
  1259. #if SRVDBG_PERF
  1260. if ( LockWaitForever ) {
  1261. lockTimeout = (ULONG)-1;
  1262. }
  1263. #endif
  1264. failImmediately = (BOOLEAN)(lockTimeout == 0);
  1265. if ( SkipFastPath ) {
  1266. SkipFastPath = FALSE;
  1267. } else {
  1268. //
  1269. // Try the turbo lock path first.
  1270. //
  1271. #if SRVDBG_PERF
  1272. WorkContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  1273. if ( (LockBypass == 3) ||
  1274. ((LockBypass == 2) && (offset.LowPart >= LockBypassMirror)) ||
  1275. ((LockBypass == 1) && (offset.LowPart >= LockBypassConst)) ||
  1276. #else
  1277. if (
  1278. #endif
  1279. ((lfcb->FastIoLock != NULL) &&
  1280. lfcb->FastIoLock(
  1281. lfcb->FileObject,
  1282. &offset,
  1283. &length,
  1284. IoGetCurrentProcess(),
  1285. key,
  1286. failImmediately,
  1287. exclusiveLock,
  1288. &WorkContext->Irp->IoStatus,
  1289. lfcb->DeviceObject
  1290. )) ) {
  1291. //
  1292. // The turbo path worked. If the lock was not obtained,
  1293. // drop into the restart routine to return the error.
  1294. // Otherwise, update pointers and counters and continue.
  1295. //
  1296. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  1297. if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  1298. RestartLockingAndX( WorkContext );
  1299. return;
  1300. }
  1301. //
  1302. // Increment the count of locks on the file.
  1303. //
  1304. InterlockedIncrement( &rfcb->NumberOfLocks );
  1305. //
  1306. // If this isn't the last lock, update context
  1307. // information. If it is, RestartLockingAndX will do
  1308. // this.
  1309. //
  1310. count++; // another lock obtained
  1311. if ( count < lockCount ) {
  1312. SmbPutUshort( &request->NumberOfUnlocks, (USHORT)count );
  1313. if (largeFileLock) {
  1314. largeRange++; // point to next lock range
  1315. WorkContext->Parameters.Lock.LockRange = (PVOID)largeRange;
  1316. } else {
  1317. smallRange++; // point to next lock range
  1318. WorkContext->Parameters.Lock.LockRange = (PVOID)smallRange;
  1319. }
  1320. } else {
  1321. //
  1322. // The fast lock path successfully locked all of the
  1323. // requested ranges. Call RestartLockingAndX
  1324. // directly to complete processing of the SMB.
  1325. //
  1326. WorkContext->Irp->IoStatus.Status = STATUS_SUCCESS;
  1327. RestartLockingAndX( WorkContext );
  1328. return;
  1329. }
  1330. continue;
  1331. } else {
  1332. //
  1333. // The turbo path failed, or didn't exist.
  1334. //
  1335. if ( lfcb->FastIoLock ) {
  1336. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksAttempted );
  1337. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.FastLocksFailed );
  1338. }
  1339. }
  1340. }
  1341. //
  1342. // The turbo path failed, or was bypassed, or didn't exist.
  1343. // Start the lock request, reusing the receive IRP.
  1344. //
  1345. // If we plan to wait for the range to be available, but not
  1346. // indefinitely, we'll need a timer structure.
  1347. //
  1348. timer = NULL;
  1349. if ( !failImmediately ) {
  1350. ASSERT( lockTimeout != 0 );
  1351. if ( lockTimeout != (ULONG)-1 ) {
  1352. timer = SrvAllocateTimer( );
  1353. if ( timer == NULL ) {
  1354. failImmediately = TRUE;
  1355. }
  1356. }
  1357. }
  1358. SrvBuildLockRequest(
  1359. WorkContext->Irp, // input IRP address
  1360. lfcb->FileObject, // target file object address
  1361. WorkContext, // context
  1362. offset, // byte offset
  1363. length, // range length
  1364. key, // lock key
  1365. failImmediately,
  1366. exclusiveLock
  1367. );
  1368. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1369. WorkContext->FspRestartRoutine = RestartLockingAndX;
  1370. //
  1371. // Start the timer, if necessary.
  1372. //
  1373. if ( timer != NULL ) {
  1374. LARGE_INTEGER TimeOut;
  1375. ASSERT( lockTimeout != 0 );
  1376. ASSERT( !failImmediately );
  1377. WorkContext->Parameters.Lock.Timer = timer;
  1378. TimeOut.QuadPart = Int32x32To64( lockTimeout, -1*10*1000);
  1379. SrvSetTimer( timer, &TimeOut, TimeoutLockRequest, WorkContext );
  1380. }
  1381. //
  1382. // Pass the request to the file system.
  1383. //
  1384. (VOID)IoCallDriver( lfcb->DeviceObject, WorkContext->Irp );
  1385. //
  1386. // The lock request has been started.
  1387. //
  1388. IF_DEBUG(TRACE2) KdPrint(( "DoLockingAndX complete\n" ));
  1389. return;
  1390. } // while ( TRUE )
  1391. // can't get here
  1392. } // DoLockingAndX
  1393. BOOLEAN
  1394. ProcessOplockBreakResponse(
  1395. IN PWORK_CONTEXT WorkContext,
  1396. IN PRFCB Rfcb,
  1397. IN PREQ_LOCKING_ANDX Request
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. This function searches for a lock request in progress. If the request
  1402. is found, the request IRP is cancelled.
  1403. Arguments:
  1404. WorkContext - A pointer to the work information for this request.
  1405. Rfcb - A pointer to the rfcb containing the file and oplock information.
  1406. Request - The request lockingandx smb.
  1407. Return Value:
  1408. TRUE - Valid oplock break response
  1409. FALSE - otherwise.
  1410. --*/
  1411. {
  1412. PAGED_CODE( );
  1413. ACQUIRE_LOCK( &SrvOplockBreakListLock );
  1414. if ( Rfcb->OnOplockBreaksInProgressList ) {
  1415. Rfcb->NewOplockLevel = NO_OPLOCK_BREAK_IN_PROGRESS;
  1416. //
  1417. // Remove the Rfcb from the Oplock breaks in progress list, and
  1418. // release the Rfcb reference.
  1419. //
  1420. SrvRemoveEntryList( &SrvOplockBreaksInProgressList, &Rfcb->ListEntry );
  1421. Rfcb->OnOplockBreaksInProgressList = FALSE;
  1422. #if DBG
  1423. Rfcb->ListEntry.Flink = Rfcb->ListEntry.Blink = NULL;
  1424. #endif
  1425. RELEASE_LOCK( &SrvOplockBreakListLock );
  1426. //
  1427. // Update the session lock sequence number.
  1428. //
  1429. WorkContext->Connection->LatestOplockBreakResponse =
  1430. WorkContext->Timestamp;
  1431. SrvAcknowledgeOplockBreak( Rfcb, Request->OplockLevel );
  1432. SrvDereferenceRfcb( Rfcb );
  1433. ExInterlockedAddUlong(
  1434. &WorkContext->Connection->OplockBreaksInProgress,
  1435. (ULONG)-1,
  1436. WorkContext->Connection->EndpointSpinLock
  1437. );
  1438. return(TRUE);
  1439. } else {
  1440. RELEASE_LOCK( &SrvOplockBreakListLock );
  1441. }
  1442. return(FALSE);
  1443. } // ProcessOplockBreakResponse
  1444. VOID SRVFASTCALL
  1445. RestartLockByteRange (
  1446. IN OUT PWORK_CONTEXT WorkContext
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. Processes file lock completion for a Lock SMB.
  1451. Arguments:
  1452. WorkContext - Supplies a pointer to the work context block
  1453. describing server-specific context for the request.
  1454. Return Value:
  1455. None.
  1456. --*/
  1457. {
  1458. PREQ_LOCK_BYTE_RANGE request;
  1459. PRESP_LOCK_BYTE_RANGE response;
  1460. LARGE_INTEGER offset;
  1461. NTSTATUS status = STATUS_SUCCESS;
  1462. PSRV_TIMER timer;
  1463. BOOLEAN iAmBlockingThread = (WorkContext->UsingBlockingThread != 0);
  1464. PAGED_CODE( );
  1465. if (iAmBlockingThread) {
  1466. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1467. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCK_BYTE_RANGE;
  1468. SrvWmiStartContext(WorkContext);
  1469. }
  1470. IF_DEBUG(WORKER1) KdPrint(( " - RestartLockByteRange\n" ));
  1471. //
  1472. // If this request was being timed, cancel the timer.
  1473. //
  1474. timer = WorkContext->Parameters.Lock.Timer;
  1475. if ( timer != NULL ) {
  1476. SrvCancelTimer( timer );
  1477. SrvFreeTimer( timer );
  1478. }
  1479. //
  1480. // Get the request and response parameter pointers.
  1481. //
  1482. response = (PRESP_LOCK_BYTE_RANGE)WorkContext->ResponseParameters;
  1483. status = WorkContext->Irp->IoStatus.Status;
  1484. if ( NT_SUCCESS(status) ) {
  1485. response->WordCount = 0;
  1486. SmbPutUshort( &response->ByteCount, 0 );
  1487. InterlockedIncrement(
  1488. &WorkContext->Rfcb->NumberOfLocks
  1489. );
  1490. WorkContext->ResponseParameters = NEXT_LOCATION(
  1491. response,
  1492. RESP_LOCK_BYTE_RANGE,
  1493. 0
  1494. );
  1495. //
  1496. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  1497. // to send the response.
  1498. //
  1499. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1500. } else {
  1501. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.LockViolations );
  1502. //
  1503. // Store the failing lock offset.
  1504. //
  1505. request = (PREQ_LOCK_BYTE_RANGE)WorkContext->RequestParameters;
  1506. offset.QuadPart = SmbGetUlong( &request->Offset );
  1507. WorkContext->Rfcb->PagedRfcb->LastFailingLockOffset = offset;
  1508. //
  1509. // Send error message back
  1510. //
  1511. if ( status == STATUS_CANCELLED ) {
  1512. status = STATUS_FILE_LOCK_CONFLICT;
  1513. }
  1514. SrvSetSmbError( WorkContext, status );
  1515. //
  1516. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  1517. // to send the response.
  1518. //
  1519. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1520. }
  1521. IF_DEBUG(TRACE2) KdPrint(( "RestartLockByteRange complete\n" ));
  1522. if (iAmBlockingThread) {
  1523. SrvWmiEndContext(WorkContext);
  1524. }
  1525. return;
  1526. } // RestartLockByteRange
  1527. VOID SRVFASTCALL
  1528. RestartLockingAndX (
  1529. IN OUT PWORK_CONTEXT WorkContext
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. Processes file lock completion for a Locking and X SMB. If more
  1534. lock requests are present in the SMB, it starts the next one. If
  1535. not, it formats a response and starts the next command in the chain,
  1536. if any.
  1537. Arguments:
  1538. WorkContext - Supplies a pointer to the work context block
  1539. describing server-specific context for the request.
  1540. Return Value:
  1541. None.
  1542. --*/
  1543. {
  1544. PREQ_LOCKING_ANDX request;
  1545. PRESP_LOCKING_ANDX response;
  1546. PLOCKING_ANDX_RANGE smallRange;
  1547. PNTLOCKING_ANDX_RANGE largeRange;
  1548. NTSTATUS status = STATUS_SUCCESS;
  1549. USHORT pid;
  1550. CLONG lockCount;
  1551. CLONG count;
  1552. LARGE_INTEGER length;
  1553. LARGE_INTEGER offset;
  1554. ULONG key;
  1555. BOOLEAN largeFileLock;
  1556. UCHAR nextCommand;
  1557. USHORT reqAndXOffset;
  1558. PRFCB rfcb;
  1559. PLFCB lfcb;
  1560. PPAGED_RFCB pagedRfcb;
  1561. PSRV_TIMER timer;
  1562. PREQ_CLOSE closeRequest;
  1563. BOOLEAN iAmBlockingThread =
  1564. (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LOCKING_AND_X);
  1565. PAGED_CODE( );
  1566. if (iAmBlockingThread) {
  1567. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  1568. WorkContext->PreviousSMB = EVENT_TYPE_SMB_LOCKING_AND_X;
  1569. SrvWmiStartContext(WorkContext);
  1570. }
  1571. IF_DEBUG(WORKER1) KdPrint(( " - RestartLockingAndX\n" ));
  1572. //
  1573. // If this request was being timed, cancel the timer.
  1574. //
  1575. timer = WorkContext->Parameters.Lock.Timer;
  1576. if ( timer != NULL ) {
  1577. SrvCancelTimer( timer );
  1578. SrvFreeTimer( timer );
  1579. WorkContext->Parameters.Lock.Timer = NULL;
  1580. }
  1581. //
  1582. // Get the request and response parameter pointers.
  1583. //
  1584. request = (PREQ_LOCKING_ANDX)WorkContext->RequestParameters;
  1585. response = (PRESP_LOCKING_ANDX)WorkContext->ResponseParameters;
  1586. //
  1587. // Get the file pointer, the count of locks requested, the count of
  1588. // locks already performed, and a pointer to the current lock range.
  1589. //
  1590. rfcb = WorkContext->Rfcb;
  1591. pagedRfcb = rfcb->PagedRfcb;
  1592. lfcb = rfcb->Lfcb;
  1593. lockCount = SmbGetUshort( &request->NumberOfLocks );
  1594. count = SmbGetUshort( &request->NumberOfUnlocks );
  1595. largeFileLock =
  1596. (BOOLEAN)( (request->LockType & LOCKING_ANDX_LARGE_FILES) != 0 );
  1597. //
  1598. // Only one of the two pointers below is actually ever referenced.
  1599. //
  1600. smallRange = WorkContext->Parameters.Lock.LockRange;
  1601. largeRange = WorkContext->Parameters.Lock.LockRange;
  1602. //
  1603. // If the lock request failed, set an error status in the response
  1604. // header and release any previously obtained locks.
  1605. //
  1606. status = WorkContext->Irp->IoStatus.Status;
  1607. if ( !NT_SUCCESS(status) ) {
  1608. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.LockViolations );
  1609. IF_DEBUG(ERRORS) {
  1610. KdPrint(( "RestartLockingAndX: lock failed: %X\n", status ));
  1611. }
  1612. if ( status == STATUS_CANCELLED ) {
  1613. status = STATUS_FILE_LOCK_CONFLICT;
  1614. }
  1615. SrvSetSmbError( WorkContext, status );
  1616. ParseLockData(
  1617. largeFileLock,
  1618. smallRange,
  1619. largeRange,
  1620. &pid,
  1621. &offset,
  1622. &length
  1623. );
  1624. //
  1625. // Store the failing lock offset.
  1626. //
  1627. pagedRfcb->LastFailingLockOffset = offset;
  1628. //
  1629. // Release any previously obtained locks, in reverse order.
  1630. //
  1631. for ( smallRange--, largeRange--;
  1632. count > 0;
  1633. count--, smallRange--, largeRange-- ) {
  1634. //
  1635. // Form the key for this lock. Get the offset and length of
  1636. // the range.
  1637. //
  1638. ParseLockData(
  1639. largeFileLock,
  1640. smallRange,
  1641. largeRange,
  1642. &pid,
  1643. &offset,
  1644. &length
  1645. );
  1646. key = rfcb->ShiftedFid | pid;
  1647. IF_SMB_DEBUG(LOCK2) {
  1648. KdPrint(( "RestartLockingAndX: Unlocking in file 0x%p: ",
  1649. lfcb->FileObject ));
  1650. KdPrint(( "(%lx%08lx,%lx%08lx), ",
  1651. offset.HighPart, offset.LowPart,
  1652. length.HighPart, length.LowPart ));
  1653. KdPrint(( "key 0x%lx\n", key ));
  1654. }
  1655. //
  1656. // Issue the Unlock request.
  1657. //
  1658. status = SrvIssueUnlockRequest(
  1659. lfcb->FileObject, // target file object
  1660. &lfcb->DeviceObject, // target device object
  1661. IRP_MN_UNLOCK_SINGLE, // unlock operation
  1662. offset, // byte offset
  1663. length, // range length
  1664. key // lock key
  1665. );
  1666. if ( NT_SUCCESS(status) ) {
  1667. InterlockedDecrement( &rfcb->NumberOfLocks );
  1668. } else {
  1669. IF_DEBUG(ERRORS) {
  1670. KdPrint(( "RestartLockingAndX: Unlock failed: %X\n",
  1671. status ));
  1672. }
  1673. }
  1674. } // for ( range--; count > 0; count--, range-- )
  1675. //
  1676. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  1677. // to send the response.
  1678. //
  1679. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1680. IF_DEBUG(TRACE2) KdPrint(( "RestartLockingAndX complete\n" ));
  1681. goto Cleanup;
  1682. }
  1683. //
  1684. // The lock request succeeded. Update the count of locks on the
  1685. // RFCB and start the next one, if any.
  1686. //
  1687. InterlockedIncrement( &rfcb->NumberOfLocks );
  1688. count++; // another lock obtained
  1689. smallRange++, largeRange++; // point to next lock range
  1690. if ( count < lockCount ) {
  1691. //
  1692. // There is at least one more lock request. Save the updated
  1693. // context information.
  1694. //
  1695. SmbPutUshort( &request->NumberOfUnlocks, (USHORT)count );
  1696. if (largeFileLock) {
  1697. WorkContext->Parameters.Lock.LockRange = (PVOID)largeRange;
  1698. } else {
  1699. WorkContext->Parameters.Lock.LockRange = (PVOID)smallRange;
  1700. }
  1701. //
  1702. // Call the lock request processor. (Note that DoLockingAndX
  1703. // can call this routine (RestartLockingAndX) recursively, but
  1704. // only with !NT_SUCCESS(status), so we won't get back here and
  1705. // won't get stuck.
  1706. //
  1707. // Form the key for the lock. Get the offset and length of the
  1708. // range.
  1709. //
  1710. DoLockingAndX( WorkContext, FALSE );
  1711. IF_DEBUG(TRACE2) KdPrint(( "RestartLockingAndX complete\n" ));
  1712. goto Cleanup;
  1713. }
  1714. //
  1715. // There are no more lock requests in the SMB. Check for the Oplock
  1716. // Release flag.
  1717. //
  1718. if ( (request->LockType & LOCKING_ANDX_OPLOCK_RELEASE) != 0 ) {
  1719. (VOID)ProcessOplockBreakResponse( WorkContext, rfcb, request);
  1720. }
  1721. //
  1722. // We have (asynchronously) completed processing this SMB. Set up
  1723. // the response, then check for an AndX command.
  1724. //
  1725. nextCommand = request->AndXCommand;
  1726. reqAndXOffset = SmbGetUshort( &request->AndXOffset );
  1727. response->AndXCommand = nextCommand;
  1728. response->AndXReserved = 0;
  1729. SmbPutUshort(
  1730. &response->AndXOffset,
  1731. GET_ANDX_OFFSET(
  1732. WorkContext->ResponseHeader,
  1733. WorkContext->ResponseParameters,
  1734. RESP_LOCKING_ANDX,
  1735. 0
  1736. )
  1737. );
  1738. response->WordCount = 2;
  1739. SmbPutUshort( &response->ByteCount, 0 );
  1740. WorkContext->ResponseParameters = (PCHAR)WorkContext->ResponseHeader +
  1741. SmbGetUshort( &response->AndXOffset );
  1742. //
  1743. // If there is an AndX command, set up to process it. Otherwise,
  1744. // indicate completion to the caller.
  1745. //
  1746. if ( nextCommand == SMB_COM_NO_ANDX_COMMAND ) {
  1747. //
  1748. // Processing of the SMB is complete. Call SrvEndSmbProcessing
  1749. // to send the response.
  1750. //
  1751. // Build the response parameters.
  1752. //
  1753. PRESP_CLOSE closeResponse = WorkContext->ResponseParameters;
  1754. closeResponse->WordCount = 0;
  1755. SmbPutUshort( &closeResponse->ByteCount, 0 );
  1756. WorkContext->ResponseParameters = NEXT_LOCATION(
  1757. closeResponse,
  1758. RESP_CLOSE,
  1759. 0
  1760. );
  1761. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1762. IF_DEBUG(TRACE2) KdPrint(( "RestartLockingAndX complete\n" ));
  1763. goto Cleanup;
  1764. }
  1765. //
  1766. // Make sure the AndX command is still within the received SMB
  1767. //
  1768. if( (PCHAR)WorkContext->RequestHeader + reqAndXOffset >= END_OF_REQUEST_SMB( WorkContext ) ) {
  1769. IF_DEBUG(SMB_ERRORS) {
  1770. KdPrint(( "RestartLockingAndX: Illegal followon offset: %u\n", reqAndXOffset ));
  1771. }
  1772. SrvLogInvalidSmb( WorkContext );
  1773. //
  1774. // Return an error indicating that the followon command was bad.
  1775. //
  1776. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1777. status = STATUS_INVALID_SMB;
  1778. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1779. goto Cleanup;
  1780. }
  1781. //
  1782. // Test for legal followon command.
  1783. //
  1784. switch ( nextCommand ) {
  1785. case SMB_COM_READ:
  1786. case SMB_COM_READ_ANDX:
  1787. case SMB_COM_WRITE:
  1788. case SMB_COM_WRITE_ANDX:
  1789. case SMB_COM_LOCKING_ANDX:
  1790. case SMB_COM_FLUSH:
  1791. break;
  1792. case SMB_COM_CLOSE:
  1793. //
  1794. // Call SrvRestartChainedClose to get the file time set and the
  1795. // file closed.
  1796. //
  1797. closeRequest = (PREQ_CLOSE)((PUCHAR)WorkContext->RequestHeader + reqAndXOffset);
  1798. if( (PCHAR)closeRequest + FIELD_OFFSET(REQ_CLOSE,ByteCount) <=
  1799. END_OF_REQUEST_SMB( WorkContext ) ) {
  1800. WorkContext->Parameters.LastWriteTime = closeRequest->LastWriteTimeInSeconds;
  1801. SrvRestartChainedClose( WorkContext );
  1802. goto Cleanup;
  1803. }
  1804. default: // Illegal followon command
  1805. IF_DEBUG(SMB_ERRORS) {
  1806. KdPrint(( "RestartLockingAndX: Illegal followon command: 0x%lx\n",
  1807. nextCommand ));
  1808. }
  1809. SrvLogInvalidSmb( WorkContext );
  1810. //
  1811. // Return an error indicating that the followon command was bad.
  1812. //
  1813. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1814. status = STATUS_INVALID_SMB;
  1815. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  1816. IF_DEBUG(TRACE2) KdPrint(( "RestartLockingAndX complete\n" ));
  1817. goto Cleanup;
  1818. }
  1819. WorkContext->NextCommand = nextCommand;
  1820. WorkContext->RequestParameters = (PCHAR)WorkContext->RequestHeader +
  1821. reqAndXOffset;
  1822. SrvProcessSmb( WorkContext );
  1823. IF_DEBUG(TRACE2) KdPrint(( "RestartLockingAndX complete\n" ));
  1824. Cleanup:
  1825. if (iAmBlockingThread) {
  1826. SrvWmiEndContext(WorkContext);
  1827. }
  1828. return;
  1829. } // RestartLockingAndX
  1830. VOID
  1831. SrvAcknowledgeOplockBreak (
  1832. IN PRFCB Rfcb,
  1833. IN UCHAR NewOplockLevel
  1834. )
  1835. /*++
  1836. Routine Description:
  1837. This function is called when a client has sent an oplock break
  1838. acknowledgement. It acknowledges the oplock break locally.
  1839. Arguments:
  1840. Rfcb - A pointer to the RFCB for the file on which the oplock is
  1841. being released.
  1842. NewOplockLevel - The oplock level to break to.
  1843. Return Value:
  1844. None.
  1845. --*/
  1846. {
  1847. PPAGED_RFCB pagedRfcb = Rfcb->PagedRfcb;
  1848. PAGED_CODE( );
  1849. IF_DEBUG( OPLOCK ) {
  1850. KdPrint(( "SrvAcknowledgeOplockBreak: received oplock break response\n" ));
  1851. }
  1852. //
  1853. // Reference the RFCB to account for the IRP we about to submit.
  1854. // If the RFCB is closing, do not bother to acknowledge the oplock.
  1855. //
  1856. if ( !SrvCheckAndReferenceRfcb( Rfcb ) ) {
  1857. return;
  1858. }
  1859. if ( Rfcb->OplockState == OplockStateNone ) {
  1860. KdPrint(("SrvAcknowledgeOplockBreak: ACKed break for RFCB %p, but no break sent\n", Rfcb));
  1861. SrvDereferenceRfcb( Rfcb );
  1862. return;
  1863. }
  1864. if ( NewOplockLevel == OPLOCK_BROKEN_TO_II ) {
  1865. Rfcb->OplockState = OplockStateOwnLevelII;
  1866. } else {
  1867. Rfcb->OplockState = OplockStateNone;
  1868. }
  1869. //
  1870. // Set this event to NULL to indicate the completion routine should clean
  1871. // up the irp.
  1872. //
  1873. Rfcb->RetryOplockRequest = NULL;
  1874. //
  1875. // Generate and issue the oplock break IRP. This will attempt to
  1876. // break the oplock to level 2.
  1877. //
  1878. // *** If the client understands level II oplocks, do a regular
  1879. // acknowledge. If not, do a special acknowledge that does
  1880. // not allow the oplock to change to level II. This prevents
  1881. // the situation where the oplock package thinks there's a
  1882. // level II oplock, but the client(s) don't. In that situation,
  1883. // fast I/O (esp. reads) is disabled unnecessarily.
  1884. //
  1885. SrvBuildIoControlRequest(
  1886. Rfcb->Irp,
  1887. Rfcb->Lfcb->FileObject,
  1888. Rfcb,
  1889. IRP_MJ_FILE_SYSTEM_CONTROL,
  1890. (CLIENT_CAPABLE_OF( LEVEL_II_OPLOCKS, Rfcb->Connection ) ?
  1891. FSCTL_OPLOCK_BREAK_ACKNOWLEDGE :
  1892. FSCTL_OPLOCK_BREAK_ACK_NO_2),
  1893. NULL, // Main buffer
  1894. 0, // Input buffer length
  1895. NULL, // Auxiliary buffer
  1896. 0, // Output buffer length
  1897. NULL, // MDL
  1898. SrvFsdOplockCompletionRoutine
  1899. );
  1900. (VOID)IoCallDriver(
  1901. Rfcb->Lfcb->DeviceObject,
  1902. Rfcb->Irp
  1903. );
  1904. } // SrvAcknowledgeOplockBreak
  1905. VOID
  1906. TimeoutLockRequest (
  1907. IN PKDPC Dpc,
  1908. IN PVOID DeferredContext,
  1909. IN PVOID SystemArgument1,
  1910. IN PVOID SystemArgument2
  1911. )
  1912. {
  1913. PSRV_TIMER timer;
  1914. //
  1915. // A lock request has been waiting too long. Cancel it.
  1916. //
  1917. IoCancelIrp( ((PWORK_CONTEXT)DeferredContext)->Irp );
  1918. //
  1919. // Set the event indicating that the timer routine is done.
  1920. //
  1921. timer = CONTAINING_RECORD( Dpc, SRV_TIMER, Dpc );
  1922. KeSetEvent( &timer->Event, 0, FALSE );
  1923. return;
  1924. }