test: lock.c Source File

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

# lock.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989-1993  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     lock.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the code to implement the NtLockFile and the
    00012     NtUnlockFile system services for the NT I/O system.
    00013
    00014 Author:
    00015
    00016     Darryl E. Havens (darrylh) 29-Nov-1989
    00017
    00018 Environment:
    00019
    00020     Kernel mode only
    00021
    00022 Revision History:
    00023
    00024
    00025 --*/
    00026
    00027 #include "iop.h"
    00028
    00029 #ifdef ALLOC_PRAGMA
    00030 #pragma alloc_text(PAGE, NtLockFile)
    00031 #pragma alloc_text(PAGE, NtUnlockFile)
    00032 #endif
    00033
    00034 NTSTATUS
    00035 NtLockFile(
    00036     IN HANDLE FileHandle,
    00037     IN HANDLE Event OPTIONAL,
    00038     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    00039     IN PVOID ApcContext OPTIONAL,
    00040     OUT PIO_STATUS_BLOCK IoStatusBlock,
    00041     IN PLARGE_INTEGER ByteOffset,
    00042     IN PLARGE_INTEGER Length,
    00043     IN ULONG Key,
    00044     IN BOOLEAN FailImmediately,
    00045     IN BOOLEAN ExclusiveLock
    00046     )
    00047
    00048 /*++
    00049
    00050 Routine Description:
    00051
    00052     This service locks a specified range of bytes on the file specified by
    00053     the FileHandle parameter.  The lock may either be an exclusive lock or
    00054     a shared lock.  Furthermore, the caller has the option of specifying
    00055     whether or not the service should return immediately if the lock cannot
    00056     be acquired without waiting.
    00057
    00058 Arguments:
    00059
    00060     FileHandle - Supplies a handle to an open file.
    00061
    00062     Event - Supplies an optional event to be set to the Signaled state when
    00063         the operation is complete.
    00064
    00065     ApcRoutine - Supplies an optional APC routine to be executed when the
    00066         operation is complete.
    00067
    00068     ApcContext - Supplies a context parameter to be passed to the ApcRoutine,
    00069         if an ApcRoutine was specified.
    00070
    00071     IoStatusBlock - Address of the caller's I/O status block.
    00072
    00073     ByteOffset - Specifies the starting byte offset of the range to lock.
    00074
    00075     Length - Specifies the length of the byte range to be locked.
    00076
    00077     Key - Specifies the key to be associated with the lock.
    00078
    00079     FailImmediately - Specifies that if the lock cannot immediately be
    00080         acquired that the service should return to the caller.
    00081
    00082     ExclusiveLock - Specifies, if TRUE, that the lock should be an exclusive
    00083         lock;  otherwise the lock is a shared lock.
    00084
    00085 Return Value:
    00086
    00087     The status returned is success if the operation was properly queued to
    00088     the I/O system.  Once the operation completes, the status can be
    00089     determined by examining the Status field of the I/O status block.
    00090
    00091 --*/
    00092
    00093 {
    00094     PIRP irp;
    00095     NTSTATUS status;
    00096     PFILE_OBJECT fileObject;
    00097     PDEVICE_OBJECT deviceObject;
    00098     PFAST_IO_DISPATCH fastIoDispatch;
    00099     PKEVENT eventObject = (PKEVENT) NULL;
    00100     KPROCESSOR_MODE requestorMode;
    00101     PIO_STACK_LOCATION irpSp;
    00102     LARGE_INTEGER fileOffset;
    00103     LARGE_INTEGER length;
    00104     ACCESS_MASK grantedAccess;
    00105     OBJECT_HANDLE_INFORMATION handleInformation;
    00106     BOOLEAN synchronousIo;
    00107
    00108     PAGED_CODE();
    00109
    00110     //
    00111     // Get the previous mode;  i.e., the mode of the caller.
    00112     //
    00113
    00114     requestorMode = KeGetPreviousMode();
    00115
    00116     //
    00117     // Reference the file object so the target device can be found and the
    00118     // access rights mask can be used in the following checks for callers
    00119     // in user mode.  Note that if the handle does not refer to a file
    00120     // object, then it will fail.
    00121     //
    00122
    00123     status = ObReferenceObjectByHandle( FileHandle,
    00124                                         0L,
    00125                                         IoFileObjectType,
    00126                                         requestorMode,
    00127                                         (PVOID *) &fileObject,
    00128                                         &handleInformation);
    00129     if (!NT_SUCCESS( status )) {
    00130         return status;
    00131     }
    00132
    00133     grantedAccess = handleInformation.GrantedAccess;
    00134
    00135     if (requestorMode != KernelMode) {
    00136
    00137         //
    00138         // The caller's access mode is not kernel so probe each of the arguments
    00139         // and capture them as necessary.  If any failures occur, the condition
    00140         // handler will be invoked to handle them.  It will simply cleanup and
    00141         // return an access violation status code back to the system service
    00142         // dispatcher.
    00143         //
    00144
    00145         //
    00146         // Check to ensure that the caller has either READ or WRITE access to
    00147         // the file.  If not, cleanup and return an error.
    00148         //
    00149
    00150         if (!SeComputeGrantedAccesses( grantedAccess, FILE_READ_DATA | FILE_WRITE_DATA )) {
    00151             ObDereferenceObject( fileObject );
    00152             return STATUS_ACCESS_DENIED;
    00153         }
    00154
    00155         try {
    00156
    00157             //
    00158             // The IoStatusBlock parameter must be writeable by the caller.
    00159             //
    00160
    00161             ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine);
    00162
    00163             //
    00164             // The ByteOffset parameter must be readable by the caller.  Probe
    00165             // and capture it.
    00166             //
    00167
    00168             ProbeForRead( ByteOffset,
    00169                           sizeof( LARGE_INTEGER ),
    00170                           sizeof( ULONG ) );
    00171             fileOffset = *ByteOffset;
    00172
    00173             //
    00174             // Likewise, the Length parameter must also be readable by the
    00175             // caller.  Probe and capture it as well.
    00176             //
    00177
    00178             ProbeForRead( Length,
    00179                           sizeof( LARGE_INTEGER ),
    00180                           sizeof( ULONG ) );
    00181             length = *Length;
    00182
    00183             //
    00184             // If this file has an I/O completion port associated w/it, then
    00185             // ensure that the caller did not supply an APC routine, as the
    00186             // two are mutually exclusive methods for I/O completion
    00187             // notification.
    00188             //
    00189
    00190             if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
    00191                 ObDereferenceObject( fileObject );
    00192                 return STATUS_INVALID_PARAMETER;
    00193             }
    00194
    00195         } except(EXCEPTION_EXECUTE_HANDLER) {
    00196
    00197             //
    00198             // An exception was incurred attempting to probe the caller's
    00199             // parameters.  Dereference the file object and return an
    00200             // appropriate error status code.
    00201             //
    00202
    00203             ObDereferenceObject( fileObject );
    00204             return GetExceptionCode();
    00205         }
    00206
    00207     } else {
    00208
    00209         //
    00210         // The caller's mode was kernel.  Get the ByteOffset and Length
    00211         // parameter 's to the expected locations.
    00212         //
    00213
    00214         fileOffset = *ByteOffset;
    00215         length = *Length;
    00216     }
    00217
    00218     //
    00219     // Get the address of the event object and set the event to the Not-
    00220     // Signaled state, if an event was specified.  Note here, too, that if
    00221     // the handle does not refer to an event, or if the event cannot be
    00222     // written, then the reference will fail.  Since certain legacy
    00223     // applications rely on an old bug in Win32's LockFileEx, we must
    00224     // tolerate bad event handles.
    00225     //
    00226
    00227     if (ARGUMENT_PRESENT( Event )) {
    00228         status = ObReferenceObjectByHandle( Event,
    00229                                             EVENT_MODIFY_STATE,
    00230                                             ExEventObjectType,
    00231                                             requestorMode,
    00232                                             (PVOID *) &eventObject,
    00233                                             NULL );
    00234         if (!NT_SUCCESS( status )) {
    00235             ASSERT( !eventObject );
    00236         } else {
    00237             KeClearEvent( eventObject );
    00238         }
    00239     }
    00240
    00241     //
    00242     // Get the address of the target device object and the fast Io dispatch
    00243     // structure.
    00244     //
    00245
    00246     deviceObject = IoGetRelatedDeviceObject( fileObject );
    00247     fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
    00248
    00249     //
    00250     // Turbo lock support.  If the fast Io Dispatch specifies a fast lock
    00251     // routine then we'll first try and calling it with the specified lock
    00252     // parameters.
    00253     //
    00254
    00255     if (fastIoDispatch && fastIoDispatch->FastIoLock) {
    00256
    00257         IO_STATUS_BLOCK localIoStatus;
    00258
    00259         if (fastIoDispatch->FastIoLock( fileObject,
    00260                                         &fileOffset,
    00261                                         &length,
    00262                                         PsGetCurrentProcess(),
    00263                                         Key,
    00264                                         FailImmediately,
    00265                                         ExclusiveLock,
    00266                                         &localIoStatus,
    00267                                         deviceObject )) {
    00268
    00269             //
    00270             // Carefully return the I/O status.
    00271             //
    00272
    00273             try {
    00274                 *IoStatusBlock = localIoStatus;
    00275             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00276                 localIoStatus.Status = GetExceptionCode();
    00277                 localIoStatus.Information = 0;
    00278             }
    00279
    00280             //
    00281             // If a valid event was specified, set it.
    00282             //
    00283
    00284             if (eventObject) {
    00285                 KeSetEvent( eventObject, 0, FALSE );
    00286                 ObDereferenceObject( eventObject );
    00287             }
    00288
    00289             //
    00290             // Note that the file object event need not be set to the
    00291             // Signaled state, as it is already set.
    00292             //
    00293
    00294             //
    00295             // If this file object has a completion port associated with it
    00296             // and this request has a non-NULL APC context then a completion
    00297             // message needs to be queued.
    00298             //
    00299
    00300             if (fileObject->CompletionContext && ARGUMENT_PRESENT( ApcContext )) {
    00301                 if (!NT_SUCCESS(IoSetIoCompletion( fileObject->CompletionContext->Port,
    00302                                                    fileObject->CompletionContext->Key,
    00303                                                    ApcContext,
    00304                                                    localIoStatus.Status,
    00305                                                    localIoStatus.Information,
    00306                                                    TRUE ))) {
    00307                     localIoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
    00308                 }
    00309             }
    00310
    00311             //
    00312             // Cleanup and return.
    00313             //
    00314
    00315             fileObject->LockOperation = TRUE;
    00316             ObDereferenceObject( fileObject );
    00317             return localIoStatus.Status;
    00318         }
    00319     }
    00320
    00321     //
    00322     // Make a special check here to determine whether this is a synchronous
    00323     // I/O operation.  If it is, then wait here until the file is owned by
    00324     // the current thread.
    00325     //
    00326
    00327     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    00328
    00329         BOOLEAN interrupted;
    00330
    00331         if (!IopAcquireFastLock( fileObject )) {
    00332             status = IopAcquireFileObjectLock( fileObject,
    00333                                                requestorMode,
    00334                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    00335                                                &interrupted );
    00336             if (interrupted) {
    00337                 if (eventObject) {
    00338                     ObDereferenceObject( eventObject );
    00339                 }
    00340                 ObDereferenceObject( fileObject );
    00341                 return status;
    00342             }
    00343         }
    00344         synchronousIo = TRUE;
    00345     } else {
    00346         synchronousIo = FALSE;
    00347     }
    00348
    00349     //
    00350     // Set the file object to the Not-Signaled state and mark it as having had
    00351     // a lock operation performed on it.
    00352     //
    00353
    00354     KeClearEvent( &fileObject->Event );
    00355     fileObject->LockOperation = TRUE;
    00356
    00357     //
    00358     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    00359     // The allocation is performed with an exception handler in case the
    00360     // caller does not have enough quota to allocate the packet.
    00361
    00362     irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
    00363     if (!irp) {
    00364
    00365         //
    00366         // An IRP could not be allocated.  Cleanup and return an appropriate
    00367         // error status code.
    00368         //
    00369
    00370         IopAllocateIrpCleanup( fileObject, eventObject );
    00371
    00372         return STATUS_INSUFFICIENT_RESOURCES;
    00373     }
    00374     irp->Tail.Overlay.OriginalFileObject = fileObject;
    00375     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00376     irp->RequestorMode = requestorMode;
    00377
    00378     //
    00379     // Fill in the service independent parameters in the IRP.
    00380     //
    00381
    00382     irp->UserEvent = eventObject;
    00383     irp->UserIosb = IoStatusBlock;
    00384     irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
    00385     irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
    00386
    00387     //
    00388     // Get a pointer to the stack location for the first driver.  This will be
    00389     // used to pass the original function codes and parameters.
    00390     //
    00391
    00392     irpSp = IoGetNextIrpStackLocation( irp );
    00393     irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
    00394     irpSp->MinorFunction = IRP_MN_LOCK;
    00395     irpSp->FileObject = fileObject;
    00396
    00397     //
    00398     // Copy the caller's parameters to the service-specific portion of the
    00399     // IRP.
    00400     //
    00401
    00402     irpSp->Flags = 0;
    00403     if (FailImmediately) {
    00404         irpSp->Flags = SL_FAIL_IMMEDIATELY;
    00405     }
    00406     if (ExclusiveLock) {
    00407         irpSp->Flags |= SL_EXCLUSIVE_LOCK;
    00408     }
    00409     irpSp->Parameters.LockControl.Key = Key;
    00410     irpSp->Parameters.LockControl.ByteOffset = fileOffset;
    00411
    00412     try {
    00413         PLARGE_INTEGER lengthBuffer;
    00414
    00415         //
    00416         // Attempt to allocate an intermediary buffer to hold the length of
    00417         // this lock operation.  If it fails, either because there is no
    00418         // more quota, or because there are no more resources, then the
    00419         // exception handler will be invoked to cleanup and exit.
    00420         //
    00421
    00422         lengthBuffer = ExAllocatePoolWithQuota( NonPagedPool,
    00423                                                 sizeof( LARGE_INTEGER ) );
    00424
    00425         *lengthBuffer = length;
    00426         irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR) lengthBuffer;
    00427         irpSp->Parameters.LockControl.Length = lengthBuffer;
    00428     } except(EXCEPTION_EXECUTE_HANDLER) {
    00429
    00430         //
    00431         // An exception was incurred.  Simply clean everything up and
    00432         // return an appropriate error status code.
    00433         //
    00434
    00435         IopExceptionCleanup( fileObject,
    00436                              irp,
    00437                              eventObject,
    00438                              (PKEVENT) NULL );
    00439
    00440         return GetExceptionCode();
    00441     }
    00442
    00443     //
    00444     // Queue the packet, call the driver, and synchronize appopriately with
    00445     // I/O completion.
    00446     //
    00447
    00448     return IopSynchronousServiceTail( deviceObject,
    00449                                       irp,
    00450                                       fileObject,
    00451                                       FALSE,
    00452                                       requestorMode,
    00453                                       synchronousIo,
    00454                                       OtherTransfer );
    00455 }
    00456
    00457 NTSTATUS
    00458 NtUnlockFile(
    00459     IN HANDLE FileHandle,
    00460     OUT PIO_STATUS_BLOCK IoStatusBlock,
    00461     IN PLARGE_INTEGER ByteOffset,
    00462     IN PLARGE_INTEGER Length,
    00463     IN ULONG Key
    00464     )
    00465
    00466 /*++
    00467
    00468 Routine Description:
    00469
    00470     This service releases the lock associated with the specified byte range
    00471     for the file specified by the FileHandle parameter.
    00472
    00473 Arguments:
    00474
    00475     FileHandle - Supplies a handle to an open file.
    00476
    00477     IoStatusBlock - Address of the caller's I/O status block.
    00478
    00479     ByteOffset - Specifies the byte offset of the range to unlock.
    00480
    00481     Length - Specifies the length of the byte range to unlock.
    00482
    00483     Key - Specifies the key associated with the locked range.
    00484
    00485 Return Value:
    00486
    00487     The status returned is the final completion status of the operation.
    00488
    00489 --*/
    00490
    00491 {
    00492     PIRP irp;
    00493     NTSTATUS status;
    00494     PFILE_OBJECT fileObject;
    00495     PDEVICE_OBJECT deviceObject;
    00496     PFAST_IO_DISPATCH fastIoDispatch;
    00497     PKEVENT event;
    00498     KPROCESSOR_MODE requestorMode;
    00499     PIO_STACK_LOCATION irpSp;
    00500     IO_STATUS_BLOCK localIoStatus;
    00501     LARGE_INTEGER fileOffset;
    00502     LARGE_INTEGER length;
    00503     ACCESS_MASK grantedAccess;
    00504     OBJECT_HANDLE_INFORMATION handleInformation;
    00505     BOOLEAN synchronousIo;
    00506
    00507     PAGED_CODE();
    00508
    00509     //
    00510     // Get the previous mode;  i.e., the mode of the caller.
    00511     //
    00512
    00513     requestorMode = KeGetPreviousMode();
    00514
    00515     //
    00516     // Reference the file object so the target device can be found and the
    00517     // access rights mask can be used in the following checks for callers
    00518     // in user mode.  Note that if the handle does not refer to a file
    00519     // object, then it will fail.
    00520     //
    00521
    00522     status = ObReferenceObjectByHandle( FileHandle,
    00523                                         0L,
    00524                                         IoFileObjectType,
    00525                                         requestorMode,
    00526                                         (PVOID *) &fileObject,
    00527                                         &handleInformation);
    00528     if (!NT_SUCCESS( status )) {
    00529         return status;
    00530     }
    00531
    00532     grantedAccess = handleInformation.GrantedAccess;
    00533
    00534     //
    00535     // Check to see if the requestor mode was user.  If so, perform a bunch
    00536     // of extra checks.
    00537     //
    00538
    00539     if (requestorMode != KernelMode) {
    00540
    00541         //
    00542         // The caller's access mode is not kernel so probe each of the arguments
    00543         // and capture them as necessary.  If any failures occur, the condition
    00544         // handler will be invoked to handle them.  It will simply cleanup and
    00545         // return an access violation status code back to the system service
    00546         // dispatcher.
    00547         //
    00548
    00549         //
    00550         // Check to ensure that the caller has either READ or WRITE access
    00551         // to the file.  If not, cleanup and return an error.
    00552         //
    00553
    00554         if (!SeComputeGrantedAccesses( grantedAccess, FILE_READ_DATA | FILE_WRITE_DATA )) {
    00555             ObDereferenceObject( fileObject );
    00556             return STATUS_ACCESS_DENIED;
    00557         }
    00558
    00559         try {
    00560
    00561             //
    00562             // The IoStatusBlock parameter must be writeable by the caller.
    00563             //
    00564
    00565             ProbeForWriteIoStatus( IoStatusBlock );
    00566
    00567             //
    00568             // The ByteOffset parameter must be readable by the caller.  Probe
    00569             // and capture it.
    00570             //
    00571
    00572             ProbeForRead( ByteOffset,
    00573                           sizeof( LARGE_INTEGER ),
    00574                           sizeof( ULONG ) );
    00575             fileOffset = *ByteOffset;
    00576
    00577             //
    00578             // Likewise, the Length parameter must also be readable by the
    00579             // caller.  Probe and capture it as well.
    00580             //
    00581
    00582             ProbeForRead( Length,
    00583                           sizeof( LARGE_INTEGER ),
    00584                           sizeof( ULONG ) );
    00585             length = *Length;
    00586
    00587         } except(EXCEPTION_EXECUTE_HANDLER) {
    00588
    00589             //
    00590             // An exception was incurred while attempting to probe the
    00591             // caller's parameters.  Dereference the file object and return
    00592             // an appropriate error status code.
    00593             //
    00594
    00595             ObDereferenceObject( fileObject );
    00596             return GetExceptionCode();
    00597
    00598         }
    00599
    00600     } else {
    00601
    00602         //
    00603         // The caller's mode was kernel.  Get the ByteOffset and Length
    00604         // parameter 's to the expected locations.
    00605         //
    00606
    00607         fileOffset = *ByteOffset;
    00608         length = *Length;
    00609     }
    00610
    00611     //
    00612     // Get the address of the target device object.  If this file represents
    00613     // a device that was opened directly, then simply use the device or its
    00614     // attached device(s) directly.  Also get the fast I/O dispatch address.
    00615     //
    00616
    00617     if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
    00618         deviceObject = IoGetRelatedDeviceObject( fileObject );
    00619     } else {
    00620         deviceObject = IoGetAttachedDevice( fileObject->DeviceObject );
    00621     }
    00622     fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
    00623
    00624     //
    00625     // Turbo lock support.  If the fast Io Dispatch specifies a fast lock
    00626     // routine then we'll first try and calling it with the specified lock
    00627     // parameters.
    00628     //
    00629
    00630     if (fastIoDispatch && fastIoDispatch->FastIoUnlockSingle) {
    00631
    00632         IO_STATUS_BLOCK localIoStatus;
    00633
    00634         if (fastIoDispatch->FastIoUnlockSingle( fileObject,
    00635                                                 &fileOffset,
    00636                                                 &length,
    00637                                                 PsGetCurrentProcess(),
    00638                                                 Key,
    00639                                                 &localIoStatus,
    00640                                                 deviceObject )) {
    00641
    00642             //
    00643             // Carefully return the I/O status.
    00644             //
    00645
    00646             try {
    00647                 *IoStatusBlock = localIoStatus;
    00648             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00649                 localIoStatus.Status = GetExceptionCode();
    00650                 localIoStatus.Information = 0;
    00651             }
    00652
    00653             //
    00654             // Cleanup and return.
    00655             //
    00656
    00657             ObDereferenceObject( fileObject );
    00658             return localIoStatus.Status;
    00659         }
    00660     }
    00661
    00662     //
    00663     // Make a special check here to determine whether this is a synchronous
    00664     // I/O operation.  If it is, then wait here until the file is owned by
    00665     // the current thread.  If this is not a (serialized) synchronous I/O
    00666     // operation, then allocate and initialize the local event.
    00667     //
    00668
    00669     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    00670
    00671         BOOLEAN interrupted;
    00672
    00673         if (!IopAcquireFastLock( fileObject )) {
    00674             status = IopAcquireFileObjectLock( fileObject,
    00675                                                requestorMode,
    00676                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    00677                                                &interrupted );
    00678             if (interrupted) {
    00679                 ObDereferenceObject( fileObject );
    00680                 return status;
    00681             }
    00682         }
    00683         synchronousIo = TRUE;
    00684     } else {
    00685
    00686         //
    00687         // This is a synchronous API being invoked for a file that is opened
    00688         // for asynchronous I/O.  This means that this system service is
    00689         // to synchronize the completion of the operation before returning
    00690         // to the caller.  A local event is used to do this.
    00691         //
    00692
    00693         event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
    00694         if (event == NULL) {
    00695             ObDereferenceObject( fileObject );
    00696             return STATUS_INSUFFICIENT_RESOURCES;
    00697         }
    00698         KeInitializeEvent( event, SynchronizationEvent, FALSE );
    00699         synchronousIo = FALSE;
    00700     }
    00701
    00702     //
    00703     // Set the file object to the Not-Signaled state.
    00704     //
    00705
    00706     KeClearEvent( &fileObject->Event );
    00707
    00708     //
    00709     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    00710     // The allocation is performed with an exception handler in case the
    00711     // caller does not have enough quota to allocate the packet.
    00712     //
    00713
    00714     irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
    00715     if (!irp) {
    00716
    00717         //
    00718         // An IRP could not be allocated.  Cleanup and return an appropriate
    00719         // error status code.
    00720         //
    00721
    00722         if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
    00723             ExFreePool( event );
    00724         }
    00725
    00726         IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
    00727
    00728         return STATUS_INSUFFICIENT_RESOURCES;
    00729     }
    00730     irp->Tail.Overlay.OriginalFileObject = fileObject;
    00731     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00732     irp->RequestorMode = requestorMode;
    00733
    00734     //
    00735     // Fill in the service independent parameters in the IRP.
    00736     //
    00737
    00738     if (synchronousIo) {
    00739         irp->UserEvent = (PKEVENT) NULL;
    00740         irp->UserIosb = IoStatusBlock;
    00741     } else {
    00742         irp->UserEvent = event;
    00743         irp->UserIosb = &localIoStatus;
    00744         irp->Flags = IRP_SYNCHRONOUS_API;
    00745     }
    00746     irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
    00747
    00748     //
    00749     // Get a pointer to the stack location for the first driver.  This will
    00750     // be used to pass the original function codes and parameters.
    00751     //
    00752
    00753     irpSp = IoGetNextIrpStackLocation( irp );
    00754     irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
    00755     irpSp->MinorFunction = IRP_MN_UNLOCK_SINGLE;
    00756     irpSp->FileObject = fileObject;
    00757
    00758     try {
    00759         PLARGE_INTEGER lengthBuffer;
    00760
    00761         //
    00762         // Attempt to allocate an intermediary buffer to hold the length of
    00763         // this lock operation.  If it fails, either because there is no
    00764         // more quota, or because there are no more resources, then the
    00765         // exception handler will be invoked to cleanup and exit.
    00766         //
    00767
    00768         lengthBuffer = ExAllocatePoolWithQuota( NonPagedPool,
    00769                                                 sizeof( LARGE_INTEGER ) );
    00770
    00771         *lengthBuffer = length;
    00772         irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR) lengthBuffer;
    00773         irpSp->Parameters.LockControl.Length = lengthBuffer;
    00774     } except(EXCEPTION_EXECUTE_HANDLER) {
    00775
    00776         //
    00777         // An exception was incurred.  Simply clean everything up and
    00778         // return an appropriate error status code.
    00779         //
    00780
    00781         if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
    00782             ExFreePool( event );
    00783         }
    00784
    00785         IopExceptionCleanup( fileObject,
    00786                              irp,
    00787                              NULL,
    00788                              (PKEVENT) NULL );
    00789
    00790         return GetExceptionCode();
    00791     }
    00792
    00793     //
    00794     // Copy the caller's parameters to the service-specific portion of the
    00795     // IRP.
    00796     //
    00797
    00798     irpSp->Parameters.LockControl.Key = Key;
    00799     irpSp->Parameters.LockControl.ByteOffset = fileOffset;
    00800
    00801     //
    00802     // Queue the packet, call the driver, and synchronize appopriately with
    00803     // I/O completion.
    00804     //
    00805
    00806     status = IopSynchronousServiceTail( deviceObject,
    00807                                         irp,
    00808                                         fileObject,
    00809                                         FALSE,
    00810                                         requestorMode,
    00811                                         synchronousIo,
    00812                                         OtherTransfer );
    00813
    00814     //
    00815     // If the file for this operation was not opened for synchronous I/O, then
    00816     // synchronization of completion of the I/O operation has not yet occurred
    00817     // since the allocated event must be used for synchronous APIs on files
    00818     // opened for asynchronous I/O.  Synchronize the completion of the I/O
    00819     // operation now.
    00820     //
    00821
    00822     if (!synchronousIo) {
    00823
    00824         status = IopSynchronousApiServiceTail( status,
    00825                                                event,
    00826                                                irp,
    00827                                                requestorMode,
    00828                                                &localIoStatus,
    00829                                                IoStatusBlock );
    00830     }
    00831
    00832     return status;
    00833 }