windows-nt/Source/XPSP1/NT/base/fs/ntfs/lockctrl.c

908 lines
21 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 = NtfsInitializeTopLevelIrp( &TopLevelContext, FALSE, FALSE );
do {
try {
//
// We are either initiating this request or retrying it.
//
if (IrpContext == NULL) {
//
// Allocate and initialize the Irp.
//
NtfsInitializeIrpContext( Irp, CanFsdWait( Irp ), &IrpContext );
//
// Initialize the thread top level structure, if needed.
//
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);
ASSERT( IoGetTopLevelIrp() != (PIRP) &TopLevelContext );
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) ExAcquireResourceExclusiveLite( Fcb->Resource, TRUE );
ResourceAcquired = TRUE;
} else {
//(VOID) ExAcquireResourceSharedLite( 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) {
ExReleaseResourceLite( 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) ExAcquireResourceExclusiveLite( Fcb->Resource, TRUE );
ResourceAcquired = TRUE;
} else {
//(VOID) ExAcquireResourceSharedLite( 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) {
ExReleaseResourceLite( 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) ExAcquireResourceExclusiveLite( Fcb->Resource, TRUE );
} else {
(VOID) ExAcquireResourceSharedLite( 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
//
ExReleaseResourceLite( 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) ExAcquireResourceExclusiveLite( Fcb->Resource, TRUE );
} else {
(VOID) ExAcquireResourceSharedLite( 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
//
ExReleaseResourceLite( 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 );
ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
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, 0 );
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,
NtfsPrePostIrp );
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 );
//
// Only if this is not an abnormal termination and we did not post the irp
// do we delete the irp context
//
if (!OplockPostIrp) {
//
// Release the Fcb.
//
if (FcbAcquired) { NtfsReleaseFcb( IrpContext, Fcb ); }
if (!AbnormalTermination()) {
NtfsCompleteRequest( IrpContext, NULL, 0 );
}
}
DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> %08lx\n", Status) );
}
return Status;
}