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