Reactos
at master 632 lines 21 kB view raw
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*************************************************************************/ 40NTSTATUS 41NTAPI 42UDFFlush( 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*************************************************************************/ 109NTSTATUS 110UDFCommonFlush( 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 212try_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*************************************************************************/ 287ULONG 288UDFFlushAFile( 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*************************************************************************/ 414ULONG 415UDFFlushADirectory( 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; 479SkipFlushDir: 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*************************************************************************/ 505ULONG 506UDFFlushLogicalVolume( 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*************************************************************************/ 576NTSTATUS 577NTAPI 578UDFFlushCompletion( 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 */ 604BOOLEAN 605UDFFlushIsBreaking( 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 */ 624VOID 625UDFFlushTryBreak( 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()