xref: /reactos/drivers/filesystems/ext2/src/cleanup.c (revision 40462c92)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             cleanup.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 extern PEXT2_GLOBAL Ext2Global;
17 
18 /* DEFINITIONS *************************************************************/
19 
20 NTSTATUS
21 Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
22 {
23     PDEVICE_OBJECT  DeviceObject;
24     NTSTATUS        Status = STATUS_SUCCESS;
25     PEXT2_VCB       Vcb = NULL;
26     PFILE_OBJECT    FileObject;
27     PEXT2_FCB       Fcb = NULL;
28     PEXT2_CCB       Ccb = NULL;
29     PIRP            Irp = NULL;
30     PEXT2_MCB       Mcb = NULL;
31 
32 
33     BOOLEAN         VcbResourceAcquired = FALSE;
34     BOOLEAN         FcbResourceAcquired = FALSE;
35     BOOLEAN         FcbPagingIoResourceAcquired = FALSE;
36     BOOLEAN         SymLinkDelete = FALSE;
37 
38     _SEH2_TRY {
39 
40         ASSERT(IrpContext != NULL);
41         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
42                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
43 
44         DeviceObject = IrpContext->DeviceObject;
45         if (IsExt2FsDevice(DeviceObject))  {
46             Status = STATUS_SUCCESS;
47             _SEH2_LEAVE;
48         }
49 
50         Irp = IrpContext->Irp;
51         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
52         ASSERT(Vcb != NULL);
53         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
54                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
55 
56         if (!IsVcbInited(Vcb)) {
57             Status = STATUS_SUCCESS;
58             _SEH2_LEAVE;
59         }
60 
61         FileObject = IrpContext->FileObject;
62         Fcb = (PEXT2_FCB) FileObject->FsContext;
63         if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
64                      Fcb->Identifier.Type != EXT2FCB)) {
65             Status = STATUS_SUCCESS;
66             _SEH2_LEAVE;
67         }
68         Mcb = Fcb->Mcb;
69         Ccb = (PEXT2_CCB) FileObject->FsContext2;
70 
71         if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
72             Status = STATUS_SUCCESS;
73             _SEH2_LEAVE;
74         }
75 
76         if (Fcb->Identifier.Type == EXT2VCB) {
77 
78             ExAcquireResourceExclusiveLite(
79                     &Vcb->MainResource, TRUE);
80             VcbResourceAcquired = TRUE;
81 
82             if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
83                 Vcb->LockFile == FileObject ){
84 
85                 ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
86                 Vcb->LockFile = NULL;
87                 Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
88             }
89 
90             if (Ccb) {
91                 Ext2DerefXcb(&Vcb->OpenHandleCount);
92                 Ext2DerefXcb(&Vcb->OpenVolumeCount);
93             }
94 
95             IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
96 
97             Status = STATUS_SUCCESS;
98             _SEH2_LEAVE;
99         }
100 
101         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
102                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
103 
104         FcbResourceAcquired =
105             ExAcquireResourceExclusiveLite(
106                 &Fcb->MainResource,
107                 TRUE
108             );
109 
110         if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
111             if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
112                     IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
113                     !IsVcbReadOnly(Vcb) ) {
114                 Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
115             }
116             _SEH2_LEAVE;
117         }
118 
119         if (Ccb == NULL) {
120             Status = STATUS_SUCCESS;
121             _SEH2_LEAVE;
122         }
123 
124         if (IsDirectory(Fcb)) {
125             if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
126                 SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
127 
128                 FsRtlNotifyFullChangeDirectory(
129                     Vcb->NotifySync,
130                     &Vcb->NotifyList,
131                     Ccb,
132                     NULL,
133                     FALSE,
134                     FALSE,
135                     0,
136                     NULL,
137                     NULL,
138                     NULL );
139             }
140 
141             FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);
142         }
143 
144         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
145                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
146 
147         Ext2DerefXcb(&Vcb->OpenHandleCount);
148         Ext2DerefXcb(&Fcb->OpenHandleCount);
149 
150         if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
151             Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
152         }
153 
154         if (IsDirectory(Fcb)) {
155 
156             ext3_release_dir(Fcb->Inode, &Ccb->filp);
157 
158         } else {
159 
160             if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
161                     !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
162 
163                 LARGE_INTEGER   SysTime;
164                 KeQuerySystemTime(&SysTime);
165 
166                 Fcb->Inode->i_atime =
167                     Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
168                 Fcb->Mcb->LastAccessTime =
169                     Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);
170 
171                 Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
172 
173                 Ext2NotifyReportChange(
174                     IrpContext,
175                     Vcb,
176                     Fcb->Mcb,
177                     FILE_NOTIFY_CHANGE_ATTRIBUTES |
178                     FILE_NOTIFY_CHANGE_LAST_WRITE |
179                     FILE_NOTIFY_CHANGE_LAST_ACCESS,
180                     FILE_ACTION_MODIFIED );
181             }
182 
183             FsRtlCheckOplock( &Fcb->Oplock,
184                               Irp,
185                               IrpContext,
186                               NULL,
187                               NULL );
188 
189             Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
190 
191             if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
192                 Fcb->NonCachedOpenCount--;
193             }
194 
195             if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
196                 if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
197                     SymLinkDelete = TRUE;
198                 } else {
199                     SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
200                 }
201             }
202 
203             //
204             // Drop any byte range locks this process may have on the file.
205             //
206 
207             FsRtlFastUnlockAll(
208                 &Fcb->FileLockAnchor,
209                 FileObject,
210                 IoGetRequestorProcess(Irp),
211                 NULL  );
212 
213             //
214             // If there are no byte range locks owned by other processes on the
215             // file the fast I/O read/write functions doesn't have to check for
216             // locks so we set IsFastIoPossible to FastIoIsPossible again.
217             //
218             if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
219                 if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
220 #if EXT2_DEBUG
221                     DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
222                                    Ext2GetCurrentProcessName(),
223                                    "FastIoIsPossible",
224                                    &Fcb->Mcb->FullName
225                                   ));
226 #endif
227 
228                     Fcb->Header.IsFastIoPossible = FastIoIsPossible;
229                 }
230             }
231 
232             if (Fcb->OpenHandleCount == 0 && FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE |
233                                                                 FCB_ALLOC_IN_SETINFO) ){
234 
235                 if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_SETINFO)) {
236                     if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
237                         if (!INODE_HAS_EXTENT(Fcb->Inode)) {
238                         #if EXT2_PRE_ALLOCATION_SUPPORT
239                             _SEH2_TRY {
240                                 CcZeroData( FileObject,
241                                            &Fcb->Header.ValidDataLength,
242                                            &Fcb->Header.AllocationSize,
243                                            TRUE);
244                             } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
245                                 DbgBreak();
246                             } _SEH2_END;
247                         #endif
248                         }
249                     }
250                 }
251 
252                 if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
253 
254                     LARGE_INTEGER Size;
255 
256                     ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
257                     FcbPagingIoResourceAcquired = TRUE;
258 
259                     Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
260                                                     (ULONGLONG)Fcb->Mcb->Inode.i_size,
261                                                     (ULONGLONG)BLOCK_SIZE);
262                     if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
263 
264                         Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
265                         Fcb->Header.AllocationSize = Size;
266                         Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
267                         if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart)
268                             Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
269                         if (CcIsFileCached(FileObject)) {
270                             CcSetFileSizes(FileObject,
271                                            (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
272                         }
273                     }
274                     ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE|FCB_ALLOC_IN_SETINFO);
275                     ExReleaseResourceLite(&Fcb->PagingIoResource);
276                     FcbPagingIoResourceAcquired = FALSE;
277                 }
278             }
279         }
280 
281         IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
282 
283         if (!IsDirectory(Fcb)) {
284 
285             if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
286                     (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
287                     (Fcb->SectionObject.DataSectionObject != NULL)) {
288 
289                 if (!IsVcbReadOnly(Vcb)) {
290                     CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
291                     ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
292                 }
293 
294                 /* purge cache if all remaining openings are non-cached */
295                 if (Fcb->NonCachedOpenCount > 0 ||
296                     IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
297                     if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
298                         ExReleaseResourceLite(&(Fcb->PagingIoResource));
299                     }
300 
301                     /* CcPurge could generate recursive IRP_MJ_CLOSE request */
302                     CcPurgeCacheSection( &Fcb->SectionObject,
303                                          NULL,
304                                          0,
305                                          FALSE );
306                 }
307             }
308 
309             CcUninitializeCacheMap(FileObject, NULL, NULL);
310         }
311 
312         if (SymLinkDelete ||
313             (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
314              Fcb->OpenHandleCount == 0) ) {
315 
316             //
317             // Ext2DeleteFile will acquire these lock inside
318             //
319 
320             if (FcbResourceAcquired) {
321                 ExReleaseResourceLite(&Fcb->MainResource);
322                 FcbResourceAcquired = FALSE;
323             }
324 
325             //
326             //  this file is to be deleted ...
327             //
328             if (Ccb->SymLink) {
329                 Mcb = Ccb->SymLink;
330                 FileObject->DeletePending = FALSE;
331             }
332 
333             Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
334 
335             if (NT_SUCCESS(Status)) {
336                 if (IsMcbDirectory(Mcb)) {
337                     Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
338                                             FILE_NOTIFY_CHANGE_DIR_NAME,
339                                             FILE_ACTION_REMOVED );
340                 } else {
341                     Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
342                                             FILE_NOTIFY_CHANGE_FILE_NAME,
343                                             FILE_ACTION_REMOVED );
344                 }
345             }
346 
347             //
348             // re-acquire the main resource lock
349             //
350 
351             FcbResourceAcquired =
352                 ExAcquireResourceExclusiveLite(
353                     &Fcb->MainResource,
354                     TRUE
355                 );
356             if (!SymLinkDelete) {
357                  SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
358                 if (CcIsFileCached(FileObject)) {
359                     CcSetFileSizes(FileObject,
360                                    (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
361                 }
362             }
363         }
364 
365         DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
366                         Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));
367 
368         Status = STATUS_SUCCESS;
369 
370         if (FileObject) {
371             SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
372         }
373 
374     } _SEH2_FINALLY {
375 
376         if (FcbPagingIoResourceAcquired) {
377             ExReleaseResourceLite(&Fcb->PagingIoResource);
378         }
379 
380         if (FcbResourceAcquired) {
381             ExReleaseResourceLite(&Fcb->MainResource);
382         }
383 
384         if (VcbResourceAcquired) {
385             ExReleaseResourceLite(&Vcb->MainResource);
386         }
387 
388         if (!IrpContext->ExceptionInProgress) {
389             if (Status == STATUS_PENDING) {
390                 Ext2QueueRequest(IrpContext);
391             } else {
392                 IrpContext->Irp->IoStatus.Status = Status;
393                 Ext2CompleteIrpContext(IrpContext, Status);
394             }
395         }
396     } _SEH2_END;
397 
398     return Status;
399 }
400