mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
238 lines
8.6 KiB
C++
238 lines
8.6 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: Shutdown.cpp
|
|
*
|
|
* Module: UDF File System Driver (Kernel mode execution only)
|
|
*
|
|
* Description:
|
|
* Contains code to handle the "shutdown notification" dispatch entry point.
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include "udffs.h"
|
|
|
|
// define the file specific bug-check id
|
|
#define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFShutdown()
|
|
*
|
|
* Description:
|
|
* All disk-based FSDs can expect to receive this shutdown notification
|
|
* request whenever the system is about to be halted gracefully. If you
|
|
* design and implement a network redirector, you must register explicitly
|
|
* for shutdown notification by invoking the IoRegisterShutdownNotification()
|
|
* routine from your driver entry.
|
|
*
|
|
* Note that drivers that register to receive shutdown notification get
|
|
* invoked BEFORE disk-based FSDs are told about the shutdown notification.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: Irrelevant.
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
NTAPI
|
|
UDFShutdown(
|
|
PDEVICE_OBJECT DeviceObject, // the logical volume device object
|
|
PIRP Irp // I/O Request Packet
|
|
)
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PtrUDFIrpContext PtrIrpContext = NULL;
|
|
BOOLEAN AreWeTopLevel = FALSE;
|
|
|
|
UDFPrint(("UDFShutDown\n"));
|
|
// BrutePoint();
|
|
|
|
FsRtlEnterFileSystem();
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
|
|
// set the top level context
|
|
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
|
|
//ASSERT(!UDFIsFSDevObj(DeviceObject));
|
|
|
|
_SEH2_TRY {
|
|
|
|
// get an IRP context structure and issue the request
|
|
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
|
|
if(PtrIrpContext) {
|
|
RC = UDFCommonShutdown(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 UDFShutdown()
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFCommonShutdown()
|
|
*
|
|
* Description:
|
|
* The actual work is performed here. Basically, all we do here is
|
|
* internally invoke a flush on all mounted logical volumes. This, in
|
|
* tuen, will result in all open file streams being flushed to disk.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: Irrelevant
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
UDFCommonShutdown(
|
|
PtrUDFIrpContext PtrIrpContext,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PVCB Vcb;
|
|
PLIST_ENTRY Link;
|
|
PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
|
|
LARGE_INTEGER delay;
|
|
|
|
UDFPrint(("UDFCommonShutdown\n"));
|
|
|
|
_SEH2_TRY {
|
|
// First, get a pointer to the current I/O stack location
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp);
|
|
|
|
Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
|
|
if(!Buf)
|
|
try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
// (a) Block all new "mount volume" requests by acquiring an appropriate
|
|
// global resource/lock.
|
|
// (b) Go through your linked list of mounted logical volumes and for
|
|
// each such volume, do the following:
|
|
// (i) acquire the volume resource exclusively
|
|
// (ii) invoke UDFFlushLogicalVolume() (internally) to flush the
|
|
// open data streams belonging to the volume from the system
|
|
// cache
|
|
// (iii) Invoke the physical/virtual/logical target device object
|
|
// on which the volume is mounted and inform this device
|
|
// about the shutdown request (Use IoBuildSynchronouFsdRequest()
|
|
// to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you
|
|
// will then issue to the target device object).
|
|
// (iv) Wait for the completion of the shutdown processing by the target
|
|
// device object
|
|
// (v) Release the VCB resource we will have acquired in (i) above.
|
|
|
|
// Acquire GlobalDataResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
|
|
// Walk through all of the Vcb's attached to the global data.
|
|
Link = UDFGlobalData.VCBQueue.Flink;
|
|
|
|
while (Link != &(UDFGlobalData.VCBQueue)) {
|
|
// Get 'next' Vcb
|
|
Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
|
|
// Move to the next link now since the current Vcb may be deleted.
|
|
Link = Link->Flink;
|
|
ASSERT(Link != Link->Flink);
|
|
|
|
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {
|
|
|
|
#ifdef UDF_DELAYED_CLOSE
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
UDFPrint((" UDFCommonShutdown: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
#endif //UDF_DELAYED_CLOSE
|
|
|
|
// Note: UDFCloseAllDelayed() doesn't acquire DelayedCloseResource if
|
|
// GlobalDataResource is already acquired. Thus for now we should
|
|
// release GlobalDataResource and re-acquire it later.
|
|
UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
|
|
if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) {
|
|
UDFPrint((" UDFCommonShutdown: UDFCloseAllSystemDelayedInDir\n"));
|
|
RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
|
|
ASSERT(OS_SUCCESS(RC));
|
|
}
|
|
|
|
#ifdef UDF_DELAYED_CLOSE
|
|
UDFCloseAllDelayed(Vcb);
|
|
// UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
|
|
#endif //UDF_DELAYED_CLOSE
|
|
|
|
// re-acquire GlobalDataResource
|
|
UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
|
|
|
|
// disable Eject Waiter
|
|
UDFStopEjectWaiter(Vcb);
|
|
// Acquire Vcb resource
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
|
|
ASSERT(!Vcb->OverflowQueueCount);
|
|
|
|
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {
|
|
|
|
UDFDoDismountSequence(Vcb, Buf, FALSE);
|
|
if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
|
|
// let drive flush all data before reset
|
|
delay.QuadPart = -10000000; // 1 sec
|
|
KeDelayExecutionThread(KernelMode, FALSE, &delay);
|
|
}
|
|
Vcb->VCBFlags |= (UDF_VCB_FLAGS_SHUTDOWN |
|
|
UDF_VCB_FLAGS_VOLUME_READ_ONLY);
|
|
}
|
|
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
}
|
|
}
|
|
// Once we have processed all the mounted logical volumes, we can release
|
|
// all acquired global resources and leave (in peace :-)
|
|
UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
|
|
RC = STATUS_SUCCESS;
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if(Buf) MyFreePool__(Buf);
|
|
if(!_SEH2_AbnormalTermination()) {
|
|
Irp->IoStatus.Status = RC;
|
|
Irp->IoStatus.Information = 0;
|
|
// Free up the Irp Context
|
|
UDFReleaseIrpContext(PtrIrpContext);
|
|
// complete the IRP
|
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
|
}
|
|
|
|
} _SEH2_END; // end of "__finally" processing
|
|
|
|
return(RC);
|
|
} // end UDFCommonShutdown()
|