+++ /dev/null
-////////////////////////////////////////////////////////////////////
-// 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()