1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 ////////////////////////////////////////////////////////////////////
5 /*************************************************************************
9 * Module: UDF File System Driver (Kernel mode execution only)
12 * Contains code to handle the "shutdown notification" dispatch entry point.
14 *************************************************************************/
18 // define the file specific bug-check id
19 #define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
23 /*************************************************************************
25 * Function: UDFShutdown()
28 * All disk-based FSDs can expect to receive this shutdown notification
29 * request whenever the system is about to be halted gracefully. If you
30 * design and implement a network redirector, you must register explicitly
31 * for shutdown notification by invoking the IoRegisterShutdownNotification()
32 * routine from your driver entry.
34 * Note that drivers that register to receive shutdown notification get
35 * invoked BEFORE disk-based FSDs are told about the shutdown notification.
37 * Expected Interrupt Level (for execution) :
41 * Return Value: Irrelevant.
43 *************************************************************************/
47 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
48 PIRP Irp
// I/O Request Packet
51 NTSTATUS RC
= STATUS_SUCCESS
;
52 PtrUDFIrpContext PtrIrpContext
= NULL
;
53 BOOLEAN AreWeTopLevel
= FALSE
;
55 KdPrint(("UDFShutDown\n"));
58 FsRtlEnterFileSystem();
62 // set the top level context
63 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
64 //ASSERT(!UDFIsFSDevObj(DeviceObject));
68 // get an IRP context structure and issue the request
69 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
71 RC
= UDFCommonShutdown(PtrIrpContext
, Irp
);
73 RC
= STATUS_INSUFFICIENT_RESOURCES
;
74 Irp
->IoStatus
.Status
= RC
;
75 Irp
->IoStatus
.Information
= 0;
77 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
80 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
82 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
84 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
88 IoSetTopLevelIrp(NULL
);
91 FsRtlExitFileSystem();
94 } // end UDFShutdown()
97 /*************************************************************************
99 * Function: UDFCommonShutdown()
102 * The actual work is performed here. Basically, all we do here is
103 * internally invoke a flush on all mounted logical volumes. This, in
104 * tuen, will result in all open file streams being flushed to disk.
106 * Expected Interrupt Level (for execution) :
110 * Return Value: Irrelevant
112 *************************************************************************/
115 PtrUDFIrpContext PtrIrpContext
,
119 NTSTATUS RC
= STATUS_SUCCESS
;
120 PIO_STACK_LOCATION IrpSp
= NULL
;
123 PPREVENT_MEDIA_REMOVAL_USER_IN Buf
= NULL
;
126 KdPrint(("UDFCommonShutdown\n"));
129 // First, get a pointer to the current I/O stack location
130 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
133 Buf
= (PPREVENT_MEDIA_REMOVAL_USER_IN
)MyAllocatePool__(NonPagedPool
, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN
));
135 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
137 // (a) Block all new "mount volume" requests by acquiring an appropriate
138 // global resource/lock.
139 // (b) Go through your linked list of mounted logical volumes and for
140 // each such volume, do the following:
141 // (i) acquire the volume resource exclusively
142 // (ii) invoke UDFFlushLogicalVolume() (internally) to flush the
143 // open data streams belonging to the volume from the system
145 // (iii) Invoke the physical/virtual/logical target device object
146 // on which the volume is mounted and inform this device
147 // about the shutdown request (Use IoBuildSynchronouFsdRequest()
148 // to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you
149 // will then issue to the target device object).
150 // (iv) Wait for the completion of the shutdown processing by the target
152 // (v) Release the VCB resource we will have acquired in (i) above.
154 // Acquire GlobalDataResource
155 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
156 // Walk through all of the Vcb's attached to the global data.
157 Link
= UDFGlobalData
.VCBQueue
.Flink
;
159 while (Link
!= &(UDFGlobalData
.VCBQueue
)) {
161 Vcb
= CONTAINING_RECORD( Link
, VCB
, NextVCB
);
162 // Move to the next link now since the current Vcb may be deleted.
164 ASSERT(Link
!= Link
->Flink
);
166 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_SHUTDOWN
)) {
168 #ifdef UDF_DELAYED_CLOSE
169 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
170 KdPrint((" UDFCommonShutdown: set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
171 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
172 UDFReleaseResource(&(Vcb
->VCBResource
));
173 #endif //UDF_DELAYED_CLOSE
175 // Note: UDFCloseAllDelayed() doesn't acquire DelayedCloseResource if
176 // GlobalDataResource is already acquired. Thus for now we should
177 // release GlobalDataResource and re-acquire it later.
178 UDFReleaseResource( &(UDFGlobalData
.GlobalDataResource
) );
179 if(Vcb
->RootDirFCB
&& Vcb
->RootDirFCB
->FileInfo
) {
180 KdPrint((" UDFCommonShutdown: UDFCloseAllSystemDelayedInDir\n"));
181 RC
= UDFCloseAllSystemDelayedInDir(Vcb
, Vcb
->RootDirFCB
->FileInfo
);
182 ASSERT(OS_SUCCESS(RC
));
185 #ifdef UDF_DELAYED_CLOSE
186 UDFCloseAllDelayed(Vcb
);
187 // UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
188 #endif //UDF_DELAYED_CLOSE
190 // re-acquire GlobalDataResource
191 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
193 // disable Eject Waiter
194 UDFStopEjectWaiter(Vcb
);
195 // Acquire Vcb resource
196 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
198 ASSERT(!Vcb
->OverflowQueueCount
);
200 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_SHUTDOWN
)) {
202 UDFDoDismountSequence(Vcb
, Buf
, FALSE
);
203 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_REMOVABLE_MEDIA
) {
204 // let drive flush all data before reset
205 delay
.QuadPart
= -10000000; // 1 sec
206 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
208 Vcb
->VCBFlags
|= (UDF_VCB_FLAGS_SHUTDOWN
|
209 UDF_VCB_FLAGS_VOLUME_READ_ONLY
);
212 UDFReleaseResource(&(Vcb
->VCBResource
));
215 // Once we have processed all the mounted logical volumes, we can release
216 // all acquired global resources and leave (in peace :-)
217 UDFReleaseResource( &(UDFGlobalData
.GlobalDataResource
) );
224 if(Buf
) MyFreePool__(Buf
);
225 if(!_SEH2_AbnormalTermination()) {
226 Irp
->IoStatus
.Status
= RC
;
227 Irp
->IoStatus
.Information
= 0;
228 // Free up the Irp Context
229 UDFReleaseIrpContext(PtrIrpContext
);
231 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
234 } _SEH2_END
; // end of "__finally" processing
237 } // end UDFCommonShutdown()