xref: /reactos/drivers/filesystems/ext2/src/close.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             close.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 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2QueueCloseRequest)
22 #pragma alloc_text(PAGE, Ext2DeQueueCloseRequest)
23 #endif
24 
25 NTSTATUS
Ext2Close(IN PEXT2_IRP_CONTEXT IrpContext)26 Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
27 {
28     PDEVICE_OBJECT  DeviceObject;
29     NTSTATUS        Status = STATUS_SUCCESS;
30     PEXT2_VCB       Vcb = NULL;
31     PFILE_OBJECT    FileObject;
32     PEXT2_FCB       Fcb = NULL;
33     PEXT2_CCB       Ccb = NULL;
34 
35     BOOLEAN         VcbResourceAcquired = FALSE;
36     BOOLEAN         FcbResourceAcquired = FALSE;
37     BOOLEAN         FcbDerefDeferred = FALSE;
38 
39     _SEH2_TRY {
40 
41         ASSERT(IrpContext != NULL);
42         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
43                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
44 
45         DeviceObject = IrpContext->DeviceObject;
46         if (IsExt2FsDevice(DeviceObject)) {
47             Status = STATUS_SUCCESS;
48             Vcb = NULL;
49             _SEH2_LEAVE;
50         }
51 
52         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
53         ASSERT(Vcb != NULL);
54         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
55                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
56 
57         if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
58 
59             FileObject = NULL;
60             Fcb = IrpContext->Fcb;
61             Ccb = IrpContext->Ccb;
62 
63         } else {
64 
65             FileObject = IrpContext->FileObject;
66             Fcb = (PEXT2_FCB) FileObject->FsContext;
67             if (!Fcb) {
68                 Status = STATUS_SUCCESS;
69                 _SEH2_LEAVE;
70             }
71             ASSERT(Fcb != NULL);
72             Ccb = (PEXT2_CCB) FileObject->FsContext2;
73         }
74 
75         DEBUG(DL_INF, ( "Ext2Close: (VCB) Vcb = %p ReferCount = %d\n",
76                          Vcb, Vcb->ReferenceCount));
77 
78         /*
79          * WARNING: don't release Vcb resource lock here.
80          *
81          *  CcPurgeCacheSection will lead a recursive irp: IRP_MJ_CLOSE
82          *  which would cause revrese order of lock acquirision:
83          *  1) IRP_MJ_CLEANUP: a) Vcb lock -> b) Fcb lock
84          *  2) IRP_MJ_CLOSE:   c) Vcb lock -> d) Fcb lock
85          */
86 
87         if (Fcb->Identifier.Type == EXT2VCB) {
88 
89             if (!ExAcquireResourceExclusiveLite(
90                             &Vcb->MainResource,
91                             TRUE )) {
92                 DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
93                                    Vcb->OpenHandleCount, Vcb->ReferenceCount));
94                 Status = STATUS_PENDING;
95                 _SEH2_LEAVE;
96             }
97             VcbResourceAcquired = TRUE;
98 
99             if (Ccb) {
100 
101                 Ext2DerefXcb(&Vcb->ReferenceCount);
102                 Ext2FreeCcb(Vcb, Ccb);
103 
104                 if (FileObject) {
105                     FileObject->FsContext2 = Ccb = NULL;
106                 }
107             }
108 
109             Status = STATUS_SUCCESS;
110             _SEH2_LEAVE;
111         }
112 
113         if ( Fcb->Identifier.Type != EXT2FCB ||
114              Fcb->Identifier.Size != sizeof(EXT2_FCB)) {
115             _SEH2_LEAVE;
116         }
117 
118         if (!ExAcquireResourceExclusiveLite(
119                     &Fcb->MainResource,
120                     TRUE )) {
121             Status = STATUS_PENDING;
122             _SEH2_LEAVE;
123         }
124         FcbResourceAcquired = TRUE;
125 
126         Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
127 
128         if (Ccb == NULL ||
129             Ccb->Identifier.Type != EXT2CCB ||
130             Ccb->Identifier.Size != sizeof(EXT2_CCB)) {
131             Status = STATUS_SUCCESS;
132             _SEH2_LEAVE;
133         }
134 
135         DEBUG(DL_INF, ( "Ext2Close: Fcb = %p OpenHandleCount= %u ReferenceCount=%u NonCachedCount=%u %wZ\n",
136                         Fcb, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName ));
137 
138         Ext2FreeCcb(Vcb, Ccb);
139         if (FileObject) {
140             FileObject->FsContext2 = Ccb = NULL;
141         }
142 
143         /* only deref fcb, Ext2ReleaseFcb might lead deadlock */
144         FcbDerefDeferred = TRUE;
145         if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
146             NULL == Fcb->Mcb ||
147             IsFileDeleted(Fcb->Mcb)) {
148             Fcb->TsDrop.QuadPart = 0;
149         } else {
150             KeQuerySystemTime(&Fcb->TsDrop);
151         }
152         Ext2DerefXcb(&Vcb->ReferenceCount);
153 
154         if (FileObject) {
155             FileObject->FsContext = NULL;
156         }
157 
158         Status = STATUS_SUCCESS;
159 
160     } _SEH2_FINALLY {
161 
162         if (FcbResourceAcquired) {
163             ExReleaseResourceLite(&Fcb->MainResource);
164         }
165 
166         if (VcbResourceAcquired) {
167             ExReleaseResourceLite(&Vcb->MainResource);
168         }
169 
170         if (!IrpContext->ExceptionInProgress) {
171 
172             if (Status == STATUS_PENDING) {
173 
174                 Ext2QueueCloseRequest(IrpContext);
175 
176             } else {
177 
178                 Ext2CompleteIrpContext(IrpContext, Status);
179             }
180         }
181 
182         if (FcbDerefDeferred)
183             Ext2DerefXcb(&Fcb->ReferenceCount);
184     } _SEH2_END;
185 
186     return Status;
187 }
188 
189 VOID
Ext2QueueCloseRequest(IN PEXT2_IRP_CONTEXT IrpContext)190 Ext2QueueCloseRequest (IN PEXT2_IRP_CONTEXT IrpContext)
191 {
192     ASSERT(IrpContext);
193     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
194            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
195 
196     if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
197 
198         if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_FILE_BUSY)) {
199             Ext2Sleep(500); /* 0.5 sec*/
200         } else {
201             Ext2Sleep(50);  /* 0.05 sec*/
202         }
203 
204     } else {
205 
206         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
207         SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE);
208 
209         IrpContext->Fcb = (PEXT2_FCB) IrpContext->FileObject->FsContext;
210         IrpContext->Ccb = (PEXT2_CCB) IrpContext->FileObject->FsContext2;
211     }
212 
213     ExInitializeWorkItem(
214         &IrpContext->WorkQueueItem,
215         Ext2DeQueueCloseRequest,
216         IrpContext);
217 
218     ExQueueWorkItem(&IrpContext->WorkQueueItem, DelayedWorkQueue);
219 }
220 
221 VOID NTAPI
Ext2DeQueueCloseRequest(IN PVOID Context)222 Ext2DeQueueCloseRequest (IN PVOID Context)
223 {
224     PEXT2_IRP_CONTEXT IrpContext;
225 
226     IrpContext = (PEXT2_IRP_CONTEXT) Context;
227     ASSERT(IrpContext);
228     ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
229            (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
230 
231     _SEH2_TRY {
232 
233         _SEH2_TRY {
234 
235             FsRtlEnterFileSystem();
236             Ext2Close(IrpContext);
237 
238         } _SEH2_EXCEPT (Ext2ExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) {
239 
240             Ext2ExceptionHandler(IrpContext);
241         } _SEH2_END;
242 
243     } _SEH2_FINALLY {
244 
245         FsRtlExitFileSystem();
246     } _SEH2_END;
247 }
248