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