[NTFS]
[reactos.git] / 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 /* acquire gd lock to avoid gd/bh creation */
88 ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
89
90 /* discard buffer_headers for group_desc */
91 Ext2DropBH(Vcb);
92
93 /* do flushing */
94 CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
95
96 /* release gd lock */
97 ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
98
99 return IoStatus.Status;
100 }
101
102 NTSTATUS
103 Ext2FlushFile (
104 IN PEXT2_IRP_CONTEXT IrpContext,
105 IN PEXT2_FCB Fcb,
106 IN PEXT2_CCB Ccb
107 )
108 {
109 IO_STATUS_BLOCK IoStatus;
110
111 ASSERT(Fcb != NULL);
112 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
113 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
114
115 _SEH2_TRY {
116
117 /* update timestamp and achieve attribute */
118 if (Ccb != NULL) {
119
120 if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
121
122 LARGE_INTEGER SysTime;
123 KeQuerySystemTime(&SysTime);
124
125 Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
126 Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
127 Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
128 }
129 }
130
131 if (IsDirectory(Fcb)) {
132 IoStatus.Status = STATUS_SUCCESS;
133 _SEH2_LEAVE;
134 }
135
136 DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
137 Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
138
139 CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
140 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
141
142 } _SEH2_FINALLY {
143
144 /* do cleanup here */
145 } _SEH2_END;
146
147 return IoStatus.Status;
148 }
149
150
151 NTSTATUS
152 Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
153 {
154 NTSTATUS Status = STATUS_SUCCESS;
155
156 PIRP Irp = NULL;
157 PIO_STACK_LOCATION IrpSp = NULL;
158
159 PEXT2_VCB Vcb = NULL;
160 PEXT2_FCB Fcb = NULL;
161 PEXT2_FCBVCB FcbOrVcb = NULL;
162 PEXT2_CCB Ccb = NULL;
163 PFILE_OBJECT FileObject = NULL;
164
165 PDEVICE_OBJECT DeviceObject = NULL;
166
167 BOOLEAN MainResourceAcquired = FALSE;
168
169 _SEH2_TRY {
170
171 ASSERT(IrpContext);
172
173 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
174 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
175
176 DeviceObject = IrpContext->DeviceObject;
177
178 //
179 // This request is not allowed on the main device object
180 //
181 if (IsExt2FsDevice(DeviceObject)) {
182 Status = STATUS_INVALID_DEVICE_REQUEST;
183 _SEH2_LEAVE;
184 }
185
186 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
187 ASSERT(Vcb != NULL);
188 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
189 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
190
191 ASSERT(IsMounted(Vcb));
192 if (IsVcbReadOnly(Vcb)) {
193 Status = STATUS_SUCCESS;
194 _SEH2_LEAVE;
195 }
196
197 Irp = IrpContext->Irp;
198 IrpSp = IoGetCurrentIrpStackLocation(Irp);
199
200 FileObject = IrpContext->FileObject;
201 FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
202 ASSERT(FcbOrVcb != NULL);
203
204 Ccb = (PEXT2_CCB) FileObject->FsContext2;
205 if (Ccb == NULL) {
206 Status = STATUS_SUCCESS;
207 _SEH2_LEAVE;
208 }
209
210 MainResourceAcquired =
211 ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
212 ASSERT(MainResourceAcquired);
213 DEBUG(DL_INF, ("Ext2Flush-pre: total mcb records=%u\n",
214 FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
215
216 if (FcbOrVcb->Identifier.Type == EXT2VCB) {
217
218 Ext2VerifyVcb(IrpContext, Vcb);
219 Status = Ext2FlushFiles(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
220 if (NT_SUCCESS(Status)) {
221 _SEH2_LEAVE;
222 }
223
224 Status = Ext2FlushVolume(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
225
226 if (NT_SUCCESS(Status) && IsFlagOn(Vcb->Volume->Flags, FO_FILE_MODIFIED)) {
227 ClearFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
228 }
229
230 } else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
231
232 Fcb = (PEXT2_FCB)(FcbOrVcb);
233
234 Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
235 if (NT_SUCCESS(Status)) {
236 if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
237 Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
238 ClearFlag(FileObject->Flags, FO_FILE_MODIFIED);
239 }
240 }
241 }
242
243 DEBUG(DL_INF, ("Ext2Flush-post: total mcb records=%u\n",
244 FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
245
246
247 } _SEH2_FINALLY {
248
249 if (MainResourceAcquired) {
250 ExReleaseResourceLite(&FcbOrVcb->MainResource);
251 }
252
253 if (!IrpContext->ExceptionInProgress) {
254
255 if (Vcb && Irp && IrpSp && !IsVcbReadOnly(Vcb)) {
256
257 // Call the disk driver to flush the physial media.
258 NTSTATUS DriverStatus;
259 PIO_STACK_LOCATION NextIrpSp;
260
261 NextIrpSp = IoGetNextIrpStackLocation(Irp);
262
263 *NextIrpSp = *IrpSp;
264
265 IoSetCompletionRoutine( Irp,
266 Ext2FlushCompletionRoutine,
267 NULL,
268 TRUE,
269 TRUE,
270 TRUE );
271
272 DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
273
274 Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
275 Status : DriverStatus;
276
277 IrpContext->Irp = Irp = NULL;
278 }
279
280 Ext2CompleteIrpContext(IrpContext, Status);
281 }
282 } _SEH2_END;
283
284 return Status;
285 }