425 lines
11 KiB
C
425 lines
11 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
oplock.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the oplock code for SPUD.
|
||
|
||
Author:
|
||
|
||
John Ballard (jballard) 13-Dec-1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "spudp.h"
|
||
|
||
#ifdef PAGE_DRIVER
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, SPUDCancel)
|
||
#endif
|
||
#endif
|
||
|
||
#if DBG
|
||
#define ENABLE_OPLOCK_COUNTERS 1
|
||
#define OPLOCKDBG 0
|
||
#else
|
||
#define ENABLE_OPLOCK_COUNTERS 0
|
||
#define OPLOCKDBG 0
|
||
#endif
|
||
|
||
#if ENABLE_OPLOCK_COUNTERS
|
||
typedef struct _OPLOCK_COUNTERS {
|
||
LONG OplockIrpInitiated;
|
||
LONG OplockIrpCompleted;
|
||
} OPLOCK_COUNTERS;
|
||
|
||
OPLOCK_COUNTERS SpudOplockCounters;
|
||
|
||
#define UPDATE_OPLOCK_IRP_INITIATED() \
|
||
InterlockedIncrement( &SpudOplockCounters.OplockIrpInitiated )
|
||
|
||
#define UPDATE_OPLOCK_IRP_COMPLETED() \
|
||
InterlockedIncrement( &SpudOplockCounters.OplockIrpCompleted )
|
||
#else // !ENABLE_OPLOCK_COUNTERS
|
||
#define UPDATE_OPLOCK_IRP_INITIATED()
|
||
#define UPDATE_OPLOCK_IRP_COMPLETED()
|
||
#endif // ENABLE_OPLOCK_COUNTERS
|
||
|
||
NTSTATUS
|
||
SpudOplockCompletion(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp,
|
||
PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
SPUDCreateFile(
|
||
OUT PHANDLE FileHandle,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||
IN ULONG FileAttributes,
|
||
IN ULONG ShareAccess,
|
||
IN ULONG CreateOptions,
|
||
IN SECURITY_INFORMATION SecurityInformation,
|
||
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||
IN ULONG Length,
|
||
OUT PULONG LengthNeeded,
|
||
PVOID pOplock
|
||
)
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
KPROCESSOR_MODE requestorMode;
|
||
PFILE_OBJECT fileObject;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PULONG majorFunction;
|
||
PDEVICE_OBJECT deviceObject;
|
||
CLONG method;
|
||
|
||
#ifdef PAGE_DRIVER
|
||
PAGED_CODE();
|
||
#endif
|
||
|
||
if (!DriverInitialized) {
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
requestorMode = KeGetPreviousMode();
|
||
|
||
if (requestorMode != KernelMode) {
|
||
try {
|
||
|
||
//
|
||
// Make sure we can write to Args
|
||
//
|
||
|
||
//
|
||
// The FileHandle parameter must be writeable by the caller.
|
||
// Probe it for a write operation.
|
||
//
|
||
|
||
ProbeAndWriteHandle( FileHandle, 0L );
|
||
|
||
//
|
||
// The IoStatusBlock parameter must be writeable by the caller.
|
||
//
|
||
|
||
ProbeForWriteIoStatus( IoStatusBlock );
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// An exception has occurred while trying to probe one
|
||
// of the callers parameters. Simply return the error
|
||
// status code.
|
||
//
|
||
|
||
return GetExceptionCode();
|
||
|
||
}
|
||
}
|
||
|
||
Status = IoCreateFile( FileHandle,
|
||
GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
|
||
ObjectAttributes,
|
||
IoStatusBlock,
|
||
NULL,
|
||
FileAttributes,
|
||
ShareAccess,
|
||
FILE_OPEN,
|
||
CreateOptions,
|
||
NULL,
|
||
0,
|
||
CreateFileTypeNone,
|
||
(PVOID)NULL,
|
||
0 );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// If Length == 0 then no Security support is requested.
|
||
//
|
||
|
||
if (Length > 0) {
|
||
|
||
if (requestorMode != KernelMode) {
|
||
try {
|
||
|
||
//
|
||
// Make sure we can write to Args
|
||
//
|
||
|
||
ProbeForWriteUlong( LengthNeeded );
|
||
|
||
ProbeForWrite( SecurityDescriptor, Length, sizeof(ULONG) );
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
//
|
||
// An exception has occurred while trying to probe one
|
||
// of the callers parameters. Simply return the error
|
||
// status code.
|
||
//
|
||
|
||
return GetExceptionCode();
|
||
|
||
}
|
||
}
|
||
|
||
Status = NtQuerySecurityObject( *FileHandle,
|
||
SecurityInformation,
|
||
SecurityDescriptor,
|
||
Length,
|
||
LengthNeeded );
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
if (Status == STATUS_NOT_SUPPORTED) {
|
||
*LengthNeeded = 0;
|
||
Status = STATUS_SUCCESS;
|
||
} else {
|
||
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
Status = STATUS_SUCCESS;
|
||
} else {
|
||
return Status;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If CompletionRoutine == NULL then no OPLOCK support is requested
|
||
//
|
||
|
||
if (pOplock == NULL) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Reference the file handle
|
||
//
|
||
|
||
Status = ObReferenceObjectByHandle( *FileHandle,
|
||
0L,
|
||
NULL,
|
||
requestorMode,
|
||
(PVOID *) &fileObject,
|
||
NULL );
|
||
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
#if OPLOCKDBG
|
||
DbgPrint("SPUDCreateFile - FileName = >%ws<\n", fileObject->FileName.Buffer );
|
||
#endif
|
||
|
||
deviceObject = IoGetRelatedDeviceObject( fileObject );
|
||
|
||
//
|
||
// Allocate and initialize the irp
|
||
//
|
||
|
||
irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
|
||
|
||
if (!irp) {
|
||
ObDereferenceObject( fileObject );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
irp->Tail.Overlay.OriginalFileObject = fileObject;
|
||
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||
irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)pOplock;
|
||
irp->RequestorMode = requestorMode;
|
||
irp->IoStatus.Status = 0;
|
||
irp->IoStatus.Information = 0;
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
IoSetCompletionRoutine( irp,
|
||
SpudOplockCompletion,
|
||
(PVOID)0x0a0a0a0a, // SpudOplockContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
irpSp->MajorFunction = (UCHAR)IRP_MJ_FILE_SYSTEM_CONTROL;
|
||
irpSp->MinorFunction = 0;
|
||
irpSp->FileObject = fileObject;
|
||
irpSp->DeviceObject = deviceObject;
|
||
|
||
irpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
|
||
irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
|
||
irpSp->Parameters.FileSystemControl.FsControlCode = FSCTL_REQUEST_BATCH_OPLOCK;
|
||
|
||
UPDATE_OPLOCK_IRP_INITIATED();
|
||
IRP_TRACE( irp, INITIATE, pOplock );
|
||
IoCallDriver( deviceObject, irp );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} // SPUDCreateFile
|
||
|
||
|
||
NTSTATUS
|
||
SpudOplockCompletion(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp,
|
||
PVOID Context
|
||
)
|
||
{
|
||
PFILE_OBJECT fileObject;
|
||
PVOID pOplock;
|
||
|
||
UPDATE_OPLOCK_IRP_COMPLETED();
|
||
|
||
fileObject = Irp->Tail.Overlay.OriginalFileObject;
|
||
pOplock = (PVOID)Irp->Tail.Overlay.AuxiliaryBuffer;
|
||
|
||
if( Irp->IoStatus.Status == STATUS_SUCCESS ) {
|
||
IRP_TRACE( Irp, SUCCESS, pOplock );
|
||
ASSERT( Irp->IoStatus.Information == FILE_OPLOCK_BROKEN_TO_LEVEL_2 ||
|
||
Irp->IoStatus.Information == FILE_OPLOCK_BROKEN_TO_NONE );
|
||
} else {
|
||
IRP_TRACE( Irp, FAILURE, pOplock );
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
ASSERT( Irp->IoStatus.Information == 0 );
|
||
Irp->IoStatus.Information = 1; // OPLOCK_BREAK_NO_OPLOCK from atq.h
|
||
}
|
||
|
||
#if OPLOCKDBG
|
||
DbgPrint("SpudpOplockComplete - FileName = >%ws<\n", fileObject->FileName.Buffer );
|
||
#endif
|
||
|
||
ObDereferenceObject( fileObject );
|
||
|
||
Irp->Tail.CompletionKey = (ULONG)pOplock;
|
||
Irp->Tail.Overlay.CurrentStackLocation = NULL;
|
||
Irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
|
||
|
||
KeInsertQueue( (PKQUEUE) ATQOplockCompletionPort,
|
||
&Irp->Tail.Overlay.ListEntry );
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
} // SpudOplockCompletion
|
||
|
||
|
||
NTSTATUS
|
||
SPUDOplockAcknowledge(
|
||
IN HANDLE FileHandle,
|
||
IN PVOID pOplock
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
KPROCESSOR_MODE requestorMode;
|
||
PFILE_OBJECT fileObject;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PULONG majorFunction;
|
||
PDEVICE_OBJECT deviceObject;
|
||
CLONG method;
|
||
|
||
#ifdef PAGE_DRIVER
|
||
PAGED_CODE();
|
||
#endif
|
||
|
||
if (!DriverInitialized) {
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
requestorMode = KeGetPreviousMode();
|
||
|
||
//
|
||
// Reference the file handle
|
||
//
|
||
|
||
Status = ObReferenceObjectByHandle( FileHandle,
|
||
0L,
|
||
NULL,
|
||
requestorMode,
|
||
(PVOID *) &fileObject,
|
||
NULL );
|
||
|
||
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
#if OPLOCKDBG
|
||
DbgPrint("SPUDOplockAcknowledge - FileName = >%ws<\n", fileObject->FileName.Buffer );
|
||
#endif
|
||
|
||
deviceObject = IoGetRelatedDeviceObject( fileObject );
|
||
|
||
//
|
||
// Allocate and initialize the irp
|
||
//
|
||
|
||
irp = IoAllocateIrp( deviceObject->StackSize, FALSE );
|
||
|
||
if (!irp) {
|
||
ObDereferenceObject( fileObject );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
irp->Tail.Overlay.OriginalFileObject = fileObject;
|
||
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||
irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)pOplock;
|
||
irp->RequestorMode = requestorMode;
|
||
irp->IoStatus.Status = 0;
|
||
irp->IoStatus.Information = 0;
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
IoSetCompletionRoutine( irp,
|
||
SpudOplockCompletion,
|
||
(PVOID)0x0a0a0a0a, // SpudOplockContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
irpSp->MajorFunction = (UCHAR)IRP_MJ_FILE_SYSTEM_CONTROL;
|
||
irpSp->MinorFunction = 0;
|
||
irpSp->FileObject = fileObject;
|
||
irpSp->DeviceObject = deviceObject;
|
||
|
||
irpSp->Parameters.FileSystemControl.OutputBufferLength = 0;
|
||
irpSp->Parameters.FileSystemControl.InputBufferLength = 0;
|
||
irpSp->Parameters.FileSystemControl.FsControlCode = FSCTL_OPLOCK_BREAK_ACKNOWLEDGE;
|
||
|
||
Status = IoCallDriver( deviceObject, irp );
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if (Status == STATUS_INVALID_PARAMETER) {
|
||
Status = STATUS_SUCCESS;
|
||
ObDereferenceObject( fileObject );
|
||
}
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
ObDereferenceObject( fileObject );
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // SPUDOplockAcknowledge
|
||
|