[UDFS] Import a UDF File System Driver created by Alexander Telyatnikov (Alter) and...
[reactos.git] / reactos / drivers / filesystems / udfs / shutdown.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 ////////////////////////////////////////////////////////////////////
5 /*************************************************************************
6 *
7 * File: Shutdown.cpp
8 *
9 * Module: UDF File System Driver (Kernel mode execution only)
10 *
11 * Description:
12 * Contains code to handle the "shutdown notification" dispatch entry point.
13 *
14 *************************************************************************/
15
16 #include "udffs.h"
17
18 // define the file specific bug-check id
19 #define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
20
21
22
23 /*************************************************************************
24 *
25 * Function: UDFShutdown()
26 *
27 * Description:
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.
33 *
34 * Note that drivers that register to receive shutdown notification get
35 * invoked BEFORE disk-based FSDs are told about the shutdown notification.
36 *
37 * Expected Interrupt Level (for execution) :
38 *
39 * IRQL_PASSIVE_LEVEL
40 *
41 * Return Value: Irrelevant.
42 *
43 *************************************************************************/
44 NTSTATUS
45 NTAPI
46 UDFShutdown(
47 PDEVICE_OBJECT DeviceObject, // the logical volume device object
48 PIRP Irp // I/O Request Packet
49 )
50 {
51 NTSTATUS RC = STATUS_SUCCESS;
52 PtrUDFIrpContext PtrIrpContext = NULL;
53 BOOLEAN AreWeTopLevel = FALSE;
54
55 KdPrint(("UDFShutDown\n"));
56 // BrutePoint();
57
58 FsRtlEnterFileSystem();
59 ASSERT(DeviceObject);
60 ASSERT(Irp);
61
62 // set the top level context
63 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
64 //ASSERT(!UDFIsFSDevObj(DeviceObject));
65
66 _SEH2_TRY {
67
68 // get an IRP context structure and issue the request
69 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
70 if(PtrIrpContext) {
71 RC = UDFCommonShutdown(PtrIrpContext, Irp);
72 } else {
73 RC = STATUS_INSUFFICIENT_RESOURCES;
74 Irp->IoStatus.Status = RC;
75 Irp->IoStatus.Information = 0;
76 // complete the IRP
77 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
78 }
79
80 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
81
82 RC = UDFExceptionHandler(PtrIrpContext, Irp);
83
84 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
85 } _SEH2_END;
86
87 if (AreWeTopLevel) {
88 IoSetTopLevelIrp(NULL);
89 }
90
91 FsRtlExitFileSystem();
92
93 return(RC);
94 } // end UDFShutdown()
95
96
97 /*************************************************************************
98 *
99 * Function: UDFCommonShutdown()
100 *
101 * Description:
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.
105 *
106 * Expected Interrupt Level (for execution) :
107 *
108 * IRQL_PASSIVE_LEVEL
109 *
110 * Return Value: Irrelevant
111 *
112 *************************************************************************/
113 NTSTATUS
114 UDFCommonShutdown(
115 PtrUDFIrpContext PtrIrpContext,
116 PIRP Irp
117 )
118 {
119 NTSTATUS RC = STATUS_SUCCESS;
120 PIO_STACK_LOCATION IrpSp = NULL;
121 PVCB Vcb;
122 PLIST_ENTRY Link;
123 PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
124 LARGE_INTEGER delay;
125
126 KdPrint(("UDFCommonShutdown\n"));
127
128 _SEH2_TRY {
129 // First, get a pointer to the current I/O stack location
130 IrpSp = IoGetCurrentIrpStackLocation(Irp);
131 ASSERT(IrpSp);
132
133 Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
134 if(!Buf)
135 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
136
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
144 // cache
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
151 // device object
152 // (v) Release the VCB resource we will have acquired in (i) above.
153
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;
158
159 while (Link != &(UDFGlobalData.VCBQueue)) {
160 // Get 'next' Vcb
161 Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
162 // Move to the next link now since the current Vcb may be deleted.
163 Link = Link->Flink;
164 ASSERT(Link != Link->Flink);
165
166 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {
167
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
174
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));
183 }
184
185 #ifdef UDF_DELAYED_CLOSE
186 UDFCloseAllDelayed(Vcb);
187 // UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
188 #endif //UDF_DELAYED_CLOSE
189
190 // re-acquire GlobalDataResource
191 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
192
193 // disable Eject Waiter
194 UDFStopEjectWaiter(Vcb);
195 // Acquire Vcb resource
196 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
197
198 ASSERT(!Vcb->OverflowQueueCount);
199
200 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {
201
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);
207 }
208 Vcb->VCBFlags |= (UDF_VCB_FLAGS_SHUTDOWN |
209 UDF_VCB_FLAGS_VOLUME_READ_ONLY);
210 }
211
212 UDFReleaseResource(&(Vcb->VCBResource));
213 }
214 }
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) );
218 RC = STATUS_SUCCESS;
219
220 try_exit: NOTHING;
221
222 } _SEH2_FINALLY {
223
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);
230 // complete the IRP
231 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
232 }
233
234 } _SEH2_END; // end of "__finally" processing
235
236 return(RC);
237 } // end UDFCommonShutdown()