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