Reactos
at master 238 lines 8.8 kB view raw
1//////////////////////////////////////////////////////////////////// 2// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3// All rights reserved 4// This file was released under the GPLv2 on June 2015. 5//////////////////////////////////////////////////////////////////// 6/************************************************************************* 7* 8* File: Shutdown.cpp 9* 10* Module: UDF File System Driver (Kernel mode execution only) 11* 12* Description: 13* Contains code to handle the "shutdown notification" dispatch entry point. 14* 15*************************************************************************/ 16 17#include "udffs.h" 18 19// define the file specific bug-check id 20#define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN 21 22 23 24/************************************************************************* 25* 26* Function: UDFShutdown() 27* 28* Description: 29* All disk-based FSDs can expect to receive this shutdown notification 30* request whenever the system is about to be halted gracefully. If you 31* design and implement a network redirector, you must register explicitly 32* for shutdown notification by invoking the IoRegisterShutdownNotification() 33* routine from your driver entry. 34* 35* Note that drivers that register to receive shutdown notification get 36* invoked BEFORE disk-based FSDs are told about the shutdown notification. 37* 38* Expected Interrupt Level (for execution) : 39* 40* IRQL_PASSIVE_LEVEL 41* 42* Return Value: Irrelevant. 43* 44*************************************************************************/ 45NTSTATUS 46NTAPI 47UDFShutdown( 48 PDEVICE_OBJECT DeviceObject, // the logical volume device object 49 PIRP Irp // I/O Request Packet 50 ) 51{ 52 NTSTATUS RC = STATUS_SUCCESS; 53 PtrUDFIrpContext PtrIrpContext = NULL; 54 BOOLEAN AreWeTopLevel = FALSE; 55 56 UDFPrint(("UDFShutDown\n")); 57// BrutePoint(); 58 59 FsRtlEnterFileSystem(); 60 ASSERT(DeviceObject); 61 ASSERT(Irp); 62 63 // set the top level context 64 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 65 //ASSERT(!UDFIsFSDevObj(DeviceObject)); 66 67 _SEH2_TRY { 68 69 // get an IRP context structure and issue the request 70 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 71 if(PtrIrpContext) { 72 RC = UDFCommonShutdown(PtrIrpContext, Irp); 73 } else { 74 RC = STATUS_INSUFFICIENT_RESOURCES; 75 Irp->IoStatus.Status = RC; 76 Irp->IoStatus.Information = 0; 77 // complete the IRP 78 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 79 } 80 81 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 82 83 RC = UDFExceptionHandler(PtrIrpContext, Irp); 84 85 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 86 } _SEH2_END; 87 88 if (AreWeTopLevel) { 89 IoSetTopLevelIrp(NULL); 90 } 91 92 FsRtlExitFileSystem(); 93 94 return(RC); 95} // end UDFShutdown() 96 97 98/************************************************************************* 99* 100* Function: UDFCommonShutdown() 101* 102* Description: 103* The actual work is performed here. Basically, all we do here is 104* internally invoke a flush on all mounted logical volumes. This, in 105* tuen, will result in all open file streams being flushed to disk. 106* 107* Expected Interrupt Level (for execution) : 108* 109* IRQL_PASSIVE_LEVEL 110* 111* Return Value: Irrelevant 112* 113*************************************************************************/ 114NTSTATUS 115UDFCommonShutdown( 116 PtrUDFIrpContext PtrIrpContext, 117 PIRP Irp 118 ) 119{ 120 NTSTATUS RC = STATUS_SUCCESS; 121 PIO_STACK_LOCATION IrpSp = NULL; 122 PVCB Vcb; 123 PLIST_ENTRY Link; 124 PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL; 125 LARGE_INTEGER delay; 126 127 UDFPrint(("UDFCommonShutdown\n")); 128 129 _SEH2_TRY { 130 // First, get a pointer to the current I/O stack location 131 IrpSp = IoGetCurrentIrpStackLocation(Irp); 132 ASSERT(IrpSp); 133 134 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN)); 135 if(!Buf) 136 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 137 138 // (a) Block all new "mount volume" requests by acquiring an appropriate 139 // global resource/lock. 140 // (b) Go through your linked list of mounted logical volumes and for 141 // each such volume, do the following: 142 // (i) acquire the volume resource exclusively 143 // (ii) invoke UDFFlushLogicalVolume() (internally) to flush the 144 // open data streams belonging to the volume from the system 145 // cache 146 // (iii) Invoke the physical/virtual/logical target device object 147 // on which the volume is mounted and inform this device 148 // about the shutdown request (Use IoBuildSynchronouFsdRequest() 149 // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you 150 // will then issue to the target device object). 151 // (iv) Wait for the completion of the shutdown processing by the target 152 // device object 153 // (v) Release the VCB resource we will have acquired in (i) above. 154 155 // Acquire GlobalDataResource 156 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 157 // Walk through all of the Vcb's attached to the global data. 158 Link = UDFGlobalData.VCBQueue.Flink; 159 160 while (Link != &(UDFGlobalData.VCBQueue)) { 161 // Get 'next' Vcb 162 Vcb = CONTAINING_RECORD( Link, VCB, NextVCB ); 163 // Move to the next link now since the current Vcb may be deleted. 164 Link = Link->Flink; 165 ASSERT(Link != Link->Flink); 166 167 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) { 168 169#ifdef UDF_DELAYED_CLOSE 170 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 171 UDFPrint((" UDFCommonShutdown: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n")); 172 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; 173 UDFReleaseResource(&(Vcb->VCBResource)); 174#endif //UDF_DELAYED_CLOSE 175 176 // Note: UDFCloseAllDelayed() doesn't acquire DelayedCloseResource if 177 // GlobalDataResource is already acquired. Thus for now we should 178 // release GlobalDataResource and re-acquire it later. 179 UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); 180 if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) { 181 UDFPrint((" UDFCommonShutdown: UDFCloseAllSystemDelayedInDir\n")); 182 RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 183 ASSERT(OS_SUCCESS(RC)); 184 } 185 186#ifdef UDF_DELAYED_CLOSE 187 UDFCloseAllDelayed(Vcb); 188// UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); 189#endif //UDF_DELAYED_CLOSE 190 191 // re-acquire GlobalDataResource 192 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 193 194 // disable Eject Waiter 195 UDFStopEjectWaiter(Vcb); 196 // Acquire Vcb resource 197 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 198 199 ASSERT(!Vcb->OverflowQueueCount); 200 201 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) { 202 203 UDFDoDismountSequence(Vcb, Buf, FALSE); 204 if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) { 205 // let drive flush all data before reset 206 delay.QuadPart = -10000000; // 1 sec 207 KeDelayExecutionThread(KernelMode, FALSE, &delay); 208 } 209 Vcb->VCBFlags |= (UDF_VCB_FLAGS_SHUTDOWN | 210 UDF_VCB_FLAGS_VOLUME_READ_ONLY); 211 } 212 213 UDFReleaseResource(&(Vcb->VCBResource)); 214 } 215 } 216 // Once we have processed all the mounted logical volumes, we can release 217 // all acquired global resources and leave (in peace :-) 218 UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) ); 219 RC = STATUS_SUCCESS; 220 221try_exit: NOTHING; 222 223 } _SEH2_FINALLY { 224 225 if(Buf) MyFreePool__(Buf); 226 if(!_SEH2_AbnormalTermination()) { 227 Irp->IoStatus.Status = RC; 228 Irp->IoStatus.Information = 0; 229 // Free up the Irp Context 230 UDFReleaseIrpContext(PtrIrpContext); 231 // complete the IRP 232 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 233 } 234 235 } _SEH2_END; // end of "__finally" processing 236 237 return(RC); 238} // end UDFCommonShutdown()