1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     Shutdown.c
8 
9 Abstract:
10 
11     This module implements the file system shutdown routine for Fat
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 //
19 //  Local debug trace level
20 //
21 
22 #define Dbg                              (DEBUG_TRACE_SHUTDOWN)
23 
24 #ifdef ALLOC_PRAGMA
25 #pragma alloc_text(PAGE, FatCommonShutdown)
26 #pragma alloc_text(PAGE, FatFsdShutdown)
27 #endif
28 
29 
30 _Function_class_(IRP_MJ_SHUTDOWN)
31 _Function_class_(DRIVER_DISPATCH)
32 NTSTATUS
33 NTAPI
34 FatFsdShutdown (
35     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
36     _Inout_ PIRP Irp
37     )
38 
39 /*++
40 
41 Routine Description:
42 
43     This routine implements the FSD part of shutdown.  Note that Shutdown will
44     never be done asynchronously so we will never need the Fsp counterpart
45     to shutdown.
46 
47     This is the shutdown routine for the Fat file system device driver.
48     This routine locks the global file system lock and then syncs all the
49     mounted volumes.
50 
51 Arguments:
52 
53     VolumeDeviceObject - Supplies the volume device object where the
54         file exists
55 
56     Irp - Supplies the Irp being processed
57 
58 Return Value:
59 
60     NTSTATUS - Always STATUS_SUCCESS
61 
62 --*/
63 
64 {
65     NTSTATUS Status;
66     PIRP_CONTEXT IrpContext = NULL;
67 
68     BOOLEAN TopLevel;
69 
70     PAGED_CODE();
71 
72     DebugTrace(+1, Dbg, "FatFsdShutdown\n", 0);
73 
74     //
75     //  Call the common shutdown routine.
76     //
77 
78     FsRtlEnterFileSystem();
79 
80     TopLevel = FatIsIrpTopLevel( Irp );
81 
82     _SEH2_TRY {
83 
84         IrpContext = FatCreateIrpContext( Irp, TRUE );
85 
86         Status = FatCommonShutdown( IrpContext, Irp );
87 
88     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
89 
90         //
91         //  We had some trouble trying to perform the requested
92         //  operation, so we'll abort the I/O request with
93         //  the error status that we get back from the
94         //  execption code
95         //
96 
97         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
98     } _SEH2_END;
99 
100     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
101 
102     FsRtlExitFileSystem();
103 
104     //
105     //  And return to our caller
106     //
107 
108     DebugTrace(-1, Dbg, "FatFsdShutdown -> %08lx\n", Status);
109 
110     UNREFERENCED_PARAMETER( VolumeDeviceObject );
111 
112     return Status;
113 }
114 
115 
116 _Requires_lock_held_(_Global_critical_region_)
117 NTSTATUS
118 FatCommonShutdown (
119     IN PIRP_CONTEXT IrpContext,
120     IN PIRP Irp
121     )
122 
123 /*++
124 
125 Routine Description:
126 
127     This is the common routine for shutdown called by both the fsd and
128     fsp threads.
129 
130 Arguments:
131 
132     Irp - Supplies the Irp being processed
133 
134 Return Value:
135 
136     NTSTATUS - The return status for the operation
137 
138 --*/
139 
140 {
141     KEVENT Event;
142     PLIST_ENTRY Links;
143     PVCB Vcb;
144     PIRP NewIrp;
145     IO_STATUS_BLOCK Iosb;
146     BOOLEAN VcbDeleted;
147 
148     PAGED_CODE();
149 
150     //
151     //  Make sure we don't get any pop-ups, and write everything through.
152     //
153 
154     SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_POPUPS |
155                                IRP_CONTEXT_FLAG_WRITE_THROUGH);
156 
157     //
158     //  Initialize an event for doing calls down to
159     //  our target device objects.
160     //
161 
162     KeInitializeEvent( &Event, NotificationEvent, FALSE );
163 
164     //
165     //  Indicate that shutdown has started.  This is used in FatFspClose.
166     //
167 
168     FatData.ShutdownStarted = TRUE;
169 
170     //
171     //  Get everyone else out of the way
172     //
173 
174     NT_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
175 
176 #ifdef _MSC_VER
177 #pragma prefast( push )
178 #pragma prefast( disable: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
179 #pragma prefast( disable: 28193, "this will always wait" )
180 #endif
181 
182     (VOID) FatAcquireExclusiveGlobal( IrpContext );
183 
184 #ifdef _MSC_VER
185 #pragma prefast( pop )
186 #endif
187 
188     _SEH2_TRY {
189 
190         //
191         //  For every volume that is mounted we will flush the
192         //  volume and then shutdown the target device objects.
193         //
194 
195         Links = FatData.VcbQueue.Flink;
196         while (Links != &FatData.VcbQueue) {
197 
198             Vcb = CONTAINING_RECORD(Links, VCB, VcbLinks);
199 
200             Links = Links->Flink;
201 
202             //
203             //  If we have already been called before for this volume
204             //  (and yes this does happen), skip this volume as no writes
205             //  have been allowed since the first shutdown.
206             //
207 
208             if ( FlagOn( Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ||
209                  (Vcb->VcbCondition != VcbGood) ) {
210 
211                 continue;
212             }
213 
214             FatAcquireExclusiveVolume( IrpContext, Vcb );
215 
216             _SEH2_TRY {
217 
218                 (VOID)FatFlushVolume( IrpContext, Vcb, Flush );
219 
220                 //
221                 //  The volume is now clean, note it.  We purge the
222                 //  volume file cache map before marking the volume
223                 //  clean incase there is a stale Bpb in the cache.
224                 //
225 
226                 if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {
227 
228                     CcPurgeCacheSection( &Vcb->SectionObjectPointers,
229                                          NULL,
230                                          0,
231                                          FALSE );
232 
233                     FatMarkVolume( IrpContext, Vcb, VolumeClean );
234                 }
235 
236             } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) {
237 
238                   FatResetExceptionState( IrpContext );
239             } _SEH2_END;
240 
241             //
242             //  Sometimes we take an excepion while flushing the volume, such
243             //  as when autoconv has converted the volume and is rebooting.
244             //  Even in that case we want to send the shutdown irp to the
245             //  target device so it can know to flush its cache, if it has one.
246             //
247 
248             _SEH2_TRY {
249 
250                 NewIrp = IoBuildSynchronousFsdRequest( IRP_MJ_SHUTDOWN,
251                                                        Vcb->TargetDeviceObject,
252                                                        NULL,
253                                                        0,
254                                                        NULL,
255                                                        &Event,
256                                                        &Iosb );
257 
258                 if (NewIrp != NULL) {
259 
260                     if (NT_SUCCESS(IoCallDriver( Vcb->TargetDeviceObject, NewIrp ))) {
261 
262                         (VOID) KeWaitForSingleObject( &Event,
263                                                       Executive,
264                                                       KernelMode,
265                                                       FALSE,
266                                                       NULL );
267 
268                         KeClearEvent( &Event );
269                     }
270                 }
271 
272             } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) {
273 
274                   FatResetExceptionState( IrpContext );
275             } _SEH2_END;
276 
277             SetFlag( Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN );
278 
279             //
280             //  Attempt to punch the volume down.
281             //
282 
283             VcbDeleted = FatCheckForDismount( IrpContext,
284                                               Vcb,
285                                               FALSE );
286 
287             if (!VcbDeleted) {
288 
289                 FatReleaseVolume( IrpContext, Vcb );
290             }
291         }
292 
293     } _SEH2_FINALLY {
294 
295 
296         FatReleaseGlobal( IrpContext );
297 
298         //
299         //  Unregister the file system.
300         //
301 
302         IoUnregisterFileSystem( FatDiskFileSystemDeviceObject);
303         IoUnregisterFileSystem( FatCdromFileSystemDeviceObject);
304         IoDeleteDevice( FatDiskFileSystemDeviceObject);
305         IoDeleteDevice( FatCdromFileSystemDeviceObject);
306 
307         FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
308     } _SEH2_END;
309 
310     //
311     //  And return to our caller
312     //
313 
314     DebugTrace(-1, Dbg, "FatFsdShutdown -> STATUS_SUCCESS\n", 0);
315 
316     return STATUS_SUCCESS;
317 }
318 
319