reactos/drivers/filesystems/udfs/lockctrl.cpp

566 lines
16 KiB
C++

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*************************************************************************
*
* File: LockCtrl.cpp.cpp
*
* Module: UDF File System Driver (Kernel mode execution only)
*
* Description:
* Contains code to handle the "byte-range locking" dispatch entry point.
*
*************************************************************************/
#include "udffs.h"
// define the file specific bug-check id
#define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
/*************************************************************************
*
* Function: UDFLockControl()
*
* Description:
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant.
*
*************************************************************************/
NTSTATUS
NTAPI
UDFLockControl(
IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
IN PIRP Irp) // I/O Request Packet
{
NTSTATUS RC = STATUS_SUCCESS;
PtrUDFIrpContext PtrIrpContext = NULL;
BOOLEAN AreWeTopLevel = FALSE;
UDFPrint(("UDFLockControl\n"));
// BrutePoint();
FsRtlEnterFileSystem();
ASSERT(DeviceObject);
ASSERT(Irp);
// set the top level context
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
// Call the common Lock Control routine, with blocking allowed if
// synchronous
_SEH2_TRY {
// get an IRP context structure and issue the request
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
if(PtrIrpContext) {
RC = UDFCommonLockControl(PtrIrpContext, Irp);
} else {
RC = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = RC;
Irp->IoStatus.Information = 0;
// complete the IRP
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
}
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
} _SEH2_END;
if (AreWeTopLevel) {
IoSetTopLevelIrp(NULL);
}
FsRtlExitFileSystem();
return(RC);
} // end UDFLockControl()
/*************************************************************************
*
* Function: UDFCommonLockControl()
*
* Description:
* This is the common routine for doing Lock control operations called
* by both the fsd and fsp threads
*
* Expected Interrupt Level (for execution) :
*
* IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant
*
*************************************************************************/
NTSTATUS
NTAPI
UDFCommonLockControl(
IN PtrUDFIrpContext PtrIrpContext,
IN PIRP Irp)
{
NTSTATUS RC = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpSp = NULL;
//IO_STATUS_BLOCK LocalIoStatus;
// BOOLEAN CompleteRequest = FALSE;
BOOLEAN PostRequest = FALSE;
BOOLEAN CanWait = FALSE;
PtrUDFNTRequiredFCB NtReqFcb = NULL;
BOOLEAN AcquiredFCB = FALSE;
PFILE_OBJECT FileObject = NULL;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
UDFPrint(("UDFCommonLockControl\n"));
_SEH2_TRY {
// First, get a pointer to the current I/O stack location.
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IrpSp);
FileObject = IrpSp->FileObject;
ASSERT(FileObject);
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Validate the sent-in FCB
if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
// CompleteRequest = TRUE;
try_return(RC = STATUS_INVALID_PARAMETER);
}
NtReqFcb = Fcb->NTRequiredFCB;
CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
// Acquire the FCB resource shared
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
PostRequest = TRUE;
try_return(RC = STATUS_PENDING);
}
AcquiredFCB = TRUE;
RC = FsRtlProcessFileLock(&(NtReqFcb->FileLock), Irp, NULL);
// CompleteRequest = TRUE;
try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the FCB resources if acquired.
if (AcquiredFCB) {
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
UDFReleaseResource(&(NtReqFcb->MainResource));
AcquiredFCB = FALSE;
}
if (PostRequest) {
// Perform appropriate post related processing here
RC = UDFPostRequest(PtrIrpContext, Irp);
} else
if(!_SEH2_AbnormalTermination()) {
// Simply free up the IrpContext since the IRP has been queued or
// Completed by FsRtlProcessFileLock
UDFReleaseIrpContext(PtrIrpContext);
}
} _SEH2_END; // end of "__finally" processing
return(RC);
} // end UDFCommonLockControl()
/*
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
NTAPI
UDFFastLock (
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
)
{
BOOLEAN Results = FALSE;
// BOOLEAN AcquiredFCB = FALSE;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
UDFPrint(("UDFFastLock\n"));
// Decode the type of file object we're being asked to process and make
// sure it is only a user file open.
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Validate the sent-in FCB
if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
IoStatus->Information = 0;
return TRUE;
}
// Acquire exclusive access to the Fcb this operation can always wait
FsRtlEnterFileSystem();
// BUGBUG: kenr
// (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE );
_SEH2_TRY {
// We check whether we can proceed
// based on the state of the file oplocks.
// Now call the FsRtl routine to do the actual processing of the
// Lock request
if ((Results = FsRtlFastLock( &(Fcb->NTRequiredFCB->FileLock),
FileObject,
FileOffset,
Length,
ProcessId,
Key,
FailImmediately,
ExclusiveLock,
IoStatus,
NULL,
FALSE ))) {
// Set the flag indicating if Fast I/O is possible
Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
}
//try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the Fcb, and return to our caller
// BUGBUG: kenr
// UDFReleaseResource( (Fcb)->Header.Resource );
FsRtlExitFileSystem();
} _SEH2_END;
return Results;
} // end UDFFastLock()
/*
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
NTAPI
UDFFastUnlockSingle(
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
)
{
BOOLEAN Results = FALSE;
// BOOLEAN AcquiredFCB = FALSE;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
UDFPrint(("UDFFastUnlockSingle\n"));
// Decode the type of file object we're being asked to process and make
// sure it is only a user file open.
IoStatus->Information = 0;
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Validate the sent-in FCB
if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
return TRUE;
}
// Acquire exclusive access to the Fcb this operation can always wait
FsRtlEnterFileSystem();
// BUGBUG: kenr
// (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE );
_SEH2_TRY {
// We check whether we can proceed
// based on the state of the file oplocks.
// Now call the FsRtl routine to do the actual processing of the
// Lock request
Results = TRUE;
IoStatus->Status = FsRtlFastUnlockSingle( &(Fcb->NTRequiredFCB->FileLock),
FileObject,
FileOffset,
Length,
ProcessId,
Key,
NULL,
FALSE );
// Set the flag indicating if Fast I/O is possible
Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
//try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the Fcb, and return to our caller
// BUGBUG: kenr
// UDFReleaseResource( (Fcb)->Header.Resource );
FsRtlExitFileSystem();
} _SEH2_END;
return Results;
} // end UDFFastUnlockSingle()
/*
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
NTAPI
UDFFastUnlockAll(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN Results = FALSE;
// BOOLEAN AcquiredFCB = FALSE;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
UDFPrint(("UDFFastUnlockAll\n"));
IoStatus->Information = 0;
// Decode the type of file object we're being asked to process and make
// sure it is only a user file open.
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Validate the sent-in FCB
if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
return TRUE;
}
// Acquire shared access to the Fcb this operation can always wait
FsRtlEnterFileSystem();
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE );
_SEH2_TRY {
// We check whether we can proceed
// based on the state of the file oplocks.
// Now call the FsRtl routine to do the actual processing of the
// Lock request
Results = TRUE;
IoStatus->Status = FsRtlFastUnlockAll( &(Fcb->NTRequiredFCB->FileLock),
FileObject,
ProcessId,
NULL );
// Set the flag indicating if Fast I/O is questionable
Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb );
//try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the Fcb, and return to our caller
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
FsRtlExitFileSystem();
} _SEH2_END;
return Results;
} // end UDFFastUnlockAll()
/*
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
NTAPI
UDFFastUnlockAllByKey(
IN PFILE_OBJECT FileObject,
PEPROCESS ProcessId,
ULONG Key,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
BOOLEAN Results = FALSE;
// BOOLEAN AcquiredFCB = FALSE;
PtrUDFFCB Fcb = NULL;
PtrUDFCCB Ccb = NULL;
UDFPrint(("UDFFastUnlockAllByKey\n"));
IoStatus->Information = 0;
// Decode the type of file object we're being asked to process and make
// sure it is only a user file open.
// Get the FCB and CCB pointers.
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
ASSERT(Ccb);
Fcb = Ccb->Fcb;
ASSERT(Fcb);
// Validate the sent-in FCB
if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
return TRUE;
}
// Acquire shared access to the Fcb this operation can always wait
FsRtlEnterFileSystem();
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE );
_SEH2_TRY {
// We check whether we can proceed
// based on the state of the file oplocks.
// Now call the FsRtl routine to do the actual processing of the
// Lock request
Results = TRUE;
IoStatus->Status = FsRtlFastUnlockAllByKey( &(Fcb->NTRequiredFCB->FileLock),
FileObject,
ProcessId,
Key,
NULL );
// Set the flag indicating if Fast I/O is possible
Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb );
//try_exit: NOTHING;
} _SEH2_FINALLY {
// Release the Fcb, and return to our caller
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
FsRtlExitFileSystem();
} _SEH2_END;
return Results;
} // end UDFFastUnlockAllByKey()