xref: /reactos/drivers/filesystems/udfs/flush.cpp (revision c2c66aff)
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: Flush.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 *   Contains code to handle the "Flush Buffers" dispatch entry point.
14 *
15 *************************************************************************/
16 
17 #include            "udffs.h"
18 
19 // define the file specific bug-check id
20 #define         UDF_BUG_CHECK_ID                UDF_FILE_FLUSH
21 
22 
23 
24 /*************************************************************************
25 *
26 * Function: UDFFlush()
27 *
28 * Description:
29 *   The I/O Manager will invoke this routine to handle a flush buffers
30 *   request
31 *
32 * Expected Interrupt Level (for execution) :
33 *
34 *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
35 *   to be deferred to a worker thread context)
36 *
37 * Return Value: STATUS_SUCCESS/Error
38 *
39 *************************************************************************/
40 NTSTATUS
41 NTAPI
UDFFlush(PDEVICE_OBJECT DeviceObject,PIRP Irp)42 UDFFlush(
43     PDEVICE_OBJECT      DeviceObject,       // the logical volume device object
44     PIRP                Irp)                // I/O Request Packet
45 {
46     NTSTATUS            RC = STATUS_SUCCESS;
47     PtrUDFIrpContext    PtrIrpContext = NULL;
48     BOOLEAN             AreWeTopLevel = FALSE;
49 
50     UDFPrint(("UDFFlush: \n"));
51 
52     FsRtlEnterFileSystem();
53     ASSERT(DeviceObject);
54     ASSERT(Irp);
55 
56     // set the top level context
57     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
58     ASSERT(!UDFIsFSDevObj(DeviceObject));
59 
60     _SEH2_TRY {
61 
62         // get an IRP context structure and issue the request
63         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
64         if(PtrIrpContext) {
65             RC = UDFCommonFlush(PtrIrpContext, Irp);
66         } else {
67             RC = STATUS_INSUFFICIENT_RESOURCES;
68             Irp->IoStatus.Status = RC;
69             Irp->IoStatus.Information = 0;
70             // complete the IRP
71             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
72         }
73 
74     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
75 
76         RC = UDFExceptionHandler(PtrIrpContext, Irp);
77 
78         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
79     } _SEH2_END;
80 
81     if (AreWeTopLevel) {
82         IoSetTopLevelIrp(NULL);
83     }
84 
85     FsRtlExitFileSystem();
86 
87     return(RC);
88 } // end UDFFlush()
89 
90 
91 
92 /*************************************************************************
93 *
94 * Function: UDFCommonFlush()
95 *
96 * Description:
97 *   The actual work is performed here. This routine may be invoked in one'
98 *   of the two possible contexts:
99 *   (a) in the context of a system worker thread
100 *   (b) in the context of the original caller
101 *
102 * Expected Interrupt Level (for execution) :
103 *
104 *  IRQL_PASSIVE_LEVEL
105 *
106 * Return Value: STATUS_SUCCESS/Error
107 *
108 *************************************************************************/
109 NTSTATUS
UDFCommonFlush(PtrUDFIrpContext PtrIrpContext,PIRP Irp)110 UDFCommonFlush(
111     PtrUDFIrpContext PtrIrpContext,
112     PIRP             Irp
113     )
114 {
115     NTSTATUS            RC = STATUS_SUCCESS;
116     PIO_STACK_LOCATION  IrpSp = NULL;
117     PFILE_OBJECT        FileObject = NULL;
118     PtrUDFFCB           Fcb = NULL;
119     PtrUDFCCB           Ccb = NULL;
120     PVCB                Vcb = NULL;
121     PtrUDFNTRequiredFCB NtReqFcb = NULL;
122     BOOLEAN             AcquiredVCB = FALSE;
123     BOOLEAN             AcquiredFCB = FALSE;
124     BOOLEAN             PostRequest = FALSE;
125     BOOLEAN             CanWait = TRUE;
126 
127     UDFPrint(("UDFCommonFlush: \n"));
128 
129     _SEH2_TRY {
130 
131         // Get some of the parameters supplied to us
132         CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
133         // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous.
134         if (!CanWait) {
135             PostRequest = TRUE;
136             try_return(RC);
137         }
138 
139         // First, get a pointer to the current I/O stack location
140         IrpSp = IoGetCurrentIrpStackLocation(Irp);
141         ASSERT(IrpSp);
142 
143         FileObject = IrpSp->FileObject;
144         ASSERT(FileObject);
145 
146         // Get the FCB and CCB pointers
147         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
148         ASSERT(Ccb);
149         Fcb = Ccb->Fcb;
150         ASSERT(Fcb);
151         NtReqFcb = Fcb->NTRequiredFCB;
152 
153         // Check the type of object passed-in. That will determine the course of
154         // action we take.
155         if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || (Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) {
156 
157             if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
158                 Vcb = (PVCB)(Fcb);
159             } else {
160                 Vcb = Fcb->Vcb;
161             }
162             Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
163 
164 #ifdef UDF_DELAYED_CLOSE
165             UDFCloseAllDelayed(Vcb);
166 #endif //UDF_DELAYED_CLOSE
167 
168             UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
169             AcquiredVCB = TRUE;
170             // The caller wishes to flush all files for the mounted
171             // logical volume. The flush volume routine below should simply
172             // walk through all of the open file streams, acquire the
173             // VCB resource, and request the flush operation from the Cache
174             // Manager. Basically, the sequence of operations listed below
175             // for a single file should be executed on all open files.
176 
177             UDFFlushLogicalVolume(PtrIrpContext, Irp, Vcb, 0);
178 
179             UDFReleaseResource(&(Vcb->VCBResource));
180             AcquiredVCB = FALSE;
181 
182             try_return(RC);
183         } else
184         if (!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
185             // This is a regular file.
186             Vcb = Fcb->Vcb;
187             ASSERT(Vcb);
188             if(!ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) &&
189                !ExIsResourceAcquiredSharedLite(&(Vcb->VCBResource))) {
190                 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
191                 AcquiredVCB = TRUE;
192             }
193             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
194             UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE);
195             AcquiredFCB = TRUE;
196 
197             // Request the Cache Manager to perform a flush operation.
198             // Further, instruct the Cache Manager that we wish to flush the
199             // entire file stream.
200             UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0);
201             RC = Irp->IoStatus.Status;
202 
203             // Some log-based FSD implementations may wish to flush their
204             // log files at this time. Finally, we should update the time-stamp
205             // values for the file stream appropriately. This would involve
206             // obtaining the current time and modifying the appropriate directory
207             // entry fields.
208         } else {
209             Vcb = Fcb->Vcb;
210         }
211 
212 try_exit:   NOTHING;
213 
214     } _SEH2_FINALLY {
215 
216         if (AcquiredFCB) {
217             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
218             UDFReleaseResource(&(NtReqFcb->MainResource));
219             AcquiredFCB = FALSE;
220         }
221         if (AcquiredVCB) {
222             UDFReleaseResource(&(Vcb->VCBResource));
223             AcquiredVCB = FALSE;
224         }
225 
226         if(!_SEH2_AbnormalTermination()) {
227             if (PostRequest) {
228                 // Nothing to lock now.
229                 BrutePoint();
230                 RC = UDFPostRequest(PtrIrpContext, Irp);
231             } else {
232                 // Some applications like this request very much
233                 // (ex. WinWord). But it's not a good idea for CD-R/RW media
234                 if(Vcb->FlushMedia) {
235                     PIO_STACK_LOCATION      PtrNextIoStackLocation = NULL;
236                     NTSTATUS                RC1 = STATUS_SUCCESS;
237 
238                     // Send the request down at this point.
239                     // To do this, we must set the next IRP stack location, and
240                     // maybe set a completion routine.
241                     // Be careful about marking the IRP pending if the lower level
242                     // driver returned pending and we do have a completion routine!
243                     PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp);
244                     *PtrNextIoStackLocation = *IrpSp;
245 
246                     // Set the completion routine to "eat-up" any
247                     // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower
248                     // level driver.
249                     IoSetCompletionRoutine(Irp, UDFFlushCompletion, NULL, TRUE, TRUE, TRUE);
250 
251                     RC1 = IoCallDriver(Vcb->TargetDeviceObject, Irp);
252 
253                     RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1);
254 
255                     // Release the IRP context at this time.
256                     UDFReleaseIrpContext(PtrIrpContext);
257                 } else {
258                     Irp->IoStatus.Status = RC;
259                     Irp->IoStatus.Information = 0;
260                     // Free up the Irp Context
261                     UDFReleaseIrpContext(PtrIrpContext);
262                     // complete the IRP
263                     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
264                 }
265             }
266         }
267     } _SEH2_END;
268 
269     return(RC);
270 } // end UDFCommonFlush()
271 
272 
273 /*************************************************************************
274 *
275 * Function: UDFFlushAFile()
276 *
277 * Description:
278 *   Tell the Cache Manager to perform a flush.
279 *
280 * Expected Interrupt Level (for execution) :
281 *
282 *  IRQL_PASSIVE_LEVEL
283 *
284 * Return Value: None
285 *
286 *************************************************************************/
287 ULONG
UDFFlushAFile(IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,OUT PIO_STATUS_BLOCK PtrIoStatus,IN ULONG FlushFlags)288 UDFFlushAFile(
289     IN PtrUDFFCB           Fcb,
290     IN PtrUDFCCB           Ccb,
291     OUT PIO_STATUS_BLOCK   PtrIoStatus,
292     IN ULONG               FlushFlags
293     )
294 {
295     BOOLEAN SetArchive = FALSE;
296 //    BOOLEAN PurgeCache = FALSE;
297     ULONG ret_val = 0;
298 
299     UDFPrint(("UDFFlushAFile: \n"));
300     if(!Fcb)
301         return 0;
302 
303     _SEH2_TRY {
304         if(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
305             return 0;
306     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
307         BrutePoint();
308     } _SEH2_END;
309 #ifndef UDF_READ_ONLY_BUILD
310     // Flush Security if required
311     _SEH2_TRY {
312         UDFWriteSecurity(Fcb->Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
313     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
314         BrutePoint();
315     } _SEH2_END;
316 #endif //UDF_READ_ONLY_BUILD
317     // Flush SDir if any
318     _SEH2_TRY {
319         if(UDFHasAStreamDir(Fcb->FileInfo) &&
320            Fcb->FileInfo->Dloc->SDirInfo &&
321            !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) ) {
322             ret_val |=
323                 UDFFlushADirectory(Fcb->Vcb, Fcb->FileInfo->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
324         }
325     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
326         BrutePoint();
327     } _SEH2_END;
328     // Flush File
329     _SEH2_TRY {
330         if((Fcb->CachedOpenHandleCount || !Fcb->OpenHandleCount) &&
331             Fcb->NTRequiredFCB->SectionObject.DataSectionObject) {
332             if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)
333                                          &&
334                 ((Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED) ||
335                  (Ccb && !(Ccb->CCBFlags & UDF_CCB_FLUSHED)) )) {
336                 MmPrint(("    CcFlushCache()\n"));
337                 CcFlushCache(&(Fcb->NTRequiredFCB->SectionObject), NULL, 0, PtrIoStatus);
338             }
339             // notice, that we should purge cache
340             // we can't do it now, because it may cause last Close
341             // request & thus, structure deallocation
342 //            PurgeCache = TRUE;
343 
344 #ifndef UDF_READ_ONLY_BUILD
345             if(Ccb) {
346                 if( (Ccb->FileObject->Flags & FO_FILE_MODIFIED) &&
347                    !(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET)) {
348                     if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME) {
349                         LONGLONG NtTime;
350                         KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
351                         UDFSetFileXTime(Fcb->FileInfo, NULL, NULL, NULL, &NtTime);
352                         Fcb->NTRequiredFCB->LastWriteTime.QuadPart = NtTime;
353                     }
354                     SetArchive = TRUE;
355                     Ccb->FileObject->Flags &= ~FO_FILE_MODIFIED;
356                 }
357                 if(Ccb->FileObject->Flags & FO_FILE_SIZE_CHANGED) {
358                     LONGLONG ASize = UDFGetFileAllocationSize(Fcb->Vcb, Fcb->FileInfo);
359                     UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, &ASize);
360                     Ccb->FileObject->Flags &= ~FO_FILE_SIZE_CHANGED;
361                 }
362             }
363 #endif //UDF_READ_ONLY_BUILD
364         }
365     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
366         BrutePoint();
367     } _SEH2_END;
368 
369     _SEH2_TRY {
370 #ifndef UDF_READ_ONLY_BUILD
371         if(SetArchive &&
372            (Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) {
373             ULONG Attr;
374             PDIR_INDEX_ITEM DirNdx;
375             DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index);
376             // Archive bit
377             Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry);
378             if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
379                 UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
380         }
381 #endif //UDF_READ_ONLY_BUILD
382         UDFFlushFile__( Fcb->Vcb, Fcb->FileInfo, FlushFlags);
383     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
384         BrutePoint();
385     } _SEH2_END;
386 
387 /*    if(PurgeCache) {
388         _SEH2_TRY {
389             MmPrint(("    CcPurgeCacheSection()\n"));
390             CcPurgeCacheSection( &(Fcb->NTRequiredFCB->SectionObject), NULL, 0, FALSE );
391         } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
392             BrutePoint();
393         } _SEH2_END;
394     }*/
395 
396     return ret_val;
397 } // end UDFFlushAFile()
398 
399 /*************************************************************************
400 *
401 * Function: UDFFlushADirectory()
402 *
403 * Description:
404 *   Tell the Cache Manager to perform a flush for all files
405 *   in current directory & all subdirectories and flush all metadata
406 *
407 * Expected Interrupt Level (for execution) :
408 *
409 *  IRQL_PASSIVE_LEVEL
410 *
411 * Return Value: None
412 *
413 *************************************************************************/
414 ULONG
UDFFlushADirectory(IN PVCB Vcb,IN PUDF_FILE_INFO FI,OUT PIO_STATUS_BLOCK PtrIoStatus,IN ULONG FlushFlags)415 UDFFlushADirectory(
416     IN PVCB                Vcb,
417     IN PUDF_FILE_INFO      FI,
418     OUT PIO_STATUS_BLOCK   PtrIoStatus,
419     IN ULONG               FlushFlags
420     )
421 {
422     UDFPrint(("UDFFlushADirectory: \n"));
423 //    PDIR_INDEX_HDR hDI;
424     PDIR_INDEX_ITEM DI;
425 //    BOOLEAN Referenced = FALSE;
426     ULONG ret_val = 0;
427 
428     if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
429         return 0;
430 
431     if(!FI || !FI->Dloc || !FI->Dloc->DirIndex) goto SkipFlushDir;
432 //    hDI = FI->Dloc->DirIndex;
433 
434     // Flush Security if required
435     _SEH2_TRY {
436         UDFWriteSecurity(Vcb, FI->Fcb, &(FI->Fcb->NTRequiredFCB->SecurityDesc));
437     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
438         BrutePoint();
439     } _SEH2_END;
440     // Flush SDir if any
441     _SEH2_TRY {
442         if(UDFHasAStreamDir(FI) &&
443            FI->Dloc->SDirInfo &&
444            !UDFIsSDirDeleted(FI->Dloc->SDirInfo) ) {
445             ret_val |=
446                 UDFFlushADirectory(Vcb, FI->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
447         }
448     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
449         BrutePoint();
450     } _SEH2_END;
451 
452     // Flush Dir Tree
453     _SEH2_TRY {
454         UDF_DIR_SCAN_CONTEXT ScanContext;
455         PUDF_FILE_INFO      tempFI;
456 
457         if(UDFDirIndexInitScan(FI, &ScanContext, 2)) {
458             while((DI = UDFDirIndexScan(&ScanContext, &tempFI))) {
459                 // Flush Dir entry
460                 _SEH2_TRY {
461                     if(!tempFI) continue;
462                     if(UDFIsADirectory(tempFI)) {
463                         UDFFlushADirectory(Vcb, tempFI, PtrIoStatus, FlushFlags);
464                     } else {
465                         UDFFlushAFile(tempFI->Fcb, NULL, PtrIoStatus, FlushFlags);
466                     }
467                 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
468                     BrutePoint();
469                 } _SEH2_END;
470                 if(UDFFlushIsBreaking(Vcb, FlushFlags)) {
471                     ret_val |= UDF_FLUSH_FLAGS_INTERRUPTED;
472                     break;
473                 }
474             }
475         }
476     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
477         BrutePoint();
478     } _SEH2_END;
479 SkipFlushDir:
480     // Flush Dir
481     _SEH2_TRY {
482         UDFFlushFile__( Vcb, FI, FlushFlags );
483     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
484         BrutePoint();
485     } _SEH2_END;
486 
487     return ret_val;
488 } // end UDFFlushADirectory()
489 
490 /*************************************************************************
491 *
492 * Function: UDFFlushLogicalVolume()
493 *
494 * Description:
495 *   Flush everything beginning from root directory.
496 *   Vcb must be previously acquired exclusively.
497 *
498 * Expected Interrupt Level (for execution) :
499 *
500 *  IRQL_PASSIVE_LEVEL
501 *
502 * Return Value: None
503 *
504 *************************************************************************/
505 ULONG
UDFFlushLogicalVolume(IN PtrUDFIrpContext PtrIrpContext,IN PIRP Irp,IN PVCB Vcb,IN ULONG FlushFlags)506 UDFFlushLogicalVolume(
507     IN PtrUDFIrpContext PtrIrpContext,
508     IN PIRP             Irp,
509     IN PVCB             Vcb,
510     IN ULONG            FlushFlags
511     )
512 {
513     ULONG ret_val = 0;
514 #ifndef UDF_READ_ONLY_BUILD
515     IO_STATUS_BLOCK IoStatus;
516 
517     UDFPrint(("UDFFlushLogicalVolume: \n"));
518 
519     _SEH2_TRY {
520         if(Vcb->VCBFlags & (UDF_VCB_FLAGS_RAW_DISK/* |
521                             UDF_VCB_FLAGS_MEDIA_READ_ONLY*/))
522             return 0;
523         if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)
524             return 0;
525         if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED))
526             return 0;
527 
528         // NOTE: This function may also be invoked internally as part of
529         // processing a shutdown request.
530         ASSERT(Vcb->RootDirFCB);
531         ret_val |= UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, FlushFlags);
532 
533 //        if(UDFFlushIsBreaking(Vcb, FlushFlags))
534 //            return;
535         // flush internal cache
536         if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
537             UDFPrint(("  Lite flush, keep Modified=%d.\n", Vcb->Modified));
538         } else {
539             if(Vcb->VerifyOnWrite) {
540                 UDFPrint(("UDF: Flushing cache for verify\n"));
541                 //WCacheFlushAll__(&(Vcb->FastCache), Vcb);
542                 WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA);
543                 UDFVFlush(Vcb);
544             }
545             // umount (this is internal operation, NT will "dismount" volume later)
546             UDFUmount__(Vcb);
547 
548             UDFPreClrModified(Vcb);
549             WCacheFlushAll__(&(Vcb->FastCache), Vcb);
550             UDFClrModified(Vcb);
551         }
552 
553     } _SEH2_FINALLY {
554         ;
555     } _SEH2_END;
556 #endif //UDF_READ_ONLY_BUILD
557 
558     return ret_val;
559 } // end UDFFlushLogicalVolume()
560 
561 
562 /*************************************************************************
563 *
564 * Function: UDFFlushCompletion()
565 *
566 * Description:
567 *   Eat up any bad errors.
568 *
569 * Expected Interrupt Level (for execution) :
570 *
571 *  IRQL_PASSIVE_LEVEL
572 *
573 * Return Value: None
574 *
575 *************************************************************************/
576 NTSTATUS
577 NTAPI
UDFFlushCompletion(PDEVICE_OBJECT PtrDeviceObject,PIRP Irp,PVOID Context)578 UDFFlushCompletion(
579     PDEVICE_OBJECT  PtrDeviceObject,
580     PIRP            Irp,
581     PVOID           Context
582     )
583 {
584 //    NTSTATUS        RC = STATUS_SUCCESS;
585 
586     UDFPrint(("UDFFlushCompletion: \n"));
587 
588     if (Irp->PendingReturned) {
589         IoMarkIrpPending(Irp);
590     }
591 
592     if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
593         // cannot do much here, can we?
594         Irp->IoStatus.Status = STATUS_SUCCESS;
595     }
596 
597     return(STATUS_SUCCESS);
598 } // end UDFFlushCompletion()
599 
600 
601 /*
602   Check if we should break FlushTree process
603  */
604 BOOLEAN
UDFFlushIsBreaking(IN PVCB Vcb,IN ULONG FlushFlags)605 UDFFlushIsBreaking(
606     IN PVCB         Vcb,
607     IN ULONG        FlushFlags
608     )
609 {
610     BOOLEAN ret_val = FALSE;
611 //    if(!(FlushFlags & UDF_FLUSH_FLAGS_BREAKABLE))
612         return FALSE;
613     UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
614     ret_val = (Vcb->VCBFlags & UDF_VCB_FLAGS_FLUSH_BREAK_REQ) ? TRUE : FALSE;
615     Vcb->VCBFlags &= ~UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
616     UDFReleaseResource(&(Vcb->FlushResource));
617     return ret_val;
618 } // end UDFFlushIsBreaking()
619 
620 /*
621   Signal FlushTree break request. Note, this is
622   treated as recommendation only
623  */
624 VOID
UDFFlushTryBreak(IN PVCB Vcb)625 UDFFlushTryBreak(
626     IN PVCB         Vcb
627     )
628 {
629     UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
630     Vcb->VCBFlags |= UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
631     UDFReleaseResource(&(Vcb->FlushResource));
632 } // end UDFFlushTryBreak()
633