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.

1326 lines
31 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. Lock.c
  5. Abstract:
  6. This module implements the Lock routine for the NetWare redirector.
  7. Notes on the implementation of locks.
  8. o Netware servers handle lock conflicts differently than a LAN Man
  9. server, or NT file system would. In particular:
  10. - A lock conflict on a single file handle (i.e. the same app owns
  11. the lock, and is trying to obtain a conflicting lock): The
  12. netware server will fail the request only if the lock range is
  13. identical to a held lock. Also, the lock fails immediately, even
  14. if the app requested a blocking lock.
  15. - A lock conflict generated by 2 app from the same workstation:
  16. The server will fail the request if the request lock overlaps an
  17. existing lock by even a single byte, but the server will fail the
  18. request immediately, even if the app requested a blocking lock.
  19. - A lock conflict generated by 2 different workstations: This works
  20. as expected. The lock fails if it overlaps an existing lock, and
  21. the request blocks if requested by the app.
  22. o The NT workstation needs to impose NT file system behaviour when dealing
  23. with a netware server. There are 2 key elements (complications)
  24. added to the redirector to handle this.
  25. - A locally maintained lock database. This is used to test for
  26. lock conflicts locally. If a conflict is detected and the
  27. requestor asks for a blocking lock, the lock request is queued
  28. to a local lock conflict list. This list is processed when real
  29. locks are released.
  30. - A pending lock list. This is used to poll the netware server
  31. about remote lock conflicts. We could not let our lock request
  32. block indefinitely as this would tie up our one channel of
  33. communication to the server.
  34. o The data structures
  35. - NonPagedFcb
  36. -> FileLockList - The list of existing locks.
  37. -> PendingLockList - The list of locks pending due to a
  38. local conflict.
  39. - NwPendingLockList
  40. The list of locks pending due to a remote conflict. The
  41. locks are retried indefinitely using a polling mechanism.
  42. A request can be removed from the pending list via (1) a
  43. cleanup for the correct ICB (2) the IRP can be cancelled.
  44. (3) The server actually grants the lock.
  45. o Other notes:
  46. We play some games to allow us to use the FCB resource as the
  47. synchronization mechanism, even though much processing happens
  48. at raised IRQL. Be careful not to break this.
  49. Author:
  50. Colin Watson [ColinW] 13-May-1993
  51. Manny Weiser [MannyW] 16-May-1993
  52. Revision History:
  53. --*/
  54. #include "Procs.h"
  55. //
  56. // The debug trace level
  57. //
  58. #define Dbg (DEBUG_TRACE_LOCKCTRL)
  59. NTSTATUS
  60. NwCommonLock(
  61. PIRP_CONTEXT pIrpContext
  62. );
  63. NTSTATUS
  64. LockNcp(
  65. PIRP_CONTEXT IrpContext,
  66. PICB Icb
  67. );
  68. NTSTATUS
  69. LockNcpCallback (
  70. IN PIRP_CONTEXT IrpContext,
  71. IN ULONG BytesAvailable,
  72. IN PUCHAR Response
  73. );
  74. NTSTATUS
  75. UnlockNcpCallback (
  76. IN PIRP_CONTEXT IrpContext,
  77. IN ULONG BytesAvailable,
  78. IN PUCHAR Response
  79. );
  80. BOOLEAN
  81. LockIsOverlapping(
  82. PNONPAGED_FCB pNpFcb,
  83. LONG StartFileOffset,
  84. ULONG Length
  85. );
  86. VOID
  87. AddLockToFcb(
  88. PNONPAGED_FCB pNpFcb,
  89. PNW_FILE_LOCK FileLock
  90. );
  91. VOID
  92. RemoveLockFromFcb(
  93. PNONPAGED_FCB pNpFcb,
  94. PNW_FILE_LOCK FileLock
  95. );
  96. VOID
  97. ReattemptPendingLocks(
  98. PNONPAGED_FCB pNpFcb
  99. );
  100. BOOLEAN
  101. LockExists(
  102. PNONPAGED_FCB pNpFcb,
  103. LONG StartOffset,
  104. ULONG Length,
  105. PNW_FILE_LOCK *FileLock
  106. );
  107. NTSTATUS
  108. UnlockIcbLocks(
  109. PIRP_CONTEXT pIrpContext
  110. );
  111. #ifdef ALLOC_PRAGMA
  112. #pragma alloc_text( PAGE, NwFsdLockControl )
  113. #pragma alloc_text( PAGE, NwCommonLock )
  114. #pragma alloc_text( PAGE, LockNcp )
  115. #pragma alloc_text( PAGE, LockIsOverlapping )
  116. #pragma alloc_text( PAGE, NwFreeLocksForIcb )
  117. #pragma alloc_text( PAGE, UnlockIcbLocks )
  118. #ifndef QFE_BUILD
  119. #pragma alloc_text( PAGE1, LockNcpCallback )
  120. #pragma alloc_text( PAGE1, UnlockNcpCallback )
  121. #pragma alloc_text( PAGE1, AddLockToFcb )
  122. #pragma alloc_text( PAGE1, RemoveLockFromFcb )
  123. #pragma alloc_text( PAGE1, ReattemptPendingLocks )
  124. #pragma alloc_text( PAGE1, LockExists )
  125. #endif
  126. #endif
  127. #if 0 // Not pageable
  128. // see ifndef QFE_BUILD above
  129. #endif
  130. NTSTATUS
  131. NwFsdLockControl (
  132. IN PDEVICE_OBJECT DeviceObject,
  133. IN PIRP Irp
  134. )
  135. /*++
  136. Routine Description:
  137. This routine implements the FSD part of the NtCreateFile and NtOpenFile
  138. API calls.
  139. Arguments:
  140. DeviceObject - Supplies the device object for the redirector.
  141. Irp - Supplies the Irp being processed
  142. Return Value:
  143. NTSTATUS - The Fsd status for the Irp
  144. --*/
  145. {
  146. NTSTATUS Status;
  147. PIRP_CONTEXT IrpContext = NULL;
  148. BOOLEAN TopLevel;
  149. PAGED_CODE();
  150. TimerStart(Dbg);
  151. DebugTrace(+1, Dbg, "NwFsdLockControl\n", 0);
  152. //
  153. // Call the common lock routine, with block allowed if the operation
  154. // is synchronous.
  155. //
  156. FsRtlEnterFileSystem();
  157. TopLevel = NwIsIrpTopLevel( Irp );
  158. try {
  159. IrpContext = AllocateIrpContext( Irp );
  160. Status = NwCommonLock( IrpContext );
  161. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  162. if ( IrpContext == NULL ) {
  163. //
  164. // If we couldn't allocate an irp context, just complete
  165. // irp without any fanfare.
  166. //
  167. Status = STATUS_INSUFFICIENT_RESOURCES;
  168. Irp->IoStatus.Status = Status;
  169. Irp->IoStatus.Information = 0;
  170. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  171. } else {
  172. //
  173. // We had some trouble trying to perform the requested
  174. // operation, so we'll abort the I/O request with
  175. // the error Status that we get back from the
  176. // execption code
  177. //
  178. Status = NwProcessException( IrpContext, GetExceptionCode() );
  179. }
  180. }
  181. if ( IrpContext ) {
  182. NwCompleteRequest( IrpContext, Status );
  183. }
  184. if ( TopLevel ) {
  185. NwSetTopLevelIrp( NULL );
  186. }
  187. FsRtlExitFileSystem();
  188. //
  189. // And return to our caller
  190. //
  191. DebugTrace(-1, Dbg, "NwFsdLock -> %08lx\n", Status );
  192. TimerStop(Dbg,"NwFsdLockControl");
  193. return Status;
  194. UNREFERENCED_PARAMETER(DeviceObject);
  195. }
  196. NTSTATUS
  197. NwCommonLock (
  198. IN PIRP_CONTEXT IrpContext
  199. )
  200. /*++
  201. Routine Description:
  202. This routine does the common code for NtLockFile/NtUnlockFile.
  203. Arguments:
  204. IrpContext - Supplies the request being processed.
  205. Return Value:
  206. NTSTATUS - The return status for the operation
  207. --*/
  208. {
  209. NTSTATUS status;
  210. PIRP Irp;
  211. PIO_STACK_LOCATION irpSp;
  212. NODE_TYPE_CODE nodeTypeCode;
  213. PICB icb;
  214. PFCB fcb;
  215. PVOID fsContext;
  216. PAGED_CODE();
  217. //
  218. // Get the current stack location
  219. //
  220. Irp = IrpContext->pOriginalIrp;
  221. irpSp = IoGetCurrentIrpStackLocation( Irp );
  222. DebugTrace(+1, Dbg, "CommonLock...\n", 0);
  223. DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
  224. //
  225. // Decode the file object to figure out who we are. If the result
  226. // is not the root DCB then its an illegal parameter.
  227. //
  228. nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
  229. &fsContext,
  230. (PVOID *)&icb );
  231. if (nodeTypeCode != NW_NTC_ICB) {
  232. DebugTrace(0, Dbg, "Not a file\n", 0);
  233. status = STATUS_INVALID_PARAMETER;
  234. DebugTrace(-1, Dbg, "CommonLock -> %08lx\n", status );
  235. return status;
  236. }
  237. //
  238. // Make sure that this ICB is still active.
  239. //
  240. NwVerifyIcb( icb );
  241. fcb = (PFCB)icb->SuperType.Fcb;
  242. nodeTypeCode = fcb->NodeTypeCode;
  243. if (nodeTypeCode == NW_NTC_FCB ) {
  244. IrpContext->pScb = fcb->Scb;
  245. IrpContext->pNpScb = IrpContext->pScb->pNpScb;
  246. IrpContext->Icb = icb;
  247. } else {
  248. DebugTrace(0, Dbg, "Not a file\n", 0);
  249. status = STATUS_INVALID_PARAMETER;
  250. DebugTrace(-1, Dbg, "CommonLock -> %08lx\n", status );
  251. return status;
  252. }
  253. switch (irpSp->MinorFunction) {
  254. case IRP_MN_LOCK:
  255. case IRP_MN_UNLOCK_SINGLE:
  256. case IRP_MN_UNLOCK_ALL:
  257. case IRP_MN_UNLOCK_ALL_BY_KEY:
  258. status = LockNcp( IrpContext, icb );
  259. break;
  260. default:
  261. //
  262. // Minor function added to I/O system that this driver does
  263. // not understand.
  264. //
  265. status = STATUS_INVALID_PARAMETER;
  266. }
  267. DebugTrace(-1, Dbg, "CommonLock -> %08lx\n", status);
  268. return status;
  269. }
  270. NTSTATUS
  271. LockNcp(
  272. PIRP_CONTEXT IrpContext,
  273. PICB Icb
  274. )
  275. /*++
  276. Routine Description:
  277. This routine exchanges a series of Lock NCPs with the server.
  278. Arguments:
  279. IrpContext - A pointer to IRP context information for this request.
  280. Icb - Supplies the file specific information.
  281. Return Value:
  282. Status of transfer.
  283. --*/
  284. {
  285. PIRP irp;
  286. PIO_STACK_LOCATION irpSp;
  287. LARGE_INTEGER ByteOffset;
  288. LARGE_INTEGER Length;
  289. ULONG Key;
  290. PSCB pScb;
  291. PNONPAGED_FCB pNpFcb;
  292. NTSTATUS status = STATUS_UNSUCCESSFUL;
  293. PNW_FILE_LOCK FileLock = NULL;
  294. USHORT LockFlags = 3;
  295. PAGED_CODE();
  296. irp = IrpContext->pOriginalIrp;
  297. irpSp = IoGetCurrentIrpStackLocation( irp );
  298. ByteOffset = irpSp->Parameters.LockControl.ByteOffset;
  299. if ( irpSp->Parameters.LockControl.Length != NULL ) {
  300. Length = *irpSp->Parameters.LockControl.Length;
  301. } else {
  302. Length.HighPart = 0;
  303. Length.LowPart = 0;
  304. }
  305. Key = irpSp->Parameters.LockControl.Key;
  306. DebugTrace(+1, Dbg, "LockNcp...\n", 0);
  307. DebugTrace( 0, Dbg, "irp = %08lx\n", (ULONG_PTR)irp);
  308. DebugTrace( 0, Dbg, "MinorFun= %08lx\n", (ULONG)irpSp->MinorFunction);
  309. DebugTrace( 0, Dbg, "File = %wZ\n", &Icb->SuperType.Fcb->FullFileName);
  310. DebugTrace( 0, Dbg, "HOffset = %lx\n", ByteOffset.HighPart);
  311. DebugTrace( 0, Dbg, "LOffset = %lx\n", ByteOffset.LowPart);
  312. DebugTrace( 0, Dbg, "HLength = %lx\n", Length.HighPart);
  313. DebugTrace( 0, Dbg, "LLength = %lx\n", Length.LowPart);
  314. DebugTrace( 0, Dbg, "Key = %lx\n", Key);
  315. pScb = Icb->SuperType.Fcb->Scb;
  316. ASSERT (pScb->NodeTypeCode == NW_NTC_SCB);
  317. pNpFcb = Icb->SuperType.Fcb->NonPagedFcb;
  318. //
  319. // Get to the front of the ScbQueue to protect access to the lock list.
  320. //
  321. NwAppendToQueueAndWait( IrpContext );
  322. try {
  323. switch ( irpSp->MinorFunction ) {
  324. case IRP_MN_LOCK:
  325. //
  326. // Since we are doing a lock we will need to send an End Of Job
  327. // for this PID.
  328. //
  329. NwSetEndOfJobRequired( pScb->pNpScb, Icb->Pid );
  330. //
  331. // Try to allocate a lock structure before we ask the
  332. // server to perform the lock.
  333. //
  334. FileLock = ALLOCATE_POOL_EX( NonPagedPool, sizeof( NW_FILE_LOCK ) );
  335. IrpContext->Specific.Lock.FileLock = FileLock;
  336. FileLock->NodeTypeCode = NW_NTC_FILE_LOCK;
  337. FileLock->NodeByteSize = sizeof( NW_FILE_LOCK );
  338. FileLock->StartFileOffset = ByteOffset.LowPart;
  339. FileLock->Length = Length.LowPart;
  340. FileLock->EndFileOffset = ByteOffset.LowPart + Length.LowPart - 1;
  341. FileLock->Key = Key;
  342. FileLock->Icb = Icb;
  343. FileLock->IrpContext = IrpContext;
  344. //
  345. // Remember the originating process because NT locks
  346. // have PROCESS level granularity!!
  347. //
  348. FileLock->pOwnerProc = PsGetCurrentProcessId();
  349. if ( irpSp->Flags & SL_EXCLUSIVE_LOCK ) {
  350. LockFlags = 0x00;
  351. } else {
  352. LockFlags = 0x02;
  353. }
  354. FileLock->Flags = LockFlags;
  355. //
  356. // Is this is an overlapping lock
  357. //
  358. if ( irpSp->Flags & SL_FAIL_IMMEDIATELY ) {
  359. IrpContext->Specific.Lock.Wait = FALSE;
  360. } else {
  361. IrpContext->Specific.Lock.Wait = TRUE;
  362. }
  363. if ( LockIsOverlapping( pNpFcb, ByteOffset.LowPart, Length.LowPart ) ) {
  364. if ( IrpContext->Specific.Lock.Wait ) {
  365. //
  366. // Queue this IRP context to the FCB. We'll process it
  367. // when the local conflict is removed.
  368. //
  369. InsertTailList( &pNpFcb->PendingLockList, &FileLock->ListEntry );
  370. status = STATUS_PENDING;
  371. NwDequeueIrpContext( IrpContext, FALSE );
  372. } else {
  373. status = STATUS_FILE_LOCK_CONFLICT;
  374. }
  375. } else {
  376. //
  377. // Send the lock request.
  378. //
  379. status = Exchange (
  380. IrpContext,
  381. LockNcpCallback,
  382. "Fbrddw",
  383. NCP_LOCK_RANGE,
  384. LockFlags | 0x01,
  385. Icb->Handle, sizeof( Icb->Handle ),
  386. ByteOffset.LowPart,
  387. Length.LowPart,
  388. LockTimeoutThreshold );
  389. }
  390. break;
  391. case IRP_MN_UNLOCK_SINGLE:
  392. if ( !LockExists( pNpFcb, ByteOffset.LowPart, Length.LowPart, &FileLock ) ) {
  393. status = STATUS_RANGE_NOT_LOCKED;
  394. } else {
  395. //
  396. // Verify that this lock belongs to this process.
  397. //
  398. if ( FileLock->pOwnerProc != PsGetCurrentProcessId() ) {
  399. DebugTrace( 0, Dbg, "Unlock process not owner!\n", 0 );
  400. status = STATUS_ACCESS_DENIED;
  401. //
  402. // Ensure that we don't free the filelock
  403. //
  404. FileLock = NULL;
  405. } else {
  406. IrpContext->Specific.Lock.FileLock = FileLock;
  407. status = Exchange (
  408. IrpContext,
  409. UnlockNcpCallback,
  410. "F-rddw",
  411. NCP_UNLOCK_RANGE,
  412. Icb->Handle, sizeof( Icb->Handle ),
  413. ByteOffset.LowPart,
  414. Length.LowPart,
  415. 1 );
  416. }
  417. }
  418. break;
  419. case IRP_MN_UNLOCK_ALL:
  420. IrpContext->Icb = Icb;
  421. IrpContext->Specific.Lock.ByKey = FALSE ;
  422. status = UnlockIcbLocks( IrpContext );
  423. break;
  424. case IRP_MN_UNLOCK_ALL_BY_KEY:
  425. IrpContext->Icb = Icb;
  426. IrpContext->Specific.Lock.Key = Key ;
  427. IrpContext->Specific.Lock.ByKey = TRUE ;
  428. status = UnlockIcbLocks( IrpContext );
  429. break;
  430. }
  431. } finally {
  432. if ( AbnormalTermination() || !NT_SUCCESS( status ) ) {
  433. if ( FileLock != NULL ) {
  434. FREE_POOL( FileLock );
  435. }
  436. NwDequeueIrpContext( IrpContext, FALSE );
  437. }
  438. }
  439. DebugTrace(-1, Dbg, "LockNcb -> %08lx\n", status );
  440. return status;
  441. }
  442. NTSTATUS
  443. LockNcpCallback (
  444. IN PIRP_CONTEXT IrpContext,
  445. IN ULONG BytesAvailable,
  446. IN PUCHAR Response
  447. )
  448. /*++
  449. Routine Description:
  450. This routine receives the response from a user NCP.
  451. Arguments:
  452. Return Value:
  453. VOID
  454. --*/
  455. {
  456. NTSTATUS Status;
  457. PIRP Irp;
  458. PIO_STACK_LOCATION irpSp;
  459. DebugTrace(+1, Dbg, "LockNcpCallback...\n", 0);
  460. if ( BytesAvailable == 0) {
  461. //
  462. // No response from server. Status is in pIrpContext->
  463. // ResponseParameters.Error
  464. //
  465. FREE_POOL( IrpContext->Specific.Lock.FileLock );
  466. NwDequeueIrpContext( IrpContext, FALSE );
  467. NwCompleteRequest( IrpContext, STATUS_REMOTE_NOT_LISTENING );
  468. DebugTrace(-1, Dbg, "LockNcpCallback -> %08lx\n", STATUS_REMOTE_NOT_LISTENING);
  469. return STATUS_REMOTE_NOT_LISTENING;
  470. }
  471. Irp = IrpContext->pOriginalIrp;
  472. irpSp = IoGetCurrentIrpStackLocation( Irp );
  473. Status = ParseResponse( IrpContext, Response, BytesAvailable, "N" );
  474. if (NT_SUCCESS(Status) ) {
  475. DebugTrace(0, Dbg, "Lock successfully applied\n", 0);
  476. //
  477. // Record this lock in the Icb lock chain
  478. //
  479. AddLockToFcb(
  480. IrpContext->Icb->NpFcb,
  481. IrpContext->Specific.Lock.FileLock );
  482. } else if ( Status == STATUS_FILE_LOCK_CONFLICT &&
  483. IrpContext->Specific.Lock.Wait ) {
  484. DebugTrace(0, Dbg, "Lock conflict, adding %08lx to Pending Lock list\n", IrpContext );
  485. //
  486. // The lock conflicts with an existing lock, but the app wants
  487. // to wait. Queue the request to the pending lock list and
  488. // return, pending.
  489. //
  490. NwDequeueIrpContext( IrpContext, FALSE );
  491. IrpContext->Specific.Lock.Key = 5;
  492. ExInterlockedInsertTailList(
  493. &NwPendingLockList,
  494. &IrpContext->NextRequest,
  495. &NwPendingLockSpinLock );
  496. Status = STATUS_PENDING;
  497. DebugTrace(-1, Dbg, "LockNcpCallback -> %08lx\n", Status);
  498. return( Status );
  499. } else {
  500. //
  501. // Status unsuccesful is returned when trying to lock 0 bytes.
  502. // Map the error.
  503. //
  504. if ( Status == STATUS_UNSUCCESSFUL ) {
  505. DebugTrace(-1, Dbg, "Locklength -> %08lx\n",IrpContext->Specific.Lock.FileLock->Length );
  506. if (IrpContext->Specific.Lock.FileLock->Length == 0) {
  507. Status = STATUS_INVALID_PARAMETER;
  508. }
  509. }
  510. FREE_POOL( IrpContext->Specific.Lock.FileLock );
  511. }
  512. //
  513. // If any locks were pending due to a local lock conflict, try
  514. // them now.
  515. //
  516. ReattemptPendingLocks(IrpContext->Icb->NpFcb);
  517. //
  518. // We're done with this request. Dequeue the IRP context from
  519. // SCB and complete the request.
  520. //
  521. NwDequeueIrpContext( IrpContext, FALSE );
  522. NwCompleteRequest( IrpContext, Status );
  523. DebugTrace(-1, Dbg, "LockNcpCallback -> %08lx\n", Status);
  524. return Status;
  525. }
  526. NTSTATUS
  527. UnlockNcpCallback (
  528. IN PIRP_CONTEXT IrpContext,
  529. IN ULONG BytesAvailable,
  530. IN PUCHAR Response
  531. )
  532. /*++
  533. Routine Description:
  534. This routine receives the response from a user NCP.
  535. Arguments:
  536. Return Value:
  537. VOID
  538. --*/
  539. {
  540. NTSTATUS Status;
  541. PIRP Irp;
  542. PIO_STACK_LOCATION irpSp;
  543. DebugTrace(0, Dbg, "UnlockNcpCallback...\n", 0);
  544. //
  545. // Remove this lock in the Fcb lock chain, regardlesss of the status
  546. // of the IO.
  547. //
  548. RemoveLockFromFcb(
  549. IrpContext->Icb->NpFcb,
  550. IrpContext->Specific.Lock.FileLock );
  551. FREE_POOL( IrpContext->Specific.Lock.FileLock );
  552. //
  553. // If any locks were pending due to a local lock conflict, try
  554. // them now.
  555. //
  556. ReattemptPendingLocks(IrpContext->Icb->NpFcb);
  557. if ( BytesAvailable == 0) {
  558. //
  559. // No response from server. Status is in pIrpContext->
  560. // ResponseParameters.Error
  561. //
  562. NwDequeueIrpContext( IrpContext, FALSE );
  563. NwCompleteRequest( IrpContext, STATUS_REMOTE_NOT_LISTENING );
  564. return STATUS_REMOTE_NOT_LISTENING;
  565. }
  566. Irp = IrpContext->pOriginalIrp;
  567. irpSp = IoGetCurrentIrpStackLocation( Irp );
  568. Status = ParseResponse( IrpContext, Response, BytesAvailable, "N" );
  569. if (!NT_SUCCESS( Status )) {
  570. Error(
  571. EVENT_NWRDR_FAILED_UNLOCK,
  572. Status,
  573. NULL,
  574. 0,
  575. 1,
  576. IrpContext->pNpScb->ServerName.Buffer );
  577. }
  578. //
  579. // We're done with this request. Dequeue the IRP context from
  580. // SCB and complete the request.
  581. //
  582. NwDequeueIrpContext( IrpContext, FALSE );
  583. NwCompleteRequest( IrpContext, Status );
  584. return STATUS_SUCCESS;
  585. }
  586. BOOLEAN
  587. LockIsOverlapping(
  588. PNONPAGED_FCB pNpFcb,
  589. LONG StartFileOffset,
  590. ULONG Length
  591. )
  592. /*++
  593. Routine Description:
  594. This routine tests to see if the requested lock would overlap an
  595. existing lock.
  596. *** This routine must be called at the front of the queue.
  597. Arguments:
  598. pNpFcb - The FCB of the file being locked.
  599. StartFileOffset - The first byte in the range to lock.
  600. Length - The number of bytes to lock.
  601. Return Value:
  602. TRUE - This lock overlaps an existing lock.
  603. FALSE - This lock does not overlap an existing lock.
  604. --*/
  605. {
  606. PLIST_ENTRY ListEntry;
  607. PNW_FILE_LOCK pFileLock;
  608. LONG EndFileOffset = StartFileOffset + Length - 1;
  609. PAGED_CODE();
  610. if ( Length == 0 ) {
  611. return( FALSE );
  612. }
  613. for ( ListEntry = pNpFcb->FileLockList.Flink;
  614. ListEntry != &pNpFcb->FileLockList;
  615. ListEntry = ListEntry->Flink ) {
  616. pFileLock = CONTAINING_RECORD( ListEntry, NW_FILE_LOCK, ListEntry );
  617. //
  618. // Stop the search if the current lock starts before the potential
  619. // new lock ends.
  620. //
  621. if ( pFileLock->StartFileOffset > EndFileOffset ) {
  622. break;
  623. }
  624. //
  625. // The new lock overlaps if it starts of ends in the middle of
  626. // an existing lock.
  627. //
  628. if (( StartFileOffset >= pFileLock->StartFileOffset &&
  629. StartFileOffset <= pFileLock->EndFileOffset )
  630. ||
  631. ( EndFileOffset >= pFileLock->StartFileOffset &&
  632. EndFileOffset <= pFileLock->EndFileOffset ) ) {
  633. DebugTrace(0, Dbg, "Lock is overlapping\n", 0);
  634. return( TRUE );
  635. }
  636. }
  637. DebugTrace(0, Dbg, "Lock is NOT overlapping\n", 0);
  638. return( FALSE );
  639. }
  640. VOID
  641. AddLockToFcb(
  642. PNONPAGED_FCB pNpFcb,
  643. PNW_FILE_LOCK FileLock
  644. )
  645. /*++
  646. Routine Description:
  647. This routine inserts a lock structure into the ordered list of locks
  648. for this ICB.
  649. *** This routine must be called when at the front of the ScbQueue.
  650. Arguments:
  651. NpFcb - The non paged FCB of file that is being locked.
  652. FileLock - The file lock structure to insert.
  653. Return Value:
  654. None.
  655. --*/
  656. {
  657. PLIST_ENTRY ListEntry;
  658. PNW_FILE_LOCK pFileLock;
  659. LONG StartFileOffset = FileLock->StartFileOffset;
  660. LONG EndFileOffset = FileLock->EndFileOffset;
  661. DebugTrace(0, Dbg, "Adding Lock to FCB %08lx\n", pNpFcb);
  662. DebugTrace(0, Dbg, "Lock is %08lx\n", FileLock );
  663. if ( IsListEmpty( &pNpFcb->FileLockList ) ) {
  664. InsertHeadList( &pNpFcb->FileLockList, &FileLock->ListEntry );
  665. return;
  666. }
  667. for ( ListEntry = pNpFcb->FileLockList.Flink;
  668. ListEntry != &pNpFcb->FileLockList;
  669. ListEntry = ListEntry->Flink ) {
  670. pFileLock = CONTAINING_RECORD( ListEntry, NW_FILE_LOCK, ListEntry );
  671. //
  672. // Stop the search if the current lock starts after the
  673. // new lock ends.
  674. //
  675. if ( pFileLock->StartFileOffset > EndFileOffset ) {
  676. break;
  677. }
  678. }
  679. //
  680. // Insert the file lock into the ordered list.
  681. //
  682. InsertTailList( ListEntry, &FileLock->ListEntry );
  683. }
  684. VOID
  685. RemoveLockFromFcb(
  686. PNONPAGED_FCB pNpFcb,
  687. PNW_FILE_LOCK FileLock
  688. )
  689. /*++
  690. Routine Description:
  691. This routine removes a lock structure from the ordered list of locks
  692. for this FCB.
  693. *** This routine must be called when at the front of the ScbQueue.
  694. Arguments:
  695. pNpFcb - The non paged FCB of file that is being unlocked.
  696. FileLock - The file lock structure to remove.
  697. Return Value:
  698. None.
  699. --*/
  700. {
  701. #if DBG
  702. PNW_FILE_LOCK foundFileLock;
  703. #endif
  704. DebugTrace(0, Dbg, "Removing Lock from FCB %08lx\n", pNpFcb);
  705. DebugTrace(0, Dbg, "Lock is %08lx\n", FileLock );
  706. ASSERT( LockExists( pNpFcb, FileLock->StartFileOffset, FileLock->Length, &foundFileLock ) );
  707. ASSERT( foundFileLock == FileLock );
  708. RemoveEntryList( &FileLock->ListEntry );
  709. return;
  710. }
  711. VOID
  712. ReattemptPendingLocks(
  713. PNONPAGED_FCB pNpFcb
  714. )
  715. /*++
  716. Routine Description:
  717. This routine reattempts locks that are pending due to a local lock
  718. conflict.
  719. *** This routine must be called when at the front of the ScbQueue.
  720. Arguments:
  721. pNpFcb - The non paged FCB of file that is being processed.
  722. Return Value:
  723. None.
  724. --*/
  725. {
  726. PLIST_ENTRY listEntry, nextListEntry;
  727. PNW_FILE_LOCK fileLock;
  728. NTSTATUS status;
  729. DebugTrace(+1, Dbg, "ReattemptPendingLocks...\n", 0);
  730. //
  731. // Run the list of pending locks.
  732. //
  733. for ( listEntry = pNpFcb->PendingLockList.Flink;
  734. listEntry != &pNpFcb->PendingLockList;
  735. listEntry = nextListEntry ) {
  736. nextListEntry = listEntry->Flink;
  737. fileLock = CONTAINING_RECORD( listEntry, NW_FILE_LOCK, ListEntry );
  738. if ( !LockIsOverlapping( pNpFcb, fileLock->StartFileOffset, fileLock->Length ) ) {
  739. //
  740. // It is now safe to try this lock.
  741. //
  742. RemoveEntryList( listEntry );
  743. DebugTrace(0, Dbg, "Reattempt lock %08lx\n", fileLock->IrpContext);
  744. status = Exchange (
  745. fileLock->IrpContext,
  746. LockNcpCallback,
  747. "Fbrddw",
  748. NCP_LOCK_RANGE,
  749. fileLock->Flags | 0x01,
  750. fileLock->Icb->Handle, sizeof( fileLock->Icb->Handle ),
  751. fileLock->StartFileOffset,
  752. fileLock->Length,
  753. LockTimeoutThreshold );
  754. if ( !NT_SUCCESS( status ) ) {
  755. NwDequeueIrpContext( fileLock->IrpContext, FALSE );
  756. NwCompleteRequest( fileLock->IrpContext, status );
  757. FREE_POOL( fileLock );
  758. } else if ( status == STATUS_PENDING ) {
  759. DebugTrace(-1, Dbg, "ReattemptPendingLocks\n", 0);
  760. return;
  761. }
  762. }
  763. }
  764. DebugTrace(-1, Dbg, "ReattemptPendingLocks\n", 0);
  765. return;
  766. }
  767. BOOLEAN
  768. LockExists(
  769. PNONPAGED_FCB pNpFcb,
  770. LONG StartOffset,
  771. ULONG Length,
  772. PNW_FILE_LOCK *FileLock
  773. )
  774. /*++
  775. Routine Description:
  776. This routine test whether or not a lock is owned for this ICB.
  777. *** This routine must be called when at the front of the ScbQueue.
  778. Arguments:
  779. pNpFcb - The non paged FCB of file that is being locked.
  780. StartOffset - The starting file offset of the lock.
  781. Length - The number of bytes to lock.
  782. FileLock - Returns a pointer to the FileLock structure if it was found.
  783. Return Value:
  784. TRUE - This lock is being held for this ICB.
  785. FALSE - This lock is NOT being held for this ICB.
  786. --*/
  787. {
  788. PLIST_ENTRY ListEntry;
  789. PNW_FILE_LOCK pFileLock;
  790. LONG EndOffset = StartOffset + Length - 1;
  791. for ( ListEntry = pNpFcb->FileLockList.Flink;
  792. ListEntry != &pNpFcb->FileLockList;
  793. ListEntry = ListEntry->Flink ) {
  794. pFileLock = CONTAINING_RECORD( ListEntry, NW_FILE_LOCK, ListEntry );
  795. //
  796. // Search for the lock that exactly matches this one.
  797. //
  798. if ( pFileLock->StartFileOffset == StartOffset &&
  799. pFileLock->EndFileOffset == EndOffset ) {
  800. *FileLock = pFileLock;
  801. DebugTrace(0, Dbg, "Found lock\n", 0);
  802. return( TRUE );
  803. }
  804. }
  805. *FileLock = NULL;
  806. DebugTrace(0, Dbg, "Could not find lock\n", 0);
  807. return( FALSE );
  808. }
  809. NTSTATUS
  810. UnlockIcbLocks(
  811. PIRP_CONTEXT pIrpContext
  812. )
  813. /*++
  814. Routine Description:
  815. This routine unlocks the first lock for an ICB.
  816. *** This routine must be called when at the front of the ScbQueue.
  817. Arguments:
  818. IrpContext - A pointer to the IRP context pointers for this request.
  819. Return Value:
  820. None.
  821. --*/
  822. {
  823. PICB pIcb;
  824. PNW_FILE_LOCK pFileLock;
  825. PLIST_ENTRY pLockEntry;
  826. NTSTATUS Status;
  827. PNONPAGED_FCB pNpFcb;
  828. PVOID pLockProc;
  829. DebugTrace(+1, Dbg, "UnlockIcbLocks...\n", 0);
  830. pIcb = pIrpContext->Icb;
  831. pNpFcb = pIcb->NpFcb;
  832. pLockEntry = &pNpFcb->FileLockList;
  833. pLockProc = PsGetCurrentProcessId();
  834. DebugTrace(0, Dbg, "UnlockIcbLocks: current process is %08lx.\n", pLockProc);
  835. while ( pLockEntry->Flink != &pNpFcb->FileLockList ) {
  836. pFileLock = CONTAINING_RECORD( pLockEntry->Flink, NW_FILE_LOCK, ListEntry );
  837. //
  838. // If this lock isn't for this process, skip it.
  839. //
  840. if ( pFileLock->pOwnerProc != pLockProc ) {
  841. DebugTrace(0, Dbg, "Skipping lock %08lx, not for this process.\n", pLockEntry);
  842. pLockEntry = pLockEntry->Flink;
  843. continue;
  844. }
  845. //
  846. // If we're unlocking by key and the key doesn't match, skip it.
  847. //
  848. if ( ( pIrpContext->Specific.Lock.ByKey ) &&
  849. ( pFileLock->Key != pIrpContext->Specific.Lock.Key ) ) {
  850. DebugTrace(0, Dbg, "Skipping lock %08lx, bad key.\n", pLockEntry);
  851. pLockEntry = pLockEntry->Flink;
  852. continue;
  853. }
  854. //
  855. // Otherwise, Do our best to free the lock.
  856. //
  857. DebugTrace(0, Dbg, "Freeing lock %08lx.\n", pLockEntry);
  858. RemoveEntryList( &pFileLock->ListEntry );
  859. Status = ExchangeWithWait (
  860. pIrpContext,
  861. SynchronousResponseCallback,
  862. "F-rddw",
  863. NCP_UNLOCK_RANGE,
  864. pIcb->Handle, sizeof( pIcb->Handle ),
  865. pFileLock->StartFileOffset,
  866. pFileLock->Length,
  867. 1 );
  868. FREE_POOL( pFileLock );
  869. pLockEntry = pLockEntry->Flink;
  870. }
  871. //
  872. // We are finished.
  873. //
  874. DebugTrace(-1, Dbg, "UnlockIcbLocks -> %08lx\n", 0);
  875. NwDequeueIrpContext( pIrpContext, FALSE );
  876. return STATUS_SUCCESS;
  877. }
  878. VOID
  879. NwFreeLocksForIcb(
  880. IN PIRP_CONTEXT pIrpContext,
  881. PICB Icb
  882. )
  883. /*++
  884. Routine Description:
  885. This routine unlocks all locks held for a specific ICB.
  886. Because its only called from Cleanup prior to a close we can
  887. simply free the internal structures. The server will clear the
  888. locks on the handle when it gets the close.
  889. Arguments:
  890. ICB - The ICB to free the locks for.
  891. Return Value:
  892. VOID
  893. --*/
  894. {
  895. PLIST_ENTRY listEntry, nextListEntry;
  896. PNW_FILE_LOCK pFileLock;
  897. PAGED_CODE();
  898. DebugTrace(+1, Dbg, "NwFreeLockForIcb...\n", 0);
  899. NwAppendToQueueAndWait( pIrpContext );
  900. for ( listEntry = Icb->NpFcb->FileLockList.Flink;
  901. listEntry != &Icb->NpFcb->FileLockList;
  902. listEntry = nextListEntry ) {
  903. nextListEntry = listEntry->Flink;
  904. pFileLock = CONTAINING_RECORD(
  905. listEntry,
  906. NW_FILE_LOCK,
  907. ListEntry );
  908. if ( pFileLock->Icb == Icb ) {
  909. RemoveEntryList( listEntry );
  910. FREE_POOL( pFileLock );
  911. DebugTrace( 0, Dbg, "Freed lock %08lx\n", pFileLock );
  912. }
  913. }
  914. ReattemptPendingLocks( Icb->NpFcb );
  915. DebugTrace(-1, Dbg, "NwFreeLockForIcb -> VOID\n", 0);
  916. }