Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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