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