Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1076 lines
36 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. LockCtrl.c
  5. Abstract:
  6. This module implements the Lock Control routines for Rx called
  7. by the dispatch driver.
  8. Author:
  9. Joe Linn [JoeLinn] 9-Nov-1994
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_LOCKCTRL)
  18. NTSTATUS
  19. RxLowIoLockControlShellCompletion (
  20. IN PRX_CONTEXT RxContext
  21. );
  22. NTSTATUS
  23. RxLockOperationCompletionWithAcquire (
  24. IN PRX_CONTEXT RxContext,
  25. IN PIRP Irp
  26. );
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text(PAGE, RxCommonLockControl)
  29. #pragma alloc_text(PAGE, RxLockOperationCompletion)
  30. #pragma alloc_text(PAGE, RxLockOperationCompletionWithAcquire)
  31. #pragma alloc_text(PAGE, RxUnlockOperation)
  32. #pragma alloc_text(PAGE, RxLowIoLockControlShellCompletion)
  33. #pragma alloc_text(PAGE, RxFinalizeLockList)
  34. #pragma alloc_text(PAGE, RxLowIoLockControlShell)
  35. #endif
  36. NTSTATUS
  37. RxCommonLockControl (
  38. IN PRX_CONTEXT RxContext,
  39. IN PIRP Irp
  40. )
  41. /*++
  42. Routine Description:
  43. This is the common routine for doing Lock control operations called
  44. by both the fsd and fsp threads
  45. Arguments:
  46. Irp - Supplies the Irp to process
  47. Return Value:
  48. RXSTATUS - The return status for the operation
  49. --*/
  50. {
  51. NTSTATUS Status;
  52. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  53. PFCB Fcb;
  54. PFOBX Fobx;
  55. NODE_TYPE_CODE TypeOfOpen;
  56. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  57. PAGED_CODE();
  58. TypeOfOpen = RxDecodeFileObject( IrpSp->FileObject, &Fcb, &Fobx );
  59. RxDbgTrace( +1, Dbg, ("RxCommonLockControl...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
  60. RxContext, Fobx, Fcb) );
  61. RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) );
  62. RxLog(( "Lock %lx %lx %lx %lx\n", RxContext, Fobx, Fcb, IrpSp->MinorFunction ));
  63. RxWmiLog( LOG,
  64. RxCommonLockControl_1,
  65. LOGPTR( RxContext )
  66. LOGPTR( Fobx )
  67. LOGPTR( Fcb )
  68. LOGUCHAR( IrpSp->MinorFunction ));
  69. //
  70. // If the file is not a user file open then we reject the request
  71. // as an invalid parameter
  72. //
  73. if (TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) {
  74. RxDbgTrace(-1, Dbg, ("RxCommonLockControl -> RxStatus(INVALID_PARAMETER\n)", 0));
  75. return STATUS_INVALID_PARAMETER;
  76. }
  77. //
  78. // Acquire shared access to the Fcb and enqueue the Irp if we didn't
  79. // get access.
  80. //
  81. Status = RxAcquireSharedFcb( RxContext, Fcb );
  82. if (Status == STATUS_LOCK_NOT_GRANTED) {
  83. Status = RxFsdPostRequest( RxContext );
  84. RxDbgTrace(-1, Dbg, ("RxCommonLockControl -> %08lx\n", Status));
  85. return Status;
  86. } else if (Status != STATUS_SUCCESS) {
  87. RxDbgTrace(-1, Dbg, ("RxCommonLockControl -> error accquiring Fcb (%lx) %08lx\n", Fcb, Status));
  88. return Status;
  89. }
  90. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD );
  91. try {
  92. //
  93. // tell the buffering change guys that locks are outstanding
  94. //
  95. InterlockedIncrement( &Fcb->OutstandingLockOperationsCount );
  96. //
  97. // setup the bit telling the unlock routine whether to pitch or save the unlocks passed down
  98. // from fsrtl.
  99. //
  100. switch (IrpSp->MinorFunction) {
  101. case IRP_MN_LOCK:
  102. //
  103. // find out if this lock is realizable......if not, don't proceed........
  104. //
  105. if ((Fcb->MRxDispatch != NULL) && (Fcb->MRxDispatch->MRxIsLockRealizable != NULL)) {
  106. Status = Fcb->MRxDispatch->MRxIsLockRealizable( (PMRX_FCB)Fcb,
  107. &IrpSp->Parameters.LockControl.ByteOffset,
  108. IrpSp->Parameters.LockControl.Length,
  109. IrpSp->Flags );
  110. }
  111. if (Status != STATUS_SUCCESS) {
  112. try_return( Status );
  113. }
  114. if (!FlagOn( IrpSp->Flags, SL_FAIL_IMMEDIATELY )) {
  115. //
  116. // we cannot handout in the lock queue with the resource held
  117. //
  118. RxReleaseFcb( RxContext, Fcb );
  119. ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD );
  120. }
  121. break;
  122. case IRP_MN_UNLOCK_SINGLE:
  123. break;
  124. case IRP_MN_UNLOCK_ALL:
  125. case IRP_MN_UNLOCK_ALL_BY_KEY:
  126. SetFlag( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SAVEUNLOCKS );
  127. break;
  128. }
  129. //
  130. // Now call the FsRtl routine to do the actual processing of the
  131. // Lock request; take a reference before we go in that will be removed
  132. // by the LockOperationComplete guy.
  133. //
  134. RxLog(( "Inc RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  135. RxWmiLog( LOG,
  136. RxCommonLockControl_2,
  137. LOGPTR( RxContext )
  138. LOGULONG( RxContext->ReferenceCount ));
  139. InterlockedIncrement( &RxContext->ReferenceCount );
  140. //
  141. // Store the current thread id. in the lock manager context to
  142. // distinguisgh between the case when the request was pended in the
  143. // lock manager and the case when it was immediately satisfied.
  144. //
  145. InterlockedExchangePointer( &RxContext->LockManagerContext, PsGetCurrentThread() );
  146. try {
  147. Status = FsRtlProcessFileLock( &Fcb->FileLock,
  148. Irp,
  149. RxContext );
  150. } except(EXCEPTION_EXECUTE_HANDLER) {
  151. return RxProcessException( RxContext, GetExceptionCode() );
  152. }
  153. //
  154. // see bug: 514303
  155. //
  156. if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_OPERATION_COMPLETED )) {
  157. //
  158. // reset the status in order to force a completion
  159. //
  160. Status = STATUS_SUCCESS;
  161. }
  162. //
  163. // call the completion wrapper that reacquires the resource
  164. //
  165. if ((Status == STATUS_SUCCESS) &&
  166. !FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD )) {
  167. //
  168. // if we get queued then we have to keep the refcount up to prevent early finalization
  169. // from later in this routine. so take a reference here and set up to remove it
  170. // if we call down to lowio
  171. //
  172. RxLog(( "Inc RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  173. RxWmiLog( LOG,
  174. RxCommonLockControl_3,
  175. LOGPTR( RxContext )
  176. LOGULONG( RxContext->ReferenceCount ) );
  177. InterlockedIncrement( &RxContext->ReferenceCount );
  178. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_WAS_QUEUED_IN_LOCKMANAGER );
  179. Status = RxLockOperationCompletionWithAcquire( RxContext, Irp );
  180. if (Status != STATUS_PENDING) {
  181. //
  182. // take back the reference....didn't need it. this cannot
  183. // be the last one, so we just decrement
  184. //
  185. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext,__LINE__,RxContext->ReferenceCount ));
  186. RxWmiLog( LOG,
  187. RxCommonLockControl_4,
  188. LOGPTR( RxContext )
  189. LOGULONG( RxContext->ReferenceCount ) );
  190. InterlockedDecrement( &RxContext->ReferenceCount);
  191. }
  192. } else if (Status == STATUS_PENDING) {
  193. InterlockedExchangePointer( &RxContext->LockManagerContext, NULL );
  194. }
  195. try_exit: NOTHING;
  196. } finally {
  197. DebugUnwind( RxCommonLockControl );
  198. //
  199. // If resources have been acquired, release them under the right conditions.
  200. // the right conditions are these:
  201. // 1) if we have abnormal termination. here we obviously release the since no one else will.
  202. // 2) if the underlying call did not succeed: Status==Pending.
  203. // 3) if we posted the request
  204. // We also take away a opcount since the context is about to be completed.
  205. //
  206. if (AbnormalTermination() || (Status != STATUS_PENDING)) {
  207. if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD )) {
  208. InterlockedDecrement( &Fcb->OutstandingLockOperationsCount );
  209. //
  210. // If we have set the resource owner to the RxContext, then we have to call
  211. // ReleaseForThread.
  212. if( RESOURCE_OWNER_SET( LowIoContext->ResourceThreadId ) ) {
  213. RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  214. } else {
  215. RxReleaseFcb( RxContext, Fcb );
  216. }
  217. }
  218. } else {
  219. //
  220. // here the guy below is going to handle the completion....but, we
  221. // don't know the finish order....in all likelihood the deletecontext
  222. // call below just reduces the refcount but the guy may already have
  223. // finished in which case this will really delete the context.
  224. //
  225. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  226. RxWmiLog( LOG,
  227. RxCommonLockControl_5,
  228. LOGPTR( RxContext )
  229. LOGULONG( RxContext->ReferenceCount ));
  230. RxDereferenceAndDeleteRxContext( RxContext );
  231. }
  232. RxDbgTrace( -1, Dbg, ("RxCommonLockControl -> %08lx\n", Status) );
  233. } // finally
  234. return Status;
  235. }
  236. #define RDBSS_LOCK_MANAGER_REQUEST_RESUMED (IntToPtr(0xaaaaaaaa)) // Sundown: sign-extended.
  237. NTSTATUS
  238. RxLockOperationCompletion (
  239. IN PVOID Context,
  240. IN PIRP Irp
  241. )
  242. /*++
  243. Routine Description:
  244. This routine is called after the FSRTL lock package has processed a lock
  245. operation. If locks are not being held, we call down to the correct minirdr
  246. routine. BTW, we do not actually complete the packet here. that is either
  247. done above (fsd or fsp) or it will be done asynchronously.
  248. The logic for locks is greatly complicated by locks that do not fail
  249. immediately but wait until they can be completed. If the request is not of
  250. this type then we will go into the normal lowio stuff from here.
  251. If the request is !failimmediately, then there are two cases depending on
  252. whether or not the lock was enqueued. In both cases, we have to reacquire
  253. the resource before we can proceed. In the case where the lock was NOT
  254. enqueued, we back up into CommonLock where there is code to call back into
  255. this routine with the resource held. Then things proceed as normal.
  256. However, if we did wait in the lock queue then we will have to post to a
  257. worker thread to get our work. Here, PENDING is returned to CommonLock so he
  258. removes one refcount leaving only one for this routine. However, the normal
  259. entrystate for this routine is 2 refcounts....one that is taken away here
  260. and one that belongs to whoever completes the request. So, we take an extra
  261. one before we post. Posting leaves us still with two cases: locks-buffered
  262. vs locks-not-buffered. In the locks-buffered case, we come back in here with
  263. 2 refcounts; we take awayone here and the fspdispatch takes away the other
  264. when it completes. Finally, if locks are not buffered then we go to the
  265. wire: since it is async, pending could be returned. no-pending is just as
  266. before. With pending, lowio takes an extra reference that belongs to the
  267. completion routine and that leaves one reference to take away on this path.
  268. Unlike commonlock, fspdispatch does not have the clause that takes away a
  269. reference on pending-returned. SOOOOOO, we take one away here if lowio
  270. returns pending AND we were enqueued. got that???
  271. A minirdr should not go for an indefinite stay at the wire with the resource
  272. held; if necessary, it should drop the resource and reacquire it.
  273. Arguments:
  274. IN PVOID Context - Provides the context supplied to FsRtlProcessFileLock.
  275. In this case, it is the original RxContext.
  276. IN PIRP Irp - Supplies an IRP describing the lock operation.
  277. Return Value:
  278. RXSTATUS - Final status of operation..
  279. --*/
  280. {
  281. PRX_CONTEXT RxContext = Context;
  282. NTSTATUS Status = Irp->IoStatus.Status;
  283. PVOID LockManagerContext;
  284. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  285. PFCB Fcb = (PFCB)RxContext->pFcb;
  286. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  287. PAGED_CODE();
  288. RxDbgTrace( +1, Dbg, ("RxLockOperationCompletion -> RxContext = %08lx, 1stStatus= %08lx\n", RxContext, Status) );
  289. RxLog(( "LockCompEntry %lx %lx\n", RxContext, Status ));
  290. RxWmiLog( LOG,
  291. RxLockOperationCompletion_1,
  292. LOGPTR( RxContext )
  293. LOGULONG( Status ) );
  294. ASSERT( Context );
  295. ASSERT( Irp == RxContext->CurrentIrp );
  296. //
  297. // The LockManagerContext field in the RxContext supplied to the lock
  298. // manager routine is initialized to the thread id. of the thread submitting
  299. // the request and set to RDBSS_LOCK_MANAGER_REQUEST_PENDING on return if
  300. // STATUS_PENDING is returned. Thus if this routine is called with the
  301. // value in this field is not equal to either the current thread id. or
  302. // RDBSS_LOCK_MANAGER_REQUEST_RESUMED, we are guaranteed that this request
  303. // was pended in the the lock manager.
  304. //
  305. LockManagerContext = InterlockedExchangePointer( &RxContext->LockManagerContext, RDBSS_LOCK_MANAGER_REQUEST_RESUMED );
  306. if ((LockManagerContext != PsGetCurrentThread()) &&
  307. (LockManagerContext != RDBSS_LOCK_MANAGER_REQUEST_RESUMED)) {
  308. //
  309. // here we were hung out in the lock queue........turn the operation to
  310. // async and post to get the resource back. read the notes above to see
  311. // why we inc the refcount
  312. //
  313. RxLog(( "Inc RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  314. RxWmiLog( LOG,
  315. RxLockOperationCompletion_3,
  316. LOGPTR( RxContext )
  317. LOGULONG( RxContext->ReferenceCount ));
  318. InterlockedIncrement( &RxContext->ReferenceCount );
  319. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  320. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_WAS_QUEUED_IN_LOCKMANAGER );
  321. RxDbgTrace( -1, Dbg, ("Posting Queued LockReq = %08lx\n", RxContext) );
  322. if (FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD )) {
  323. RxReleaseFcb( RxContext, Fcb );
  324. ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD );
  325. }
  326. Status = RxFsdPostRequestWithResume( RxContext, RxLockOperationCompletionWithAcquire );
  327. return Status;
  328. }
  329. //
  330. // if we dropped the resource before we came in, then we reacquire it now.
  331. // the guy above me must be the commonlock routine and he come back down
  332. // thru the reacquire wrapper...sort of a post without posting
  333. //
  334. if (!FlagOn( RxContext->FlagsForLowIo,RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD )) {
  335. //
  336. // see bug: 514303
  337. // force completion regardless of return status. fsrtlprocessfilelock can return status_pending
  338. // and we will loss this completion, so mark it
  339. //
  340. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_OPERATION_COMPLETED );
  341. Status = STATUS_SUCCESS;
  342. RxLog(( "ResDropUp! %lx %lx\n", RxContext, Fcb->FcbState ));
  343. RxWmiLog( LOG,
  344. RxLockOperationCompletion_4,
  345. LOGPTR( RxContext )
  346. LOGULONG( Fcb->FcbState ) );
  347. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletion Resdropup-> Status = %08lx\n", Status) );
  348. return Status;
  349. }
  350. //
  351. // this is the normal case. remove the extra reference. this cannot
  352. // be the last one, so we just decrement
  353. //
  354. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  355. RxWmiLog( LOG,
  356. RxLockOperationCompletion_5,
  357. LOGPTR( RxContext )
  358. LOGULONG( RxContext->ReferenceCount ) );
  359. InterlockedDecrement( &RxContext->ReferenceCount );
  360. //
  361. // if we have nonsuccess, just get out!
  362. //
  363. if (!NT_SUCCESS( Status )) {
  364. RxLog(( "NONSUCCESS %lx %lx\n", RxContext, Status ));
  365. RxWmiLog( LOG,
  366. RxLockOperationCompletion_6,
  367. LOGPTR( RxContext )
  368. LOGULONG( Status ) );
  369. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletion NONSUCCESS-> Rxc,Status =%08lx %08lx\n", RxContext, Status ));
  370. return Status;
  371. }
  372. //
  373. // if locks are buffered, just get out
  374. //
  375. if (FlagOn( Fcb->FcbState, FCB_STATE_LOCK_BUFFERING_ENABLED )) {
  376. Status = STATUS_SUCCESS;
  377. RxLog(("LocksBuffered! %lx %lx %lx\n", RxContext, Fcb->FcbState, RxContext->ReferenceCount ));
  378. RxWmiLog( LOG,
  379. RxLockOperationCompletion_7,
  380. LOGPTR( RxContext )
  381. LOGULONG( Fcb->FcbState )
  382. LOGULONG( RxContext->ReferenceCount ));
  383. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletion LockOpBuffered-> Status = %08lx\n", Status) );
  384. return Status;
  385. }
  386. //
  387. // otherwise, let's go to the mini
  388. //
  389. RxInitializeLowIoContext( RxContext, LOWIO_OP_UNLOCK, LowIoContext );
  390. LowIoContext->ParamsFor.Locks.ByteOffset = IrpSp->Parameters.LockControl.ByteOffset.QuadPart;
  391. LowIoContext->ParamsFor.Locks.Key = IrpSp->Parameters.LockControl.Key;
  392. LowIoContext->ParamsFor.Locks.Flags = 0; // no flags
  393. switch (IrpSp->MinorFunction) {
  394. case IRP_MN_LOCK:
  395. if (FlagOn( IrpSp->Flags, SL_EXCLUSIVE_LOCK )) {
  396. LowIoContext->Operation = LOWIO_OP_EXCLUSIVELOCK;
  397. } else {
  398. LowIoContext->Operation = LOWIO_OP_SHAREDLOCK;
  399. }
  400. LowIoContext->ParamsFor.Locks.Flags = IrpSp->Flags;
  401. LowIoContext->ParamsFor.Locks.Length = (*IrpSp->Parameters.LockControl.Length).QuadPart;
  402. break;
  403. case IRP_MN_UNLOCK_SINGLE:
  404. LowIoContext->ParamsFor.Locks.Length = (*IrpSp->Parameters.LockControl.Length).QuadPart;
  405. break;
  406. case IRP_MN_UNLOCK_ALL:
  407. case IRP_MN_UNLOCK_ALL_BY_KEY:
  408. LowIoContext->ParamsFor.Locks.Length = 0;
  409. if (LowIoContext->ParamsFor.Locks.LockList == NULL) {
  410. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletion -> Nothing to unlock\n") );
  411. return STATUS_SUCCESS;
  412. }
  413. LowIoContext->Operation = LOWIO_OP_UNLOCK_MULTIPLE;
  414. break;
  415. }
  416. RxDbgTrace( 0, Dbg, ("--->Operation = %08lx\n", LowIoContext->Operation) );
  417. Status = RxLowIoLockControlShell( RxContext, Irp, Fcb );
  418. if ((Status == STATUS_PENDING) &&
  419. FlagOn( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_WAS_QUEUED_IN_LOCKMANAGER )) {
  420. //
  421. // the fsp dispatch routine doesn't have a clause to take away a
  422. // reference on pended operations. so, if we were queued AND we are
  423. // returning pending back thru the fsp, then take away a reference here.
  424. //
  425. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext,__LINE__,RxContext->ReferenceCount ));
  426. RxWmiLog( LOG,
  427. RxLockOperationCompletion_8,
  428. LOGPTR( RxContext )
  429. LOGULONG( RxContext->ReferenceCount ) );
  430. RxDereferenceAndDeleteRxContext( RxContext );
  431. }
  432. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletion -> Status = %08lx\n", Status) );
  433. return Status;
  434. }
  435. NTSTATUS
  436. RxLockOperationCompletionWithAcquire (
  437. IN PRX_CONTEXT RxContext,
  438. IN PIRP Irp
  439. )
  440. /*++
  441. Routine Description:
  442. This routine is responsible to get the resource back in case we were held up
  443. in the lock queue. Then it calls the LockOperationComplete. Of course, it has
  444. to mess around with giving the resource back for abnormal termination and the
  445. like.
  446. Two things are invariant ... first, when we get here there are two references
  447. on the rxcontext. also, unless we return pending, the fsp guy above will try
  448. to complete this request. here's what we do.
  449. this routine is refcount-neutral: it always takes away as many as it places.
  450. it has to place refcount on the context if it acquires the resource in order
  451. to maintain the invariant that a context always!!!!! has the same number of
  452. releases as acquires. if it takes this refcount, then it releases it
  453. EVEN IF THE FCB IS NOT RELEASED HERE. (it might be relased on the async
  454. path instead.)
  455. Last, we can also be called from the original commonlock routine. in this
  456. case, we take care of releasing the fcb and clear the flag so that it will
  457. not be released above.
  458. Arguments:
  459. Return Value:
  460. RXSTATUS - The return status for the operation
  461. --*/
  462. {
  463. NTSTATUS Status;
  464. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  465. PFCB Fcb = (PFCB)RxContext->pFcb;
  466. PFOBX Fobx = (PFOBX)RxContext->pFobx;
  467. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  468. BOOLEAN ReleaseFcb = FALSE;
  469. PAGED_CODE();
  470. RxDbgTrace( +1, Dbg, ("RxLockOperationCompletionWithAcquire...IrpC %08lx, Fobx %08lx, Fcb %08lx\n",
  471. RxContext, Fobx, Fcb ));
  472. RxDbgTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) );
  473. RxLog(( "LockAcq %lx %lx %lx %lx\n", RxContext, Fobx, Fcb, IrpSp->MinorFunction ));
  474. RxWmiLog( LOG,
  475. RxLockOperationCompletionWithAcquire_1,
  476. LOGPTR( RxContext )
  477. LOGPTR( Fobx )
  478. LOGPTR( Fcb )
  479. LOGUCHAR( IrpSp->MinorFunction ) );
  480. //
  481. // Acquire shared access to the Fcb
  482. //
  483. Status = RxAcquireSharedFcb( RxContext, Fcb );
  484. if (Status == STATUS_LOCK_NOT_GRANTED) {
  485. Status = RxFsdPostRequestWithResume( RxContext, RxLockOperationCompletionWithAcquire );
  486. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletionWithAcquire -> %08lx\n", Status) );
  487. return Status;
  488. } else if (Status != STATUS_SUCCESS) {
  489. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext,__LINE__,RxContext->ReferenceCount ));
  490. InterlockedDecrement( &RxContext->ReferenceCount);
  491. return Status;
  492. }
  493. SetFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD );
  494. RxLog(( "Inc RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  495. RxWmiLog( LOG,
  496. RxLockOperationCompletionWithAcquire_2,
  497. LOGPTR( RxContext )
  498. LOGULONG( RxContext->ReferenceCount ) );
  499. InterlockedIncrement( &RxContext->ReferenceCount ); // we MUST!!! deref
  500. try {
  501. //
  502. // Call the guy to complete the lock request....with the resrouce held
  503. //
  504. Status = RxLockOperationCompletion( RxContext, Irp );
  505. } finally {
  506. DebugUnwind( RxLockOperationCompletionWithAcquire );
  507. //
  508. // If resources have been acquired, release them under the right conditions.
  509. // the right conditions are these:
  510. // 1) if we have abnormal termination. here we obviously release the
  511. // resource since no one else will.
  512. // 2) if the underlying call did not succeed: Status==Pending.
  513. // We also take away a opcount since the context is about to be completed.
  514. //
  515. if (AbnormalTermination() || (Status != STATUS_PENDING)) {
  516. ReleaseFcb = TRUE;
  517. } else {
  518. //
  519. // here the guy below is going to handle the completion
  520. //
  521. ASSERT( FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION ) );
  522. }
  523. if (ReleaseFcb) {
  524. InterlockedDecrement( &Fcb->OutstandingLockOperationsCount );
  525. if(RESOURCE_OWNER_SET(LowIoContext->ResourceThreadId ) ) {
  526. RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  527. } else {
  528. RxReleaseFcb( RxContext, Fcb );
  529. }
  530. ClearFlag( RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_LOCK_FCB_RESOURCE_HELD );
  531. }
  532. //
  533. // if we took a refcount we MUST deref no matter what!
  534. //
  535. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  536. RxWmiLog( LOG,
  537. RxLockOperationCompletionWithAcquire_3,
  538. LOGPTR( RxContext )
  539. LOGULONG( RxContext->ReferenceCount ) );
  540. RxDereferenceAndDeleteRxContext( RxContext );
  541. RxDbgTrace( -1, Dbg, ("RxLockOperationCompletionWithAcquire -> %08lx\n", Status) );
  542. } // finally
  543. return Status;
  544. }
  545. VOID
  546. RxUnlockOperation (
  547. IN PVOID Context,
  548. IN PFILE_LOCK_INFO LockInfo
  549. )
  550. /*++
  551. Routine Description:
  552. This routine is called after the FSRTL lock package has determined that a
  553. locked region is to be unlocked. We do one of two things as determined by a
  554. bit in the lowio_flags field. If the bit is clear, we just ignore the call.
  555. This happens on unlock single calls that are passed down to the minirdr
  556. exactly as a single lock. For a unlock_all or unlock_all_by_key, we use
  557. these calls to get an enumeration of the lock set. then, these go thru lowIO
  558. but using the list method.
  559. Arguments:
  560. IN PVOID Context - Provides the context supplied to FsRtlProcessFileLock.
  561. In this case, it is the RxContext of the Ongoing unlock
  562. operation OR of a cleanup operation
  563. IN PFILE_LOCK_INFO LockInfo - Describes the region being unlock
  564. Return Value:
  565. RXSTATUS - Status of unlock operation (it can't really fail, though).
  566. --*/
  567. {
  568. PRX_CONTEXT RxContext = Context;
  569. PFCB Fcb;
  570. NTSTATUS Status = STATUS_SUCCESS;
  571. PAGED_CODE();
  572. RxDbgTrace( +1, Dbg, ("RxUnlockOperation -> RxContext/LowByte = %08lx/%08lx\n",
  573. RxContext,LockInfo->StartingByte.LowPart) );
  574. RxLog(( "Unlck %x %x",RxContext,LockInfo->StartingByte.LowPart ));
  575. RxWmiLog(LOG,
  576. RxUnlockOperation,
  577. LOGPTR( RxContext )
  578. LOGULONG( LockInfo->StartingByte.LowPart ) );
  579. //
  580. // If there is a NULL context, this means that this routine was called
  581. // on behalf of a failed lock request, so we return immediately.
  582. //
  583. if (Context != NULL) {
  584. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  585. PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation( RxContext->CurrentIrp)->FileObject;
  586. Fcb = (PFCB) RxContext->pFcb;
  587. ASSERT( FileObject == LockInfo->FileObject ); // ok4->FileObj
  588. if (FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SAVEUNLOCKS ) &&
  589. !FlagOn( Fcb->FcbState, FCB_STATE_LOCK_BUFFERING_ENABLED )) {
  590. PLOWIO_LOCK_LIST LockList,ThisElement;
  591. LockList = LowIoContext->ParamsFor.Locks.LockList;
  592. ThisElement = RxAllocatePoolWithTag( PagedPool, sizeof( LOWIO_LOCK_LIST ), 'LLxR' );
  593. if (ThisElement==NULL) {
  594. RxDbgTrace( -1, Dbg, ("RxUnlockOperation FAILED ALLOCATION!\n") );
  595. return;
  596. }
  597. if (LockList == NULL) {
  598. ThisElement->LockNumber = 1;
  599. } else {
  600. ThisElement->LockNumber = LockList->LockNumber + 1;
  601. }
  602. ThisElement->Next = LockList;
  603. ThisElement->ByteOffset = LockInfo->StartingByte.QuadPart;
  604. ThisElement->Length = LockInfo->Length.QuadPart;
  605. LowIoContext->ParamsFor.Locks.LockList = ThisElement;
  606. }
  607. }
  608. RxDbgTrace(-1, Dbg, ("RxUnlockOperation -> status=%08lx\n", Status));
  609. return;
  610. }
  611. //
  612. // Internal support routine
  613. //
  614. NTSTATUS
  615. RxLowIoLockControlShellCompletion (
  616. IN PRX_CONTEXT RxContext
  617. )
  618. /*++
  619. Routine Description:
  620. This routine postprocesses a read request after it comes back from the
  621. minirdr. It does callouts to handle compression, buffering and
  622. shadowing. It is the opposite number of LowIoLockControlShell.
  623. This will be called from LowIo; for async, originally in the
  624. completion routine. If RxStatus(MORE_PROCESSING_REQUIRED) is returned,
  625. LowIo will call again in a thread. If this was syncIo, you'll be back
  626. in the user's thread; if async, lowIo will requeue to a thread.
  627. Currrently, we always get to a thread before anything; this is a bit slower
  628. than completing at DPC time,
  629. but it's aheckuva lot safer and we may often have stuff to do
  630. (like decompressing, shadowing, etc) that we don't want to do at DPC
  631. time.
  632. Arguments:
  633. RxContext - the usual
  634. Return Value:
  635. whatever value supplied by the caller or RxStatus(MORE_PROCESSING_REQUIRED).
  636. --*/
  637. {
  638. NTSTATUS Status;
  639. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  640. PIRP Irp = RxContext->CurrentIrp;
  641. PFCB Fcb = (PFCB) RxContext->pFcb;
  642. BOOLEAN SynchronousIo = !BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  643. PAGED_CODE();
  644. Status = RxContext->StoredStatus;
  645. RxDbgTrace( +1, Dbg, ("RxLowIoLockControlShellCompletion entry Status = %08lx\n", Status) );
  646. RxLog(( "LkShlComp" ));
  647. RxWmiLog( LOG,
  648. RxLowIoLockControlShellCompletion_1,
  649. LOGPTR( RxContext ) );
  650. switch (Status) {
  651. case STATUS_SUCCESS:
  652. break;
  653. case STATUS_FILE_LOCK_CONFLICT:
  654. break;
  655. case STATUS_CONNECTION_INVALID:
  656. //
  657. // NOT YET IMPLEMENTED here is where the failover will happen
  658. // first we give the local guy current minirdr another chance...then we go
  659. // to fullscale retry
  660. // return(RxStatus(DISCONNECTED)); //special....let LowIo get us back
  661. //
  662. break;
  663. }
  664. //
  665. // for a unlock_multiple, get rid of the lock_list
  666. //
  667. if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) {
  668. RxFinalizeLockList( RxContext );
  669. }
  670. if (FlagOn( LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL )){
  671. //
  672. // if we're being called from lowioubmit then just get out
  673. //
  674. RxDbgTrace( -1, Dbg, ("RxLowIoLockControlShellCompletion syncexit Status = %08lx\n", Status) );
  675. return Status;
  676. }
  677. //
  678. // so we're doing an asynchronous completion. well, the only reason why we would be
  679. // trying a lock at the server would be if the lock manager already completed it
  680. // successfully! but if it didn't complete successfully at the server then we have
  681. // to remove it.
  682. //
  683. if ((Status != STATUS_SUCCESS) &&
  684. (RxContext->MajorFunction == IRP_MJ_LOCK_CONTROL) &&
  685. (RxContext->MinorFunction == IRP_MN_LOCK)) {
  686. PFILE_OBJECT FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;
  687. NTSTATUS LocalStatus;
  688. LocalStatus = FsRtlFastUnlockSingle( &Fcb->FileLock,
  689. FileObject,
  690. (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset,
  691. (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length,
  692. IoGetRequestorProcess( Irp ),
  693. LowIoContext->ParamsFor.Locks.Key,
  694. NULL,
  695. TRUE );
  696. RxLog(( "RetractLck %lx %lx %lx",RxContext,Status,LocalStatus ));
  697. RxWmiLog( LOG,
  698. RxLowIoLockControlShellCompletion_2,
  699. LOGPTR( RxContext )
  700. LOGULONG( Status )
  701. LOGULONG( LocalStatus ) );
  702. }
  703. //
  704. // otherwise we have to do the end of the lock from here
  705. //
  706. InterlockedDecrement( &Fcb->OutstandingLockOperationsCount );
  707. RxReleaseFcbForThread( RxContext, Fcb, LowIoContext->ResourceThreadId );
  708. ASSERT( Status != STATUS_RETRY );
  709. if (Status != STATUS_RETRY) {
  710. ASSERT( RxContext->MajorFunction == IRP_MJ_LOCK_CONTROL );
  711. }
  712. RxDbgTrace( -1, Dbg, ("RxLowIoLockControlShellCompletion exit Status = %08lx\n", Status) );
  713. return Status;
  714. }
  715. VOID
  716. RxFinalizeLockList (
  717. PRX_CONTEXT RxContext
  718. )
  719. /*++
  720. Routine Description:
  721. This routine runs down a lock lis and frees each member
  722. Arguments:
  723. RxContext - the usual
  724. Return Value:
  725. n/a
  726. --*/
  727. {
  728. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  729. PLOWIO_LOCK_LIST LockList = LowIoContext->ParamsFor.Locks.LockList;
  730. PAGED_CODE();
  731. RxDbgTrace( +1, Dbg, ("RxFinalizeLockList entry rxcontext=%08lx\n", RxContext) );
  732. RxWmiLog( LOG,
  733. RxFinalizeLockList,
  734. LOGPTR( RxContext ) );
  735. for(;;){
  736. PLOWIO_LOCK_LIST NextLockList;
  737. if (LockList == NULL) break;
  738. NextLockList = LockList->Next;
  739. RxFreePool( LockList );
  740. LockList = NextLockList;
  741. }
  742. RxDbgTrace(-1, Dbg, ("RxFinalizeLockList exit \n"));
  743. return;
  744. }
  745. NTSTATUS
  746. RxLowIoLockControlShell (
  747. IN PRX_CONTEXT RxContext,
  748. IN PIRP Irp,
  749. IN PFCB Fcb
  750. )
  751. /*++
  752. Routine Description:
  753. This routine preprocesses a read request before it goes down to the minirdr.
  754. It does callouts to handle compression, buffering and shadowing. It is the
  755. opposite number of LowIoLockControlShellCompletion. By the time we get here,
  756. we are going to the wire. Lock buffering is handled in the
  757. lockcompletionroutine (not lowio)
  758. Arguments:
  759. RxContext - the usual
  760. Return Value:
  761. whatever value is returned by a callout....or by LowIo.
  762. --*/
  763. {
  764. NTSTATUS Status;
  765. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  766. PAGED_CODE();
  767. RxDbgTrace( +1, Dbg, ("RxLowIoLockControlShell entry %08lx\n", 0) );
  768. RxLog(( "%s\n", "skL" ));
  769. RxWmiLog( LOG,
  770. RxLowIoLockControlShell,
  771. LOGPTR( RxContext ) );
  772. //
  773. // If we are in FSP, we are not guaranteed the thread will stay around till the
  774. // operation is completed. So we set the resource owner to the RX_CONTEXT
  775. // so that the resource package does not touch it.
  776. //
  777. if( BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION ) &&
  778. BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP )) {
  779. LowIoContext->ResourceThreadId = MAKE_RESOURCE_OWNER(RxContext);
  780. ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)LowIoContext->ResourceThreadId);
  781. }
  782. Status = RxLowIoSubmit( RxContext, Irp, Fcb, RxLowIoLockControlShellCompletion );
  783. RxDbgTrace(-1, Dbg, ("RxLowIoLockControlShell exit Status = %08lx\n", Status));
  784. return(Status);
  785. }