xref: /reactos/drivers/filesystems/ext2/src/flush.c (revision 40462c92)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             flush.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 
21 NTSTATUS NTAPI
22 Ext2FlushCompletionRoutine (
23     IN PDEVICE_OBJECT DeviceObject,
24     IN PIRP Irp,
25     IN PVOID Context  )
26 
27 {
28     if (Irp->PendingReturned)
29         IoMarkIrpPending( Irp );
30 
31 
32     if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST)
33         Irp->IoStatus.Status = STATUS_SUCCESS;
34 
35     return STATUS_SUCCESS;
36 }
37 
38 NTSTATUS
39 Ext2FlushVolume (
40     IN PEXT2_IRP_CONTEXT    IrpContext,
41     IN PEXT2_VCB            Vcb,
42     IN BOOLEAN              bShutDown
43 )
44 {
45     DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
46 
47     ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
48     ExReleaseResourceLite(&Vcb->PagingIoResource);
49 
50     return Ext2FlushVcb(Vcb);
51 }
52 
53 NTSTATUS
54 Ext2FlushFile (
55     IN PEXT2_IRP_CONTEXT    IrpContext,
56     IN PEXT2_FCB            Fcb,
57     IN PEXT2_CCB            Ccb
58 )
59 {
60     IO_STATUS_BLOCK     IoStatus = {0};
61 
62     ASSERT(Fcb != NULL);
63     ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
64            (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
65 
66     _SEH2_TRY {
67 
68         /* do nothing if target fie was deleted */
69         if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
70             IoStatus.Status = STATUS_FILE_DELETED;
71             _SEH2_LEAVE;
72         }
73 
74         /* update timestamp and achieve attribute */
75         if (Ccb != NULL) {
76 
77             if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
78 
79                 LARGE_INTEGER   SysTime;
80                 KeQuerySystemTime(&SysTime);
81 
82                 Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
83                 Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
84                 Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
85             }
86         }
87 
88         if (IsDirectory(Fcb)) {
89             IoStatus.Status = STATUS_SUCCESS;
90             _SEH2_LEAVE;
91         }
92 
93         DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
94                         Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
95 
96         CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
97         ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
98 
99     } _SEH2_FINALLY {
100 
101         /* do cleanup here */
102     } _SEH2_END;
103 
104     return IoStatus.Status;
105 }
106 
107 NTSTATUS
108 Ext2FlushFiles(
109     IN PEXT2_IRP_CONTEXT    IrpContext,
110     IN PEXT2_VCB            Vcb,
111     IN BOOLEAN              bShutDown
112 )
113 {
114     IO_STATUS_BLOCK    IoStatus;
115 
116     PEXT2_FCB       Fcb;
117     PLIST_ENTRY     ListEntry;
118 
119     if (IsVcbReadOnly(Vcb)) {
120         return STATUS_SUCCESS;
121     }
122 
123     IoStatus.Status = STATUS_SUCCESS;
124 
125     DEBUG(DL_INF, ( "Flushing Files ...\n"));
126 
127     // Flush all Fcbs in Vcb list queue.
128     for (ListEntry = Vcb->FcbList.Flink;
129             ListEntry != &Vcb->FcbList;
130             ListEntry = ListEntry->Flink ) {
131 
132         Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
133         ExAcquireResourceExclusiveLite(
134             &Fcb->MainResource, TRUE);
135         Ext2FlushFile(IrpContext, Fcb, NULL);
136         ExReleaseResourceLite(&Fcb->MainResource);
137     }
138 
139     return IoStatus.Status;
140 }
141 
142 
143 NTSTATUS
144 Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
145 {
146     NTSTATUS                Status = STATUS_SUCCESS;
147 
148     PIRP                    Irp = NULL;
149     PIO_STACK_LOCATION      IrpSp = NULL;
150 
151     PEXT2_VCB               Vcb = NULL;
152     PEXT2_FCB               Fcb = NULL;
153     PEXT2_FCBVCB            FcbOrVcb = NULL;
154     PEXT2_CCB               Ccb = NULL;
155     PFILE_OBJECT            FileObject = NULL;
156 
157     PDEVICE_OBJECT          DeviceObject = NULL;
158 
159     BOOLEAN                 MainResourceAcquired = FALSE;
160 
161     _SEH2_TRY {
162 
163         ASSERT(IrpContext);
164 
165         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
166                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
167 
168         DeviceObject = IrpContext->DeviceObject;
169 
170         //
171         // This request is not allowed on the main device object
172         //
173         if (IsExt2FsDevice(DeviceObject)) {
174             Status = STATUS_INVALID_DEVICE_REQUEST;
175             _SEH2_LEAVE;
176         }
177 
178         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
179         ASSERT(Vcb != NULL);
180         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
181                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
182 
183         ASSERT(IsMounted(Vcb));
184         if (IsVcbReadOnly(Vcb)) {
185             Status =  STATUS_SUCCESS;
186             _SEH2_LEAVE;
187         }
188 
189         Irp = IrpContext->Irp;
190         IrpSp = IoGetCurrentIrpStackLocation(Irp);
191 
192         FileObject = IrpContext->FileObject;
193         FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
194         ASSERT(FcbOrVcb != NULL);
195 
196         Ccb = (PEXT2_CCB) FileObject->FsContext2;
197         if (Ccb == NULL) {
198             Status =  STATUS_SUCCESS;
199             _SEH2_LEAVE;
200         }
201 
202         MainResourceAcquired =
203             ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
204         ASSERT(MainResourceAcquired);
205         DEBUG(DL_INF, ("Ext2Flush-pre:  total mcb records=%u\n",
206                        FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
207 
208         if (FcbOrVcb->Identifier.Type == EXT2VCB) {
209 
210             Ext2VerifyVcb(IrpContext, Vcb);
211             Status = Ext2FlushFiles(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
212             if (NT_SUCCESS(Status)) {
213                 _SEH2_LEAVE;
214             }
215 
216             Status = Ext2FlushVolume(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
217 
218             if (NT_SUCCESS(Status) && IsFlagOn(Vcb->Volume->Flags, FO_FILE_MODIFIED)) {
219                 ClearFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
220             }
221 
222         } else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
223 
224             Fcb = (PEXT2_FCB)(FcbOrVcb);
225 
226             Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
227             if (NT_SUCCESS(Status)) {
228                 if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
229                     Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
230                     ClearFlag(FileObject->Flags, FO_FILE_MODIFIED);
231                 }
232             }
233         }
234 
235         DEBUG(DL_INF, ("Ext2Flush-post: total mcb records=%u\n",
236                        FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
237 
238 
239     } _SEH2_FINALLY {
240 
241         if (MainResourceAcquired) {
242             ExReleaseResourceLite(&FcbOrVcb->MainResource);
243         }
244 
245         if (!IrpContext->ExceptionInProgress) {
246 
247             if (Vcb && Irp && IrpSp && !IsVcbReadOnly(Vcb)) {
248 
249                 // Call the disk driver to flush the physial media.
250                 NTSTATUS DriverStatus;
251                 PIO_STACK_LOCATION NextIrpSp;
252 
253                 NextIrpSp = IoGetNextIrpStackLocation(Irp);
254 
255                 *NextIrpSp = *IrpSp;
256 
257                 IoSetCompletionRoutine( Irp,
258                                         Ext2FlushCompletionRoutine,
259                                         NULL,
260                                         TRUE,
261                                         TRUE,
262                                         TRUE );
263 
264                 DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
265 
266                 Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
267                          Status : DriverStatus;
268 
269                 IrpContext->Irp = Irp = NULL;
270             }
271 
272             Ext2CompleteIrpContext(IrpContext, Status);
273         }
274     } _SEH2_END;
275 
276     return Status;
277 }
278