1 /*************************************************************************
5 * Module: Ext2 File System Driver (Kernel mode execution only)
8 * Should contain code to handle the "Cleanup" dispatch entry point.
9 * This file serves as a placeholder. Please update this file as part
10 * of designing and implementing your FSD.
12 * Author: Manoj Paul Joseph
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define EXT2_BUG_CHECK_ID EXT2_FILE_CLEANUP
21 #define DEBUG_LEVEL (DEBUG_TRACE_CLEANUP)
24 /*************************************************************************
26 * Function: Ext2Cleanup()
29 * The I/O Manager will invoke this routine to handle a cleanup
32 * Expected Interrupt Level (for execution) :
34 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
35 * to be deferred to a worker thread context)
37 * Return Value: Does not matter!
39 *************************************************************************/
40 NTSTATUS NTAPI
Ext2Cleanup(
41 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
42 PIRP Irp
) // I/O Request Packet
44 NTSTATUS RC
= STATUS_SUCCESS
;
45 PtrExt2IrpContext PtrIrpContext
= NULL
;
46 BOOLEAN AreWeTopLevel
= FALSE
;
48 DebugTrace( DEBUG_TRACE_IRP_ENTRY
, "Cleanup IRP Received...", 0);
50 FsRtlEnterFileSystem();
54 // set the top level context
55 AreWeTopLevel
= Ext2IsIrpTopLevel(Irp
);
60 // get an IRP context structure and issue the request
61 PtrIrpContext
= Ext2AllocateIrpContext(Irp
, DeviceObject
);
62 ASSERT(PtrIrpContext
);
64 RC
= Ext2CommonCleanup(PtrIrpContext
, Irp
, TRUE
);
67 except( Ext2ExceptionFilter(PtrIrpContext
, GetExceptionInformation() ) )
70 RC
= Ext2ExceptionHandler(PtrIrpContext
, Irp
);
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR
, RC
);
77 IoSetTopLevelIrp(NULL
);
80 FsRtlExitFileSystem();
85 /*************************************************************************
87 * Function: Ext2CommonCleanup()
90 * The actual work is performed here. This routine may be invoked in one'
91 * of the two possible contexts:
92 * (a) in the context of a system worker thread
93 * (b) in the context of the original caller
95 * Expected Interrupt Level (for execution) :
99 * Return Value: Does not matter!
101 *************************************************************************/
102 NTSTATUS NTAPI
Ext2CommonCleanup(
103 PtrExt2IrpContext PtrIrpContext
,
105 BOOLEAN FirstAttempt
)
108 NTSTATUS RC
= STATUS_SUCCESS
;
109 PIO_STACK_LOCATION PtrIoStackLocation
= NULL
;
110 PFILE_OBJECT PtrFileObject
= NULL
;
111 PtrExt2FCB PtrFCB
= NULL
;
112 PtrExt2CCB PtrCCB
= NULL
;
113 PtrExt2VCB PtrVCB
= NULL
;
114 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
115 PERESOURCE PtrResourceAcquired
= NULL
;
117 BOOLEAN CompleteIrp
= TRUE
;
118 BOOLEAN PostRequest
= FALSE
;
119 BOOLEAN AcquiredVCB
= FALSE
;
120 BOOLEAN BlockForResource
;
125 // First, get a pointer to the current I/O stack location
126 PtrIoStackLocation
= IoGetCurrentIrpStackLocation(PtrIrp
);
127 ASSERT(PtrIoStackLocation
);
129 PtrFileObject
= PtrIoStackLocation
->FileObject
;
130 ASSERT(PtrFileObject
);
132 if( !PtrFileObject
->FsContext2
)
134 // This must be a Cleanup request received
135 // as a result of IoCreateStreamFileObject
136 // Only such a File object would have a NULL CCB
138 DebugTrace( DEBUG_TRACE_MISC
, " === Cleanup with NULL CCB", 0);
141 DebugTrace( DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject
);
147 Ext2GetFCB_CCB_VCB_FromFileObject (
148 PtrFileObject
, &PtrFCB
, &PtrCCB
, &PtrVCB
);
150 if( PtrFCB
&& PtrFCB
->FCBName
&& PtrFCB
->FCBName
->ObjectName
.Length
&& PtrFCB
->FCBName
->ObjectName
.Buffer
)
151 //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer )
153 DebugTrace( DEBUG_TRACE_FILE_NAME
, " === Cleanup File Name : -%S-", PtrFCB
->FCBName
->ObjectName
.Buffer
);
157 DebugTrace( DEBUG_TRACE_FILE_NAME
, " === Cleanup Volume", 0);
161 PtrVCB
= (PtrExt2VCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
163 ASSERT(PtrVCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
);
165 // (a) Acquiring the VCBResource Exclusively...
166 // This is done to synchronise with the close and cleanup routines...
167 BlockForResource
= !FirstAttempt
;
171 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0);
175 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0);
180 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject
);
184 while( !AcquiredVCB
)
186 DebugTraceState("VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB
->VCBResource
.ActiveCount
, PtrVCB
->VCBResource
.NumberOfExclusiveWaiters
, PtrVCB
->VCBResource
.NumberOfSharedWaiters
);
187 if( ! ExAcquireResourceExclusiveLite( &(PtrVCB
->VCBResource
), FALSE
) )
189 DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** VCB Acquisition FAILED [Cleanup]", 0);
190 if( BlockForResource
&& i
!= 1000 )
193 Delay
.QuadPart
= -500 * i
;
194 KeDelayExecutionThread( KernelMode
, FALSE
, &Delay
);
195 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY
, "*** Retrying... after 50 * %ld ms [Cleanup]", i
);
200 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY
, "*** Reposting... [Cleanup]", 0 );
202 try_return( RC
= STATUS_PENDING
);
207 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** VCB Acquired in [Cleanup]", 0);
214 // (b) Acquire the file (FCB) exclusively
215 if( PtrFCB
&& PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_FCB
)
217 // This FCB is an FCB indeed. ;)
218 // So acquiring it exclusively...
219 // This is done to synchronise with read/write routines...
222 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0);
226 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0);
230 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject
);
234 while( !PtrResourceAcquired
)
236 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
237 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
238 if(! ExAcquireResourceExclusiveLite( &(PtrFCB
->NTRequiredFCB
.MainResource
), FALSE
) )
240 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** FCB Acquisition FAILED [Cleanup]", 0);
241 if( BlockForResource
&& i
!= 1000 )
244 Delay
.QuadPart
= -500 * i
;
245 KeDelayExecutionThread( KernelMode
, FALSE
, &Delay
);
246 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY
, "*** Retrying... after 50 * %ld ms [Cleanup]", i
);
251 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY
, "*** Reposting... [Cleanup]", 0 );
253 try_return( RC
= STATUS_PENDING
);
258 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE
, "*** FCB acquired [Cleanup]", 0);
259 PtrResourceAcquired
= & ( PtrFCB
->NTRequiredFCB
.MainResource
);
264 // (c) Flush file data to disk
265 if ( PtrFileObject
->PrivateCacheMap
!= NULL
)
267 IO_STATUS_BLOCK Status
;
268 CcFlushCache( PtrFileObject
->SectionObjectPointer
, NULL
, 0, &Status
);
271 // (d) Talk to the FSRTL package (if you use it) about pending oplocks.
272 // (e) Notify the FSRTL package (if you use it) for use with pending
274 // (f) Unlock byte-range locks (if any were acquired by process)
276 // (g) Attempting to update time stamp values
277 // Errors are ignored...
278 // Not considered as critical errors...
281 if( PtrFCB->OpenHandleCount == 1 )
283 ULONG CreationTime, AccessTime, ModificationTime;
286 CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart
287 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
288 AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart
289 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
290 ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart
291 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
292 if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
294 // Update time stamps in the inode...
295 Inode.i_ctime = CreationTime;
296 Inode.i_atime = AccessTime;
297 Inode.i_mtime = ModificationTime;
299 // Updating the inode...
300 Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode );
305 // (h) Inform the Cache Manager to uninitialize Cache Maps ...
306 CcUninitializeCacheMap( PtrFileObject
, NULL
, NULL
);
308 // (i) Decrementing the Open Handle count...
309 if( PtrFCB
->OpenHandleCount
)
311 InterlockedDecrement( &PtrFCB
->OpenHandleCount
);
318 PtrFCB
->FCBFlags
|= FO_CLEANUP_COMPLETE
;
320 DebugTrace(DEBUG_TRACE_REFERENCE
, "^^^^^ReferenceCount = 0x%lX [Cleanup]", PtrFCB
->ReferenceCount
);
321 DebugTrace(DEBUG_TRACE_REFERENCE
, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB
->OpenHandleCount
);
323 // (j) Remove share access...
324 // Will do that later ;)
326 // (k) Is this a close on delete file?
327 // If so, delete the file...
328 if( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_DELETE_ON_CLOSE
) &&
329 !PtrFCB
->OpenHandleCount
)
332 // Have to delete this file...
334 Ext2DeleteFile( PtrFCB
, PtrIrpContext
);
335 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
= 0;
341 // This must be a volume close...
342 // Just go ahead and complete this IRP...
343 PtrVCB
->VCBOpenCount
--;
344 DebugTrace(DEBUG_TRACE_MISC
, "VCB Cleanup Requested !!!", 0);
355 if(PtrResourceAcquired
)
357 Ext2ReleaseResource(PtrResourceAcquired
);
358 DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE
, "*** Resource Released [Cleanup]", 0);
359 DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]",
360 PtrResourceAcquired
->ActiveCount
,
361 PtrResourceAcquired
->NumberOfExclusiveWaiters
,
362 PtrResourceAcquired
->NumberOfSharedWaiters
);
366 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject
);
374 Ext2ReleaseResource(&(PtrVCB
->VCBResource
));
375 DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE
, "*** VCB Released [Cleanup]", 0);
376 DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Cleanup]", PtrVCB
->VCBResource
.ActiveCount
, PtrVCB
->VCBResource
.NumberOfExclusiveWaiters
, PtrVCB
->VCBResource
.NumberOfSharedWaiters
);
380 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject
);
387 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
389 if( RC
!= STATUS_PENDING
)
391 Ext2ReleaseIrpContext( PtrIrpContext
);
393 IoCompleteRequest( PtrIrp
, IO_DISK_INCREMENT
);
395 } // end of "finally" processing