d5d33c5f528cd8b03538624cf4300ab731714b5d
[reactos.git] / reactos / drivers / filesystems / ext2 / src / cleanup.c
1 /*************************************************************************
2 *
3 * File: cleanup.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
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.
11 *
12 * Author: Manoj Paul Joseph
13 *
14 *
15 *************************************************************************/
16
17 #include "ext2fsd.h"
18
19 // define the file specific bug-check id
20 #define EXT2_BUG_CHECK_ID EXT2_FILE_CLEANUP
21 #define DEBUG_LEVEL (DEBUG_TRACE_CLEANUP)
22
23
24 /*************************************************************************
25 *
26 * Function: Ext2Cleanup()
27 *
28 * Description:
29 * The I/O Manager will invoke this routine to handle a cleanup
30 * request
31 *
32 * Expected Interrupt Level (for execution) :
33 *
34 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
35 * to be deferred to a worker thread context)
36 *
37 * Return Value: Does not matter!
38 *
39 *************************************************************************/
40 NTSTATUS NTAPI Ext2Cleanup(
41 PDEVICE_OBJECT DeviceObject, // the logical volume device object
42 PIRP Irp) // I/O Request Packet
43 {
44 NTSTATUS RC = STATUS_SUCCESS;
45 PtrExt2IrpContext PtrIrpContext = NULL;
46 BOOLEAN AreWeTopLevel = FALSE;
47
48 DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Cleanup IRP Received...", 0);
49
50 FsRtlEnterFileSystem();
51 ASSERT(DeviceObject);
52 ASSERT(Irp);
53
54 // set the top level context
55 AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
56
57 try
58 {
59
60 // get an IRP context structure and issue the request
61 PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
62 ASSERT(PtrIrpContext);
63
64 RC = Ext2CommonCleanup(PtrIrpContext, Irp, TRUE);
65
66 }
67 except( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) )
68 {
69
70 RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
71
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
73 }
74
75 if (AreWeTopLevel)
76 {
77 IoSetTopLevelIrp(NULL);
78 }
79
80 FsRtlExitFileSystem();
81
82 return(RC);
83 }
84
85 /*************************************************************************
86 *
87 * Function: Ext2CommonCleanup()
88 *
89 * Description:
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
94 *
95 * Expected Interrupt Level (for execution) :
96 *
97 * IRQL_PASSIVE_LEVEL
98 *
99 * Return Value: Does not matter!
100 *
101 *************************************************************************/
102 NTSTATUS NTAPI Ext2CommonCleanup(
103 PtrExt2IrpContext PtrIrpContext,
104 PIRP PtrIrp,
105 BOOLEAN FirstAttempt )
106 {
107
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;
116
117 BOOLEAN CompleteIrp = TRUE;
118 BOOLEAN PostRequest = FALSE;
119 BOOLEAN AcquiredVCB = FALSE;
120 BOOLEAN BlockForResource;
121 int i = 1;
122
123 try
124 {
125 // First, get a pointer to the current I/O stack location
126 PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
127 ASSERT(PtrIoStackLocation);
128
129 PtrFileObject = PtrIoStackLocation->FileObject;
130 ASSERT(PtrFileObject);
131
132 if( !PtrFileObject->FsContext2 )
133 {
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
137
138 DebugTrace( DEBUG_TRACE_MISC, " === Cleanup with NULL CCB", 0);
139 if( PtrFileObject )
140 {
141 DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
142 }
143 try_return();
144 }
145
146
147 Ext2GetFCB_CCB_VCB_FromFileObject (
148 PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
149
150 if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
151 //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer )
152 {
153 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
154 }
155 else
156 {
157 DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup Volume", 0);
158 }
159
160
161 PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
162 ASSERT(PtrVCB);
163 ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
164
165 // (a) Acquiring the VCBResource Exclusively...
166 // This is done to synchronise with the close and cleanup routines...
167 BlockForResource = !FirstAttempt;
168 if( !FirstAttempt )
169 {
170
171 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0);
172 }
173 else
174 {
175 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0);
176 }
177
178 if( PtrFileObject )
179 {
180 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
181 }
182
183 i = 1;
184 while( !AcquiredVCB )
185 {
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 ) )
188 {
189 DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Cleanup]", 0);
190 if( BlockForResource && i != 1000 )
191 {
192 LARGE_INTEGER Delay;
193 Delay.QuadPart = -500 * i;
194 KeDelayExecutionThread( KernelMode, FALSE, &Delay );
195 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i);
196 }
197 else
198 {
199 if( i == 1000 )
200 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 );
201 PostRequest = TRUE;
202 try_return( RC = STATUS_PENDING );
203 }
204 }
205 else
206 {
207 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired in [Cleanup]", 0);
208 AcquiredVCB = TRUE;
209 }
210 i *= 10;
211 }
212
213
214 // (b) Acquire the file (FCB) exclusively
215 if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB )
216 {
217 // This FCB is an FCB indeed. ;)
218 // So acquiring it exclusively...
219 // This is done to synchronise with read/write routines...
220 if( !FirstAttempt )
221 {
222 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0);
223 }
224 else
225 {
226 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0);
227 }
228 if( PtrFileObject )
229 {
230 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
231 }
232
233 i = 1;
234 while( !PtrResourceAcquired )
235 {
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 ) )
239 {
240 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Cleanup]", 0);
241 if( BlockForResource && i != 1000 )
242 {
243 LARGE_INTEGER Delay;
244 Delay.QuadPart = -500 * i;
245 KeDelayExecutionThread( KernelMode, FALSE, &Delay );
246 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i);
247 }
248 else
249 {
250 if( i == 1000 )
251 DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 );
252 PostRequest = TRUE;
253 try_return( RC = STATUS_PENDING );
254 }
255 }
256 else
257 {
258 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB acquired [Cleanup]", 0);
259 PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource );
260 }
261 i *= 10;
262 }
263
264 // (c) Flush file data to disk
265 if ( PtrFileObject->PrivateCacheMap != NULL)
266 {
267 IO_STATUS_BLOCK Status;
268 CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status );
269 }
270
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
273 // notification IRPs
274 // (f) Unlock byte-range locks (if any were acquired by process)
275
276 // (g) Attempting to update time stamp values
277 // Errors are ignored...
278 // Not considered as critical errors...
279
280 /*
281 if( PtrFCB->OpenHandleCount == 1 )
282 {
283 ULONG CreationTime, AccessTime, ModificationTime;
284 EXT2_INODE Inode;
285
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 ) ) )
293 {
294 // Update time stamps in the inode...
295 Inode.i_ctime = CreationTime;
296 Inode.i_atime = AccessTime;
297 Inode.i_mtime = ModificationTime;
298
299 // Updating the inode...
300 Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode );
301 }
302 }
303 */
304
305 // (h) Inform the Cache Manager to uninitialize Cache Maps ...
306 CcUninitializeCacheMap( PtrFileObject, NULL, NULL );
307
308 // (i) Decrementing the Open Handle count...
309 if( PtrFCB->OpenHandleCount )
310 {
311 InterlockedDecrement( &PtrFCB->OpenHandleCount );
312 }
313 else
314 {
315 Ext2BreakPoint();
316 }
317
318 PtrFCB->FCBFlags |= FO_CLEANUP_COMPLETE;
319
320 DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Cleanup]", PtrFCB->ReferenceCount );
321 DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB->OpenHandleCount );
322
323 // (j) Remove share access...
324 // Will do that later ;)
325
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 )
330 {
331 //
332 // Have to delete this file...
333 //
334 Ext2DeleteFile( PtrFCB, PtrIrpContext );
335 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = 0;
336 PtrFCB->INodeNo = 0;
337 }
338 }
339 else
340 {
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);
345 CompleteIrp = TRUE;
346 }
347
348 try_return();
349
350 try_exit: NOTHING;
351
352 }
353 finally
354 {
355 if(PtrResourceAcquired)
356 {
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 );
363
364 if( PtrFileObject )
365 {
366 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
367 }
368
369 }
370
371 if( AcquiredVCB )
372 {
373 ASSERT(PtrVCB);
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 );
377 AcquiredVCB = FALSE;
378 if( PtrFileObject )
379 {
380 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
381 }
382
383 }
384
385 if( PostRequest )
386 {
387 RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
388 }
389 if( RC != STATUS_PENDING )
390 {
391 Ext2ReleaseIrpContext( PtrIrpContext );
392 // complete the IRP
393 IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT );
394 }
395 } // end of "finally" processing
396
397 return(RC);
398 }