Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

filelock.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 FileLock.c 00008 00009 Abstract: 00010 00011 The file lock package provides a set of routines that allow the 00012 caller to handle byte range file lock requests. A variable of 00013 type FILE_LOCK is needed for every file with byte range locking. 00014 The package provides routines to set and clear locks, and to 00015 test for read or write access to a file with byte range locks. 00016 00017 The main idea of the package is to have the file system initialize 00018 a FILE_LOCK variable for every data file as its opened, and then 00019 to simply call a file lock processing routine to handle all IRP's 00020 with a major function code of LOCK_CONTROL. The package is responsible 00021 for keeping track of locks and for completing the LOCK_CONTROL IRPS. 00022 When processing a read or write request the file system can then call 00023 two query routines to check for access. 00024 00025 Most of the code for processing IRPS and checking for access use 00026 paged pool and can encounter a page fault, therefore the check routines 00027 cannot be called at DPC level. To help servers that do call the file 00028 system to do read/write operations at DPC level there is a additional 00029 routine that simply checks for the existence of a lock on a file and 00030 can be run at DPC level. 00031 00032 Concurrent access to the FILE_LOCK variable must be controlled by the 00033 caller. 00034 00035 The functions provided in this package are as follows: 00036 00037 o FsRtlInitializeFileLock - Initialize a new FILE_LOCK structure. 00038 00039 o FsRtlUninitializeFileLock - Uninitialize an existing FILE_LOCK 00040 structure. 00041 00042 o FsRtlProcessFileLock - Process an IRP whose major function code 00043 is LOCK_CONTROL. 00044 00045 o FsRtlCheckLockForReadAccess - Check for read access to a range 00046 of bytes in a file given an IRP. 00047 00048 o FsRtlCheckLockForWriteAccess - Check for write access to a range 00049 of bytes in a file given an IRP. 00050 00051 o FsRtlAreThereCurrentFileLocks - Check if there are any locks 00052 currently assigned to a file. 00053 00054 o FsRtlGetNextFileLock - This procedure enumerates the current locks 00055 of a file lock variable. 00056 00057 o FsRtlFastCheckLockForRead - Check for read access to a range of 00058 bytes in a file given separate parameters. 00059 00060 o FsRtlFastCheckLockForWrite - Check for write access to a range of 00061 bytes in a file given separate parameters. 00062 00063 o FsRtlFastLock - A fast non-Irp based way to get a lock 00064 00065 o FsRtlFastUnlockSingle - A fast non-Irp based way to release a single 00066 lock 00067 00068 o FsRtlFastUnlockAll - A fast non-Irp based way to release all locks 00069 held by a file object. 00070 00071 o FsRtlFastUnlockAllByKey - A fast non-Irp based way to release all 00072 locks held by a file object that match a key. 00073 00074 00075 Authors: 00076 00077 Gary Kimura [GaryKi] 24-Apr-1990 00078 Dan Lovinger [DanLo] 22-Sep-1995 00079 00080 Revision History: 00081 00082 --*/ 00083 00084 #include "FsRtlP.h" 00085 00086 // 00087 // Local constants 00088 // 00089 00090 // 00091 // Local debug trace level 00092 // 00093 00094 #define Dbg (0x20000000) 00095 00096 // 00097 // YA definition of INLINE 00098 // 00099 00100 #ifndef INLINE 00101 #define INLINE __inline 00102 #endif 00103 00104 #define TAG_EXCLUSIVE_LOCK 'xeLF' 00105 #define TAG_FILE_LOCK 'lfLF' 00106 #define TAG_LOCK_INFO 'ilLF' 00107 #define TAG_LOCKTREE_NODE 'nlLF' 00108 #define TAG_SHARED_LOCK 'hsLF' 00109 #define TAG_WAITING_LOCK 'lwLF' 00110 00111 // 00112 // Globals 00113 // 00114 00115 // 00116 // This mutex synchronizes threads competing to initialize file lock structures. 00117 // 00118 00119 FAST_MUTEX FsRtlCreateLockInfo; 00120 00121 // 00122 // Lookaside lists 00123 // 00124 // Here is a good place to note why this is still nonpaged. We need to be able 00125 // to cancel lock IRPs at DPC, and the ripple effects of this (esp. granting waiting 00126 // locks and synchronizing the waiting list) implies some unfortunate realities. 00127 // 00128 // This should be reinvestigated post NT 5.0. 00129 // 00130 00131 NPAGED_LOOKASIDE_LIST FsRtlSharedLockLookasideList; 00132 NPAGED_LOOKASIDE_LIST FsRtlExclusiveLockLookasideList; 00133 NPAGED_LOOKASIDE_LIST FsRtlWaitingLockLookasideList; 00134 NPAGED_LOOKASIDE_LIST FsRtlLockTreeNodeLookasideList; 00135 NPAGED_LOOKASIDE_LIST FsRtlLockInfoLookasideList; 00136 00137 PAGED_LOOKASIDE_LIST FsRtlFileLockLookasideList; 00138 00139 00140 // 00141 // Local structures 00142 // 00143 00144 /*++ 00145 00146 Some of the decisions made regarding the internal datastructres may not be clear, 00147 so I should discuss the evolution of this design. 00148 00149 The original file lock implementation was a single linked list, extended in the MP 00150 case to a set of linked lists which each held locks in page-aligned segments of the 00151 file. If locks spilled over these page-aligned segments the code fell back to the 00152 UP single linked list. There are clearly peformance implications with substantial 00153 usage of file locks, since these are mandatory locks. 00154 00155 This implementation goes for O(lgn) search performance by using splay trees. In order to 00156 apply simple trees to this problem no node of the tree can overlap, so since shared 00157 locks can in fact overlap something must be done. The solution used here is to have 00158 a meta-structure contain all locks which do overlap and have the tree operations 00159 split and merge these nodes of (potentially) multiple locks. This is the LOCKTREE_NODE. 00160 It should be noted that the worst case add/delete lock times are still linear. 00161 00162 Exclusive locks pose a problem because of an asymmetry in the semantics of applying 00163 locks to a file. If a process applies a shared lock to a section of a file, no application 00164 of an exclusive lock to bytes in that section can succeed. However, if a process 00165 applies an exclusive lock, that same process can get a shared lock as well. This 00166 behavior conflicts with the mergeable node since by applying locks in a given order 00167 we can get a node to have many shared locks and "rogue" exclusive locks which are 00168 hidden except to a linear search, which is what we're designing out. So exclusive locks 00169 must be seperated from the shared locks. This is the reason we have two lock trees. 00170 00171 Since we have two lock trees, the average case search is now O(lgm + lgn) for m exlcusive 00172 and n shared. Also, since no exclusive locks can ever overlap each other it is now 00173 unreasonable to have them use LOCKTREE_NODES - this would impose a memory penalty on code 00174 which was weighted toward exclusive locks. This means that the exclusive locks should 00175 be wired into the splay tree directly. So we need an RTL_SPLAY_LINKS, but this is 64 bits 00176 bigger than the SINGLE_LIST_ENTRY which shared locks need (to be threaded off of a 00177 LOCKTREE_NODE), which dictates seperate shared and exclusive lock structures to avoid 00178 penalizing code which was weighted toward shared locks by having that wasted 64 bits per 00179 lock. Hence EX_LOCK and SH_LOCK (they actually occupy different pool block sizes). 00180 00181 Zero length locks are a bizzare creation, and there is some errata relating to them. It 00182 used to be the case that zero length locks would be granted without exception. This is 00183 flat out bogus, and has been changed (NT 4.0). They are now subject to failure if they 00184 occupy a point interior to a lock of a type that can cause an access failure. A particular 00185 case that was previously allowed was a zero length exclusive lock interior to another 00186 exclusive lock. 00187 00188 Zero length locks cannot conflict with zero length locks. This is the subject of some 00189 special code throughout the module. Note especially that zero length exclusive locks can 00190 "overlap". Zero length locks also cannot conflict at the starting byte and ending byte of a 00191 range - they are points on the line. 00192 00193 --*/ 00194 00195 typedef struct _LOCKTREE_NODE { 00196 00197 // 00198 // List of locks under this node 00199 // 00200 00201 SINGLE_LIST_ENTRY Locks; 00202 00203 // 00204 // Flag whether this node is holey as a result of a failed allocation 00205 // during a node split. During deletion of shared locks, we may 00206 // discover that the locks in the node no longer have total overlap 00207 // but cannot allocate resources to create the new nodes in the tree. 00208 // 00209 // Any insert into the region occupied by a holey node will finish by 00210 // trying to split a holey node up. Any split or access check in a 00211 // holey node must completely traverse the locks at the node. 00212 // 00213 00214 BOOLEAN HoleyNode; 00215 00216 // 00217 // Maximum byte offset affected by locks in this node. 00218 // Note: minimum offset is the starting offset of the 00219 // first lock at this node. 00220 // 00221 00222 ULONGLONG Extent; 00223 00224 // 00225 // Splay tree links to parent, lock groups strictly less than 00226 // and lock groups strictly greater than locks in this node. 00227 // 00228 00229 RTL_SPLAY_LINKS Links; 00230 00231 // 00232 // Last lock in the list (useful for node collapse under insert) 00233 // 00234 00235 SINGLE_LIST_ENTRY Tail; 00236 00237 } LOCKTREE_NODE, *PLOCKTREE_NODE; 00238 00239 // 00240 // Define the threading wrappers for lock information 00241 // 00242 00243 // 00244 // Each shared lock record corresponds to a current granted lock and is 00245 // maintained in a queue off of a LOCKTREE_NODE's Locks list. The list 00246 // of current locks is ordered according to the starting byte of the lock. 00247 // 00248 00249 typedef struct _SH_LOCK { 00250 00251 // 00252 // The link structures for the list of shared locks. 00253 // 00254 00255 SINGLE_LIST_ENTRY Link; 00256 00257 // 00258 // The actual locked range 00259 // 00260 00261 FILE_LOCK_INFO LockInfo; 00262 00263 } SH_LOCK, *PSH_LOCK; 00264 00265 // 00266 // Each exclusive lock record corresponds to a current granted lock and is 00267 // threaded into the exclusive lock tree. 00268 // 00269 00270 typedef struct _EX_LOCK { 00271 00272 // 00273 // The link structures for the list of current locks. 00274 // 00275 00276 RTL_SPLAY_LINKS Links; 00277 00278 // 00279 // The actual locked range 00280 // 00281 00282 FILE_LOCK_INFO LockInfo; 00283 00284 } EX_LOCK, *PEX_LOCK; 00285 00286 // 00287 // Each Waiting lock record corresponds to a IRP that is waiting for a 00288 // lock to be granted and is maintained in a queue off of the FILE_LOCK's 00289 // WaitingLockQueue list. 00290 // 00291 00292 typedef struct _WAITING_LOCK { 00293 00294 // 00295 // The link structures for the list of waiting locks 00296 // 00297 00298 SINGLE_LIST_ENTRY Link; 00299 00300 // 00301 // The context field to use when completing the irp via the alternate 00302 // routine 00303 // 00304 00305 PVOID Context; 00306 00307 // 00308 // A pointer to the IRP that is waiting for a lock 00309 // 00310 00311 PIRP Irp; 00312 00313 } WAITING_LOCK, *PWAITING_LOCK; 00314 00315 00316 // 00317 // Each lock or waiting onto some lock queue. 00318 // 00319 00320 typedef struct _LOCK_QUEUE { 00321 00322 // 00323 // Sync to guard queue access. 00324 // 00325 00326 KSPIN_LOCK QueueSpinLock; 00327 00328 // 00329 // The items contain locktrees of the current granted 00330 // locks and a list of the waiting locks 00331 // 00332 00333 PRTL_SPLAY_LINKS SharedLockTree; 00334 PRTL_SPLAY_LINKS ExclusiveLockTree; 00335 SINGLE_LIST_ENTRY WaitingLocks; 00336 SINGLE_LIST_ENTRY WaitingLocksTail; 00337 00338 } LOCK_QUEUE, *PLOCK_QUEUE; 00339 00340 00341 // 00342 // Any file_lock which has had a lock applied gets a non-paged pool 00343 // structure which tracks the current locks applied to the file 00344 // 00345 00346 typedef struct _LOCK_INFO { 00347 00348 // 00349 // LowestLockOffset retains the offset of the lowest existing 00350 // lock. This facilitates a quick check to see if a read or 00351 // write can proceed without locking the lock database. This is 00352 // helpful for applications that use mirrored locks -- all locks 00353 // are higher than file data. 00354 // 00355 // If the lowest lock has an offset > 0xffffffff, LowestLockOffset 00356 // is set to 0xffffffff. 00357 // 00358 00359 ULONG LowestLockOffset; 00360 00361 // 00362 // The optional procedure to call to complete a request 00363 // 00364 00365 PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine; 00366 00367 // 00368 // The optional procedure to call when unlocking a byte range 00369 // 00370 00371 PUNLOCK_ROUTINE UnlockRoutine; 00372 00373 // 00374 // The locked ranges 00375 // 00376 00377 LOCK_QUEUE LockQueue; 00378 00379 } LOCK_INFO, *PLOCK_INFO; 00380 00381 // 00382 // Local Macros 00383 // 00384 00385 // 00386 // The following macros sort out the allocation of internal structures. 00387 // 00388 00389 INLINE 00390 PSH_LOCK 00391 FsRtlAllocateSharedLock ( 00392 VOID 00393 ) 00394 { 00395 return (PSH_LOCK) ExAllocateFromNPagedLookasideList( &FsRtlSharedLockLookasideList ); 00396 } 00397 00398 INLINE 00399 PEX_LOCK 00400 FsRtlAllocateExclusiveLock ( 00401 VOID 00402 ) 00403 { 00404 return (PEX_LOCK) ExAllocateFromNPagedLookasideList( &FsRtlExclusiveLockLookasideList ); 00405 } 00406 00407 INLINE 00408 PWAITING_LOCK 00409 FsRtlAllocateWaitingLock ( 00410 VOID 00411 ) 00412 { 00413 return (PWAITING_LOCK) ExAllocateFromNPagedLookasideList( &FsRtlWaitingLockLookasideList ); 00414 } 00415 00416 INLINE 00417 PLOCKTREE_NODE 00418 FsRtlAllocateLockTreeNode ( 00419 VOID 00420 ) 00421 { 00422 return (PLOCKTREE_NODE) ExAllocateFromNPagedLookasideList( &FsRtlLockTreeNodeLookasideList ); 00423 } 00424 00425 INLINE 00426 PLOCK_INFO 00427 FsRtlAllocateLockInfo ( 00428 VOID 00429 ) 00430 { 00431 return (PLOCK_INFO) ExAllocateFromNPagedLookasideList( &FsRtlLockInfoLookasideList ); 00432 } 00433 00434 00435 INLINE 00436 VOID 00437 FsRtlFreeSharedLock ( 00438 IN PSH_LOCK C 00439 ) 00440 { 00441 ExFreeToNPagedLookasideList( &FsRtlSharedLockLookasideList, (PVOID)C ); 00442 } 00443 00444 INLINE 00445 VOID 00446 FsRtlFreeExclusiveLock ( 00447 IN PEX_LOCK C 00448 ) 00449 { 00450 ExFreeToNPagedLookasideList( &FsRtlExclusiveLockLookasideList, (PVOID)C ); 00451 } 00452 00453 INLINE 00454 VOID 00455 FsRtlFreeWaitingLock ( 00456 IN PWAITING_LOCK C 00457 ) 00458 { 00459 ExFreeToNPagedLookasideList( &FsRtlWaitingLockLookasideList, (PVOID)C ); 00460 } 00461 00462 INLINE 00463 VOID 00464 FsRtlFreeLockTreeNode ( 00465 IN PLOCKTREE_NODE C 00466 ) 00467 { 00468 ExFreeToNPagedLookasideList( &FsRtlLockTreeNodeLookasideList, (PVOID)C ); 00469 } 00470 00471 INLINE 00472 VOID 00473 FsRtlFreeLockInfo ( 00474 IN PLOCK_INFO C 00475 ) 00476 { 00477 ExFreeToNPagedLookasideList( &FsRtlLockInfoLookasideList, (PVOID)C ); 00478 } 00479 00480 00481 #define FsRtlAcquireLockQueue(a,b) \ 00482 ExAcquireSpinLock(&(a)->QueueSpinLock, b); 00483 00484 #define FsRtlReacquireLockQueue(a,b,c) \ 00485 ExAcquireSpinLock(&(b)->QueueSpinLock, c); 00486 00487 #define FsRtlReleaseLockQueue(a,b) \ 00488 ExReleaseSpinLock(&(a)->QueueSpinLock, b); 00489 00490 00491 // 00492 // Generic way to complete a lock IRP. We like to treat this as an overloaded 00493 // function so it can be used with LOCK_INFO and FILE_LOCK structures, as 00494 // appropriate using paged/nonpaged pool to discover the completion routine. 00495 // 00496 00497 #define FsRtlCompleteLockIrp( A, B, C, D, E, F ) \ 00498 FsRtlCompleteLockIrpReal( (A)->CompleteLockIrpRoutine, \ 00499 B, \ 00500 C, \ 00501 D, \ 00502 E, \ 00503 F ) 00504 00505 INLINE 00506 VOID 00507 FsRtlCompleteLockIrpReal ( 00508 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine, 00509 IN PVOID Context, 00510 IN PIRP Irp, 00511 IN NTSTATUS Status, 00512 IN PNTSTATUS NewStatus, 00513 IN PFILE_OBJECT FileObject 00514 ) 00515 { 00516 // 00517 // This fools the compiler into generating the Status only once 00518 // if it is calculated from an expression. 00519 // 00520 00521 NTSTATUS LocalStatus = Status; 00522 00523 if (CompleteLockIrpRoutine != NULL) { 00524 00525 if (FileObject != NULL) { 00526 00527 FileObject->LastLock = NULL; 00528 } 00529 00530 Irp->IoStatus.Status = LocalStatus; 00531 *NewStatus = CompleteLockIrpRoutine( Context, Irp ); 00532 00533 } else { 00534 00535 FsRtlCompleteRequest( Irp, LocalStatus ); 00536 *NewStatus = LocalStatus; 00537 } 00538 } 00539 00540 // 00541 // Define USERTEST to get a version which compiles into a usermode test rig 00542 // 00543 00544 #ifdef USERTEST 00545 #include <stdio.h> 00546 #include <stdlib.h> 00547 #undef FsRtlAllocateSharedLock 00548 #undef FsRtlAllocateExclusiveLock 00549 #undef FsRtlAllocateLockTreeNode 00550 #undef FsRtlAllocateWaitingLock 00551 #undef FsRtlFreeSharedLock 00552 #undef FsRtlFreeExclusiveLock 00553 #undef FsRtlFreeLockTreeNode 00554 #undef FsRtlFreeWaitingLock 00555 #undef FsRtlAcquireLockQueue 00556 #undef FsRtlReacquireLockQueue 00557 #undef FsRtlReleaseLockQueue 00558 #undef FsRtlCompleteLockIrp 00559 #undef IoCompleteRequest 00560 00561 #define FsRtlAllocateSharedLock( C ) (PSH_LOCK)malloc(sizeof(SH_LOCK)) 00562 #define FsRtlAllocateExclusiveLock( C ) (PEX_LOCK)malloc(sizeof(EX_LOCK)) 00563 #define FsRtlAllocateLockTreeNode( C ) (PLOCKTREE_NODE)malloc(sizeof(LOCKTREE_NODE)) 00564 #define FsRtlAllocateWaitingLock( C ) (PWAITING_LOCK)malloc(sizeof(WAITING_LOCK)) 00565 #define FsRtlAllocateLockInfo( C ) (PLOCK_INFO)malloc(sizeof(LOCK_INFO)) 00566 #define FsRtlFreeSharedLock( C ) free(C) 00567 #define FsRtlFreeExclusiveLock( C ) free(C) 00568 #define FsRtlFreeLockTreeNode( C ) free(C) 00569 #define FsRtlFreeWaitingLock( C ) free(C) 00570 #define FsRtlFreeLockInfo( C ) free(C) 00571 #define FsRtlAcquireLockQueue(a,b) (*(b) = '\0') 00572 #define FsRtlReacquireLockQueue(a,b,c) (*(c) = '\0') 00573 #define FsRtlReleaseLockQueue(a,b) 00574 #define FsRtlCompleteLockIrp(_FileLock, _Context, _Irp, _Status, _NewStatus, _FileObject) \ 00575 { \ 00576 DbgBreakPoint(); \ 00577 *_NewStatus = STATUS_SUCCESS; \ 00578 } 00579 00580 #define ExReleaseFastMutex(M) 00581 #define ExAcquireFastMutex(M) 00582 #define KeInitializeSpinLock(L) 00583 #define KfRaiseIrql(L) ('\0') 00584 #define KfLowerIrql(I) 00585 #define IoAcquireCancelSpinLock(I) 00586 #define IoReleaseCancelSpinLock(I) 00587 #define IoCompleteRequest(I, S) 00588 #endif 00589 00590 // 00591 // The following routines are private to this module 00592 // 00593 00594 VOID 00595 FsRtlSplitLocks ( 00596 IN PLOCKTREE_NODE ParentNode, 00597 IN PSINGLE_LIST_ENTRY *pStartLink, 00598 IN PLARGE_INTEGER LastShadowedByte, 00599 IN PLARGE_INTEGER GlueOffset 00600 ); 00601 00602 PRTL_SPLAY_LINKS 00603 FsRtlFindFirstOverlappingSharedNode ( 00604 IN PRTL_SPLAY_LINKS Tree, 00605 IN PLARGE_INTEGER StartingByte, 00606 IN PLARGE_INTEGER EndingByte, 00607 IN OUT PRTL_SPLAY_LINKS *LastEdgeNode, 00608 IN OUT PBOOLEAN GreaterThan 00609 ); 00610 00611 PRTL_SPLAY_LINKS 00612 FsRtlFindFirstOverlappingExclusiveNode ( 00613 IN PRTL_SPLAY_LINKS Tree, 00614 IN PLARGE_INTEGER StartingByte, 00615 IN PLARGE_INTEGER EndingByte, 00616 IN OUT PRTL_SPLAY_LINKS *LastEdgeNode, 00617 IN OUT PBOOLEAN GreaterThan 00618 ); 00619 00620 PSH_LOCK 00621 FsRtlFindFirstOverlapInNode ( 00622 IN PLOCKTREE_NODE Node, 00623 IN PLARGE_INTEGER StartingByte, 00624 IN PLARGE_INTEGER EndingByte 00625 ); 00626 00627 BOOLEAN 00628 FsRtlPrivateInsertLock ( 00629 IN PLOCK_INFO LockInfo, 00630 IN PFILE_OBJECT FileObject, 00631 IN PFILE_LOCK_INFO FileLockInfo 00632 ); 00633 00634 BOOLEAN 00635 FsRtlPrivateInsertSharedLock ( 00636 IN PLOCK_QUEUE LockQueue, 00637 IN PSH_LOCK NewLock 00638 ); 00639 00640 VOID 00641 FsRtlPrivateInsertExclusiveLock ( 00642 IN PLOCK_QUEUE LockQueue, 00643 IN PEX_LOCK NewLock 00644 ); 00645 00646 VOID 00647 FsRtlPrivateCheckWaitingLocks ( 00648 IN PLOCK_INFO LockInfo, 00649 IN PLOCK_QUEUE LockQueue, 00650 IN KIRQL OldIrql 00651 ); 00652 00653 VOID 00654 FsRtlPrivateCancelFileLockIrp ( 00655 IN PDEVICE_OBJECT DeviceObject, 00656 IN PIRP Irp 00657 ); 00658 00659 BOOLEAN 00660 FsRtlPrivateCheckForExclusiveLockAccess ( 00661 IN PLOCK_QUEUE LockInfo, 00662 IN PFILE_LOCK_INFO FileLockInfo 00663 ); 00664 00665 BOOLEAN 00666 FsRtlPrivateCheckForSharedLockAccess ( 00667 IN PLOCK_QUEUE LockInfo, 00668 IN PFILE_LOCK_INFO FileLockInfo 00669 ); 00670 00671 NTSTATUS 00672 FsRtlPrivateFastUnlockAll ( 00673 IN PFILE_LOCK FileLock, 00674 IN PFILE_OBJECT FileObject, 00675 IN PEPROCESS ProcessId, 00676 IN ULONG Key, 00677 IN BOOLEAN MatchKey, 00678 IN PVOID Context OPTIONAL 00679 ); 00680 00681 BOOLEAN 00682 FsRtlPrivateInitializeFileLock ( 00683 IN PFILE_LOCK FileLock, 00684 IN BOOLEAN ViaFastCall 00685 ); 00686 00687 VOID 00688 FsRtlPrivateRemoveLock ( 00689 IN PLOCK_INFO LockInfo, 00690 IN PFILE_LOCK_INFO, 00691 IN BOOLEAN CheckForWaiters 00692 ); 00693 00694 BOOLEAN 00695 FsRtlCheckNoSharedConflict ( 00696 IN PLOCK_QUEUE LockQueue, 00697 IN PLARGE_INTEGER Starting, 00698 IN PLARGE_INTEGER Ending 00699 ); 00700 00701 BOOLEAN 00702 FsRtlCheckNoExclusiveConflict ( 00703 IN PLOCK_QUEUE LockQueue, 00704 IN PLARGE_INTEGER Starting, 00705 IN PLARGE_INTEGER Ending, 00706 IN ULONG Key, 00707 IN PFILE_OBJECT FileObject, 00708 IN PVOID ProcessId 00709 ); 00710 00711 VOID 00712 FsRtlPrivateResetLowestLockOffset ( 00713 PLOCK_INFO LockInfo 00714 ); 00715 00716 NTSTATUS 00717 FsRtlFastUnlockSingleShared ( 00718 IN PLOCK_INFO LockInfo, 00719 IN PFILE_OBJECT FileObject, 00720 IN LARGE_INTEGER UNALIGNED *FileOffset, 00721 IN PLARGE_INTEGER Length, 00722 IN PEPROCESS ProcessId, 00723 IN ULONG Key, 00724 IN PVOID Context OPTIONAL, 00725 IN BOOLEAN IgnoreUnlockRoutine, 00726 IN BOOLEAN CheckForWaiters 00727 ); 00728 00729 NTSTATUS 00730 FsRtlFastUnlockSingleExclusive ( 00731 IN PLOCK_INFO LockInfo, 00732 IN PFILE_OBJECT FileObject, 00733 IN LARGE_INTEGER UNALIGNED *FileOffset, 00734 IN PLARGE_INTEGER Length, 00735 IN PEPROCESS ProcessId, 00736 IN ULONG Key, 00737 IN PVOID Context OPTIONAL, 00738 IN BOOLEAN IgnoreUnlockRoutine, 00739 IN BOOLEAN CheckForWaiters 00740 ); 00741 00742 00743 VOID 00744 FsRtlInitializeFileLocks ( 00745 VOID 00746 ) 00747 /*++ 00748 00749 Routine Description: 00750 00751 Initializes the global portion of the filelock package. 00752 00753 Arguments: 00754 00755 None 00756 00757 Return Value: 00758 00759 None. 00760 00761 --*/ 00762 { 00763 #ifndef USERTEST 00764 00765 // 00766 // Build the lookaside lists for our internal structures. 00767 // 00768 00769 ExInitializeNPagedLookasideList( &FsRtlSharedLockLookasideList, 00770 NULL, 00771 NULL, 00772 0, 00773 sizeof(SH_LOCK), 00774 TAG_SHARED_LOCK, 00775 16 ); 00776 00777 ExInitializeNPagedLookasideList( &FsRtlExclusiveLockLookasideList, 00778 NULL, 00779 NULL, 00780 0, 00781 sizeof(EX_LOCK), 00782 TAG_EXCLUSIVE_LOCK, 00783 16 ); 00784 00785 ExInitializeNPagedLookasideList( &FsRtlWaitingLockLookasideList, 00786 NULL, 00787 NULL, 00788 0, 00789 sizeof(WAITING_LOCK), 00790 TAG_WAITING_LOCK, 00791 16 ); 00792 00793 ExInitializeNPagedLookasideList( &FsRtlLockTreeNodeLookasideList, 00794 NULL, 00795 NULL, 00796 0, 00797 sizeof(LOCKTREE_NODE), 00798 TAG_LOCKTREE_NODE, 00799 16 ); 00800 00801 ExInitializeNPagedLookasideList( &FsRtlLockInfoLookasideList, 00802 NULL, 00803 NULL, 00804 0, 00805 sizeof(LOCK_INFO), 00806 TAG_LOCK_INFO, 00807 8 ); 00808 00809 ExInitializePagedLookasideList( &FsRtlFileLockLookasideList, 00810 NULL, 00811 NULL, 00812 0, 00813 sizeof(FILE_LOCK), 00814 TAG_FILE_LOCK, 00815 8 ); 00816 00817 // 00818 // Initialize the LockInfo creation mutex 00819 // 00820 00821 ExInitializeFastMutex(&FsRtlCreateLockInfo); 00822 00823 00824 #endif 00825 } 00826 00827 00828 VOID 00829 FsRtlInitializeFileLock ( 00830 IN PFILE_LOCK FileLock, 00831 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, 00832 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL 00833 ) 00834 00835 /*++ 00836 00837 Routine Description: 00838 00839 This routine initializes a new FILE_LOCK structure. The caller must 00840 supply the memory for the structure. This call must precede all other 00841 calls that utilize the FILE_LOCK variable. 00842 00843 Arguments: 00844 00845 FileLock - Supplies a pointer to the FILE_LOCK structure to 00846 initialize. 00847 00848 CompleteLockIrpRoutine - Optionally supplies an alternate routine to 00849 call for completing IRPs. FsRtlProcessFileLock by default will 00850 call IoCompleteRequest to finish up an IRP; however if the caller 00851 want to process the completion itself then it needs to specify 00852 a completion routine here. This routine will then be called in 00853 place of IoCompleteRequest. 00854 00855 UnlockRoutine - Optionally supplies a routine to call when removing 00856 a lock. 00857 00858 Return Value: 00859 00860 None. 00861 00862 --*/ 00863 00864 { 00865 DebugTrace(+1, Dbg, "FsRtlInitializeFileLock, FileLock = %08lx\n", FileLock); 00866 00867 // 00868 // Clear non-paged pool pointer 00869 // 00870 00871 FileLock->LockInformation = NULL; 00872 FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine; 00873 FileLock->UnlockRoutine = UnlockRoutine; 00874 00875 FileLock->FastIoIsQuestionable = FALSE; 00876 00877 // 00878 // and return to our caller 00879 // 00880 00881 DebugTrace(-1, Dbg, "FsRtlInitializeFileLock -> VOID\n", 0 ); 00882 00883 return; 00884 } 00885 00886 00887 BOOLEAN 00888 FsRtlPrivateInitializeFileLock ( 00889 IN PFILE_LOCK FileLock, 00890 IN BOOLEAN ViaFastCall 00891 ) 00892 /*++ 00893 00894 Routine Description: 00895 00896 This routine initializes a new LOCK_INFO structure in non-paged 00897 pool for the FILE_LOCK. This routines only occurs once for a given 00898 FILE_LOCK and it only occurs if any locks are applied to that file. 00899 00900 Arguments: 00901 00902 FileLock - Supplies a pointer to the FILE_LOCK structure to 00903 initialize. 00904 00905 ViaFastCall - Indicates if we are being invoked via a fast call or 00906 via the slow irp based method. 00907 00908 Return Value: 00909 00910 TRUE - If LockInfo structure was allocated and initialized 00911 00912 --*/ 00913 { 00914 PLOCK_INFO LockInfo; 00915 BOOLEAN Results = FALSE; 00916 00917 ExAcquireFastMutex( &FsRtlCreateLockInfo ); 00918 00919 try { 00920 00921 if (FileLock->LockInformation != NULL) { 00922 00923 // 00924 // Structure is already allocated, just return 00925 // 00926 00927 try_return( Results = TRUE ); 00928 } 00929 00930 // 00931 // Allocate pool for lock structures. If we fail then we will either return false or 00932 // raise based on if we know the caller has an try-except to handle a raise. 00933 // 00934 00935 LockInfo = FsRtlAllocateLockInfo(); 00936 00937 if (LockInfo == NULL) { 00938 00939 if (ViaFastCall) { 00940 00941 try_return( Results = FALSE ); 00942 00943 } else { 00944 00945 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 00946 } 00947 } 00948 00949 // 00950 // Allocate and initialize the waiting lock queue 00951 // spinlock, and initialize the queues 00952 // 00953 00954 LockInfo->LowestLockOffset = 0xffffffff; 00955 00956 KeInitializeSpinLock( &LockInfo->LockQueue.QueueSpinLock ); 00957 LockInfo->LockQueue.SharedLockTree = NULL; 00958 LockInfo->LockQueue.ExclusiveLockTree = NULL; 00959 LockInfo->LockQueue.WaitingLocks.Next = NULL; 00960 LockInfo->LockQueue.WaitingLocksTail.Next = NULL; 00961 00962 // 00963 // Copy Irp & Unlock routines from pagable FileLock structure 00964 // to non-pagable LockInfo structure 00965 // 00966 00967 LockInfo->CompleteLockIrpRoutine = FileLock->CompleteLockIrpRoutine; 00968 LockInfo->UnlockRoutine = FileLock->UnlockRoutine; 00969 00970 // 00971 // Clear continuation info for enum routine 00972 // 00973 00974 FileLock->LastReturnedLockInfo.FileObject = NULL; 00975 FileLock->LastReturnedLock = NULL; 00976 00977 // 00978 // Link LockInfo into FileLock 00979 // 00980 00981 FileLock->LockInformation = (PVOID) LockInfo; 00982 Results = TRUE; 00983 00984 try_exit: NOTHING; 00985 } finally { 00986 00987 ExReleaseFastMutex( &FsRtlCreateLockInfo ); 00988 } 00989 00990 return Results; 00991 } 00992 00993 00994 VOID 00995 FsRtlUninitializeFileLock ( 00996 IN PFILE_LOCK FileLock 00997 ) 00998 00999 /*++ 01000 01001 Routine Description: 01002 01003 This routine uninitializes a FILE_LOCK structure. After calling this 01004 routine the File lock must be reinitialized before being used again. 01005 01006 This routine will free all files locks and completes any outstanding 01007 lock requests as a result of cleaning itself up. 01008 01009 Arguments: 01010 01011 FileLock - Supplies a pointer to the FILE_LOCK struture being 01012 decommissioned. 01013 01014 Return Value: 01015 01016 None. 01017 01018 --*/ 01019 01020 { 01021 PLOCK_INFO LockInfo; 01022 PSH_LOCK ShLock; 01023 PEX_LOCK ExLock; 01024 PSINGLE_LIST_ENTRY Link; 01025 PWAITING_LOCK WaitingLock; 01026 PLOCKTREE_NODE LockTreeNode; 01027 PIRP Irp; 01028 NTSTATUS NewStatus; 01029 KIRQL OldIrql; 01030 PKPRCB Prcb; 01031 01032 DebugTrace(+1, Dbg, "FsRtlUninitializeFileLock, FileLock = %08lx\n", FileLock); 01033 01034 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 01035 return ; 01036 } 01037 01038 // 01039 // Lock the queue 01040 // 01041 01042 FsRtlAcquireLockQueue(&LockInfo->LockQueue, &OldIrql); 01043 01044 // 01045 // Free lock trees 01046 // 01047 01048 while (LockInfo->LockQueue.SharedLockTree != NULL) { 01049 01050 LockTreeNode = CONTAINING_RECORD(LockInfo->LockQueue.SharedLockTree, LOCKTREE_NODE, Links); 01051 01052 // 01053 // Remove all locks associated with the root node 01054 // 01055 01056 while (LockTreeNode->Locks.Next != NULL) { 01057 Link = PopEntryList (&LockTreeNode->Locks); 01058 ShLock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 01059 01060 FsRtlFreeSharedLock(ShLock); 01061 } 01062 01063 // 01064 // Slice off the root node of the tree 01065 // 01066 01067 RtlDeleteNoSplay(&LockTreeNode->Links, &LockInfo->LockQueue.SharedLockTree); 01068 01069 FsRtlFreeLockTreeNode(LockTreeNode); 01070 } 01071 01072 while (LockInfo->LockQueue.ExclusiveLockTree != NULL) { 01073 01074 ExLock = CONTAINING_RECORD(LockInfo->LockQueue.ExclusiveLockTree, EX_LOCK, Links); 01075 01076 RtlDeleteNoSplay(&ExLock->Links, &LockInfo->LockQueue.ExclusiveLockTree); 01077 01078 FsRtlFreeExclusiveLock(ExLock); 01079 } 01080 01081 // 01082 // Free WaitingLockQueue 01083 // 01084 01085 while (LockInfo->LockQueue.WaitingLocks.Next != NULL) { 01086 01087 Link = PopEntryList( &LockInfo->LockQueue.WaitingLocks ); 01088 WaitingLock = CONTAINING_RECORD( Link, WAITING_LOCK, Link ); 01089 01090 Irp = WaitingLock->Irp; 01091 01092 // 01093 // To complete an irp in the waiting queue we need to 01094 // void the cancel routine (protected by a spinlock) before 01095 // we can complete the irp 01096 // 01097 01098 FsRtlReleaseLockQueue (&LockInfo->LockQueue, OldIrql); 01099 01100 IoAcquireCancelSpinLock( &Irp->CancelIrql ); 01101 IoSetCancelRoutine( Irp, NULL ); 01102 IoReleaseCancelSpinLock( Irp->CancelIrql ); 01103 01104 Irp->IoStatus.Information = 0; 01105 01106 FsRtlCompleteLockIrp( 01107 LockInfo, 01108 WaitingLock->Context, 01109 Irp, 01110 STATUS_RANGE_NOT_LOCKED, 01111 &NewStatus, 01112 NULL ); 01113 01114 FsRtlAcquireLockQueue(&LockInfo->LockQueue, &OldIrql); 01115 FsRtlFreeWaitingLock( WaitingLock ); 01116 } 01117 01118 // 01119 // Free pool used to track the lock info on this file 01120 // 01121 01122 FsRtlReleaseLockQueue( &LockInfo->LockQueue, OldIrql ); 01123 FsRtlFreeLockInfo( LockInfo ); 01124 01125 // 01126 // Unlink LockInfo from FileLock 01127 // 01128 01129 FileLock->LockInformation = NULL; 01130 01131 // 01132 // And return to our caller 01133 // 01134 01135 DebugTrace(-1, Dbg, "FsRtlUninitializeFileLock -> VOID\n", 0 ); 01136 return; 01137 } 01138 01139 01140 PFILE_LOCK 01141 FsRtlAllocateFileLock ( 01142 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, 01143 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL 01144 01145 ) 01146 { 01147 PFILE_LOCK FileLock; 01148 01149 FileLock = ExAllocateFromPagedLookasideList( &FsRtlFileLockLookasideList ); 01150 01151 if (FileLock != NULL) { 01152 01153 FsRtlInitializeFileLock( FileLock, 01154 CompleteLockIrpRoutine, 01155 UnlockRoutine ); 01156 } 01157 01158 return FileLock; 01159 } 01160 01161 VOID 01162 FsRtlFreeFileLock ( 01163 IN PFILE_LOCK FileLock 01164 ) 01165 { 01166 FsRtlUninitializeFileLock( FileLock ); 01167 01168 ExFreeToPagedLookasideList( &FsRtlFileLockLookasideList, FileLock ); 01169 } 01170 01171 01172 NTSTATUS 01173 FsRtlProcessFileLock ( 01174 IN PFILE_LOCK FileLock, 01175 IN PIRP Irp, 01176 IN PVOID Context OPTIONAL 01177 ) 01178 01179 /*++ 01180 01181 Routine Description: 01182 01183 This routine processes a file lock IRP it does either a lock request, 01184 or an unlock request. It also completes the IRP. Once called the user 01185 (i.e., File System) has relinquished control of the input IRP. 01186 01187 If pool is not available to store the information this routine will raise a 01188 status value indicating insufficient resources. 01189 01190 Arguments: 01191 01192 FileLock - Supplies the File lock being modified/queried. 01193 01194 Irp - Supplies the Irp being processed. 01195 01196 Context - Optionally supplies a context to use when calling the user 01197 alternate IRP completion routine. 01198 01199 Return Value: 01200 01201 NTSTATUS - The return status for the operation. 01202 01203 --*/ 01204 01205 { 01206 PIO_STACK_LOCATION IrpSp; 01207 01208 IO_STATUS_BLOCK Iosb; 01209 NTSTATUS Status; 01210 LARGE_INTEGER ByteOffset; 01211 01212 DebugTrace(+1, Dbg, "FsRtlProcessFileLock, FileLock = %08lx\n", FileLock); 01213 01214 Iosb.Information = 0; 01215 01216 // 01217 // Get a pointer to the current Irp stack location and assert that 01218 // the major function code is for a lock operation 01219 // 01220 01221 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01222 01223 ASSERT( IrpSp->MajorFunction == IRP_MJ_LOCK_CONTROL ); 01224 01225 // 01226 // Now process the different minor lock operations 01227 // 01228 01229 switch (IrpSp->MinorFunction) { 01230 01231 case IRP_MN_LOCK: 01232 01233 ByteOffset = IrpSp->Parameters.LockControl.ByteOffset; 01234 01235 (VOID) FsRtlPrivateLock( FileLock, 01236 IrpSp->FileObject, 01237 &ByteOffset, 01238 IrpSp->Parameters.LockControl.Length, 01239 IoGetRequestorProcess(Irp), 01240 IrpSp->Parameters.LockControl.Key, 01241 BooleanFlagOn(IrpSp->Flags, SL_FAIL_IMMEDIATELY), 01242 BooleanFlagOn(IrpSp->Flags, SL_EXCLUSIVE_LOCK), 01243 &Iosb, 01244 Irp, 01245 Context, 01246 FALSE ); 01247 01248 break; 01249 01250 case IRP_MN_UNLOCK_SINGLE: 01251 01252 ByteOffset = IrpSp->Parameters.LockControl.ByteOffset; 01253 01254 Iosb.Status = FsRtlFastUnlockSingle( FileLock, 01255 IrpSp->FileObject, 01256 &ByteOffset, 01257 IrpSp->Parameters.LockControl.Length, 01258 IoGetRequestorProcess(Irp), 01259 IrpSp->Parameters.LockControl.Key, 01260 Context, 01261 FALSE ); 01262 01263 FsRtlCompleteLockIrp( FileLock, Context, Irp, Iosb.Status, &Status, NULL ); 01264 break; 01265 01266 case IRP_MN_UNLOCK_ALL: 01267 01268 Iosb.Status = FsRtlFastUnlockAll( FileLock, 01269 IrpSp->FileObject, 01270 IoGetRequestorProcess(Irp), 01271 Context ); 01272 01273 FsRtlCompleteLockIrp( FileLock, Context, Irp, Iosb.Status, &Status, NULL ); 01274 break; 01275 01276 case IRP_MN_UNLOCK_ALL_BY_KEY: 01277 01278 Iosb.Status = FsRtlFastUnlockAllByKey( FileLock, 01279 IrpSp->FileObject, 01280 IoGetRequestorProcess(Irp), 01281 IrpSp->Parameters.LockControl.Key, 01282 Context ); 01283 01284 FsRtlCompleteLockIrp( FileLock, Context, Irp, Iosb.Status, &Status, NULL ); 01285 break; 01286 01287 default: 01288 01289 // 01290 // For all other minor function codes we say they're invalid and 01291 // complete the request. Note that the IRP has not been marked 01292 // pending so this error will be returned directly to the caller. 01293 // 01294 01295 DebugTrace(0, 1, "Invalid LockFile Minor Function Code %08lx\n", IrpSp->MinorFunction); 01296 01297 01298 FsRtlCompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST ); 01299 01300 Iosb.Status = STATUS_INVALID_DEVICE_REQUEST; 01301 break; 01302 } 01303 01304 // 01305 // And return to our caller 01306 // 01307 01308 DebugTrace(-1, Dbg, "FsRtlProcessFileLock -> %08lx\n", Iosb.Status); 01309 01310 return Iosb.Status; 01311 } 01312 01313 01314 BOOLEAN 01315 FsRtlCheckLockForReadAccess ( 01316 IN PFILE_LOCK FileLock, 01317 IN PIRP Irp 01318 ) 01319 01320 /*++ 01321 01322 Routine Description: 01323 01324 This routine checks to see if the caller has read access to the 01325 range indicated in the IRP due to file locks. This call does not 01326 complete the Irp it only uses it to get the lock information and read 01327 information. The IRP must be for a read operation. 01328 01329 Arguments: 01330 01331 FileLock - Supplies the File Lock to check. 01332 01333 Irp - Supplies the Irp being processed. 01334 01335 Return Value: 01336 01337 BOOLEAN - TRUE if the indicated user/request has read access to the 01338 entire specified byte range, and FALSE otherwise 01339 01340 --*/ 01341 01342 { 01343 BOOLEAN Result; 01344 01345 PIO_STACK_LOCATION IrpSp; 01346 01347 PLOCK_INFO LockInfo; 01348 LARGE_INTEGER StartingByte; 01349 LARGE_INTEGER Length; 01350 ULONG Key; 01351 PFILE_OBJECT FileObject; 01352 PVOID ProcessId; 01353 LARGE_INTEGER BeyondLastByte; 01354 01355 DebugTrace(+1, Dbg, "FsRtlCheckLockForReadAccess, FileLock = %08lx\n", FileLock); 01356 01357 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 01358 DebugTrace(-1, Dbg, "FsRtlCheckLockForReadAccess (No current lock info) -> TRUE\n", 0); 01359 return TRUE; 01360 } 01361 01362 // 01363 // Do a really fast test to see if there are any exclusive locks to start with 01364 // 01365 01366 if (LockInfo->LockQueue.ExclusiveLockTree == NULL) { 01367 DebugTrace(-1, Dbg, "FsRtlCheckLockForReadAccess (No current locks) -> TRUE\n", 0); 01368 return TRUE; 01369 } 01370 01371 // 01372 // Get the read offset and compare it to the lowest existing lock. 01373 // 01374 01375 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01376 01377 StartingByte = IrpSp->Parameters.Read.ByteOffset; 01378 (ULONGLONG)Length.QuadPart = (ULONGLONG)IrpSp->Parameters.Read.Length; 01379 01380 (ULONGLONG)BeyondLastByte.QuadPart = (ULONGLONG)StartingByte.QuadPart + Length.LowPart; 01381 if ( (ULONGLONG)BeyondLastByte.QuadPart <= (ULONGLONG)LockInfo->LowestLockOffset ) { 01382 DebugTrace(-1, Dbg, "FsRtlCheckLockForReadAccess (Below lowest lock) -> TRUE\n", 0); 01383 return TRUE; 01384 } 01385 01386 // 01387 // Get remaining parameters. 01388 // 01389 01390 Key = IrpSp->Parameters.Read.Key; 01391 FileObject = IrpSp->FileObject; 01392 ProcessId = IoGetRequestorProcess( Irp ); 01393 01394 // 01395 // Call our private work routine to do the real check 01396 // 01397 01398 Result = FsRtlFastCheckLockForRead( FileLock, 01399 &StartingByte, 01400 &Length, 01401 Key, 01402 FileObject, 01403 ProcessId ); 01404 01405 // 01406 // And return to our caller 01407 // 01408 01409 DebugTrace(-1, Dbg, "FsRtlCheckLockForReadAccess -> %08lx\n", Result); 01410 01411 return Result; 01412 } 01413 01414 01415 BOOLEAN 01416 FsRtlCheckLockForWriteAccess ( 01417 IN PFILE_LOCK FileLock, 01418 IN PIRP Irp 01419 ) 01420 01421 /*++ 01422 01423 Routine Description: 01424 01425 This routine checks to see if the caller has write access to the 01426 indicated range due to file locks. This call does not complete the 01427 Irp it only uses it to get the lock information and write information. 01428 The IRP must be for a write operation. 01429 01430 Arguments: 01431 01432 FileLock - Supplies the File Lock to check. 01433 01434 Irp - Supplies the Irp being processed. 01435 01436 Return Value: 01437 01438 BOOLEAN - TRUE if the indicated user/request has write access to the 01439 entire specified byte range, and FALSE otherwise 01440 01441 --*/ 01442 01443 { 01444 BOOLEAN Result; 01445 01446 PIO_STACK_LOCATION IrpSp; 01447 01448 PLOCK_INFO LockInfo; 01449 LARGE_INTEGER StartingByte; 01450 LARGE_INTEGER Length; 01451 ULONG Key; 01452 PFILE_OBJECT FileObject; 01453 PVOID ProcessId; 01454 LARGE_INTEGER BeyondLastByte; 01455 01456 DebugTrace(+1, Dbg, "FsRtlCheckLockForWriteAccess, FileLock = %08lx\n", FileLock); 01457 01458 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 01459 DebugTrace(-1, Dbg, "FsRtlCheckLockForWriteAccess (No current lock info) -> TRUE\n", 0); 01460 return TRUE; 01461 } 01462 01463 // 01464 // Do a really fast test to see if there are any locks to start with 01465 // 01466 01467 if (LockInfo->LockQueue.ExclusiveLockTree == NULL && LockInfo->LockQueue.SharedLockTree == NULL) { 01468 DebugTrace(-1, Dbg, "FsRtlCheckLockForWriteAccess (No current locks) -> TRUE\n", 0); 01469 return TRUE; 01470 } 01471 01472 // 01473 // Get the write offset and compare it to the lowest existing lock. 01474 // 01475 01476 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 01477 01478 StartingByte = IrpSp->Parameters.Write.ByteOffset; 01479 (ULONGLONG)Length.QuadPart = (ULONGLONG)IrpSp->Parameters.Write.Length; 01480 01481 (ULONGLONG)BeyondLastByte.QuadPart = (ULONGLONG)StartingByte.QuadPart + Length.LowPart; 01482 if ( (ULONGLONG)BeyondLastByte.QuadPart <= (ULONGLONG)LockInfo->LowestLockOffset ) { 01483 DebugTrace(-1, Dbg, "FsRtlCheckLockForWriteAccess (Below lowest lock) -> TRUE\n", 0); 01484 return TRUE; 01485 } 01486 01487 // 01488 // Get remaining parameters. 01489 // 01490 01491 Key = IrpSp->Parameters.Write.Key; 01492 FileObject = IrpSp->FileObject; 01493 ProcessId = IoGetRequestorProcess( Irp ); 01494 01495 // 01496 // Call our private work routine to do the real work 01497 // 01498 01499 Result = FsRtlFastCheckLockForWrite( FileLock, 01500 &StartingByte, 01501 &Length, 01502 Key, 01503 FileObject, 01504 ProcessId ); 01505 01506 // 01507 // And return to our caller 01508 // 01509 01510 DebugTrace(-1, Dbg, "FsRtlCheckLockForWriteAccess -> %08lx\n", Result); 01511 01512 return Result; 01513 } 01514 01515 01516 PRTL_SPLAY_LINKS 01517 FsRtlFindFirstOverlappingSharedNode ( 01518 IN PRTL_SPLAY_LINKS Tree, 01519 IN PLARGE_INTEGER StartingByte, 01520 IN PLARGE_INTEGER EndingByte, 01521 IN OUT PRTL_SPLAY_LINKS *LastEdgeNode, 01522 IN OUT PBOOLEAN GreaterThan 01523 ) 01524 /*++ 01525 01526 Routine Description: 01527 01528 This routine returns the first node in the shared lock tree which 01529 overlaps with the range given. No nodes given by RtlRealPredecessor() 01530 on the result overlap the range. 01531 01532 Arguments: 01533 01534 Tree - supplies the splay links of the root node of the shared tree 01535 to search 01536 01537 StartingByte - supplies the first byte offset of the range to check 01538 01539 EndingByte - supplies the last byte offset of the range to check 01540 01541 LastEdgeNode - optional, will be set to the last node searched in the 01542 not including returned node (presumeably where a new node will 01543 be inserted if return is NULL). 01544 01545 GreaterThan - optional, set according to whether LastEdgeNode is covering 01546 a range greater than the queried range. !GreaterThan == LessThan, since 01547 we would have returned this node in the "Equals" (overlap) case. 01548 01549 Return Value: 01550 01551 The splay links of the node, if such a node exists, NULL otherwise 01552 01553 --*/ 01554 { 01555 PLOCKTREE_NODE Node, LastOverlapNode; 01556 PRTL_SPLAY_LINKS SplayLinks; 01557 PSH_LOCK Lock; 01558 01559 if (LastEdgeNode) *LastEdgeNode = NULL; 01560 if (GreaterThan) *GreaterThan = FALSE; 01561 01562 LastOverlapNode = NULL; 01563 SplayLinks = Tree; 01564 01565 while (SplayLinks) { 01566 01567 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 01568 01569 // 01570 // Pull up the first lock on the chain at this node to check 01571 // the starting byte offset of locks at this node 01572 // 01573 01574 Lock = CONTAINING_RECORD( Node->Locks.Next, SH_LOCK, Link ); 01575 01576 // 01577 // We may have to go right in the tree if this lock covers a range before the start of this 01578 // range we are looking for overlap on or this lock is [0, 0). This is important since a lock 01579 // on [0, 0) will look like the extent is from [0, ~0], which is the only case where the zero 01580 // length lock relation of End < Start does not hold. 01581 // 01582 01583 if (Node->Extent < (ULONGLONG)StartingByte->QuadPart || 01584 (Lock->LockInfo.StartingByte.QuadPart == 0 && Lock->LockInfo.Length.QuadPart == 0)) { 01585 01586 if ((ULONGLONG)Lock->LockInfo.EndingByte.QuadPart == (ULONGLONG)EndingByte->QuadPart && 01587 (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart == (ULONGLONG)StartingByte->QuadPart) { 01588 01589 // 01590 // The extent of the node is less than the starting position of the 01591 // range we are checking and the first lock on this node is equal to 01592 // the range, which implies that the range and the lock are zero 01593 // length. 01594 // 01595 // This is a zero length lock node and we are searching for zero 01596 // length overlap. This makes multiple zero length shared locks 01597 // occupy the same node, which is a win, but makes application of 01598 // zero length exclusive locks check the length of the overlapping 01599 // lock to see if they really conflict. 01600 // 01601 01602 break; 01603 } 01604 01605 // 01606 // All locks at this node are strictly less than this 01607 // byterange, so go right in the tree. 01608 // 01609 01610 if (LastEdgeNode) *LastEdgeNode = SplayLinks; 01611 if (GreaterThan) *GreaterThan = FALSE; 01612 01613 SplayLinks = RtlRightChild(SplayLinks); 01614 continue; 01615 } 01616 01617 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart <= (ULONGLONG)EndingByte->QuadPart) { 01618 01619 // 01620 // We have an overlap, but we need to see if the byterange starts 01621 // before this node so that there is the guarantee that we start 01622 // the search at the correct point. There may be still be predecessor 01623 // nodes covering the byterange. 01624 // 01625 01626 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart <= (ULONGLONG)StartingByte->QuadPart) { 01627 01628 // 01629 // This node begins at a byte offset prior to the byterange we 01630 // are checking, so it must be the correct starting position. 01631 // 01632 01633 break; 01634 } 01635 01636 // 01637 // Drop a marker at this node so that we can come back if it turns out 01638 // that the left subtree does not cover the range of bytes before this 01639 // node in the byterange. 01640 // 01641 01642 LastOverlapNode = Node; 01643 } 01644 01645 // 01646 // It must now be the case that all locks at this node are strictly greater 01647 // than the byterange, or we have the candidate overlap case above, 01648 // so go left in the tree. 01649 // 01650 01651 if (LastEdgeNode) *LastEdgeNode = SplayLinks; 01652 if (GreaterThan) *GreaterThan = TRUE; 01653 01654 SplayLinks = RtlLeftChild(SplayLinks); 01655 } 01656 01657 if (SplayLinks == NULL) { 01658 01659 // 01660 // We hit the edge of the tree. If the LastOverlapNode is set, it means that 01661 // we had kept searching left in the tree for a node that covered the starting 01662 // byte of the byterange, but didn't find it. If it isn't set, we'll do the 01663 // right thing anyway since Node <- NULL. 01664 // 01665 01666 Node = LastOverlapNode; 01667 } 01668 01669 if (Node == NULL) { 01670 01671 // 01672 // No overlapping node existed 01673 // 01674 01675 return NULL; 01676 } 01677 01678 // 01679 // Return the splay links of the first overlapping node 01680 // 01681 01682 return &Node->Links; 01683 } 01684 01685 01686 PRTL_SPLAY_LINKS 01687 FsRtlFindFirstOverlappingExclusiveNode ( 01688 IN PRTL_SPLAY_LINKS Tree, 01689 IN PLARGE_INTEGER StartingByte, 01690 IN PLARGE_INTEGER EndingByte, 01691 IN OUT PRTL_SPLAY_LINKS *LastEdgeNode, 01692 IN OUT PBOOLEAN GreaterThan 01693 ) 01694 /*++ 01695 01696 Routine Description: 01697 01698 This routine returns the first node in the exclusive lock tree which 01699 overlaps with the range given. No nodes given by RtlRealPredecessor() 01700 on the result overlap the range. 01701 01702 Arguments: 01703 01704 Tree - supplies the splay links of the root node of the exclusive tree 01705 to search 01706 01707 StartingByte - supplies the first byte offset of the range to check 01708 01709 EndingByte - supplies the last byte offset of the range to check 01710 01711 LastEdgeNode - optional, will be set to the last node searched 01712 not including returned node (presumeably where a new node will 01713 be inserted if return is NULL). 01714 01715 GreaterThan - optional, set according to whether LastEdgeNode is covering 01716 a range greater than the queried range. !GreaterThan == LessThan, since 01717 we would have returned this node in the "Equals" (overlap) case. 01718 01719 Return Value: 01720 01721 The splay links of the node, if such a node exists, NULL otherwise 01722 01723 --*/ 01724 { 01725 PRTL_SPLAY_LINKS SplayLinks; 01726 PEX_LOCK Lock, LastOverlapNode; 01727 01728 if (LastEdgeNode) *LastEdgeNode = NULL; 01729 if (GreaterThan) *GreaterThan = FALSE; 01730 01731 LastOverlapNode = NULL; 01732 SplayLinks = Tree; 01733 01734 while (SplayLinks) { 01735 01736 Lock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 01737 01738 // 01739 // We may have to go right in the tree if this lock covers a range before the start of this 01740 // range we are looking for overlap on or this lock is [0, 0). This is important since a lock 01741 // on [0, 0) will look like the extent is from [0, ~0], which is the only case where the zero 01742 // length lock relation of End < Start does not hold. 01743 // 01744 01745 if ((ULONGLONG)Lock->LockInfo.EndingByte.QuadPart < (ULONGLONG)StartingByte->QuadPart || 01746 (Lock->LockInfo.StartingByte.QuadPart == 0 && Lock->LockInfo.Length.QuadPart == 0)) { 01747 01748 if ((ULONGLONG)Lock->LockInfo.EndingByte.QuadPart == (ULONGLONG)EndingByte->QuadPart && 01749 (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart == (ULONGLONG)StartingByte->QuadPart) { 01750 01751 // 01752 // The extent of the lock is less than the starting position of the 01753 // range we are checking and the lock is equal to the range, which 01754 // implies that the range and the lock are zero length. 01755 // 01756 // This is a zero length lock node and we are searching for zero 01757 // length overlap. Since the exclusive tree is one lock per node, 01758 // we are in the potential middle of a run of zero length locks in 01759 // the tree. Go left to find the first zero length lock. 01760 // 01761 // This is actually the same logic we'd use for equivalent locks, 01762 // but the only time that can happen in this tree is for zero length 01763 // locks. 01764 // 01765 01766 LastOverlapNode = Lock; 01767 01768 if (LastEdgeNode) *LastEdgeNode = SplayLinks; 01769 if (GreaterThan) *GreaterThan = FALSE; 01770 01771 SplayLinks = RtlLeftChild(SplayLinks); 01772 continue; 01773 } 01774 01775 // 01776 // This lock is strictly less than this byterange, so go 01777 // right in the tree. 01778 // 01779 01780 if (LastEdgeNode) *LastEdgeNode = SplayLinks; 01781 if (GreaterThan) *GreaterThan = FALSE; 01782 01783 SplayLinks = RtlRightChild(SplayLinks); 01784 continue; 01785 } 01786 01787 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart <= (ULONGLONG)EndingByte->QuadPart) { 01788 01789 // 01790 // We have an overlap, but we need to see if the byterange starts 01791 // before this node so that there is the guarantee that we start 01792 // the search at the correct point. There may be still be predecessor 01793 // nodes covering the byterange. 01794 // 01795 01796 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart <= (ULONGLONG)StartingByte->QuadPart) { 01797 01798 // 01799 // This node begins at a byte offset prior to the byterange we 01800 // are checking, so it must be the correct starting position. 01801 // 01802 01803 break; 01804 } 01805 01806 // 01807 // Drop a marker at this node so that we can come back if it turns out 01808 // that the left subtree does not cover the range of bytes before this 01809 // node in the byterange. 01810 // 01811 01812 LastOverlapNode = Lock; 01813 } 01814 01815 // 01816 // It must now be the case this lock is strictly greater than the byterange, 01817 // or we have the candidate overlap case above, so go left in the tree. 01818 // 01819 01820 if (LastEdgeNode) *LastEdgeNode = SplayLinks; 01821 if (GreaterThan) *GreaterThan = TRUE; 01822 01823 SplayLinks = RtlLeftChild(SplayLinks); 01824 } 01825 01826 if (SplayLinks == NULL) { 01827 01828 // 01829 // We hit the edge of the tree. If the LastOverlapNode is set, it means that 01830 // we had kept searching left in the tree for a node that covered the starting 01831 // byte of the byterange, but didn't find it. If it isn't set, we'll do the 01832 // right thing anyway since Node <- NULL. 01833 // 01834 01835 Lock = LastOverlapNode; 01836 } 01837 01838 if (Lock == NULL) { 01839 01840 // 01841 // No overlapping lock existed 01842 // 01843 01844 return NULL; 01845 } 01846 01847 // 01848 // Return the splay links of the first overlapping lock 01849 // 01850 01851 return &Lock->Links; 01852 } 01853 01854 01855 PSH_LOCK 01856 FsRtlFindFirstOverlapInNode ( 01857 IN PLOCKTREE_NODE Node, 01858 IN PLARGE_INTEGER StartingByte, 01859 IN PLARGE_INTEGER EndingByte 01860 ) 01861 01862 /*++ 01863 01864 Routine Description: 01865 01866 This routine examines a shared lock node, usually a node which is known to be composed 01867 of several non-overlapping lock segments (holey), for true overlap with the indicated 01868 range. This is not handled in the normal overlap check (..FindFirstOverlappingSharedLock) 01869 since the needs for holey checks are rather different than the full node check. 01870 01871 Arguments: 01872 01873 Node - the lock tree node to be examined for overlap 01874 01875 StartingByte - supplies the first byte offset of the range to check 01876 01877 EndingByte - supplies the last byte offset of the range to check 01878 01879 Return Value: 01880 01881 PSH_LOCK - the first lock which overlaps with the specified range. 01882 01883 --*/ 01884 { 01885 PSH_LOCK Lock; 01886 PSINGLE_LIST_ENTRY Link; 01887 01888 for (Link = Node->Locks.Next; 01889 Link; 01890 Link = Link->Next) { 01891 01892 Lock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 01893 01894 // 01895 // Logic is the same as above checkers. If the ending byte of the lock is less than the 01896 // starting byte of the range, OR we have the weird [0, 0) case, then the lock is almost 01897 // certainly less than the range. 01898 // 01899 01900 if ((ULONGLONG)Lock->LockInfo.EndingByte.QuadPart < (ULONGLONG)StartingByte->QuadPart || 01901 (Lock->LockInfo.StartingByte.QuadPart == 0 && Lock->LockInfo.Length.QuadPart == 0)) { 01902 01903 // 01904 // ... except if the lock and range are equivalent, in which case we have discovered 01905 // zero lock/range overlap. 01906 // 01907 01908 if ((ULONGLONG)Lock->LockInfo.EndingByte.QuadPart == (ULONGLONG)EndingByte->QuadPart && 01909 (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart == (ULONGLONG)StartingByte->QuadPart) { 01910 01911 return Lock; 01912 } 01913 01914 // 01915 // Look forward in the node. 01916 // 01917 01918 continue; 01919 } 01920 01921 // 01922 // No overlap at all if the lock begins at a higher byte than the last of the range. 01923 // We already covered zero length locks (where this is true, and overlap could still 01924 // occur). 01925 // 01926 01927 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)EndingByte->QuadPart) { 01928 01929 return NULL; 01930 } 01931 01932 // 01933 // Regular overlap has occured. Return this lock. 01934 // 01935 01936 return Lock; 01937 } 01938 01939 // 01940 // If we invoke this check and wander off the end of the node without determining what is 01941 // going on, something is terribly wrong. 01942 // 01943 01944 ASSERT( FALSE ); 01945 01946 return NULL; 01947 } 01948 01949 01950 PFILE_LOCK_INFO 01951 FsRtlGetNextFileLock ( 01952 IN PFILE_LOCK FileLock, 01953 IN BOOLEAN Restart 01954 ) 01955 01956 /*++ 01957 01958 Routine Description: 01959 01960 This routine enumerates the individual file locks denoted by the input file lock 01961 variable. It returns a pointer to the file lock information stored for each lock. 01962 The caller is responsible for synchronizing call to this procedure and for not 01963 altering any of the data returned by this procedure. If the caller does not 01964 synchronize the enumeration will not be reliably complete. 01965 01966 The way a programmer will use this procedure to enumerate all of the locks 01967 is as follows: 01968 01969 for (p = FsRtlGetNextFileLock( FileLock, TRUE ); 01970 p != NULL; 01971 p = FsRtlGetNextFileLock( FileLock, FALSE )) { 01972 01973 // Process the lock information referenced by p 01974 } 01975 01976 Order is *not* guaranteed. 01977 01978 Arguments: 01979 01980 FileLock - Supplies the File Lock to enumerate. The current 01981 enumeration state is stored in the file lock variable so if multiple 01982 threads are enumerating the lock at the same time the results will 01983 be unpredictable. 01984 01985 Restart - Indicates if the enumeration is to start at the beginning of the 01986 file lock tree or if we are continuing from a previous call. 01987 01988 Return Value: 01989 01990 PFILE_LOCK_INFO - Either it returns a pointer to the next file lock 01991 record for the input file lock or it returns NULL if there 01992 are not more locks. 01993 01994 --*/ 01995 01996 { 01997 FILE_LOCK_INFO FileLockInfo; 01998 PVOID ContinuationPointer; 01999 PLOCK_INFO LockInfo; 02000 PLOCKTREE_NODE Node; 02001 PSINGLE_LIST_ENTRY Link; 02002 PRTL_SPLAY_LINKS SplayLinks, LastSplayLinks; 02003 PSH_LOCK ShLock; 02004 PEX_LOCK ExLock; 02005 BOOLEAN FoundReturnable, GreaterThan; 02006 KIRQL OldIrql; 02007 02008 DebugTrace(+1, Dbg, "FsRtlGetNextFileLock, FileLock = %08lx\n", FileLock); 02009 02010 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 02011 // 02012 // No lock information on this FileLock 02013 // 02014 02015 return NULL; 02016 } 02017 02018 FoundReturnable = FALSE; 02019 02020 // 02021 // Before getting the spinlock, copy pagable info onto stack 02022 // 02023 02024 FileLockInfo = FileLock->LastReturnedLockInfo; 02025 ContinuationPointer = FileLock->LastReturnedLock; 02026 02027 FsRtlAcquireLockQueue (&LockInfo->LockQueue, &OldIrql); 02028 02029 if (!Restart) { 02030 // 02031 // Given the last returned lock, find its current successor in the tree. 02032 // Previous implementations would reset the enumeration if the last returned 02033 // lock had been removed from the tree but I think we can be better in that 02034 // case since every other structure modifying event (add new locks, delete 02035 // other locks) would *not* have caused the reset. Possible minor performance 02036 // enhancement. 02037 // 02038 02039 // 02040 // Find the node which could contain the last returned lock. We enumerate the 02041 // exclusive lock tree, then the shared lock tree. Find the one we're enumerating. 02042 // 02043 02044 if (FileLockInfo.ExclusiveLock) { 02045 02046 // 02047 // Continue enumeration in the exclusive lock tree 02048 // 02049 02050 ExLock = NULL; 02051 02052 SplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockInfo->LockQueue.ExclusiveLockTree, 02053 &FileLockInfo.StartingByte, 02054 &FileLockInfo.EndingByte, 02055 &LastSplayLinks, 02056 &GreaterThan ); 02057 02058 if (SplayLinks == NULL) { 02059 02060 // 02061 // No overlapping nodes were found, try to find successor 02062 // 02063 02064 if (GreaterThan) { 02065 02066 // 02067 // Last node looked at was greater than the lock so it is 02068 // the place to pick up the enumeration 02069 // 02070 02071 SplayLinks = LastSplayLinks; 02072 02073 } else { 02074 02075 // 02076 // Last node looked at was less than the lock so grab its successor 02077 // 02078 02079 if (LastSplayLinks) { 02080 02081 SplayLinks = RtlRealSuccessor(LastSplayLinks); 02082 } 02083 } 02084 02085 } else { 02086 02087 // 02088 // Found an overlapping lock, see if it is the last returned 02089 // 02090 02091 for (; 02092 SplayLinks; 02093 SplayLinks = RtlRealSuccessor(SplayLinks)) { 02094 02095 ExLock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 02096 02097 if (ContinuationPointer == ExLock && 02098 (ULONGLONG)FileLockInfo.StartingByte.QuadPart == (ULONGLONG)ExLock->LockInfo.StartingByte.QuadPart && 02099 (ULONGLONG)FileLockInfo.Length.QuadPart == (ULONGLONG)ExLock->LockInfo.Length.QuadPart && 02100 FileLockInfo.Key == ExLock->LockInfo.Key && 02101 FileLockInfo.FileObject == ExLock->LockInfo.FileObject && 02102 FileLockInfo.ProcessId == ExLock->LockInfo.ProcessId) { 02103 02104 // 02105 // Found last returned, dig up its successor 02106 // 02107 02108 SplayLinks = RtlRealSuccessor(SplayLinks); 02109 02110 // 02111 // Got the node cold, so we're done 02112 // 02113 02114 break; 02115 } 02116 02117 // 02118 // This lock overlapped and was not the last returned. In fact, since this lock would 02119 // have conflicted with the last returned we know it could not have been returned 02120 // before, so this should be returned to the caller. 02121 // 02122 // However, if it is a zero length lock we are looking for and a zero length lock we hit, 02123 // we are at the beginning of a run we need to inspect. If we cannot find the last lock 02124 // we returned, resume the enumeration at the beginning of the run. 02125 // 02126 02127 if (ExLock->LockInfo.Length.QuadPart != 0 || FileLockInfo.Length.QuadPart != 0) { 02128 02129 break; 02130 } 02131 02132 // 02133 // Keep wandering down the run 02134 // 02135 } 02136 } 02137 02138 // 02139 // Were we able to find a lock to return? 02140 // 02141 02142 if (SplayLinks == NULL) { 02143 02144 // 02145 // There aren't any more exclusive locks, fall over to the shared tree 02146 // 02147 02148 SplayLinks = LockInfo->LockQueue.SharedLockTree; 02149 02150 if (SplayLinks) { 02151 02152 while (RtlLeftChild(SplayLinks)) { 02153 02154 SplayLinks = RtlLeftChild(SplayLinks); 02155 } 02156 02157 Node = CONTAINING_RECORD(SplayLinks, LOCKTREE_NODE, Links); 02158 ShLock = CONTAINING_RECORD(Node->Locks.Next, SH_LOCK, Link); 02159 02160 FileLockInfo = ShLock->LockInfo; 02161 ContinuationPointer = ShLock; 02162 FoundReturnable = TRUE; 02163 } 02164 02165 } else { 02166 02167 // 02168 // This is the lock to return 02169 // 02170 02171 ExLock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 02172 02173 FileLockInfo = ExLock->LockInfo; 02174 ContinuationPointer = ExLock; 02175 FoundReturnable = TRUE; 02176 } 02177 02178 } else { 02179 02180 // 02181 // Continue enumeration in the shared lock tree 02182 // 02183 02184 Node = NULL; 02185 02186 SplayLinks = FsRtlFindFirstOverlappingSharedNode( LockInfo->LockQueue.SharedLockTree, 02187 &FileLockInfo.StartingByte, 02188 &FileLockInfo.EndingByte, 02189 &LastSplayLinks, 02190 &GreaterThan ); 02191 02192 if (SplayLinks == NULL) { 02193 02194 // 02195 // No overlapping nodes were found 02196 // 02197 02198 if (GreaterThan) { 02199 02200 // 02201 // Last node looked at was greater than the lock so it is 02202 // the place to pick up the enumeration 02203 // 02204 02205 if (LastSplayLinks) { 02206 02207 SplayLinks = LastSplayLinks; 02208 Node = CONTAINING_RECORD( LastSplayLinks, LOCKTREE_NODE, Links ); 02209 } 02210 02211 } else { 02212 02213 // 02214 // Last node looked at was less than the lock so grab its successor 02215 // 02216 02217 if (LastSplayLinks) { 02218 02219 SplayLinks = RtlRealSuccessor(LastSplayLinks); 02220 02221 if (SplayLinks) { 02222 02223 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 02224 } 02225 } 02226 } 02227 02228 } else { 02229 02230 // 02231 // Grab the node we found 02232 // 02233 02234 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 02235 } 02236 02237 // 02238 // If we have a node to look at, it may still not contain the the last returned lock 02239 // if this isn't synchronized. 02240 // 02241 02242 if (Node != NULL) { 02243 02244 // 02245 // Walk down the locks at this node looking for the last returned lock 02246 // 02247 02248 for (Link = Node->Locks.Next; 02249 Link; 02250 Link = Link->Next) { 02251 02252 // 02253 // Get a pointer to the current lock record 02254 // 02255 02256 ShLock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 02257 02258 // 02259 // See if it's a match 02260 // 02261 02262 if (ContinuationPointer == ShLock && 02263 (ULONGLONG)FileLockInfo.StartingByte.QuadPart == (ULONGLONG)ShLock->LockInfo.StartingByte.QuadPart && 02264 (ULONGLONG)FileLockInfo.Length.QuadPart == (ULONGLONG)ShLock->LockInfo.Length.QuadPart && 02265 FileLockInfo.Key == ShLock->LockInfo.Key && 02266 FileLockInfo.FileObject == ShLock->LockInfo.FileObject && 02267 FileLockInfo.ProcessId == ShLock->LockInfo.ProcessId) { 02268 02269 Link = Link->Next; 02270 break; 02271 } 02272 02273 // 02274 // See if we passed by its slot 02275 // 02276 02277 if ((ULONGLONG)FileLockInfo.StartingByte.QuadPart < (ULONGLONG)ShLock->LockInfo.StartingByte.QuadPart) { 02278 02279 break; 02280 } 02281 } 02282 02283 if (Link == NULL) { 02284 02285 // 02286 // This node doesn't contain the successor, so move 02287 // up to the successor node in the tree and return the 02288 // first lock. If we're actually at the end of the tree 02289 // we just fall off the end correctly. 02290 // 02291 02292 SplayLinks = RtlRealSuccessor(SplayLinks); 02293 02294 if (SplayLinks) { 02295 02296 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 02297 02298 Link = Node->Locks.Next; 02299 } 02300 } 02301 02302 if (Link) { 02303 02304 // 02305 // Found a Lock to return, copy it to the stack 02306 // 02307 02308 ShLock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 02309 02310 FileLockInfo = ShLock->LockInfo; 02311 ContinuationPointer = ShLock; 02312 FoundReturnable = TRUE; 02313 } 02314 02315 } 02316 } 02317 02318 } else { 02319 02320 // 02321 // Restarting the enumeration. Find leftmost node in the exclusive tree and hand back 02322 // the first lock, falling over to the shared if no exlcusive locks are applied 02323 // 02324 02325 if (LockInfo->LockQueue.ExclusiveLockTree) { 02326 02327 SplayLinks = LockInfo->LockQueue.ExclusiveLockTree; 02328 02329 while (RtlLeftChild(SplayLinks) != NULL) { 02330 02331 SplayLinks = RtlLeftChild(SplayLinks); 02332 } 02333 02334 ExLock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 02335 02336 FileLockInfo = ExLock->LockInfo; 02337 ContinuationPointer = ExLock; 02338 FoundReturnable = TRUE; 02339 02340 } else { 02341 02342 if (LockInfo->LockQueue.SharedLockTree) { 02343 02344 SplayLinks = LockInfo->LockQueue.SharedLockTree; 02345 02346 while (RtlLeftChild(SplayLinks) != NULL) { 02347 02348 SplayLinks = RtlLeftChild(SplayLinks); 02349 } 02350 02351 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 02352 ShLock = CONTAINING_RECORD( Node->Locks.Next, SH_LOCK, Link ); 02353 02354 FileLockInfo = ShLock->LockInfo; 02355 ContinuationPointer = ShLock; 02356 FoundReturnable = TRUE; 02357 } 02358 } 02359 } 02360 02361 // 02362 // Release all the lock queues 02363 // 02364 02365 FsRtlReleaseLockQueue (&LockInfo->LockQueue, OldIrql); 02366 02367 if (!FoundReturnable) { 02368 02369 // 02370 // No returnable lock was found, end of list 02371 // 02372 02373 return NULL; 02374 } 02375 02376 // 02377 // Update current enum location information 02378 // 02379 02380 FileLock->LastReturnedLockInfo = FileLockInfo; 02381 FileLock->LastReturnedLock = ContinuationPointer; 02382 02383 // 02384 // Return lock record to caller 02385 // 02386 02387 return &FileLock->LastReturnedLockInfo; 02388 } 02389 02390 02391 BOOLEAN 02392 FsRtlCheckNoSharedConflict ( 02393 IN PLOCK_QUEUE LockQueue, 02394 IN PLARGE_INTEGER Starting, 02395 IN PLARGE_INTEGER Ending 02396 ) 02397 /*++ 02398 02399 Routine Description: 02400 02401 This routine checks to see if there is overlap in the shared locks with 02402 the given range. It is intended for use in the write access check path 02403 so that a rebalance will occur. 02404 02405 Arguments: 02406 02407 FileLock - Supplies the File Lock to check 02408 02409 StartingByte - Supplies the first byte (zero based) to check 02410 02411 Length - Supplies the length, in bytes, to check 02412 02413 Key - Supplies the key to use in the check 02414 02415 FileObject - Supplies the file object to use in the check 02416 02417 ProcessId - Supplies the Process Id to use in the check 02418 02419 Return Value: 02420 02421 BOOLEAN - TRUE if the indicated user/request doesn't conflict in 02422 entire specified byte range, and FALSE otherwise 02423 02424 --*/ 02425 { 02426 PRTL_SPLAY_LINKS SplayLinks, BeginLinks; 02427 PLOCKTREE_NODE Node; 02428 02429 SplayLinks = FsRtlFindFirstOverlappingSharedNode( LockQueue->SharedLockTree, 02430 Starting, 02431 Ending, 02432 &BeginLinks, 02433 NULL); 02434 02435 if (BeginLinks) { 02436 02437 LockQueue->SharedLockTree = RtlSplay(BeginLinks); 02438 } 02439 02440 // 02441 // If this node is holey, we'll have to walk the whole thing. 02442 // 02443 02444 if (SplayLinks) { 02445 02446 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 02447 02448 if (Node->HoleyNode) { 02449 02450 return (BOOLEAN)(FsRtlFindFirstOverlapInNode( Node, Starting, Ending ) == NULL); 02451 } 02452 02453 // 02454 // Overlapping non-holey node, so we do have shared lock conflict. 02455 // 02456 02457 return FALSE; 02458 } 02459 02460 // 02461 // No node overlaps. 02462 // 02463 02464 return TRUE; 02465 } 02466 02467 02468 BOOLEAN 02469 FsRtlCheckNoExclusiveConflict ( 02470 IN PLOCK_QUEUE LockQueue, 02471 IN PLARGE_INTEGER Starting, 02472 IN PLARGE_INTEGER Ending, 02473 IN ULONG Key, 02474 IN PFILE_OBJECT FileObject, 02475 IN PVOID ProcessId 02476 ) 02477 /*++ 02478 02479 Routine Description: 02480 02481 This routine checks to see if there is conflict in the exclusive locks with 02482 a given range and identifying tuple of key, fileobject and process. This is 02483 for part of the read access path. 02484 02485 Arguments: 02486 02487 FileLock - Supplies the File Lock to check 02488 02489 StartingByte - Supplies the first byte (zero based) to check 02490 02491 Length - Supplies the length, in bytes, to check 02492 02493 Key - Supplies the key to use in the check 02494 02495 FileObject - Supplies the file object to use in the check 02496 02497 ProcessId - Supplies the Process Id to use in the check 02498 02499 Return Value: 02500 02501 BOOLEAN - TRUE if the indicated user/request doesn't conflict in 02502 entire specified byte range, and FALSE otherwise 02503 02504 --*/ 02505 { 02506 PRTL_SPLAY_LINKS SplayLinks, BeginLinks; 02507 PEX_LOCK Lock; 02508 BOOLEAN Status = TRUE; 02509 02510 // 02511 // Find the node to begin the search at and go 02512 // 02513 02514 for (SplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockQueue->ExclusiveLockTree, 02515 Starting, 02516 Ending, 02517 &BeginLinks, 02518 NULL); 02519 SplayLinks; 02520 SplayLinks = RtlRealSuccessor(SplayLinks)) { 02521 02522 Lock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 02523 02524 // 02525 // If the current lock is greater than the end of the range we're 02526 // looking for then the the user doesn't conflict 02527 // 02528 // if (Ending < Lock->StartingByte) ... 02529 // 02530 02531 if ((ULONGLONG)Ending->QuadPart < (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart) { 02532 02533 DebugTrace(0, Dbg, "FsRtlCheckForExclusiveConflict, Ending < Lock->StartingByte\n", 0); 02534 02535 break; 02536 } 02537 02538 // 02539 // Check for any overlap with the request. The test for 02540 // overlap is that starting byte is less than or equal to the locks 02541 // ending byte, and the ending byte is greater than or equal to the 02542 // locks starting byte. We already tested for this latter case in 02543 // the preceding statement. 02544 // 02545 // if (Starting <= Lock->StartingByte + Lock->Length - 1) ... 02546 // 02547 02548 if ((ULONGLONG)Starting->QuadPart <= (ULONGLONG)Lock->LockInfo.EndingByte.QuadPart) { 02549 02550 // 02551 // This request overlaps the lock. We cannot grant the request 02552 // if the file object, process id, and key do not match. Otherwise 02553 // we'll continue looping looking at locks 02554 // 02555 02556 if ((Lock->LockInfo.FileObject != FileObject) || 02557 (Lock->LockInfo.ProcessId != ProcessId) || 02558 (Lock->LockInfo.Key != Key)) { 02559 02560 DebugTrace(0, Dbg, "FsRtlCheckForExclusiveConflict, Range locked already\n", 0); 02561 02562 Status = FALSE; 02563 break; 02564 } 02565 } 02566 } 02567 02568 if (BeginLinks) { 02569 02570 LockQueue->ExclusiveLockTree = RtlSplay(BeginLinks); 02571 } 02572 02573 // 02574 // We searched the entire range without a conflict so we'll note no conflict 02575 // 02576 02577 return Status; 02578 } 02579 02580 02581 BOOLEAN 02582 FsRtlFastCheckLockForRead ( 02583 IN PFILE_LOCK FileLock, 02584 IN PLARGE_INTEGER StartingByte, 02585 IN PLARGE_INTEGER Length, 02586 IN ULONG Key, 02587 IN PFILE_OBJECT FileObject, 02588 IN PVOID ProcessId 02589 ) 02590 02591 /*++ 02592 02593 Routine Description: 02594 02595 This routine checks to see if the caller has read access to the 02596 indicated range due to file locks. 02597 02598 Arguments: 02599 02600 FileLock - Supplies the File Lock to check 02601 02602 StartingByte - Supplies the first byte (zero based) to check 02603 02604 Length - Supplies the length, in bytes, to check 02605 02606 Key - Supplies the to use in the check 02607 02608 FileObject - Supplies the file object to use in the check 02609 02610 ProcessId - Supplies the Process Id to use in the check 02611 02612 Return Value: 02613 02614 BOOLEAN - TRUE if the indicated user/request has read access to the 02615 entire specified byte range, and FALSE otherwise 02616 02617 --*/ 02618 02619 { 02620 LARGE_INTEGER Starting; 02621 LARGE_INTEGER Ending; 02622 02623 PLOCK_INFO LockInfo; 02624 PLOCK_QUEUE LockQueue; 02625 KIRQL OldIrql; 02626 PFILE_LOCK_INFO LastLock; 02627 BOOLEAN Status; 02628 02629 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 02630 02631 // 02632 // No lock information on this FileLock 02633 // 02634 02635 DebugTrace(0, Dbg, "FsRtlFastCheckLockForRead, No lock info\n", 0); 02636 return TRUE; 02637 } 02638 02639 // 02640 // If there isn't an exclusive lock then we can immediately grant access 02641 // 02642 02643 if (LockInfo->LockQueue.ExclusiveLockTree == NULL) { 02644 DebugTrace(0, Dbg, "FsRtlFastCheckLockForRead, No exlocks present\n", 0); 02645 return TRUE; 02646 } 02647 02648 // 02649 // If length is zero then automatically give grant access 02650 // 02651 02652 if ((ULONGLONG)Length->QuadPart == 0) { 02653 02654 DebugTrace(0, Dbg, "FsRtlFastCheckLockForRead, Length == 0\n", 0); 02655 return TRUE; 02656 } 02657 02658 // 02659 // Get our starting and ending byte position 02660 // 02661 02662 Starting = *StartingByte; 02663 (ULONGLONG)Ending.QuadPart = (ULONGLONG)Starting.QuadPart + (ULONGLONG)Length->QuadPart - 1; 02664 02665 // 02666 // Now check lock queue 02667 // 02668 02669 LockQueue = &LockInfo->LockQueue; 02670 02671 // 02672 // Grab the waiting lock queue spinlock to exclude anyone from messing 02673 // with the queue while we're using it 02674 // 02675 02676 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 02677 02678 // 02679 // If the range ends below the lowest existing lock, this read is OK. 02680 // 02681 02682 if ( ((ULONGLONG)Ending.QuadPart < (ULONGLONG)LockInfo->LowestLockOffset) ) { 02683 DebugTrace(0, Dbg, "FsRtlFastCheckLockForRead (below lowest lock)\n", 0); 02684 02685 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02686 return TRUE; 02687 } 02688 02689 // 02690 // If the caller just locked this range, he can read it. 02691 // 02692 02693 LastLock = (PFILE_LOCK_INFO)FileObject->LastLock; 02694 if ((LastLock != NULL) && 02695 ((ULONGLONG)Starting.QuadPart >= (ULONGLONG)LastLock->StartingByte.QuadPart) && 02696 ((ULONGLONG)Ending.QuadPart <= (ULONGLONG)LastLock->EndingByte.QuadPart) && 02697 (LastLock->Key == Key) && 02698 (LastLock->ProcessId == ProcessId)) { 02699 02700 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02701 return TRUE; 02702 } 02703 02704 // 02705 // Check the exclusive locks for a conflict. It is impossible to have 02706 // a read conflict with any shared lock. 02707 // 02708 02709 Status = FsRtlCheckNoExclusiveConflict(LockQueue, &Starting, &Ending, Key, FileObject, ProcessId); 02710 02711 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02712 02713 return Status; 02714 } 02715 02716 02717 BOOLEAN 02718 FsRtlFastCheckLockForWrite ( 02719 IN PFILE_LOCK FileLock, 02720 IN PLARGE_INTEGER StartingByte, 02721 IN PLARGE_INTEGER Length, 02722 IN ULONG Key, 02723 IN PVOID FileObject, 02724 IN PVOID ProcessId 02725 ) 02726 02727 /*++ 02728 02729 Routine Description: 02730 02731 This routine checks to see if the caller has write access to the 02732 indicated range due to file locks 02733 02734 Arguments: 02735 02736 FileLock - Supplies the File Lock to check 02737 02738 StartingByte - Supplies the first byte (zero based) to check 02739 02740 Length - Supplies the length, in bytes, to check 02741 02742 Key - Supplies the to use in the check 02743 02744 FileObject - Supplies the file object to use in the check 02745 02746 ProcessId - Supplies the Process Id to use in the check 02747 02748 Return Value: 02749 02750 BOOLEAN - TRUE if the indicated user/request has write access to the 02751 entire specified byte range, and FALSE otherwise 02752 02753 --*/ 02754 02755 { 02756 LARGE_INTEGER Starting; 02757 LARGE_INTEGER Ending; 02758 02759 PLOCK_INFO LockInfo; 02760 PLOCK_QUEUE LockQueue; 02761 KIRQL OldIrql; 02762 PFILE_LOCK_INFO LastLock; 02763 BOOLEAN Status; 02764 02765 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 02766 02767 // 02768 // No lock information on this FileLock 02769 // 02770 02771 DebugTrace(0, Dbg, "FsRtlFastCheckLockForRead, No lock info\n", 0); 02772 return TRUE; 02773 } 02774 02775 // 02776 // If there isn't a lock then we can immediately grant access 02777 // 02778 02779 if (LockInfo->LockQueue.SharedLockTree == NULL && LockInfo->LockQueue.ExclusiveLockTree == NULL) { 02780 02781 DebugTrace(0, Dbg, "FsRtlFastCheckLockForWrite, No locks present\n", 0); 02782 return TRUE; 02783 } 02784 02785 // 02786 // If length is zero then automatically grant access 02787 // 02788 02789 if ((ULONGLONG)Length->QuadPart == 0) { 02790 02791 DebugTrace(0, Dbg, "FsRtlFastCheckLockForWrite, Length == 0\n", 0); 02792 return TRUE; 02793 } 02794 02795 // 02796 // Get our starting and ending byte position 02797 // 02798 02799 Starting = *StartingByte; 02800 (ULONGLONG)Ending.QuadPart = (ULONGLONG)Starting.QuadPart + (ULONGLONG)Length->QuadPart - 1; 02801 02802 // 02803 // Now check lock queue 02804 // 02805 02806 LockQueue = &LockInfo->LockQueue; 02807 02808 // 02809 // Grab the waiting lock queue spinlock to exclude anyone from messing 02810 // with the queue while we're using it 02811 // 02812 02813 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 02814 02815 // 02816 // If the range ends below the lowest existing lock, this write is OK. 02817 // 02818 02819 if ( ((ULONGLONG)Ending.QuadPart < (ULONGLONG)LockInfo->LowestLockOffset) ) { 02820 02821 DebugTrace(0, Dbg, "FsRtlFastCheckLockForWrite (below lowest lock)\n", 0); 02822 02823 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02824 return TRUE; 02825 } 02826 02827 // 02828 // If the caller just locked this range exclusively, he can write it. 02829 // 02830 02831 LastLock = (PFILE_LOCK_INFO)((PFILE_OBJECT)FileObject)->LastLock; 02832 if ((LastLock != NULL) && 02833 ((ULONGLONG)Starting.QuadPart >= (ULONGLONG)LastLock->StartingByte.QuadPart) && 02834 ((ULONGLONG)Ending.QuadPart <= (ULONGLONG)LastLock->EndingByte.QuadPart) && 02835 (LastLock->Key == Key) && 02836 (LastLock->ProcessId == ProcessId) && 02837 LastLock->ExclusiveLock) { 02838 02839 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02840 return TRUE; 02841 } 02842 02843 // 02844 // Check the shared locks for overlap. Any overlap in the shared locks is fatal. 02845 // 02846 02847 Status = FsRtlCheckNoSharedConflict(LockQueue, &Starting, &Ending); 02848 02849 if (Status == TRUE) { 02850 02851 // 02852 // No overlap in the shared locks, so check the exclusive locks for overlap. 02853 // 02854 02855 Status = FsRtlCheckNoExclusiveConflict(LockQueue, &Starting, &Ending, Key, FileObject, ProcessId); 02856 } 02857 02858 FsRtlReleaseLockQueue(LockQueue, OldIrql); 02859 02860 return Status; 02861 } 02862 02863 02864 VOID 02865 FsRtlSplitLocks ( 02866 IN PLOCKTREE_NODE ParentNode, 02867 IN PSINGLE_LIST_ENTRY *pStartLink OPTIONAL, 02868 IN PLARGE_INTEGER LastShadowedByte OPTIONAL, 02869 IN PLARGE_INTEGER GlueOffset OPTIONAL 02870 ) 02871 /*++ 02872 02873 Routine Description: 02874 02875 This routine examines and possibly splits off shared locks associated 02876 with a node into new nodes of the lock tree. Called from routines that 02877 have just deleted locks. 02878 02879 The arguments that supply the initial conditions for the operation are 02880 optional if the node is known to be holey. 02881 02882 Arguments: 02883 02884 ParentNode- Supplies the node the locks are coming from 02885 02886 pStartLink - Supplies the pointer to the link address of the start of the 02887 range of locks in the ParentNode's locklist that need to be checked 02888 02889 LastShadowedByte - Supplies the last byte offset that needs to be checked 02890 02891 GlueOffset - Supplies the maximum offset affected by locks prior to this 02892 point in the list 02893 02894 Return Value: 02895 02896 BOOLEAN - True if the split was successful, False otherwise. The node will 02897 be marked as Holey if the split could not occur. 02898 02899 --*/ 02900 { 02901 PSH_LOCK Lock; 02902 PLOCKTREE_NODE NewNode; 02903 PSINGLE_LIST_ENTRY Link, *pLink, *NextpLink; 02904 LARGE_INTEGER MaxOffset, StartOffset, HaltOffset; 02905 02906 BOOLEAN ExtentValid; 02907 BOOLEAN FailedHoleySplit = FALSE; 02908 02909 // 02910 // There are two cases: the node is holey or not. If the node is holey, at some 02911 // point we failed to get resources to complete a split, so despite our caller's 02912 // good intentions we need to go over the entire node. 02913 // 02914 02915 if (ParentNode->HoleyNode) { 02916 02917 // 02918 // Just move the starting link back to the front. The maximum offset and 02919 // starting offset of the node will be initialized in the loop. We also turn 02920 // off the holey flag, which will be turned on again as appropriate. 02921 // 02922 02923 pStartLink = &ParentNode->Locks.Next; 02924 ParentNode->HoleyNode = FALSE; 02925 02926 HaltOffset.QuadPart = ParentNode->Extent; 02927 02928 } else { 02929 02930 HaltOffset = *LastShadowedByte; 02931 MaxOffset = *GlueOffset; 02932 StartOffset.QuadPart = 0; 02933 02934 if (!ParentNode->Locks.Next || 02935 (ULONGLONG)HaltOffset.QuadPart <= (ULONGLONG)MaxOffset.QuadPart) { 02936 02937 // 02938 // The parent node is not there, doesn't have links associated, or the 02939 // last possible byte that is affected by the operation our caller made 02940 // is interior to the max extent of all locks still in this node - in 02941 // which case there is nothing that needs to be done. 02942 // 02943 02944 return; 02945 } 02946 } 02947 02948 // 02949 // If the extent of the node is past the last byte affected by whatever 02950 // operations were done to this node, we can avoid the linear scan of 02951 // the list past that last affected byte since we already know the 02952 // extent of the entire list! If it is not (note that it would have to 02953 // be equal - by defintion) then we need to recalculate the extents of 02954 // all nodes we touch in this operation. 02955 // 02956 02957 ExtentValid = (ParentNode->Extent > (ULONGLONG)HaltOffset.QuadPart); 02958 02959 for (pLink = pStartLink; 02960 (Link = *pLink) != NULL; 02961 pLink = NextpLink) { 02962 02963 NextpLink = &Link->Next; 02964 02965 Lock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 02966 02967 if (ParentNode->Locks.Next == *pLink) { 02968 02969 // 02970 // We're at the first lock in the node, and we know that we're going to leave 02971 // at least one lock here. Skip over that lock. We also know that the max 02972 // offset must be that locks's ending byte - make sure it is. Note that this 02973 // code is *exactly* the same as the update MaxOffset code at the bottom of 02974 // the loop. 02975 // 02976 02977 MaxOffset.QuadPart = Lock->LockInfo.EndingByte.QuadPart; 02978 02979 // 02980 // Set the starting offset of the node. This is only an issue for zero length 02981 // locks, so that we can figure out what is going on if we split a node and wind 02982 // up with some number of "overlapped" zero length locks at the front of the new 02983 // node. We must be able to notice this case, and not think that each needs to 02984 // be in a seperate node. 02985 // 02986 02987 StartOffset.QuadPart = Lock->LockInfo.StartingByte.QuadPart; 02988 02989 // 02990 // If extents are invalid we also need to set it in case this turns out to 02991 // be the only lock at this node. 02992 // 02993 02994 if (!ExtentValid) { 02995 02996 ParentNode->Extent = (ULONGLONG)MaxOffset.QuadPart; 02997 } 02998 02999 continue; 03000 } 03001 03002 // 03003 // If the lock begins at a byte offset greater than the maximum offset seen to this 03004 // point, AND this is not a zero length node starting at the beginning of this node, 03005 // break the node. The second half of the test keeps co-incident zero length locks 03006 // in the same node. (zero length lock ---> starting = ending + 1). 03007 // 03008 03009 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)MaxOffset.QuadPart && 03010 !(Lock->LockInfo.Length.QuadPart == 0 && 03011 Lock->LockInfo.StartingByte.QuadPart == StartOffset.QuadPart)) { 03012 03013 // 03014 // Break the node up here 03015 // 03016 03017 NewNode = FsRtlAllocateLockTreeNode(); 03018 03019 if (NewNode == NULL) { 03020 03021 // 03022 // If we are out of resources, this node is now holey - we know that the locks at 03023 // this node do not completely cover the indicated range. Keep splitting for two 03024 // reasons: more resources may become avaliable, and we must keep updating the 03025 // node's extent if it is known to be invalid. 03026 // 03027 03028 // 03029 // Now if this node was already holey it is not possible to state that, if we 03030 // manage to split if further as we keep walking, that the resulting "left" node 03031 // is not holey. See below. 03032 // 03033 03034 if (ParentNode->HoleyNode) { 03035 03036 FailedHoleySplit = TRUE; 03037 } 03038 03039 ParentNode->HoleyNode = TRUE; 03040 03041 } else { 03042 03043 // 03044 // Initialize the node. 03045 // 03046 03047 RtlInitializeSplayLinks(&NewNode->Links); 03048 NewNode->HoleyNode = FALSE; 03049 03050 // 03051 // Find the spot in the tree to take the new node(s). If the current node has 03052 // a free right child, we use it, else find the successor node and use its 03053 // left child. One of these cases must be avaliable since we know there are 03054 // no nodes between this node and its successor. 03055 // 03056 03057 if (RtlRightChild(&ParentNode->Links) == NULL) { 03058 03059 RtlInsertAsRightChild(&ParentNode->Links, &NewNode->Links); 03060 03061 } else { 03062 03063 ASSERT(RtlLeftChild(RtlRealSuccessor(&ParentNode->Links)) == NULL); 03064 RtlInsertAsLeftChild(RtlRealSuccessor(&ParentNode->Links), &NewNode->Links); 03065 } 03066 03067 // 03068 // Move the remaining locks over to the new node and fix up extents 03069 // 03070 03071 NewNode->Locks.Next = *pLink; 03072 *pLink = NULL; 03073 03074 NewNode->Tail.Next = ParentNode->Tail.Next; 03075 ParentNode->Tail.Next = CONTAINING_RECORD( pLink, SINGLE_LIST_ENTRY, Next ); 03076 03077 // 03078 // This will cause us to fall into the first-lock clause above on the next pass 03079 // 03080 03081 NextpLink = &NewNode->Locks.Next; 03082 03083 // 03084 // The new node's extent is now copied from the parent. The old node's extent must be 03085 // the maximum offset we have seen to this point. 03086 // 03087 // Note that if ExtentValid is true, that must mean that the lock ending at that extent 03088 // is in the new node since if it was in the old node we wouldn't have been able to split. 03089 // 03090 03091 NewNode->Extent = ParentNode->Extent; 03092 ParentNode->Extent = (ULONGLONG)MaxOffset.QuadPart; 03093 03094 // 03095 // The parent node can no longer be holey if we have not failed a split in this node. 03096 // 03097 03098 if (!FailedHoleySplit) { 03099 03100 ParentNode->HoleyNode = FALSE; 03101 03102 } else { 03103 03104 // 03105 // So reset the failure flag for the new node. 03106 // 03107 03108 FailedHoleySplit = FALSE; 03109 } 03110 03111 // 03112 // Move over to the new node. 03113 // 03114 03115 ParentNode = NewNode; 03116 03117 continue; 03118 } 03119 } 03120 03121 if (ExtentValid && 03122 (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)HaltOffset.QuadPart) { 03123 03124 // 03125 // Our extents are good and this lock is past the shadow, so we can stop 03126 // 03127 03128 return; 03129 } 03130 03131 if ((ULONGLONG)MaxOffset.QuadPart < (ULONGLONG)Lock->LockInfo.EndingByte.QuadPart) { 03132 03133 // 03134 // Update maximum offset 03135 // 03136 03137 MaxOffset.QuadPart = Lock->LockInfo.EndingByte.QuadPart; 03138 03139 if (!ExtentValid) { 03140 03141 // 03142 // Extents are not good so we must update the extent 03143 // 03144 03145 ParentNode->Extent = (ULONGLONG)MaxOffset.QuadPart; 03146 } 03147 } 03148 } 03149 03150 // 03151 // Reached the end of the list, so update the extent (case of all subsequent locks 03152 // having been interior to GlueOffset) 03153 // 03154 03155 ParentNode->Extent = (ULONGLONG)MaxOffset.QuadPart; 03156 03157 return; 03158 } 03159 03160 03161 VOID 03162 FsRtlPrivateRemoveLock ( 03163 IN PLOCK_INFO LockInfo, 03164 IN PFILE_LOCK_INFO FileLockInfo, 03165 IN BOOLEAN CheckForWaiters 03166 ) 03167 03168 /*++ 03169 03170 Routine Description: 03171 03172 General purpose cleanup routine. Finds the given lock structure 03173 and removes it from the file lock list. Differs from UnlockSingle 03174 only in that it disables the UnlockRoutine of the FileLock and 03175 optionalizes walking the waiting locks list. 03176 03177 Arguments: 03178 03179 FileLock - Supplies the file's lock structure supposedly containing a stale lock 03180 03181 FileLockInfo - Supplies file lock data being freed 03182 03183 CheckForWaiters - If true check for possible waiting locks, caused 03184 by freeing the locked range 03185 03186 Return Value: 03187 03188 None. 03189 03190 --*/ 03191 03192 { 03193 NTSTATUS Status; 03194 03195 if (FileLockInfo->ExclusiveLock) { 03196 03197 // 03198 // We must find it in the exclusive lock tree 03199 // 03200 03201 Status = FsRtlFastUnlockSingleExclusive( LockInfo, 03202 03203 FileLockInfo->FileObject, 03204 &FileLockInfo->StartingByte, 03205 &FileLockInfo->Length, 03206 FileLockInfo->ProcessId, 03207 FileLockInfo->Key, 03208 03209 NULL, 03210 TRUE, 03211 CheckForWaiters ); 03212 03213 ASSERT( Status == STATUS_SUCCESS); 03214 03215 } else { 03216 03217 // 03218 // We must find it in the shared lock tree 03219 // 03220 03221 Status = FsRtlFastUnlockSingleShared( LockInfo, 03222 03223 FileLockInfo->FileObject, 03224 &FileLockInfo->StartingByte, 03225 &FileLockInfo->Length, 03226 FileLockInfo->ProcessId, 03227 FileLockInfo->Key, 03228 03229 NULL, 03230 TRUE, 03231 CheckForWaiters ); 03232 03233 ASSERT( Status == STATUS_SUCCESS); 03234 } 03235 03236 return; 03237 } 03238 03239 03240 NTSTATUS 03241 FsRtlFastUnlockSingle ( 03242 IN PFILE_LOCK FileLock, 03243 IN PFILE_OBJECT FileObject, 03244 IN LARGE_INTEGER UNALIGNED *FileOffset, 03245 IN PLARGE_INTEGER Length, 03246 IN PEPROCESS ProcessId, 03247 IN ULONG Key, 03248 IN PVOID Context OPTIONAL, 03249 IN BOOLEAN AlreadySynchronized 03250 ) 03251 03252 /*++ 03253 03254 Routine Description: 03255 03256 This routine performs an Unlock Single operation on the current locks 03257 associated with the specified file lock. Only the lock with a matching 03258 file object, process id, key, and range is freed. 03259 03260 Arguments: 03261 03262 FileLock - Supplies the file lock being freed. 03263 03264 FileObject - Supplies the file object holding the locks 03265 03266 FileOffset - Supplies the offset to be unlocked 03267 03268 Length - Supplies the length in bytes to be unlocked 03269 03270 ProcessId - Supplies the process Id to use in this operation 03271 03272 Key - Supplies the key to use in this operation 03273 03274 Context - Optionally supplies context to use when completing Irps 03275 03276 AlreadySynchronized - Indicates that the caller has already synchronized 03277 access to the file lock so the fields in the file lock and 03278 be updated without further locking, but not the queues. 03279 03280 Return Value: 03281 03282 NTSTATUS - The completion status for this operation 03283 03284 --*/ 03285 03286 { 03287 NTSTATUS Status; 03288 03289 // 03290 // XXX AlreadySynchronized is obsolete. It was apparently added for the dead 03291 // XXX SoloLock code. 03292 // 03293 03294 if (FileLock->LockInformation == NULL) { 03295 03296 // 03297 // Fast exit - no locks are applied 03298 // 03299 03300 return STATUS_RANGE_NOT_LOCKED; 03301 } 03302 03303 Status = FsRtlFastUnlockSingleExclusive( FileLock->LockInformation, 03304 FileObject, 03305 FileOffset, 03306 Length, 03307 ProcessId, 03308 Key, 03309 Context, 03310 FALSE, 03311 TRUE ); 03312 03313 if (Status == STATUS_SUCCESS) { 03314 03315 // 03316 // Found and unlocked in the exclusive tree, so we're done 03317 // 03318 03319 return Status; 03320 } 03321 03322 Status = FsRtlFastUnlockSingleShared( FileLock->LockInformation, 03323 FileObject, 03324 FileOffset, 03325 Length, 03326 ProcessId, 03327 Key, 03328 Context, 03329 FALSE, 03330 TRUE ); 03331 03332 return Status; 03333 } 03334 03335 03336 NTSTATUS 03337 FsRtlFastUnlockSingleShared ( 03338 IN PLOCK_INFO LockInfo, 03339 IN PFILE_OBJECT FileObject, 03340 IN LARGE_INTEGER UNALIGNED *FileOffset, 03341 IN PLARGE_INTEGER Length, 03342 IN PEPROCESS ProcessId, 03343 IN ULONG Key, 03344 IN PVOID Context OPTIONAL, 03345 IN BOOLEAN IgnoreUnlockRoutine, 03346 IN BOOLEAN CheckForWaiters 03347 ) 03348 03349 /*++ 03350 03351 Routine Description: 03352 03353 This routine performs an Unlock Single operation on the current locks 03354 associated with the specified file lock. Only the lock with a matching 03355 file object, process id, key, and range is freed. 03356 03357 Arguments: 03358 03359 LockInfo - Supplies the lock data being operated on 03360 03361 FileObject - Supplies the file object holding the locks 03362 03363 FileOffset - Supplies the offset to be unlocked 03364 03365 Length - Supplies the length in bytes to be unlocked 03366 03367 ProcessId - Supplies the process Id to use in this operation 03368 03369 Key - Supplies the key to use in this operation 03370 03371 Context - Optionally supplies context to use when completing Irps 03372 03373 IgnoreUnlockRoutine - inidicates that the filelock's unlock routine 03374 should not be called on lock removal (for removal of aborted 03375 locks) 03376 03377 CheckForWaiters - If true check for possible waiting locks, caused 03378 by freeing the locked range 03379 03380 Return Value: 03381 03382 NTSTATUS - The completion status for this operation 03383 03384 --*/ 03385 03386 { 03387 PSINGLE_LIST_ENTRY *pLink, Link; 03388 KIRQL OldIrql; 03389 03390 PLOCK_QUEUE LockQueue; 03391 PRTL_SPLAY_LINKS SplayLinks; 03392 LARGE_INTEGER EndingOffset, MaxOffset; 03393 PLOCKTREE_NODE Node; 03394 LARGE_INTEGER AlignedFileOffset; 03395 03396 // 03397 // General case - search the outstanding lock queue for this lock 03398 // 03399 03400 AlignedFileOffset = *FileOffset; 03401 03402 LockQueue = &LockInfo->LockQueue; 03403 03404 FsRtlAcquireLockQueue(LockQueue, &OldIrql); 03405 03406 // 03407 // Check for the no locks currently held 03408 // 03409 03410 if (LockQueue->SharedLockTree == NULL) { 03411 03412 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03413 03414 return STATUS_RANGE_NOT_LOCKED; 03415 } 03416 03417 // 03418 // Find the overlapping node, if it exists, to search. Note that 03419 // we don't have to go through more than one node in the tree 03420 // since we are assuming this is an existing lock. 03421 // 03422 03423 EndingOffset.QuadPart = (ULONGLONG)AlignedFileOffset.QuadPart + (ULONGLONG)Length->QuadPart - 1; 03424 03425 SplayLinks = FsRtlFindFirstOverlappingSharedNode( LockQueue->SharedLockTree, 03426 &AlignedFileOffset, 03427 &EndingOffset, 03428 NULL, 03429 NULL ); 03430 03431 if (SplayLinks == NULL) { 03432 03433 // 03434 // No node in the tree overlaps this range, so we're done 03435 // 03436 03437 FsRtlReleaseLockQueue(LockQueue, OldIrql); 03438 03439 return STATUS_RANGE_NOT_LOCKED; 03440 } 03441 03442 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 03443 MaxOffset.QuadPart = 0; 03444 03445 for (pLink = &Node->Locks.Next; 03446 (Link = *pLink) != NULL; 03447 pLink = &Link->Next) { 03448 03449 PSH_LOCK Lock; 03450 03451 Lock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 03452 03453 DebugTrace(0, Dbg, "Sh Top of Loop, Lock = %08lx\n", Lock ); 03454 03455 if ((Lock->LockInfo.FileObject == FileObject) && 03456 (Lock->LockInfo.ProcessId == ProcessId) && 03457 (Lock->LockInfo.Key == Key) && 03458 ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart == (ULONGLONG)AlignedFileOffset.QuadPart) && 03459 ((ULONGLONG)Lock->LockInfo.Length.QuadPart == (ULONGLONG)Length->QuadPart)) { 03460 03461 DebugTrace(0, Dbg, "Sh Found one to unlock\n", 0); 03462 03463 // 03464 // We have an exact match so now is the time to delete this 03465 // lock. Remove the lock from the list, then call the 03466 // optional unlock routine, then delete the lock. 03467 // 03468 03469 if (FileObject->LastLock == &Lock->LockInfo) { 03470 03471 FileObject->LastLock = NULL; 03472 } 03473 03474 if (*pLink == Node->Tail.Next) { 03475 03476 // 03477 // Deleting the tail node of the list. Safe even if deleting the 03478 // first node since this implies we're also deleting the last node 03479 // in the node which means we'll delete the node ... 03480 // 03481 03482 Node->Tail.Next = CONTAINING_RECORD( pLink, SINGLE_LIST_ENTRY, Next ); 03483 } 03484 03485 // 03486 // Snip the deleted lock 03487 // 03488 03489 *pLink = Link->Next; 03490 03491 if (pLink == &Node->Locks.Next) { 03492 03493 // 03494 // Deleted first lock in node 03495 // 03496 03497 if (Node->Locks.Next == NULL) { 03498 03499 // 03500 // Just deleted last lock on this node, so free it 03501 // 03502 03503 LockQueue->SharedLockTree = RtlDelete(SplayLinks); 03504 03505 FsRtlFreeLockTreeNode(Node); 03506 03507 Node = NULL; 03508 } 03509 03510 if (LockInfo->LowestLockOffset != 0xffffffff && 03511 LockInfo->LowestLockOffset == Lock->LockInfo.StartingByte.LowPart) { 03512 03513 // 03514 // This was the lowest lock in the trees, reset the lowest lock offset 03515 // 03516 03517 FsRtlPrivateResetLowestLockOffset(LockInfo); 03518 } 03519 } 03520 03521 // 03522 // Now the fun begins. It may be the case that the lock just snipped from 03523 // the chain was gluing locks at this node together, so we need to 03524 // inspect the chain. 03525 // 03526 03527 if (Node) { 03528 03529 FsRtlSplitLocks(Node, pLink, &Lock->LockInfo.EndingByte, &MaxOffset); 03530 } 03531 03532 if (!IgnoreUnlockRoutine && LockInfo->UnlockRoutine != NULL) { 03533 03534 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03535 03536 LockInfo->UnlockRoutine( Context, &Lock->LockInfo ); 03537 03538 FsRtlReacquireLockQueue( LockInfo, LockQueue, &OldIrql ); 03539 03540 } 03541 03542 FsRtlFreeSharedLock( Lock ); 03543 03544 // 03545 // See if there are additional waiting locks that we can 03546 // now release. 03547 // 03548 03549 if (CheckForWaiters && LockQueue->WaitingLocks.Next) { 03550 03551 FsRtlPrivateCheckWaitingLocks( LockInfo, LockQueue, OldIrql ); 03552 } 03553 03554 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03555 03556 return STATUS_SUCCESS; 03557 } 03558 03559 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)AlignedFileOffset.QuadPart) { 03560 03561 // 03562 // The current lock begins at a byte offset greater than the range we are seeking 03563 // to unlock. This range must therefore not be locked. 03564 // 03565 03566 break; 03567 } 03568 03569 if ((ULONGLONG)MaxOffset.QuadPart < (ULONGLONG)Lock->LockInfo.EndingByte.QuadPart) { 03570 03571 // 03572 // Maintain the maximum offset affected by locks up to this point. 03573 // 03574 03575 MaxOffset.QuadPart = Lock->LockInfo.EndingByte.QuadPart; 03576 } 03577 } 03578 03579 // 03580 // Lock was not found, return to our caller 03581 // 03582 03583 FsRtlReleaseLockQueue(LockQueue, OldIrql); 03584 return STATUS_RANGE_NOT_LOCKED; 03585 } 03586 03587 03588 NTSTATUS 03589 FsRtlFastUnlockSingleExclusive ( 03590 IN PLOCK_INFO LockInfo, 03591 IN PFILE_OBJECT FileObject, 03592 IN LARGE_INTEGER UNALIGNED *FileOffset, 03593 IN PLARGE_INTEGER Length, 03594 IN PEPROCESS ProcessId, 03595 IN ULONG Key, 03596 IN PVOID Context OPTIONAL, 03597 IN BOOLEAN IgnoreUnlockRoutine, 03598 IN BOOLEAN CheckForWaiters 03599 ) 03600 03601 /*++ 03602 03603 Routine Description: 03604 03605 This routine performs an Unlock Single operation on the exclusive locks 03606 associated with the specified lock data. Only the lock with a matching 03607 file object, process id, key, and range is freed. 03608 03609 Arguments: 03610 03611 LockInfo - Supplies the lock data being operated on 03612 03613 FileObject - Supplies the file object holding the locks 03614 03615 FileOffset - Supplies the offset to be unlocked 03616 03617 Length - Supplies the length in bytes to be unlocked 03618 03619 ProcessId - Supplies the process Id to use in this operation 03620 03621 Key - Supplies the key to use in this operation 03622 03623 Context - Optionally supplies context to use when completing Irps 03624 03625 IgnoreUnlockRoutine - inidicates that the filelock's unlock routine 03626 should not be called on lock removal (for removal of aborted 03627 locks) 03628 03629 CheckForWaiters - If true check for possible waiting locks, caused 03630 by freeing the locked range 03631 03632 Return Value: 03633 03634 NTSTATUS - The completion status for this operation 03635 03636 --*/ 03637 03638 { 03639 KIRQL OldIrql; 03640 PLOCK_QUEUE LockQueue; 03641 PRTL_SPLAY_LINKS SplayLinks; 03642 LARGE_INTEGER EndingOffset; 03643 PEX_LOCK Lock; 03644 LARGE_INTEGER AlignedFileOffset; 03645 03646 // 03647 // General case - search the outstanding lock queue for this lock 03648 // 03649 03650 AlignedFileOffset = *FileOffset; 03651 03652 LockQueue = &LockInfo->LockQueue; 03653 03654 FsRtlAcquireLockQueue(LockQueue, &OldIrql); 03655 03656 // 03657 // Check for the no locks currently held 03658 // 03659 03660 if (LockQueue->ExclusiveLockTree == NULL) { 03661 03662 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03663 03664 return STATUS_RANGE_NOT_LOCKED; 03665 } 03666 03667 // 03668 // Find the overlapping lock, if it exists. Note that this is usually 03669 // the only lock we need to check since we are assuming this is an 03670 // existing lock. However, if the lock is a zero length lock we will 03671 // have a run of locks to check. 03672 // 03673 03674 EndingOffset.QuadPart = (ULONGLONG)AlignedFileOffset.QuadPart + (ULONGLONG)Length->QuadPart - 1; 03675 03676 for (SplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockQueue->ExclusiveLockTree, 03677 &AlignedFileOffset, 03678 &EndingOffset, 03679 NULL, 03680 NULL ); 03681 SplayLinks; 03682 SplayLinks = RtlRealSuccessor(SplayLinks)) { 03683 03684 Lock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 03685 03686 if ((Lock->LockInfo.FileObject == FileObject) && 03687 (Lock->LockInfo.ProcessId == ProcessId) && 03688 (Lock->LockInfo.Key == Key) && 03689 ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart == (ULONGLONG)AlignedFileOffset.QuadPart) && 03690 ((ULONGLONG)Lock->LockInfo.Length.QuadPart == (ULONGLONG)Length->QuadPart)) { 03691 03692 DebugTrace(0, Dbg, "Ex Found one to unlock\n", 0); 03693 03694 // 03695 // We have an exact match so now is the time to delete this 03696 // lock. Remove the lock from the list, then call the 03697 // optional unlock routine, then delete the lock. 03698 // 03699 03700 if (FileObject->LastLock == &Lock->LockInfo) { 03701 03702 FileObject->LastLock = NULL; 03703 } 03704 03705 // 03706 // Snip the deleted lock 03707 // 03708 03709 LockQueue->ExclusiveLockTree = RtlDelete(&Lock->Links); 03710 03711 if (LockInfo->LowestLockOffset != 0xffffffff && 03712 LockInfo->LowestLockOffset == Lock->LockInfo.StartingByte.LowPart) { 03713 03714 // 03715 // This was the lowest lock in the tree, so reset the lowest lock 03716 // offset 03717 // 03718 03719 FsRtlPrivateResetLowestLockOffset(LockInfo); 03720 } 03721 03722 if (!IgnoreUnlockRoutine && LockInfo->UnlockRoutine != NULL) { 03723 03724 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03725 03726 LockInfo->UnlockRoutine( Context, &Lock->LockInfo ); 03727 03728 FsRtlReacquireLockQueue( LockInfo, LockQueue, &OldIrql ); 03729 03730 } 03731 03732 FsRtlFreeExclusiveLock( Lock ); 03733 03734 // 03735 // See if there are additional waiting locks that we can 03736 // now release. 03737 // 03738 03739 if (CheckForWaiters && LockQueue->WaitingLocks.Next) { 03740 03741 FsRtlPrivateCheckWaitingLocks( LockInfo, LockQueue, OldIrql ); 03742 } 03743 03744 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 03745 03746 return STATUS_SUCCESS; 03747 } 03748 03749 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)AlignedFileOffset.QuadPart) { 03750 03751 // 03752 // The current lock begins at a byte offset greater than the range we are seeking 03753 // to unlock. This range must therefore not be locked. 03754 // 03755 03756 break; 03757 } 03758 } 03759 03760 // 03761 // Lock was not found, return to our caller 03762 // 03763 03764 FsRtlReleaseLockQueue(LockQueue, OldIrql); 03765 return STATUS_RANGE_NOT_LOCKED; 03766 } 03767 03768 03769 NTSTATUS 03770 FsRtlFastUnlockAll ( 03771 IN PFILE_LOCK FileLock, 03772 IN PFILE_OBJECT FileObject, 03773 IN PEPROCESS ProcessId, 03774 IN PVOID Context OPTIONAL 03775 ) 03776 03777 /*++ 03778 03779 Routine Description: 03780 03781 This routine performs an Unlock all operation on the current locks 03782 associated with the specified file lock. Only those locks with 03783 a matching file object and process id are freed. 03784 03785 Arguments: 03786 03787 FileLock - Supplies the file lock being freed. 03788 03789 FileObject - Supplies the file object associated with the file lock 03790 03791 ProcessId - Supplies the Process Id assoicated with the locks to be 03792 freed 03793 03794 Context - Supplies an optional context to use when completing waiting 03795 lock irps. 03796 03797 Return Value: 03798 03799 None 03800 03801 --*/ 03802 03803 { 03804 return FsRtlPrivateFastUnlockAll( 03805 FileLock, 03806 FileObject, 03807 ProcessId, 03808 0, FALSE, // No Key 03809 Context ); 03810 } 03811 03812 03813 NTSTATUS 03814 FsRtlFastUnlockAllByKey ( 03815 IN PFILE_LOCK FileLock, 03816 IN PFILE_OBJECT FileObject, 03817 IN PEPROCESS ProcessId, 03818 IN ULONG Key, 03819 IN PVOID Context OPTIONAL 03820 ) 03821 03822 /*++ 03823 03824 Routine Description: 03825 03826 This routine performs an Unlock All by Key operation on the current locks 03827 associated with the specified file lock. Only those locks with 03828 a matching file object, process id, and key are freed. The input Irp 03829 is completed by this procedure 03830 03831 Arguments: 03832 03833 FileLock - Supplies the file lock being freed. 03834 03835 FileObject - Supplies the file object associated with the file lock 03836 03837 ProcessId - Supplies the Process Id assoicated with the locks to be 03838 freed 03839 03840 Key - Supplies the Key to use in this operation 03841 03842 Context - Supplies an optional context to use when completing waiting 03843 lock irps. 03844 03845 Return Value: 03846 03847 NTSTATUS - The return status for the operation. 03848 03849 --*/ 03850 03851 { 03852 return FsRtlPrivateFastUnlockAll( 03853 FileLock, 03854 FileObject, 03855 ProcessId, 03856 Key, TRUE, 03857 Context ); 03858 03859 } 03860 03861 03862 // 03863 // Local Support Routine 03864 // 03865 03866 BOOLEAN 03867 FsRtlPrivateLock ( 03868 IN PFILE_LOCK FileLock, 03869 IN PFILE_OBJECT FileObject, 03870 IN PLARGE_INTEGER FileOffset, 03871 IN PLARGE_INTEGER Length, 03872 IN PEPROCESS ProcessId, 03873 IN ULONG Key, 03874 IN BOOLEAN FailImmediately, 03875 IN BOOLEAN ExclusiveLock, 03876 OUT PIO_STATUS_BLOCK Iosb, 03877 IN PIRP Irp OPTIONAL, 03878 IN PVOID Context, 03879 IN BOOLEAN AlreadySynchronized 03880 ) 03881 03882 /*++ 03883 03884 Routine Description: 03885 03886 This routine preforms a lock operation request. This handles both the fast 03887 get lock and the Irp based get lock. If the Irp is supplied then 03888 this routine will either complete the Irp or enqueue it as a waiting 03889 lock request. 03890 03891 Arguments: 03892 03893 FileLock - Supplies the File Lock to work against 03894 03895 FileObject - Supplies the file object used in this operation 03896 03897 FileOffset - Supplies the file offset used in this operation 03898 03899 Length - Supplies the length used in this operation 03900 03901 ProcessId - Supplies the process ID used in this operation 03902 03903 Key - Supplies the key used in this operation 03904 03905 FailImmediately - Indicates if the request should fail immediately 03906 if the lock cannot be granted. 03907 03908 ExclusiveLock - Indicates if this is a request for an exclusive or 03909 shared lock 03910 03911 Iosb - Receives the Status if this operation is successful 03912 03913 Context - Supplies the context with which to complete Irp with 03914 03915 AlreadySynchronized - Indicates that the caller has already synchronized 03916 access to the file lock so the fields in the file lock and 03917 be updated without further locking, but not the queues. 03918 03919 Return Value: 03920 03921 BOOLEAN - TRUE if this operation completed and FALSE otherwise. 03922 03923 --*/ 03924 03925 { 03926 BOOLEAN Results; 03927 BOOLEAN AccessGranted; 03928 BOOLEAN ViaFastCall; 03929 BOOLEAN ReleaseQueue = FALSE; 03930 03931 PLOCK_INFO LockInfo; 03932 PLOCK_QUEUE LockQueue; 03933 KIRQL OldIrql; 03934 FILE_LOCK_INFO FileLockInfo; 03935 03936 DebugTrace(+1, Dbg, "FsRtlPrivateLock, FileLock = %08lx\n", FileLock); 03937 03938 // 03939 // If the irp is null then this is being called via the fast call method. 03940 // 03941 03942 ViaFastCall = (BOOLEAN) !ARGUMENT_PRESENT( Irp ); 03943 03944 if ((LockInfo = (PLOCK_INFO) FileLock->LockInformation) == NULL) { 03945 DebugTrace(+2, Dbg, "FsRtlPrivateLock, New LockInfo required\n", 0); 03946 03947 // 03948 // No lock information on this FileLock, create the structure. 03949 // 03950 // 03951 03952 if (!FsRtlPrivateInitializeFileLock (FileLock, ViaFastCall)) { 03953 03954 return FALSE; 03955 } 03956 03957 // 03958 // Set flag so file locks will be checked on the fast io 03959 // code paths 03960 // 03961 03962 FileLock->FastIoIsQuestionable = TRUE; 03963 03964 // 03965 // Pickup allocated lockinfo structure 03966 // 03967 03968 LockInfo = (PLOCK_INFO) FileLock->LockInformation; 03969 } 03970 03971 // 03972 // Assume success and build LockData structure prior to acquiring 03973 // the lock queue spinlock. (mp perf enhancement) 03974 // 03975 03976 FileLockInfo.StartingByte = *FileOffset; 03977 FileLockInfo.Length = *Length; 03978 (ULONGLONG)FileLockInfo.EndingByte.QuadPart = 03979 (ULONGLONG)FileLockInfo.StartingByte.QuadPart + (ULONGLONG)FileLockInfo.Length.QuadPart - 1; 03980 03981 FileLockInfo.Key = Key; 03982 FileLockInfo.FileObject = FileObject; 03983 FileLockInfo.ProcessId = ProcessId; 03984 FileLockInfo.ExclusiveLock = ExclusiveLock; 03985 03986 LockQueue = &LockInfo->LockQueue; 03987 03988 // 03989 // Now we need to actually run through our current lock queue. 03990 // 03991 03992 FsRtlAcquireLockQueue(LockQueue, &OldIrql); 03993 ReleaseQueue = TRUE; 03994 03995 try { 03996 03997 // 03998 // Case on whether we're trying to take out an exclusive lock or 03999 // a shared lock. And in both cases try to get appropriate access. 04000 // 04001 04002 if (ExclusiveLock) { 04003 04004 DebugTrace(0, Dbg, "Check for write access\n", 0); 04005 04006 AccessGranted = FsRtlPrivateCheckForExclusiveLockAccess( 04007 LockQueue, 04008 &FileLockInfo ); 04009 04010 } else { 04011 04012 DebugTrace(0, Dbg, "Check for read access\n", 0); 04013 04014 AccessGranted = FsRtlPrivateCheckForSharedLockAccess( 04015 LockQueue, 04016 &FileLockInfo ); 04017 } 04018 04019 // 04020 // Now AccessGranted tells us whether we can really get the access 04021 // for the range we want 04022 // 04023 04024 if (!AccessGranted) { 04025 04026 DebugTrace(0, Dbg, "We do not have access\n", 0); 04027 04028 // 04029 // We cannot read/write to the range, so we cannot take out 04030 // the lock. Now if the user wanted to fail immediately then 04031 // we'll complete the Irp, otherwise we'll enqueue this Irp 04032 // to the waiting lock queue 04033 // 04034 04035 if (FailImmediately) { 04036 04037 // 04038 // Set our status and return, the finally clause will 04039 // complete the request 04040 // 04041 04042 DebugTrace(0, Dbg, "And we fail immediately\n", 0); 04043 04044 Iosb->Status = STATUS_LOCK_NOT_GRANTED; 04045 try_return( Results = TRUE ); 04046 04047 } else if (ARGUMENT_PRESENT(Irp)) { 04048 04049 PWAITING_LOCK WaitingLock; 04050 04051 DebugTrace(0, Dbg, "And we enqueue the Irp for later\n", 0); 04052 04053 // 04054 // Allocate a new waiting record, set it to point to the 04055 // waiting Irp, and insert it in the tail of the waiting 04056 // locks queue 04057 // 04058 04059 WaitingLock = FsRtlAllocateWaitingLock(); 04060 04061 // 04062 // Simply raise out if we can't allocate. 04063 // 04064 04065 if (WaitingLock == NULL) { 04066 04067 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 04068 } 04069 04070 WaitingLock->Irp = Irp; 04071 WaitingLock->Context = Context; 04072 IoMarkIrpPending( Irp ); 04073 04074 // 04075 // Add WaitingLock WaitingLockQueue 04076 // 04077 04078 WaitingLock->Link.Next = NULL; 04079 if (LockQueue->WaitingLocks.Next == NULL) { 04080 04081 // 04082 // Create new list 04083 // 04084 04085 LockQueue->WaitingLocks.Next = &WaitingLock->Link; 04086 LockQueue->WaitingLocksTail.Next = &WaitingLock->Link; 04087 04088 } else { 04089 04090 // 04091 // Add waiter to tail of list 04092 // 04093 04094 LockQueue->WaitingLocksTail.Next->Next = &WaitingLock->Link; 04095 LockQueue->WaitingLocksTail.Next = &WaitingLock->Link; 04096 } 04097 04098 04099 // 04100 // Setup IRP in case it's canceled - then set the 04101 // IRP's cancel routine 04102 // 04103 04104 Irp->IoStatus.Information = (ULONG_PTR)LockInfo; 04105 IoSetCancelRoutine( Irp, FsRtlPrivateCancelFileLockIrp ); 04106 04107 if (Irp->Cancel) { 04108 04109 // 04110 // Pull the cancel routine off of the IRP - if it is not 04111 // NULL, this means we won the race with IoCancelIrp and 04112 // will be responsible for cancelling the IRP synchronously. 04113 // If NULL, we lost and our cancel routine is already being 04114 // called for us. 04115 // 04116 // This must be done while holding the lock queue down since 04117 // this is how we synchronize with the cancel. 04118 // 04119 04120 if (IoSetCancelRoutine( Irp, NULL )) { 04121 04122 // 04123 // Irp's cancel routine was not called, do it ourselves. 04124 // Indicate to the cancel routine that he does not need 04125 // to release the cancel spinlock by passing a NULL DO. 04126 // 04127 // The queue will be dropped in order to complete the Irp. 04128 // We communicate the previous IRQL through the Irp itself. 04129 // 04130 04131 Irp->CancelIrql = OldIrql; 04132 FsRtlPrivateCancelFileLockIrp( NULL, Irp ); 04133 ReleaseQueue = FALSE; 04134 } 04135 } 04136 04137 Iosb->Status = STATUS_PENDING; 04138 try_return( Results = TRUE ); 04139 04140 } else { 04141 04142 try_return( Results = FALSE ); 04143 } 04144 } 04145 04146 DebugTrace(0, Dbg, "We have access\n", 0); 04147 04148 if (!FsRtlPrivateInsertLock( LockInfo, FileObject, &FileLockInfo )) { 04149 04150 // 04151 // Resource exhaustion will cause us to fail here. Via the fast call, indicate 04152 // that it may be worthwhile to go around again via the Irp based path. If we 04153 // are already there, simply raise out. 04154 // 04155 04156 if (ViaFastCall) { 04157 04158 try_return( Results = FALSE ); 04159 04160 } else { 04161 04162 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 04163 } 04164 04165 } else { 04166 04167 Iosb->Status = STATUS_SUCCESS; 04168 } 04169 04170 // 04171 // At long last, we're done. 04172 // 04173 04174 Results = TRUE; 04175 04176 try_exit: NOTHING; 04177 } finally { 04178 04179 if (ReleaseQueue) { 04180 04181 FsRtlReleaseLockQueue(LockQueue, OldIrql); 04182 } 04183 04184 // 04185 // Complete the request provided we were given one and it is not a pending status 04186 // 04187 04188 if (!AbnormalTermination() && ARGUMENT_PRESENT(Irp) && (Iosb->Status != STATUS_PENDING)) { 04189 04190 NTSTATUS NewStatus; 04191 04192 // 04193 // We must reference the fileobject for the case that the IRP completion 04194 // fails and we need to lift the lock. Although the only reason we have 04195 // to touch the fileobject in the remove case is to unset the LastLock field, 04196 // we have no way of knowing if we will race with a reference count drop 04197 // and lose. 04198 // 04199 04200 ObReferenceObject( FileObject ); 04201 04202 // 04203 // Complete the request, if the don't get back success then 04204 // we need to possibly remove the lock that we just 04205 // inserted. 04206 // 04207 04208 FsRtlCompleteLockIrp( 04209 LockInfo, 04210 Context, 04211 Irp, 04212 Iosb->Status, 04213 &NewStatus, 04214 FileObject ); 04215 04216 if (!NT_SUCCESS(NewStatus) && NT_SUCCESS(Iosb->Status) ) { 04217 04218 // 04219 // Irp failed, remove the lock which was added 04220 // 04221 04222 FsRtlPrivateRemoveLock ( 04223 LockInfo, 04224 &FileLockInfo, 04225 TRUE ); 04226 } 04227 04228 // 04229 // Lift our private reference to the fileobject. This may induce deletion. 04230 // 04231 04232 ObDereferenceObject( FileObject ); 04233 04234 Iosb->Status = NewStatus; 04235 } 04236 04237 DebugTrace(-1, Dbg, "FsRtlPrivateLock -> %08lx\n", Results); 04238 } 04239 04240 // 04241 // and return to our caller 04242 // 04243 04244 return Results; 04245 } 04246 04247 04248 // 04249 // Internal Support Routine 04250 // 04251 04252 BOOLEAN 04253 FsRtlPrivateInsertLock ( 04254 IN PLOCK_INFO LockInfo, 04255 IN PFILE_OBJECT FileObject, 04256 IN PFILE_LOCK_INFO FileLockInfo 04257 ) 04258 04259 /*++ 04260 04261 Routine Description: 04262 04263 This routine fills in a new lock record of the appropriate type and inserts 04264 it into the lock information. 04265 04266 Arguments: 04267 04268 LockInfo - Supplies the lock being modified 04269 04270 FileObject - The associated file object to update hints in 04271 04272 FileLockInfo - Supplies the new lock data to add to the lock queue 04273 04274 Return Value: 04275 04276 BOOLEAN - True if the insert was successful, False if no resources were avaliable 04277 to complete the operation. 04278 04279 --*/ 04280 04281 { 04282 // 04283 // Now add the lock to the appropriate tree. 04284 // 04285 04286 if (FileLockInfo->ExclusiveLock) { 04287 04288 PEX_LOCK ExLock; 04289 04290 ExLock = FsRtlAllocateExclusiveLock(); 04291 04292 if (ExLock == NULL) { 04293 04294 return FALSE; 04295 } 04296 04297 ExLock->LockInfo = *FileLockInfo; 04298 04299 FsRtlPrivateInsertExclusiveLock( &LockInfo->LockQueue, ExLock ); 04300 04301 FileObject->LastLock = &ExLock->LockInfo; 04302 04303 } else { 04304 04305 PSH_LOCK ShLock; 04306 04307 ShLock = FsRtlAllocateSharedLock(); 04308 04309 if (ShLock == NULL) { 04310 04311 return FALSE; 04312 } 04313 04314 ShLock->LockInfo = *FileLockInfo; 04315 04316 if (!FsRtlPrivateInsertSharedLock( &LockInfo->LockQueue, ShLock )) { 04317 04318 return FALSE; 04319 } 04320 04321 FileObject->LastLock = &ShLock->LockInfo; 04322 } 04323 04324 // 04325 // Fix up the lowest lock offset if need be 04326 // 04327 04328 if ((ULONGLONG)FileLockInfo->StartingByte.QuadPart < (ULONGLONG)LockInfo->LowestLockOffset) { 04329 04330 ASSERT( FileLockInfo->StartingByte.HighPart == 0 ); 04331 LockInfo->LowestLockOffset = FileLockInfo->StartingByte.LowPart; 04332 } 04333 04334 return TRUE; 04335 } 04336 04337 04338 // 04339 // Internal Support Routine 04340 // 04341 04342 BOOLEAN 04343 FsRtlPrivateInsertSharedLock ( 04344 IN PLOCK_QUEUE LockQueue, 04345 IN PSH_LOCK NewLock 04346 ) 04347 04348 /*++ 04349 04350 Routine Description: 04351 04352 This routine adds a new shared lock record to the File lock's current 04353 lock queue. Locks are inserted into nodes ordered by their starting byte. 04354 04355 Arguments: 04356 04357 LockQueue - Supplies the lock queue being modified 04358 04359 NewLock - Supplies the new shared lock to add to the lock queue 04360 04361 Return Value: 04362 04363 BOOLEAN - True if the insert was successful, False if no resources were avaliable 04364 to complete the operation. 04365 04366 --*/ 04367 { 04368 PSINGLE_LIST_ENTRY pLink, Link; 04369 PRTL_SPLAY_LINKS OverlappedSplayLinks, ParentSplayLinks; 04370 PLOCKTREE_NODE Node, NextNode; 04371 PSH_LOCK NextLock; 04372 BOOLEAN GreaterThan; 04373 04374 OverlappedSplayLinks = FsRtlFindFirstOverlappingSharedNode( LockQueue->SharedLockTree, 04375 &NewLock->LockInfo.StartingByte, 04376 &NewLock->LockInfo.EndingByte, 04377 &ParentSplayLinks, 04378 &GreaterThan ); 04379 04380 if (OverlappedSplayLinks == NULL) { 04381 04382 // 04383 // Simple insert case, build a new node 04384 // 04385 04386 NextNode = FsRtlAllocateLockTreeNode(); 04387 04388 // 04389 // If no resources are avaliable, simply fail now. 04390 // 04391 04392 if (NextNode == NULL) { 04393 04394 return FALSE; 04395 } 04396 04397 RtlInitializeSplayLinks(&NextNode->Links); 04398 NextNode->HoleyNode = FALSE; 04399 04400 NextNode->Locks.Next = NextNode->Tail.Next = &NewLock->Link; 04401 NextNode->Extent = (ULONGLONG)NewLock->LockInfo.EndingByte.QuadPart; 04402 NewLock->Link.Next = NULL; 04403 04404 if (ParentSplayLinks) { 04405 04406 // 04407 // We have a real parent node in the tree 04408 // 04409 04410 if (GreaterThan) { 04411 04412 ASSERT(RtlLeftChild(ParentSplayLinks) == NULL); 04413 RtlInsertAsLeftChild(ParentSplayLinks, &NextNode->Links); 04414 04415 } else { 04416 04417 ASSERT(RtlRightChild(ParentSplayLinks) == NULL); 04418 RtlInsertAsRightChild(ParentSplayLinks, &NextNode->Links); 04419 } 04420 04421 // 04422 // Splay all new nodes in the tree 04423 // 04424 04425 LockQueue->SharedLockTree = RtlSplay(&NextNode->Links); 04426 04427 } else { 04428 04429 // 04430 // First node in the tree 04431 // 04432 04433 LockQueue->SharedLockTree = &NextNode->Links; 04434 } 04435 04436 return TRUE; 04437 } 04438 04439 // 04440 // Now we examine the node to see if it is holey as a result of a resource-failed split. 04441 // If it is, we must complete the split before adding the new lock. 04442 // 04443 04444 Node = CONTAINING_RECORD( OverlappedSplayLinks, LOCKTREE_NODE, Links ); 04445 04446 // 04447 // Search down the overlapped node finding the position for the new lock 04448 // 04449 04450 for (pLink = &Node->Locks; 04451 (Link = pLink->Next) != NULL; 04452 pLink = Link) { 04453 04454 PSH_LOCK Lock; 04455 04456 Lock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 04457 04458 // 04459 // We sort locks on this list first by starting byte, then by whether the length is zero or not. 04460 // This is important so that zero length locks appear prior to non-zero length locks, so that 04461 // they are split out of nodes into the tree in the correct order. 04462 // 04463 // if (NewLock->StartingByte <= Lock->StartingByte) ... 04464 // 04465 04466 if (((ULONGLONG)NewLock->LockInfo.StartingByte.QuadPart < (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart) || 04467 04468 ((ULONGLONG)NewLock->LockInfo.StartingByte.QuadPart == (ULONGLONG)Lock->LockInfo.StartingByte.QuadPart && 04469 (NewLock->LockInfo.Length.QuadPart == 0 || Lock->LockInfo.Length.QuadPart != 0))) { 04470 04471 break; 04472 } 04473 } 04474 04475 // 04476 // At this point pLink points to the record that comes right after 04477 // the new lock that we're inserting so we can simply push the 04478 // newlock into the entrylist 04479 // 04480 04481 DebugTrace(0, Dbg, "InsertSharedLock, Insert Before = %08lx\n", Link); 04482 04483 if (pLink->Next == NULL) { 04484 04485 // 04486 // Adding onto the tail of the list 04487 // 04488 04489 Node->Tail.Next = &NewLock->Link; 04490 } 04491 04492 NewLock->Link.Next = pLink->Next; 04493 pLink->Next = &NewLock->Link; 04494 04495 // 04496 // And splay the node we inserted into 04497 // 04498 04499 LockQueue->SharedLockTree = RtlSplay(OverlappedSplayLinks); 04500 04501 if ((ULONGLONG)NewLock->LockInfo.EndingByte.QuadPart > Node->Extent) { 04502 04503 // 04504 // The new lock extends the range of this node, so fix up the extent 04505 // 04506 04507 Node->Extent = NewLock->LockInfo.EndingByte.QuadPart; 04508 04509 // 04510 // Walk across the remainder of the tree integrating newly overlapping 04511 // nodes into the node we just inserted the new lock into. Note that 04512 // this isn't so much a walk as a repeated examination of our successor's 04513 // until one does not overlap (or we hit the end). 04514 // 04515 04516 ParentSplayLinks = OverlappedSplayLinks; 04517 04518 for (OverlappedSplayLinks = RtlRealSuccessor(ParentSplayLinks); 04519 OverlappedSplayLinks; 04520 OverlappedSplayLinks = RtlRealSuccessor(ParentSplayLinks)) { 04521 04522 NextNode = CONTAINING_RECORD( OverlappedSplayLinks, LOCKTREE_NODE, Links ); 04523 NextLock = CONTAINING_RECORD( NextNode->Locks.Next, SH_LOCK, Link ); 04524 04525 if ((ULONGLONG)NextLock->LockInfo.StartingByte.QuadPart > Node->Extent) { 04526 04527 // 04528 // This node is not overlapped, so stop 04529 // 04530 04531 break; 04532 } 04533 04534 // 04535 // If we are intergrating a holey node into a non-holey node, try to split 04536 // the node first. It will be better to get this done with a smaller node 04537 // than a big, fully integrated one. Note that we are guaranteed that the 04538 // node will remain a candidate for integration since the first lock on the 04539 // node will still be there, and overlaps. 04540 // 04541 04542 if (!Node->HoleyNode && NextNode->HoleyNode) { 04543 04544 FsRtlSplitLocks( NextNode, NULL, NULL, NULL ); 04545 } 04546 04547 // 04548 // Integrate the locks in this node into our list 04549 // 04550 04551 Node->Tail.Next->Next = NextNode->Locks.Next; 04552 Node->Tail.Next = NextNode->Tail.Next; 04553 04554 if (NextNode->Extent > Node->Extent) { 04555 04556 // 04557 // If the node we just swallowed was (still!) holey, we perhaps made this 04558 // node holey too. The resolution of this is left to the lock split we will 04559 // perform after integration is complete. 04560 // 04561 // Note that if the extent of the node we are swallowing is interior 04562 // to the current node, we just covered whatever holes it contained. 04563 // 04564 04565 if (NextNode->HoleyNode) { 04566 04567 Node->HoleyNode = TRUE; 04568 } 04569 04570 Node->Extent = NextNode->Extent; 04571 } 04572 04573 // 04574 // Free the now empty node. 04575 // 04576 04577 RtlDeleteNoSplay( OverlappedSplayLinks, &LockQueue->SharedLockTree ); 04578 FsRtlFreeLockTreeNode( NextNode ); 04579 } 04580 } 04581 04582 // 04583 // Now, perhaps this node is still holey. For grins lets try one more time to split 04584 // this thing apart. 04585 // 04586 04587 if (Node->HoleyNode) { 04588 04589 FsRtlSplitLocks( Node, NULL, NULL, NULL ); 04590 } 04591 04592 // 04593 // And return to our caller 04594 // 04595 04596 return TRUE; 04597 } 04598 04599 04600 // 04601 // Internal Support Routine 04602 // 04603 04604 VOID 04605 FsRtlPrivateInsertExclusiveLock ( 04606 IN PLOCK_QUEUE LockQueue, 04607 IN PEX_LOCK NewLock 04608 ) 04609 04610 /*++ 04611 04612 Routine Description: 04613 04614 This routine adds a new exclusive lock record to the File lock's current 04615 lock queue. 04616 04617 Arguments: 04618 04619 LockQueue - Supplies the lock queue being modified 04620 04621 NewLock - Supplies the new exclusive lock to add to the lock queue 04622 04623 Return Value: 04624 04625 None. 04626 04627 --*/ 04628 04629 { 04630 PRTL_SPLAY_LINKS OverlappedSplayLinks, ParentSplayLinks; 04631 BOOLEAN GreaterThan; 04632 04633 OverlappedSplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockQueue->ExclusiveLockTree, 04634 &NewLock->LockInfo.StartingByte, 04635 &NewLock->LockInfo.EndingByte, 04636 &ParentSplayLinks, 04637 &GreaterThan ); 04638 04639 // 04640 // This is the exclusive tree. Nothing can overlap (caller is supposed to insure this) unless 04641 // the lock is a zero length lock, in which case we just insert it - still. 04642 // 04643 04644 ASSERT(!OverlappedSplayLinks || NewLock->LockInfo.Length.QuadPart == 0); 04645 04646 // 04647 // Simple insert ... 04648 // 04649 04650 RtlInitializeSplayLinks(&NewLock->Links); 04651 04652 if (OverlappedSplayLinks) { 04653 04654 // 04655 // With zero length locks we have OverlappedSplayLinks at the starting point 04656 // of a run of zero length locks, so we have to e flexible about where the new 04657 // node is inserted. 04658 // 04659 04660 if (RtlRightChild(OverlappedSplayLinks)) { 04661 04662 // 04663 // Right slot taken. We can use the left slot or go to the sucessor's left slot 04664 // 04665 04666 if (RtlLeftChild(OverlappedSplayLinks)) { 04667 04668 ASSERT(RtlLeftChild(RtlRealSuccessor(OverlappedSplayLinks)) == NULL); 04669 RtlInsertAsLeftChild(RtlRealSuccessor(OverlappedSplayLinks), &NewLock->Links); 04670 04671 } else { 04672 04673 RtlInsertAsLeftChild(OverlappedSplayLinks, &NewLock->Links); 04674 } 04675 04676 04677 } else { 04678 04679 RtlInsertAsRightChild(OverlappedSplayLinks, &NewLock->Links); 04680 } 04681 04682 } else if (ParentSplayLinks) { 04683 04684 // 04685 // We have a real parent node in the tree, and must be at a leaf since 04686 // there was no overlap 04687 // 04688 04689 if (GreaterThan) { 04690 04691 ASSERT(RtlLeftChild(ParentSplayLinks) == NULL); 04692 RtlInsertAsLeftChild(ParentSplayLinks, &NewLock->Links); 04693 04694 } else { 04695 04696 ASSERT(RtlRightChild(ParentSplayLinks) == NULL); 04697 RtlInsertAsRightChild(ParentSplayLinks, &NewLock->Links); 04698 } 04699 04700 } else { 04701 04702 // 04703 // First node in the tree 04704 // 04705 04706 LockQueue->ExclusiveLockTree = &NewLock->Links; 04707 } 04708 04709 // 04710 // And return to our caller 04711 // 04712 04713 return; 04714 } 04715 04716 04717 // 04718 // Internal Support Routine 04719 // 04720 04721 VOID 04722 FsRtlPrivateCheckWaitingLocks ( 04723 IN PLOCK_INFO LockInfo, 04724 IN PLOCK_QUEUE LockQueue, 04725 IN KIRQL OldIrql 04726 ) 04727 04728 /*++ 04729 04730 Routine Description: 04731 04732 This routine checks to see if any of the current waiting locks are now 04733 be satisfied, and if so it completes their IRPs. 04734 04735 Arguments: 04736 04737 LockInfo - LockInfo which LockQueue is member of 04738 04739 LockQueue - Supplies queue which needs to be checked 04740 04741 OldIrql - Irql to restore when LockQueue is released 04742 04743 Return Value: 04744 04745 None. 04746 04747 --*/ 04748 04749 { 04750 PSINGLE_LIST_ENTRY *pLink, Link; 04751 NTSTATUS NewStatus; 04752 BOOLEAN Result; 04753 04754 pLink = &LockQueue->WaitingLocks.Next; 04755 while ((Link = *pLink) != NULL) { 04756 04757 PWAITING_LOCK WaitingLock; 04758 04759 PIRP Irp; 04760 PIO_STACK_LOCATION IrpSp; 04761 04762 BOOLEAN AccessGranted; 04763 04764 FILE_LOCK_INFO FileLockInfo; 04765 04766 // 04767 // Get a pointer to the waiting lock record 04768 // 04769 04770 WaitingLock = CONTAINING_RECORD( Link, WAITING_LOCK, Link ); 04771 04772 DebugTrace(0, Dbg, "FsRtlCheckWaitingLocks, Loop top, WaitingLock = %08lx\n", WaitingLock); 04773 04774 // 04775 // Get a local copy of the necessary fields we'll need to use 04776 // 04777 04778 Irp = WaitingLock->Irp; 04779 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 04780 04781 FileLockInfo.StartingByte = IrpSp->Parameters.LockControl.ByteOffset; 04782 FileLockInfo.Length = *IrpSp->Parameters.LockControl.Length; 04783 (ULONGLONG)FileLockInfo.EndingByte.QuadPart = 04784 (ULONGLONG)FileLockInfo.StartingByte.QuadPart + (ULONGLONG)FileLockInfo.Length.QuadPart - 1; 04785 04786 FileLockInfo.FileObject = IrpSp->FileObject; 04787 FileLockInfo.ProcessId = IoGetRequestorProcess( Irp ); 04788 FileLockInfo.Key = IrpSp->Parameters.LockControl.Key; 04789 FileLockInfo.ExclusiveLock = BooleanFlagOn(IrpSp->Flags, SL_EXCLUSIVE_LOCK); 04790 04791 // 04792 // Now case on whether we're trying to take out an exclusive lock or 04793 // a shared lock. And in both cases try to get the appropriate access 04794 // For the exclusive case we send in a NULL file object and process 04795 // id, this will ensure that the lookup does not give us write 04796 // access through an exclusive lock. 04797 // 04798 04799 if (FileLockInfo.ExclusiveLock) { 04800 04801 DebugTrace(0, Dbg, "FsRtlCheckWaitingLocks do we have write access?\n", 0); 04802 04803 AccessGranted = FsRtlPrivateCheckForExclusiveLockAccess( 04804 LockQueue, 04805 &FileLockInfo ); 04806 } else { 04807 04808 DebugTrace(0, Dbg, "FsRtlCheckWaitingLocks do we have read access?\n", 0); 04809 04810 AccessGranted = FsRtlPrivateCheckForSharedLockAccess( 04811 LockQueue, 04812 &FileLockInfo ); 04813 04814 } 04815 04816 // 04817 // Now AccessGranted tells us whether we can really get the access for 04818 // the range we want. 04819 // 04820 // No matter what happens, this Irp must be completed now - even if we 04821 // are resource starved. User mode deadlock could be induced since there 04822 // may no longer be a pending unlock to cause a rescan of the waiting 04823 // list. 04824 // 04825 04826 if (AccessGranted) { 04827 04828 DebugTrace(0, Dbg, "FsRtlCheckWaitingLocks now has access\n", 0); 04829 04830 // 04831 // Clear the cancel routine 04832 // 04833 04834 IoSetCancelRoutine( Irp, NULL ); 04835 04836 Result = FsRtlPrivateInsertLock( LockInfo, IrpSp->FileObject, &FileLockInfo ); 04837 04838 // 04839 // Now we need to remove this granted waiter and complete 04840 // it's irp. 04841 // 04842 04843 *pLink = Link->Next; 04844 if (Link == LockQueue->WaitingLocksTail.Next) { 04845 LockQueue->WaitingLocksTail.Next = (PSINGLE_LIST_ENTRY) pLink; 04846 } 04847 04848 // 04849 // Release LockQueue and complete this waiter 04850 // 04851 04852 FsRtlReleaseLockQueue(LockQueue, OldIrql); 04853 04854 // 04855 // Reference the fileobject over the completion attempt so we can have a 04856 // chance to cleanup safely if we fail 04857 // 04858 04859 ObReferenceObject( FileLockInfo.FileObject ); 04860 04861 // 04862 // Now we can complete the IRP, if we don't get back success 04863 // from the completion routine then we remove the lock we just 04864 // inserted. 04865 // 04866 04867 FsRtlCompleteLockIrp( LockInfo, 04868 WaitingLock->Context, 04869 Irp, 04870 (Result? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES), 04871 &NewStatus, 04872 FileLockInfo.FileObject ); 04873 04874 if (Result && !NT_SUCCESS(NewStatus)) { 04875 04876 // 04877 // Irp was not sucessfull, remove lock if it was added. 04878 // 04879 04880 FsRtlPrivateRemoveLock ( 04881 LockInfo, 04882 &FileLockInfo, 04883 FALSE ); 04884 } 04885 04886 // 04887 // Drop our private reference to the fileobject 04888 // 04889 04890 ObDereferenceObject( FileLockInfo.FileObject ); 04891 04892 // 04893 // Re-acquire queue lock 04894 // 04895 04896 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 04897 04898 // 04899 // Start scan over from begining 04900 // 04901 04902 pLink = &LockQueue->WaitingLocks.Next; 04903 04904 04905 // 04906 // Free up pool 04907 // 04908 04909 FsRtlFreeWaitingLock( WaitingLock ); 04910 04911 04912 } else { 04913 04914 DebugTrace( 0, Dbg, "FsRtlCheckWaitingLocks still no access\n", 0); 04915 04916 // 04917 // Move to next lock 04918 // 04919 04920 pLink = &Link->Next; 04921 } 04922 04923 } 04924 04925 // 04926 // And return to our caller 04927 // 04928 04929 return; 04930 } 04931 04932 04933 BOOLEAN 04934 FsRtlPrivateCheckForExclusiveLockAccess ( 04935 IN PLOCK_QUEUE LockQueue, 04936 IN PFILE_LOCK_INFO FileLockInfo 04937 ) 04938 /*++ 04939 04940 Routine Description: 04941 04942 This routine checks to see if the caller can get an exclusive lock on 04943 the indicated range due to file locks in the passed in lock queue. 04944 04945 Assumes Lock queue is held by caller 04946 04947 Arguments: 04948 04949 LockQueue - Queue which needs to be checked for collision 04950 04951 FileLockInfo - Lock which is being checked 04952 04953 04954 Return Value: 04955 04956 BOOLEAN - TRUE if the indicated user can place the exclusive lock over the 04957 entire specified byte range, and FALSE otherwise 04958 04959 --*/ 04960 04961 { 04962 PRTL_SPLAY_LINKS SplayLinks, LastSplayLinks = NULL; 04963 PLOCKTREE_NODE Node; 04964 PSH_LOCK ShLock; 04965 PEX_LOCK ExLock; 04966 04967 if (LockQueue->SharedLockTree && 04968 (SplayLinks = FsRtlFindFirstOverlappingSharedNode( LockQueue->SharedLockTree, 04969 &FileLockInfo->StartingByte, 04970 &FileLockInfo->EndingByte, 04971 &LastSplayLinks, NULL))) { 04972 04973 Node = CONTAINING_RECORD(SplayLinks, LOCKTREE_NODE, Links); 04974 04975 // 04976 // If this node is holey, we'll have to walk the whole thing. 04977 // 04978 04979 if (Node->HoleyNode) { 04980 04981 ShLock = FsRtlFindFirstOverlapInNode( Node, 04982 &FileLockInfo->StartingByte, 04983 &FileLockInfo->EndingByte ); 04984 04985 } else { 04986 04987 ShLock = CONTAINING_RECORD(Node->Locks.Next, SH_LOCK, Link); 04988 } 04989 04990 // 04991 // Look for overlap that we care about. Perhaps no overlap existed in the holey case. 04992 // 04993 04994 if (ShLock && 04995 (FileLockInfo->Length.QuadPart || ShLock->LockInfo.Length.QuadPart)) { 04996 04997 // 04998 // If we are checking a nonzero extent and overlapped, it is fatal. If we 04999 // are checking a zero extent and overlapped a nonzero extent, it is fatal. 05000 // 05001 05002 return FALSE; 05003 } 05004 } 05005 05006 if (LastSplayLinks) { 05007 05008 LockQueue->SharedLockTree = RtlSplay(LastSplayLinks); 05009 LastSplayLinks = NULL; 05010 } 05011 05012 if (LockQueue->ExclusiveLockTree && 05013 (SplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockQueue->ExclusiveLockTree, 05014 &FileLockInfo->StartingByte, 05015 &FileLockInfo->EndingByte, 05016 &LastSplayLinks, NULL))) { 05017 05018 ExLock = CONTAINING_RECORD(SplayLinks, EX_LOCK, Links); 05019 05020 if (FileLockInfo->Length.QuadPart || ExLock->LockInfo.Length.QuadPart) { 05021 05022 // 05023 // If we are checking a nonzero extent and overlapped, it is fatal. If we 05024 // are checking a zero extent and overlapped a nonzero extent, it is fatal. 05025 // 05026 05027 return FALSE; 05028 } 05029 } 05030 05031 if (LastSplayLinks) { 05032 05033 LockQueue->ExclusiveLockTree = RtlSplay(LastSplayLinks); 05034 } 05035 05036 // 05037 // We searched the entire range without a conflict so we can grant 05038 // the exclusive lock 05039 // 05040 05041 return TRUE; 05042 } 05043 05044 05045 BOOLEAN 05046 FsRtlPrivateCheckForSharedLockAccess ( 05047 IN PLOCK_QUEUE LockQueue, 05048 IN PFILE_LOCK_INFO FileLockInfo 05049 ) 05050 /*++ 05051 05052 Routine Description: 05053 05054 This routine checks to see if the caller can get a shared lock on 05055 the indicated range due to file locks in the passed in lock queue. 05056 05057 Assumes Lock queue is held by caller 05058 05059 Arguments: 05060 05061 LockQueue - Queue which needs to be checked for collision 05062 05063 FileLockInfo - Lock which is being checked 05064 05065 Arguments: 05066 05067 Return Value: 05068 05069 BOOLEAN - TRUE if the indicated user can place the shared lock over 05070 entire specified byte range, and FALSE otherwise 05071 05072 --*/ 05073 05074 { 05075 PEX_LOCK Lock; 05076 PRTL_SPLAY_LINKS SplayLinks, LastSplayLinks; 05077 BOOLEAN Status = TRUE; 05078 05079 // 05080 // If there are no exclusive locks, this is quick ... 05081 // 05082 05083 if (LockQueue->ExclusiveLockTree == NULL) { 05084 05085 return TRUE; 05086 } 05087 05088 // 05089 // No lock in the shared lock tree can prevent access, so just search the exclusive 05090 // tree for conflict. 05091 // 05092 05093 for (SplayLinks = FsRtlFindFirstOverlappingExclusiveNode( LockQueue->ExclusiveLockTree, 05094 &FileLockInfo->StartingByte, 05095 &FileLockInfo->EndingByte, 05096 &LastSplayLinks, NULL); 05097 SplayLinks; 05098 SplayLinks = RtlRealSuccessor(SplayLinks)) { 05099 05100 Lock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 05101 05102 if ((ULONGLONG)Lock->LockInfo.StartingByte.QuadPart > (ULONGLONG)FileLockInfo->EndingByte.QuadPart) { 05103 05104 // 05105 // This node is covering a range greater than the range we care about, 05106 // so we're done 05107 // 05108 05109 break; 05110 } 05111 05112 // 05113 // We may not be able to grant the request if the fileobject, processid, 05114 // and key do not match. 05115 // 05116 05117 if ((Lock->LockInfo.FileObject != FileLockInfo->FileObject) || 05118 (Lock->LockInfo.ProcessId != FileLockInfo->ProcessId) || 05119 (Lock->LockInfo.Key != FileLockInfo->Key)) { 05120 05121 // 05122 // We have a mismatch between caller and owner. It is ok not to conflict 05123 // if the caller and owner will have/have zero length locks (zero length 05124 // locks cannot conflict). 05125 // 05126 05127 if (FileLockInfo->Length.QuadPart || Lock->LockInfo.Length.QuadPart) { 05128 05129 Status = FALSE; 05130 break; 05131 } 05132 } 05133 } 05134 05135 if (LastSplayLinks) { 05136 05137 LockQueue->ExclusiveLockTree = RtlSplay(LastSplayLinks); 05138 } 05139 05140 // 05141 // We searched the entire range without a conflict so we can grant 05142 // the shared lock 05143 // 05144 05145 return Status; 05146 } 05147 05148 05149 VOID 05150 FsRtlPrivateResetLowestLockOffset ( 05151 PLOCK_INFO LockInfo 05152 ) 05153 05154 /*++ 05155 05156 Routine Description: 05157 05158 This routine resets the lowest lock offset hint in a LOCK_INFO to 05159 the lowest lock offset currently held by a lock inside of the LOCK_INFO. 05160 05161 Arguments: 05162 05163 LockInfo - the lock data to operate on 05164 05165 Return Value: 05166 05167 None 05168 05169 --*/ 05170 05171 { 05172 PEX_LOCK ExLock = NULL; 05173 PSH_LOCK ShLock = NULL; 05174 PFILE_LOCK_INFO LowestLockInfo = NULL; 05175 PRTL_SPLAY_LINKS SplayLinks; 05176 PLOCKTREE_NODE Node; 05177 05178 // 05179 // Fix up the lowest lock offset if we have non-empty trees and there was 05180 // a lock in the low 32 bit region 05181 // 05182 05183 if (LockInfo->LowestLockOffset != 0xffffffff && 05184 (LockInfo->LockQueue.SharedLockTree != NULL || 05185 LockInfo->LockQueue.ExclusiveLockTree != NULL)) { 05186 05187 // 05188 // Grab the lowest nodes in the trees 05189 // 05190 05191 if (LockInfo->LockQueue.SharedLockTree) { 05192 05193 SplayLinks = LockInfo->LockQueue.SharedLockTree; 05194 05195 while (RtlLeftChild(SplayLinks) != NULL) { 05196 05197 SplayLinks = RtlLeftChild(SplayLinks); 05198 } 05199 05200 Node = CONTAINING_RECORD( SplayLinks, LOCKTREE_NODE, Links ); 05201 ShLock = CONTAINING_RECORD( Node->Locks.Next, SH_LOCK, Link ); 05202 } 05203 05204 if (LockInfo->LockQueue.ExclusiveLockTree) { 05205 05206 SplayLinks = LockInfo->LockQueue.ExclusiveLockTree; 05207 05208 while (RtlLeftChild(SplayLinks) != NULL) { 05209 05210 SplayLinks = RtlLeftChild(SplayLinks); 05211 } 05212 05213 ExLock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 05214 } 05215 05216 // 05217 // Figure out which of the lowest locks is actually lowest. We know that one of the lock 05218 // trees at least has a lock, so if we have don't have exclusive locks then we do know 05219 // we have shared locks ... 05220 // 05221 05222 if (ExLock && 05223 (!ShLock || 05224 (ULONGLONG)ExLock->LockInfo.StartingByte.QuadPart < (ULONGLONG)ShLock->LockInfo.StartingByte.QuadPart)) { 05225 05226 LowestLockInfo = &ExLock->LockInfo; 05227 05228 } else { 05229 05230 LowestLockInfo = &ShLock->LockInfo; 05231 } 05232 05233 if (LowestLockInfo->StartingByte.HighPart == 0) { 05234 05235 LockInfo->LowestLockOffset = LowestLockInfo->StartingByte.LowPart; 05236 05237 } else { 05238 05239 LockInfo->LowestLockOffset = 0xffffffff; 05240 } 05241 05242 } else { 05243 05244 // 05245 // If there are no locks, set the lock offset high 05246 // 05247 05248 LockInfo->LowestLockOffset = 0xffffffff; 05249 } 05250 } 05251 05252 05253 NTSTATUS 05254 FsRtlPrivateFastUnlockAll ( 05255 IN PFILE_LOCK FileLock, 05256 IN PFILE_OBJECT FileObject, 05257 IN PEPROCESS ProcessId, 05258 IN ULONG Key, 05259 IN BOOLEAN MatchKey, 05260 IN PVOID Context OPTIONAL 05261 ) 05262 05263 /*++ 05264 05265 Routine Description: 05266 05267 This routine performs an Unlock all operation on the current locks 05268 associated with the specified file lock. Only those locks with 05269 a matching file object and process id are freed. Additionally, 05270 it is possible to free only those locks which also match a given 05271 key. 05272 05273 Arguments: 05274 05275 FileLock - Supplies the file lock being freed. 05276 05277 FileObject - Supplies the file object associated with the file lock 05278 05279 ProcessId - Supplies the Process Id assoicated with the locks to be 05280 freed 05281 05282 Key - Supplies the Key to use in this operation 05283 05284 MatchKey - Whether or not the Key must also match for lock to be freed. 05285 05286 Context - Supplies an optional context to use when completing waiting 05287 lock irps. 05288 05289 Return Value: 05290 05291 None 05292 05293 --*/ 05294 05295 { 05296 PLOCK_INFO LockInfo; 05297 PLOCK_QUEUE LockQueue; 05298 PSINGLE_LIST_ENTRY *pLink, *SavepLink, Link; 05299 NTSTATUS NewStatus; 05300 KIRQL OldIrql; 05301 LARGE_INTEGER MaxOffset, SaveEndingByte; 05302 BOOLEAN UnlockRoutine; 05303 PSH_LOCK ShLock; 05304 PEX_LOCK ExLock; 05305 PRTL_SPLAY_LINKS SplayLinks, SuccessorLinks; 05306 PLOCKTREE_NODE Node; 05307 05308 05309 DebugTrace(+1, Dbg, "FsRtlPrivateFastUnlockAll, FileLock = %08lx\n", FileLock); 05310 05311 if ((LockInfo = FileLock->LockInformation) == NULL) { 05312 05313 // 05314 // No lock information on this FileLock 05315 // 05316 05317 DebugTrace(+1, Dbg, "FsRtlPrivateFastUnlockAll, No LockInfo\n", FileLock); 05318 return STATUS_RANGE_NOT_LOCKED; 05319 } 05320 05321 FileObject->LastLock = NULL; 05322 05323 LockQueue = &LockInfo->LockQueue; 05324 05325 // 05326 // Grab the waiting lock queue spinlock to exclude anyone from messing 05327 // with the queue while we're using it 05328 // 05329 05330 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 05331 05332 if (LockQueue->SharedLockTree == NULL && LockQueue->ExclusiveLockTree == NULL) { 05333 05334 // 05335 // No locks on this FileLock 05336 // 05337 05338 DebugTrace(+1, Dbg, "FsRtlPrivateFastUnlockAll, No LockTrees\n", FileLock); 05339 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05340 05341 return STATUS_RANGE_NOT_LOCKED; 05342 } 05343 05344 // 05345 // Remove all matching locks in the shared lock tree 05346 // 05347 05348 if (LockQueue->SharedLockTree != NULL) { 05349 05350 // 05351 // Grab the lowest node in the tree 05352 // 05353 05354 SplayLinks = LockQueue->SharedLockTree; 05355 05356 while (RtlLeftChild(SplayLinks) != NULL) { 05357 05358 SplayLinks = RtlLeftChild(SplayLinks); 05359 } 05360 05361 // 05362 // Walk all nodes in the tree 05363 // 05364 05365 UnlockRoutine = FALSE; 05366 05367 for (; 05368 SplayLinks; 05369 SplayLinks = SuccessorLinks) { 05370 05371 Node = CONTAINING_RECORD(SplayLinks, LOCKTREE_NODE, Links ); 05372 05373 // 05374 // Save the next node because we may split this node apart in the process 05375 // of deleting locks. It would be a waste of time to traverse those split 05376 // nodes. The only case in which we will not have traversed the entire list 05377 // before doing the split will be if there is an unlock routine attached 05378 // to this FileLock in which case we will be restarting the entire scan 05379 // anyway. 05380 // 05381 05382 SuccessorLinks = RtlRealSuccessor(SplayLinks); 05383 05384 // 05385 // Search down the current lock queue looking for a match on 05386 // the file object and process id 05387 // 05388 05389 SavepLink = NULL; 05390 SaveEndingByte.QuadPart = 0; 05391 05392 pLink = &Node->Locks.Next; 05393 while ((Link = *pLink) != NULL) { 05394 05395 ShLock = CONTAINING_RECORD( Link, SH_LOCK, Link ); 05396 05397 DebugTrace(0, Dbg, "Top of ShLock Loop, Lock = %08lx\n", ShLock ); 05398 05399 if ((ShLock->LockInfo.FileObject == FileObject) && 05400 (ShLock->LockInfo.ProcessId == ProcessId) && 05401 (!MatchKey || ShLock->LockInfo.Key == Key)) { 05402 05403 DebugTrace(0, Dbg, "Found one to unlock\n", 0); 05404 05405 // 05406 // We have a match so now is the time to delete this lock. 05407 // Save the neccesary information to do the split node check. 05408 // Remove the lock from the list, then call the 05409 // optional unlock routine, then delete the lock. 05410 // 05411 05412 if (SavepLink == NULL) { 05413 05414 // 05415 // Need to remember where the first lock was deleted 05416 // 05417 05418 SavepLink = pLink; 05419 } 05420 05421 if ((ULONGLONG)ShLock->LockInfo.EndingByte.QuadPart > (ULONGLONG)SaveEndingByte.QuadPart) { 05422 05423 // 05424 // Need to remember where the last offset affected by deleted locks is 05425 // 05426 05427 SaveEndingByte.QuadPart = ShLock->LockInfo.EndingByte.QuadPart; 05428 } 05429 05430 if (*pLink == Node->Tail.Next) { 05431 05432 // 05433 // Deleting the tail node of the list. Safe even if deleting the 05434 // first node since this implies we're also deleting the last node 05435 // in the node which means we'll delete the node ... 05436 // 05437 05438 Node->Tail.Next = CONTAINING_RECORD( pLink, SINGLE_LIST_ENTRY, Next ); 05439 } 05440 05441 *pLink = Link->Next; 05442 05443 if (LockInfo->UnlockRoutine != NULL) { 05444 05445 // 05446 // Signal a lock that needs to have a special unlock routine 05447 // called on it. This is complex to deal with since we'll have 05448 // to release the queue, call it, and reacquire - meaning we 05449 // also have to restart. But we still need to reorder the node 05450 // first ... 05451 // 05452 05453 UnlockRoutine = TRUE; 05454 05455 break; 05456 } 05457 05458 FsRtlFreeSharedLock( ShLock ); 05459 05460 } else { 05461 05462 // 05463 // Move to next lock 05464 // 05465 05466 pLink = &Link->Next; 05467 } 05468 05469 if (SavepLink == NULL && (ULONGLONG)ShLock->LockInfo.EndingByte.QuadPart > (ULONGLONG)MaxOffset.QuadPart) { 05470 05471 // 05472 // Save the max offset until we have deleted our first node 05473 // 05474 05475 MaxOffset.QuadPart = ShLock->LockInfo.EndingByte.QuadPart; 05476 } 05477 } 05478 05479 if (SavepLink) { 05480 05481 // 05482 // Locks were actually deleted here, so we have to check the state of the node 05483 // 05484 05485 if (Node->Locks.Next == NULL) { 05486 05487 // 05488 // We have just deleted everything at this node 05489 // 05490 05491 LockQueue->SharedLockTree = RtlDelete(SplayLinks); 05492 05493 FsRtlFreeLockTreeNode(Node); 05494 05495 } else { 05496 05497 // 05498 // Now that we have deleted all matching locks in this node, we do the 05499 // check on the node to split out any now non-overlapping locks. Conceptually, 05500 // we have deleted just one big lock that starts at the starting byte of the 05501 // first deleted lock and extends to the last byte of the last deleted lock. 05502 // 05503 05504 FsRtlSplitLocks(Node, SavepLink, &SaveEndingByte, &MaxOffset); 05505 } 05506 } 05507 05508 if (UnlockRoutine) { 05509 05510 // 05511 // We dropped out of the node scan because we had a lock that needs extra 05512 // processing during unlock. Do it. 05513 // 05514 05515 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05516 05517 LockInfo->UnlockRoutine(Context, &ShLock->LockInfo); 05518 05519 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 05520 05521 FsRtlFreeSharedLock(ShLock); 05522 05523 UnlockRoutine = FALSE; 05524 05525 // 05526 // We have to restart the scan, because the list may have changed while 05527 // we were in the unlock routine. Careful, because the tree may be empty. 05528 // 05529 05530 if (SuccessorLinks = LockQueue->SharedLockTree) { 05531 05532 while (RtlLeftChild(SuccessorLinks) != NULL) { 05533 05534 SuccessorLinks = RtlLeftChild(SuccessorLinks); 05535 } 05536 } 05537 } 05538 } 05539 } 05540 05541 // 05542 // Remove all matching locks in the exclusive lock tree 05543 // 05544 05545 if (LockQueue->ExclusiveLockTree != NULL) { 05546 05547 SplayLinks = LockQueue->ExclusiveLockTree; 05548 05549 while (RtlLeftChild(SplayLinks) != NULL) { 05550 05551 SplayLinks = RtlLeftChild(SplayLinks); 05552 } 05553 05554 // 05555 // Walk all nodes in the tree 05556 // 05557 05558 UnlockRoutine = FALSE; 05559 05560 for (; SplayLinks; 05561 SplayLinks = SuccessorLinks ) { 05562 05563 SuccessorLinks = RtlRealSuccessor(SplayLinks); 05564 05565 ExLock = CONTAINING_RECORD( SplayLinks, EX_LOCK, Links ); 05566 05567 DebugTrace(0, Dbg, "Top of ExLock Loop, Lock = %08lx\n", ExLock ); 05568 05569 if ((ExLock->LockInfo.FileObject == FileObject) && 05570 (ExLock->LockInfo.ProcessId == ProcessId) && 05571 (!MatchKey || ExLock->LockInfo.Key == Key)) { 05572 05573 LockQueue->ExclusiveLockTree = RtlDelete(&ExLock->Links); 05574 05575 if (LockInfo->UnlockRoutine != NULL) { 05576 05577 // 05578 // We're dropping out of the node scan because we have a lock 05579 // that needs extra processing during unlock. Do it. 05580 // 05581 05582 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05583 05584 LockInfo->UnlockRoutine(Context, &ExLock->LockInfo); 05585 05586 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 05587 05588 // 05589 // We have to restart the scan, because the list may have changed while 05590 // we were in the unlock routine. Careful, because the tree may be empty. 05591 // 05592 05593 if (SuccessorLinks = LockQueue->ExclusiveLockTree) { 05594 05595 while (RtlLeftChild(SuccessorLinks) != NULL) { 05596 05597 SuccessorLinks = RtlLeftChild(SuccessorLinks); 05598 } 05599 } 05600 } 05601 05602 FsRtlFreeExclusiveLock(ExLock); 05603 } 05604 } 05605 } 05606 05607 // 05608 // Search down the waiting lock queue looking for a match on the 05609 // file object and process id. 05610 // 05611 05612 pLink = &LockQueue->WaitingLocks.Next; 05613 while ((Link = *pLink) != NULL) { 05614 05615 PWAITING_LOCK WaitingLock; 05616 PIRP WaitingIrp; 05617 PIO_STACK_LOCATION WaitingIrpSp; 05618 05619 WaitingLock = CONTAINING_RECORD( Link, WAITING_LOCK, Link ); 05620 05621 DebugTrace(0, Dbg, "Top of Waiting Loop, WaitingLock = %08lx\n", WaitingLock); 05622 05623 // 05624 // Get a copy of the necessary fields we'll need to use 05625 // 05626 05627 WaitingIrp = WaitingLock->Irp; 05628 WaitingIrpSp = IoGetCurrentIrpStackLocation( WaitingIrp ); 05629 05630 if ((FileObject == WaitingIrpSp->FileObject) && 05631 (ProcessId == IoGetRequestorProcess( WaitingIrp )) && 05632 (!MatchKey || Key == WaitingIrpSp->Parameters.LockControl.Key)) { 05633 05634 DebugTrace(0, Dbg, "Found a waiting lock to abort\n", 0); 05635 05636 // 05637 // We now void the cancel routine in the irp 05638 // 05639 05640 IoSetCancelRoutine( WaitingIrp, NULL ); 05641 WaitingIrp->IoStatus.Information = 0; 05642 05643 // 05644 // We have a match so now is the time to delete this waiter 05645 // But we must not mess up our link iteration variable. We 05646 // do this by simply starting the iteration over again, 05647 // after we delete ourselves. We also will deallocate the 05648 // lock after we delete it. 05649 // 05650 05651 *pLink = Link->Next; 05652 if (Link == LockQueue->WaitingLocksTail.Next) { 05653 LockQueue->WaitingLocksTail.Next = (PSINGLE_LIST_ENTRY) pLink; 05654 } 05655 05656 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05657 05658 // 05659 // And complete this lock request Irp 05660 // 05661 05662 FsRtlCompleteLockIrp( LockInfo, 05663 WaitingLock->Context, 05664 WaitingIrp, 05665 STATUS_SUCCESS, 05666 &NewStatus, 05667 NULL ); 05668 05669 // 05670 // Reaqcuire lock queue spinlock and start over 05671 // 05672 05673 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 05674 05675 // 05676 // Start over 05677 // 05678 05679 pLink = &LockQueue->WaitingLocks.Next; 05680 05681 // 05682 // Put memory onto free list 05683 // 05684 05685 FsRtlFreeWaitingLock( WaitingLock ); 05686 continue; 05687 } 05688 05689 // 05690 // Move to next lock 05691 // 05692 05693 pLink = &Link->Next; 05694 } 05695 05696 // 05697 // At this point we've gone through unlocking everything. So 05698 // now try and release any waiting locks. 05699 // 05700 05701 FsRtlPrivateCheckWaitingLocks( LockInfo, LockQueue, OldIrql ); 05702 05703 // 05704 // We deleted a (possible) bunch of locks, go repair the lowest lock offset 05705 // 05706 05707 FsRtlPrivateResetLowestLockOffset( LockInfo ); 05708 05709 FsRtlReleaseLockQueue( LockQueue, OldIrql ); 05710 05711 // 05712 // and return to our caller 05713 // 05714 05715 DebugTrace(-1, Dbg, "FsRtlFastUnlockAll -> VOID\n", 0); 05716 return STATUS_SUCCESS; 05717 } 05718 05719 05720 VOID 05721 FsRtlPrivateCancelFileLockIrp ( 05722 IN PDEVICE_OBJECT DeviceObject, 05723 IN PIRP Irp 05724 ) 05725 05726 /*++ 05727 05728 Routine Description: 05729 05730 This routine implements the cancel function for an irp saved in a 05731 waiting lock queue 05732 05733 Arguments: 05734 05735 DeviceObject - Ignored 05736 05737 Irp - Supplies the Irp being cancelled. A pointer to the FileLock 05738 structure for the lock is stored in the information field of the 05739 irp's iosb. 05740 05741 Return Value: 05742 05743 none. 05744 05745 --*/ 05746 05747 { 05748 PSINGLE_LIST_ENTRY *pLink, Link; 05749 PLOCK_INFO LockInfo; 05750 PLOCK_QUEUE LockQueue; 05751 KIRQL OldIrql; 05752 NTSTATUS NewStatus; 05753 05754 05755 UNREFERENCED_PARAMETER( DeviceObject ); 05756 05757 // 05758 // The information field is used to store a pointer to the file lock 05759 // containing the irp 05760 // 05761 05762 LockInfo = (PLOCK_INFO) (Irp->IoStatus.Information); 05763 05764 // 05765 // Iterate through the lock queue. 05766 // 05767 05768 LockQueue = &LockInfo->LockQueue; 05769 05770 // 05771 // Release the cancel spinlock and lock the waiting queue if this 05772 // is initiated by Io. We already have the lock queue if this is 05773 // the race fixup. 05774 // 05775 // If this is from ourselves, we have the cancel Irql in the Irp. 05776 // 05777 05778 if (DeviceObject) { 05779 05780 IoReleaseCancelSpinLock( Irp->CancelIrql ); 05781 FsRtlReacquireLockQueue(LockInfo, LockQueue, &OldIrql); 05782 05783 } else { 05784 05785 OldIrql = Irp->CancelIrql; 05786 } 05787 05788 // 05789 // Iterate through all of the waiting locks looking for a canceled one. 05790 05791 pLink = &LockQueue->WaitingLocks.Next; 05792 while ((Link = *pLink) != NULL) { 05793 05794 PWAITING_LOCK WaitingLock; 05795 05796 // 05797 // Get a pointer to the waiting lock record 05798 // 05799 05800 WaitingLock = CONTAINING_RECORD( Link, WAITING_LOCK, Link ); 05801 05802 DebugTrace(0, Dbg, "FsRtlPrivateCancelFileLockIrp, Loop top, WaitingLock = %08lx\n", WaitingLock); 05803 05804 if( WaitingLock->Irp != Irp ) { 05805 05806 pLink = &Link->Next; 05807 continue; 05808 } 05809 05810 // 05811 // We've found it -- remove it from the list 05812 // 05813 05814 *pLink = Link->Next; 05815 if (Link == LockQueue->WaitingLocksTail.Next) { 05816 05817 LockQueue->WaitingLocksTail.Next = (PSINGLE_LIST_ENTRY) pLink; 05818 } 05819 05820 Irp->IoStatus.Information = 0; 05821 05822 // 05823 // Release LockQueue and complete this waiter 05824 // 05825 05826 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05827 05828 // 05829 // Complete this waiter 05830 // 05831 05832 FsRtlCompleteLockIrp( LockInfo, 05833 WaitingLock->Context, 05834 Irp, 05835 STATUS_CANCELLED, 05836 &NewStatus, 05837 NULL ); 05838 05839 // 05840 // Free up pool 05841 // 05842 05843 FsRtlFreeWaitingLock( WaitingLock ); 05844 05845 // 05846 // Our job is done! 05847 // 05848 05849 return; 05850 } 05851 05852 // 05853 // Release lock queue 05854 // 05855 05856 FsRtlReleaseLockQueue(LockQueue, OldIrql); 05857 05858 return; 05859 } 05860

Generated on Sat May 15 19:40:00 2004 for test by doxygen 1.3.7