1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "shutdown notification" dispatch entry point.
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
24 /*************************************************************************
26 * Function: UDFShutdown()
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.
35 * Note that drivers that register to receive shutdown notification get
36 * invoked BEFORE disk-based FSDs are told about the shutdown notification.
38 * Expected Interrupt Level (for execution) :
42 * Return Value: Irrelevant.
44 *************************************************************************/
48 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
49 PIRP Irp
// I/O Request Packet
52 NTSTATUS RC
= STATUS_SUCCESS
;
53 PtrUDFIrpContext PtrIrpContext
= NULL
;
54 BOOLEAN AreWeTopLevel
= FALSE
;
56 UDFPrint(("UDFShutDown\n"));
59 FsRtlEnterFileSystem();
63 // set the top level context
64 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
65 //ASSERT(!UDFIsFSDevObj(DeviceObject));
69 // get an IRP context structure and issue the request
70 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
72 RC
= UDFCommonShutdown(PtrIrpContext
, Irp
);
74 RC
= STATUS_INSUFFICIENT_RESOURCES
;
75 Irp
->IoStatus
.Status
= RC
;
76 Irp
->IoStatus
.Information
= 0;
78 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
81 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
83 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
85 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
89 IoSetTopLevelIrp(NULL
);
92 FsRtlExitFileSystem();
95 } // end UDFShutdown()
98 /*************************************************************************
100 * Function: UDFCommonShutdown()
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.
107 * Expected Interrupt Level (for execution) :
111 * Return Value: Irrelevant
113 *************************************************************************/
116 PtrUDFIrpContext PtrIrpContext
,
120 NTSTATUS RC
= STATUS_SUCCESS
;
121 PIO_STACK_LOCATION IrpSp
= NULL
;
124 PPREVENT_MEDIA_REMOVAL_USER_IN Buf
= NULL
;
127 UDFPrint(("UDFCommonShutdown\n"));
130 // First, get a pointer to the current I/O stack location
131 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
134 Buf
= (PPREVENT_MEDIA_REMOVAL_USER_IN
)MyAllocatePool__(NonPagedPool
, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
));
136 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
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
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
153 // (v) Release the VCB resource we will have acquired in (i) above.
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
;
160 while (Link
!= &(UDFGlobalData
.VCBQueue
)) {
162 Vcb
= CONTAINING_RECORD( Link
, VCB
, NextVCB
);
163 // Move to the next link now since the current Vcb may be deleted.
165 ASSERT(Link
!= Link
->Flink
);
167 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_SHUTDOWN
)) {
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
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
));
186 #ifdef UDF_DELAYED_CLOSE
187 UDFCloseAllDelayed(Vcb
);
188 // UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
189 #endif //UDF_DELAYED_CLOSE
191 // re-acquire GlobalDataResource
192 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
194 // disable Eject Waiter
195 UDFStopEjectWaiter(Vcb
);
196 // Acquire Vcb resource
197 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
199 ASSERT(!Vcb
->OverflowQueueCount
);
201 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_SHUTDOWN
)) {
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
);
209 Vcb
->VCBFlags
|= (UDF_VCB_FLAGS_SHUTDOWN
|
210 UDF_VCB_FLAGS_VOLUME_READ_ONLY
);
213 UDFReleaseResource(&(Vcb
->VCBResource
));
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
) );
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
);
232 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
235 } _SEH2_END
; // end of "__finally" processing
238 } // end UDFCommonShutdown()