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.

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