📄 fsctrl.c
字号:
&Ccb ) != UserFileOpen ) {
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//
// Make this a waitable Irpcontext so we don't fail to acquire
// the resources.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
//
// Switch on the function control code. We grab the Fcb exclusively
// for oplock requests, shared for oplock break acknowledgement.
//
switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
case FSCTL_REQUEST_OPLOCK_LEVEL_1 :
case FSCTL_REQUEST_OPLOCK_LEVEL_2 :
case FSCTL_REQUEST_BATCH_OPLOCK :
case FSCTL_REQUEST_FILTER_OPLOCK :
UdfAcquireFcbExclusive( IrpContext, Fcb, FALSE );
if (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
if (Fcb->FileLock != NULL) {
OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks( Fcb->FileLock );
}
} else {
OplockCount = Fcb->FcbCleanup;
}
break;
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
case FSCTL_OPLOCK_BREAK_NOTIFY:
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
UdfAcquireFcbShared( IrpContext, Fcb, FALSE );
break;
default:
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//
// Use a try finally to free the Fcb.
//
try {
//
// Verify the Fcb.
//
UdfVerifyFcbOperation( IrpContext, Fcb );
//
// Call the FsRtl routine to grant/acknowledge oplock.
//
Status = FsRtlOplockFsctrl( &Fcb->Oplock,
Irp,
OplockCount );
//
// Set the flag indicating if Fast I/O is possible
//
UdfLockFcb( IrpContext, Fcb );
Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb );
UdfUnlockFcb( IrpContext, Fcb );
//
// The oplock package will complete the Irp.
//
Irp = NULL;
} finally {
//
// Release all of our resources
//
UdfReleaseFcb( IrpContext, Fcb );
}
//
// Complete the request if there was no exception.
//
UdfCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routine
//
NTSTATUS
UdfLockVolumeInternal (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN PFILE_OBJECT FileObject OPTIONAL
)
/*++
Routine Description:
This routine performs the actual lock volume operation. It will be called
by anyone wishing to try to protect the volume for a long duration. PNP
operations are such a user.
The volume must be held exclusive by the caller.
Arguments:
Vcb - The volume being locked.
FileObject - File corresponding to the handle locking the volume. If this
is not specified, a system lock is assumed.
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY);
ULONG RemainingUserReferences = (FileObject? 1: 0);
PAGED_CODE();
ASSERT_EXCLUSIVE_VCB( Vcb );
//
// If the volume is already locked then complete with success if this file
// object has the volume locked, fail otherwise.
//
if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
if (FileObject && Vcb->VolumeLockFileObject == FileObject) {
FinalStatus = STATUS_SUCCESS;
}
} else if (Vcb->VcbCleanup == RemainingUserReferences) {
//
// The cleanup count for the volume only reflects the fileobject that
// will lock the volume. Otherwise, we must fail the request.
//
// Since the only cleanup is for the provided fileobject, we will try
// to get rid of all of the other user references. If there is only one
// remaining after the purge then we can allow the volume to be locked.
//
UdfPurgeVolume( IrpContext, Vcb, FALSE );
//
// Now back out of our synchronization and wait for the lazy writer
// to finish off any lazy closes that could have been outstanding.
//
// Since we purged, we know that the lazy writer will issue all
// possible lazy closes in the next tick - if we hadn't, an otherwise
// unopened file with a large amount of dirty data could have hung
// around for a while as the data trickled out to the disk.
//
// This is even more important now since we send notification to
// alert other folks that this style of check is about to happen so
// that they can close their handles. We don't want to enter a fast
// race with the lazy writer tearing down his references to the file.
//
UdfReleaseVcb( IrpContext, Vcb );
Status = CcWaitForCurrentLazyWriterActivity();
//
// This is intentional. If we were able to get the Vcb before, just
// wait for it and take advantage of knowing that it is OK to leave
// the flag up.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
if (!NT_SUCCESS( Status )) {
return Status;
}
UdfFspClose( Vcb );
if (Vcb->VcbUserReference == Vcb->VcbResidualUserReference + RemainingUserReferences) {
SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
Vcb->VolumeLockFileObject = FileObject;
FinalStatus = STATUS_SUCCESS;
}
}
return FinalStatus;
}
NTSTATUS
UdfUnlockVolumeInternal (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN PFILE_OBJECT FileObject OPTIONAL
)
/*++
Routine Description:
This routine performs the actual unlock volume operation.
The volume must be held exclusive by the caller.
Arguments:
Vcb - The volume being locked.
FileObject - File corresponding to the handle locking the volume. If this
is not specified, a system lock is assumed.
Return Value:
NTSTATUS - The return status for the operation
Attempting to remove a system lock that did not exist is OK.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (FlagOn(Vcb->VcbState, VCB_STATE_LOCKED) && FileObject == Vcb->VolumeLockFileObject) {
ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
Vcb->VolumeLockFileObject = NULL;
Status = STATUS_SUCCESS;
}
return Status;
}
//
// Local support routine
//
NTSTATUS
UdfLockVolume (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine performs the lock volume operation. It is responsible for
either completing of enqueuing the input Irp.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PFCB Fcb;
PCCB Ccb;
PAGED_CODE();
//
// Decode the file object, the only type of opens we accept are
// user volume opens.
//
if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen) {
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//
// Send our notification so that folks that like to hold handles on
// volumes can get out of the way.
//
FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK );
//
// Acquire exclusive access to the Vcb.
//
Vcb = Fcb->Vcb;
UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
try {
//
// Verify the Vcb.
//
UdfVerifyVcb( IrpContext, Vcb );
Status = UdfLockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
} finally {
//
// Release the Vcb.
//
UdfReleaseVcb( IrpContext, Vcb );
if (AbnormalTermination() || !NT_SUCCESS( Status )) {
FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_LOCK_FAILED );
}
}
//
// Complete the request if there haven't been any exceptions.
//
UdfCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routine
//
NTSTATUS
UdfUnlockVolume (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine performs the unlock volume operation. It is responsible for
either completing of enqueuing the input Irp.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PFCB Fcb;
PCCB Ccb;
PAGED_CODE();
//
// Decode the file object, the only type of opens we accept are
// user volume opens.
//
if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//
// Acquire exclusive access to the Vcb.
//
Vcb = Fcb->Vcb;
UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
//
// We won't check for a valid Vcb for this request. An unlock will always
// succeed on a locked volume.
//
Status = UdfUnlockVolumeInternal( IrpContext, Vcb, IrpSp->FileObject );
//
// Release all of our resources
//
UdfReleaseVcb( IrpContext, Vcb );
//
// Send notification that the volume is avaliable.
//
if (NT_SUCCESS( Status )) {
FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_UNLOCK );
}
//
// Complete the request if there haven't been any exceptions.
//
UdfCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// Local support routine
//
NTSTATUS
UdfDismountVolume (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine performs the dismount volume operation. It is responsible for
either completing of enqueuing the input Irp. We only dismount a volume which
has been locked. The intent here is that someone has locked the volume (they are the
only remaining handle). We set the volume state to invalid so that it will be torn
down quickly.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PVCB Vcb;
PFCB Fcb;
PCCB Ccb;
PAGED_CODE();
if (UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb ) != UserVolumeOpen ) {
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
return STATUS_INVALID_PARAMETER;
}
//
// Send notification.
//
FsRtlNotifyVolumeEvent( IrpSp->FileObject, FSRTL_VOLUME_DISMOUNT );
//
// Acquire exclusive access to the Vcb.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -