diff options
Diffstat (limited to 'private/ntos/cntfs/lockctrl.c')
-rw-r--r-- | private/ntos/cntfs/lockctrl.c | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/private/ntos/cntfs/lockctrl.c b/private/ntos/cntfs/lockctrl.c new file mode 100644 index 000000000..b814895c1 --- /dev/null +++ b/private/ntos/cntfs/lockctrl.c @@ -0,0 +1,899 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + LockCtrl.c + +Abstract: + + This module implements the File Lock Control routine for Ntfs called by the + dispatch driver. + +Author: + + Gary Kimura [GaryKi] 28-May-1991 + +Revision History: + +--*/ + +#include "NtfsProc.h" + +// +// The local debug trace level +// + +#define Dbg (DEBUG_TRACE_LOCKCTRL) + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NtfsCommonLockControl) +#pragma alloc_text(PAGE, NtfsFastLock) +#pragma alloc_text(PAGE, NtfsFastUnlockAll) +#pragma alloc_text(PAGE, NtfsFastUnlockAllByKey) +#pragma alloc_text(PAGE, NtfsFastUnlockSingle) +#pragma alloc_text(PAGE, NtfsFsdLockControl) +#endif + + +NTSTATUS +NtfsFsdLockControl ( + IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This routine implements the FSD part of Lock Control. + +Arguments: + + VolumeDeviceObject - Supplies the volume device object where the + file exists + + Irp - Supplies the Irp being processed + +Return Value: + + NTSTATUS - The FSD status for the IRP + +--*/ + +{ + TOP_LEVEL_CONTEXT TopLevelContext; + PTOP_LEVEL_CONTEXT ThreadTopLevelContext; + + NTSTATUS Status = STATUS_SUCCESS; + PIRP_CONTEXT IrpContext = NULL; + + ASSERT_IRP( Irp ); + + UNREFERENCED_PARAMETER( VolumeDeviceObject ); + + PAGED_CODE(); + + DebugTrace( +1, Dbg, ("NtfsFsdLockControl\n") ); + + // + // Call the common Lock Control routine + // + + FsRtlEnterFileSystem(); + + ThreadTopLevelContext = NtfsSetTopLevelIrp( &TopLevelContext, FALSE, FALSE ); + + do { + + try { + + // + // We are either initiating this request or retrying it. + // + + if (IrpContext == NULL) { + + IrpContext = NtfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); + NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext ); + + } else if (Status == STATUS_LOG_FILE_FULL) { + + NtfsCheckpointForLogFileFull( IrpContext ); + } + + Status = NtfsCommonLockControl( IrpContext, Irp ); + break; + + } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) { + + // + // We had some trouble trying to perform the requested + // operation, so we'll abort the I/O request with + // the error status that we get back from the + // execption code + // + + Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() ); + } + + } while (Status == STATUS_CANT_WAIT || + Status == STATUS_LOG_FILE_FULL); + + if (ThreadTopLevelContext == &TopLevelContext) { + NtfsRestoreTopLevelIrp( ThreadTopLevelContext ); + } + + FsRtlExitFileSystem(); + + // + // And return to our caller + // + + DebugTrace( -1, Dbg, ("NtfsFsdLockControl -> %08lx\n", Status) ); + + return Status; +} + + +BOOLEAN +NtfsFastLock ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + BOOLEAN FailImmediately, + BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This is a call back routine for doing the fast lock call. + +Arguments: + + FileObject - Supplies the file object used in this operation + + FileOffset - Supplies the file offset used in this operation + + Length - Supplies the length used in this operation + + ProcessId - Supplies the process ID used in this operation + + Key - Supplies the key used in this operation + + FailImmediately - Indicates if the request should fail immediately + if the lock cannot be granted. + + ExclusiveLock - Indicates if this is a request for an exclusive or + shared lock + + IoStatus - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. + +--*/ + +{ + BOOLEAN Results; + PSCB Scb; + PFCB Fcb; + BOOLEAN ResourceAcquired = FALSE; + + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + DebugTrace( +1, Dbg, ("NtfsFastLock\n") ); + + // + // Decode the type of file object we're being asked to process and + // make sure that is is only a user file open. + // + + if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; + + DebugTrace( -1, Dbg, ("NtfsFastLock -> TRUE (STATUS_INVALID_PARAMETER)\n") ); + return TRUE; + } + + Fcb = Scb->Fcb; + + // + // Acquire shared access to the Fcb this operation can always wait + // + + FsRtlEnterFileSystem(); + + if (Scb->ScbType.Data.FileLock == NULL) { + + (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); + ResourceAcquired = TRUE; + + } else { + + //(VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); + } + + try { + + // + // We check whether we can proceed + // based on the state of the file oplocks. + // + + if ((Scb->ScbType.Data.Oplock != NULL) && + !FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { + + try_return( Results = FALSE ); + } + + // + // If we don't have a file lock, then get one now. + // + + if (Scb->ScbType.Data.FileLock == NULL + && !NtfsCreateFileLock( Scb, FALSE )) { + + try_return( Results = FALSE ); + } + + // + // Now call the FsRtl routine to do the actual processing of the + // Lock request + // + + if (Results = FsRtlFastLock( Scb->ScbType.Data.FileLock, + FileObject, + FileOffset, + Length, + ProcessId, + Key, + FailImmediately, + ExclusiveLock, + IoStatus, + NULL, + FALSE )) { + + // + // Set the flag indicating if Fast I/O is questionable. We + // only change this flag is the current state is possible. + // Retest again after synchronizing on the header. + // + + if (Scb->Header.IsFastIoPossible == FastIoIsPossible) { + + NtfsAcquireFsrtlHeader( Scb ); + Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); + NtfsReleaseFsrtlHeader( Scb ); + } + } + + try_exit: NOTHING; + } finally { + + DebugUnwind( NtfsFastLock ); + + // + // Release the Fcb, and return to our caller + // + + if (ResourceAcquired) { + ExReleaseResource( Fcb->Resource ); + } + + FsRtlExitFileSystem(); + + DebugTrace( -1, Dbg, ("NtfsFastLock -> %08lx\n", Results) ); + } + + return Results; +} + + +BOOLEAN +NtfsFastUnlockSingle ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This is a call back routine for doing the fast unlock single call. + +Arguments: + + FileObject - Supplies the file object used in this operation + + FileOffset - Supplies the file offset used in this operation + + Length - Supplies the length used in this operation + + ProcessId - Supplies the process ID used in this operation + + Key - Supplies the key used in this operation + + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. + +--*/ + +{ + BOOLEAN Results; + PFCB Fcb; + PSCB Scb; + BOOLEAN ResourceAcquired = FALSE; + + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + DebugTrace( +1, Dbg, ("NtfsFastUnlockSingle\n") ); + + IoStatus->Information = 0; + + // + // Decode the type of file object we're being asked to process and + // make sure that is is only a user file open. + // + + if ((Scb = NtfsFastDecodeUserFileOpen( FileObject )) == NULL) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + + DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> TRUE (STATUS_INVALID_PARAMETER)\n") ); + return TRUE; + } + + Fcb = Scb->Fcb; + + // + // Acquire exclusive access to the Fcb this operation can always wait + // + + FsRtlEnterFileSystem(); + + if (Scb->ScbType.Data.FileLock == NULL) { + + (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); + ResourceAcquired = TRUE; + + } else { + + //(VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); + } + + try { + + // + // We check whether we can proceed based on the state of the file oplocks. + // + + if ((Scb->ScbType.Data.Oplock != NULL) && + !FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { + + try_return( Results = FALSE ); + } + + // + // If we don't have a file lock, then get one now. + // + + if (Scb->ScbType.Data.FileLock == NULL + && !NtfsCreateFileLock( Scb, FALSE )) { + + try_return( Results = FALSE ); + } + + // + // Now call the FsRtl routine to do the actual processing of the + // Lock request. The call will always succeed. + // + + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockSingle( Scb->ScbType.Data.FileLock, + FileObject, + FileOffset, + Length, + ProcessId, + Key, + NULL, + FALSE ); + + // + // Set the flag indicating if Fast I/O is possible. We are + // only concerned if there are no longer any filelocks on this + // file. + // + + if (!FsRtlAreThereCurrentFileLocks( Scb->ScbType.Data.FileLock ) && + (Scb->Header.IsFastIoPossible != FastIoIsPossible)) { + + NtfsAcquireFsrtlHeader( Scb ); + Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); + NtfsReleaseFsrtlHeader( Scb ); + } + + try_exit: NOTHING; + } finally { + + DebugUnwind( NtfsFastUnlockSingle ); + + // + // Release the Fcb, and return to our caller + // + + if (ResourceAcquired) { + ExReleaseResource( Fcb->Resource ); + } + + FsRtlExitFileSystem(); + + DebugTrace( -1, Dbg, ("NtfsFastUnlockSingle -> %08lx\n", Results) ); + } + + return Results; +} + + +BOOLEAN +NtfsFastUnlockAll ( + IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This is a call back routine for doing the fast unlock all call. + +Arguments: + + FileObject - Supplies the file object used in this operation + + ProcessId - Supplies the process ID used in this operation + + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. + +--*/ + +{ + BOOLEAN Results; + IRP_CONTEXT IrpContext; + TYPE_OF_OPEN TypeOfOpen; + PVCB Vcb; + PFCB Fcb; + PSCB Scb; + PCCB Ccb; + + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + DebugTrace( +1, Dbg, ("NtfsFastUnlockAll\n") ); + + IoStatus->Information = 0; + + // + // Decode the type of file object we're being asked to process and + // make sure that is is only a user file open. + // + + TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE ); + + if (TypeOfOpen != UserFileOpen) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; + + DebugTrace( -1, Dbg, ("NtfsFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n") ); + return TRUE; + } + + // + // Acquire exclusive access to the Fcb this operation can always wait + // + + FsRtlEnterFileSystem(); + + if (Scb->ScbType.Data.FileLock == NULL) { + + (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); + + } else { + + (VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); + } + + try { + + // + // We check whether we can proceed based on the state of the file oplocks. + // + + if (!FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { + + try_return( Results = FALSE ); + } + + // + // If we don't have a file lock, then get one now. + // + + if (Scb->ScbType.Data.FileLock == NULL + && !NtfsCreateFileLock( Scb, FALSE )) { + + try_return( Results = FALSE ); + } + + // + // Now call the FsRtl routine to do the actual processing of the + // Lock request. The call will always succeed. + // + + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockAll( Scb->ScbType.Data.FileLock, + FileObject, + ProcessId, + NULL ); + + // + // Set the flag indicating if Fast I/O is possible + // + + NtfsAcquireFsrtlHeader( Scb ); + Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); + NtfsReleaseFsrtlHeader( Scb ); + + try_exit: NOTHING; + } finally { + + DebugUnwind( NtfsFastUnlockAll ); + + // + // Release the Fcb, and return to our caller + // + + ExReleaseResource( Fcb->Resource ); + + FsRtlExitFileSystem(); + + DebugTrace( -1, Dbg, ("NtfsFastUnlockAll -> %08lx\n", Results) ); + } + + return Results; +} + + +BOOLEAN +NtfsFastUnlockAllByKey ( + IN PFILE_OBJECT FileObject, + PVOID ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject + ) + +/*++ + +Routine Description: + + This is a call back routine for doing the fast unlock all by key call. + +Arguments: + + FileObject - Supplies the file object used in this operation + + ProcessId - Supplies the process ID used in this operation + + Key - Supplies the key used in this operation + + Status - Receives the Status if this operation is successful + +Return Value: + + BOOLEAN - TRUE if this operation completed and FALSE if caller + needs to take the long route. + +--*/ + +{ + BOOLEAN Results; + IRP_CONTEXT IrpContext; + TYPE_OF_OPEN TypeOfOpen; + PVCB Vcb; + PFCB Fcb; + PSCB Scb; + PCCB Ccb; + + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + DebugTrace( +1, Dbg, ("NtfsFastUnlockAllByKey\n") ); + + IoStatus->Information = 0; + + // + // Decode the type of file object we're being asked to process and + // make sure that is is only a user file open. + // + + TypeOfOpen = NtfsDecodeFileObject( &IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, FALSE ); + + if (TypeOfOpen != UserFileOpen) { + + IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; + + DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> TRUE (STATUS_INVALID_PARAMETER)\n") ); + return TRUE; + } + + // + // Acquire exclusive access to the Fcb this operation can always wait + // + + FsRtlEnterFileSystem(); + + if (Scb->ScbType.Data.FileLock == NULL) { + + (VOID) ExAcquireResourceExclusive( Fcb->Resource, TRUE ); + + } else { + + (VOID) ExAcquireResourceShared( Fcb->Resource, TRUE ); + } + + try { + + // + // We check whether we can proceed based on the state of the file oplocks. + // + + if (!FsRtlOplockIsFastIoPossible( &Scb->ScbType.Data.Oplock )) { + + try_return( Results = FALSE ); + } + + // + // If we don't have a file lock, then get one now. + // + + if (Scb->ScbType.Data.FileLock == NULL + && !NtfsCreateFileLock( Scb, FALSE )) { + + try_return( Results = FALSE ); + } + + // + // Now call the FsRtl routine to do the actual processing of the + // Lock request. The call will always succeed. + // + + Results = TRUE; + IoStatus->Status = FsRtlFastUnlockAllByKey( Scb->ScbType.Data.FileLock, + FileObject, + ProcessId, + Key, + NULL ); + + // + // Set the flag indicating if Fast I/O is possible + // + + NtfsAcquireFsrtlHeader( Scb ); + Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); + NtfsReleaseFsrtlHeader( Scb ); + + try_exit: NOTHING; + } finally { + + DebugUnwind( NtfsFastUnlockAllByKey ); + + // + // Release the Fcb, and return to our caller + // + + ExReleaseResource( Fcb->Resource ); + + FsRtlExitFileSystem(); + + DebugTrace( -1, Dbg, ("NtfsFastUnlockAllByKey -> %08lx\n", Results) ); + } + + return Results; +} + + +NTSTATUS +NtfsCommonLockControl ( + IN PIRP_CONTEXT IrpContext, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + This is the common routine for Lock Control called by both the fsd and fsp + threads. + +Arguments: + + Irp - Supplies the Irp to process + +Return Value: + + NTSTATUS - The return status for the operation + +--*/ + +{ + NTSTATUS Status; + PIO_STACK_LOCATION IrpSp; + PFILE_OBJECT FileObject; + + TYPE_OF_OPEN TypeOfOpen; + PVCB Vcb; + PFCB Fcb; + PSCB Scb; + PCCB Ccb; + BOOLEAN FcbAcquired = FALSE; + + BOOLEAN OplockPostIrp; + + ASSERT_IRP_CONTEXT( IrpContext ); + ASSERT_IRP( Irp ); + + PAGED_CODE(); + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + + DebugTrace( +1, Dbg, ("NtfsCommonLockControl\n") ); + DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); + DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); + DebugTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) ); + + // + // Extract and decode the type of file object we're being asked to process + // + + FileObject = IrpSp->FileObject; + TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE ); + + // + // If the file is not a user file open then we reject the request + // as an invalid parameter + // + + if (TypeOfOpen != UserFileOpen) { + + NtfsCompleteRequest( &IrpContext, &Irp, STATUS_INVALID_PARAMETER ); + + DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> STATUS_INVALID_PARAMETER\n") ); + return STATUS_INVALID_PARAMETER; + } + + // + // Acquire exclusive access to the Fcb + // + + if (Scb->ScbType.Data.FileLock == NULL) { + + NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, FALSE, FALSE ); + FcbAcquired = TRUE; + + } else { + + //NtfsAcquireSharedFcb( IrpContext, Fcb, Scb ); + } + + OplockPostIrp = FALSE; + + try { + + // + // We check whether we can proceed based on the state of the file oplocks. + // This call might post the irp for us. + // + + Status = FsRtlCheckOplock( &Scb->ScbType.Data.Oplock, + Irp, + IrpContext, + NtfsOplockComplete, + NULL ); + + if (Status != STATUS_SUCCESS) { + + OplockPostIrp = TRUE; + try_return( NOTHING ); + } + + // + // If we don't have a file lock, then get one now. + // + + if (Scb->ScbType.Data.FileLock == NULL) { + + NtfsCreateFileLock( Scb, TRUE ); + } + + // + // Now call the FsRtl routine to do the actual processing of the + // Lock request + // + + Status = FsRtlProcessFileLock( Scb->ScbType.Data.FileLock, Irp, NULL ); + + // + // Set the flag indicating if Fast I/O is possible + // + + NtfsAcquireFsrtlHeader( Scb ); + Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); + NtfsReleaseFsrtlHeader( Scb ); + + try_exit: NOTHING; + } finally { + + DebugUnwind( NtfsCommonLockControl ); + + // + // Release the Fcb, and return to our caller + // + + if (FcbAcquired) { + NtfsReleaseFcb( IrpContext, Fcb ); + } + + // + // Only if this is not an abnormal termination and we did not post the irp + // do we delete the irp context + // + + if (!AbnormalTermination() && !OplockPostIrp) { + + NtfsCompleteRequest( &IrpContext, NULL, 0 ); + } + + DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> %08lx\n", Status) ); + } + + return Status; +} |