ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

close.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS FAT file system driver
00003  * LICENSE:         GNU GPLv3 as published by the Free Software Foundation
00004  * FILE:            drivers/filesystems/fastfat/close.c
00005  * PURPOSE:         Closing routines
00006  * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)
00007  */
00008 
00009 /* INCLUDES *****************************************************************/
00010 
00011 #define NDEBUG
00012 #include "fastfat.h"
00013 
00014 VOID NTAPI
00015 FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
00016               IN BOOLEAN DelayClose);
00017 
00018 PCLOSE_CONTEXT NTAPI
00019 FatRemoveClose(PVCB Vcb OPTIONAL,
00020                PVCB LastVcbHint OPTIONAL);
00021 
00022 const ULONG FatMaxDelayedCloseCount = 16;
00023 
00024 /* FUNCTIONS ****************************************************************/
00025 
00026 NTSTATUS
00027 NTAPI
00028 FatiCommonClose(IN PVCB Vcb,
00029                 IN PFCB Fcb,
00030                 IN PCCB Ccb,
00031                 IN TYPE_OF_OPEN TypeOfOpen,
00032                 IN BOOLEAN Wait,
00033                 OUT PBOOLEAN VcbDeleted)
00034 {
00035     NTSTATUS Status;
00036     PFCB ParentDcb;
00037     BOOLEAN RecursiveClose, VcbDeletedLv = FALSE;
00038     FAT_IRP_CONTEXT IrpContext;
00039 
00040     if (VcbDeleted) *VcbDeleted = FALSE;
00041 
00042     if (TypeOfOpen == UnopenedFileObject)
00043     {
00044         DPRINT1("Closing unopened file object\n");
00045         Status = STATUS_SUCCESS;
00046         return Status;
00047     }
00048 
00049     RtlZeroMemory(&IrpContext, sizeof(FAT_IRP_CONTEXT));
00050 
00051     IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
00052     IrpContext.NodeByteSize = sizeof(IrpContext);
00053     IrpContext.MajorFunction = IRP_MJ_CLOSE;
00054 
00055     if (Wait) SetFlag(IrpContext.Flags, IRPCONTEXT_CANWAIT);
00056 
00057     if (!ExAcquireResourceExclusiveLite(&Vcb->Resource, Wait)) return STATUS_PENDING;
00058 
00059     if (Vcb->State & VCB_STATE_FLAG_CLOSE_IN_PROGRESS)
00060     {
00061         RecursiveClose = TRUE;
00062     }
00063     else
00064     {
00065         SetFlag(Vcb->State, VCB_STATE_FLAG_CLOSE_IN_PROGRESS);
00066         RecursiveClose = FALSE;
00067 
00068         Vcb->OpenFileCount++;
00069     }
00070 
00071     /* Update on-disk structures */
00072     switch (TypeOfOpen)
00073     {
00074     case VirtualVolumeFile:
00075         DPRINT1("Close VirtualVolumeFile\n");
00076 
00077         InterlockedDecrement((PLONG)&(Vcb->InternalOpenCount));
00078         InterlockedDecrement((PLONG)&(Vcb->ResidualOpenCount));
00079 
00080         Status = STATUS_SUCCESS;
00081         goto close_done;
00082         break;
00083 
00084     case UserVolumeOpen:
00085         DPRINT1("Close UserVolumeOpen\n");
00086 
00087         Vcb->DirectAccessOpenCount--;
00088         Vcb->OpenFileCount--;
00089         if (FlagOn(Ccb->Flags, CCB_READ_ONLY)) Vcb->ReadOnlyCount--;
00090 
00091         FatDeleteCcb(&IrpContext, Ccb);
00092 
00093         Status = STATUS_SUCCESS;
00094         goto close_done;
00095         break;
00096 
00097     case EaFile:
00098         UNIMPLEMENTED;
00099         break;
00100 
00101     case DirectoryFile:
00102         DPRINT1("Close DirectoryFile\n");
00103 
00104         InterlockedDecrement((PLONG)&(Fcb->Dcb.DirectoryFileOpenCount));
00105         InterlockedDecrement((PLONG)&(Vcb->InternalOpenCount));
00106 
00107         if (FatNodeType(Fcb) == FAT_NTC_ROOT_DCB)
00108         {
00109             InterlockedDecrement((PLONG)&(Vcb->ResidualOpenCount));
00110         }
00111 
00112         if (RecursiveClose)
00113         {
00114             Status = STATUS_SUCCESS;
00115             goto close_done;
00116         }
00117         else
00118         {
00119             break;
00120         }
00121 
00122     case UserDirectoryOpen:
00123     case UserFileOpen:
00124         DPRINT("Close UserFileOpen/UserDirectoryOpen\n");
00125 
00126         if ((FatNodeType(Fcb) == FAT_NTC_DCB) &&
00127             IsListEmpty(&Fcb->Dcb.ParentDcbList) &&
00128             (Fcb->OpenCount == 1) &&
00129             (Fcb->Dcb.DirectoryFile != NULL))
00130         {
00131                 PFILE_OBJECT DirectoryFileObject = Fcb->Dcb.DirectoryFile;
00132 
00133                 DPRINT1("Uninitialize the stream file object\n");
00134 
00135                 CcUninitializeCacheMap(DirectoryFileObject, NULL, NULL);
00136 
00137                 Fcb->Dcb.DirectoryFile = NULL;
00138                 ObDereferenceObject(DirectoryFileObject);
00139         }
00140 
00141         Fcb->OpenCount--;
00142         Vcb->OpenFileCount--;
00143         if (FlagOn(Ccb->Flags, CCB_READ_ONLY)) Vcb->ReadOnlyCount --;
00144 
00145         FatDeleteCcb(&IrpContext, Ccb);
00146         break;
00147 
00148     default:
00149         KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
00150     }
00151 
00152     /* Update in-memory structures */
00153     if (((FatNodeType(Fcb) == FAT_NTC_FCB) &&
00154         (Fcb->OpenCount == 0))
00155         ||
00156         ((FatNodeType(Fcb) == FAT_NTC_DCB) &&
00157         (IsListEmpty(&Fcb->Dcb.ParentDcbList)) &&
00158         (Fcb->OpenCount == 0) &&
00159         (Fcb->Dcb.DirectoryFileOpenCount == 0)))
00160     {
00161         ParentDcb = Fcb->ParentFcb;
00162 
00163         SetFlag(Vcb->State, VCB_STATE_FLAG_DELETED_FCB);
00164 
00165         FatDeleteFcb(&IrpContext, Fcb);
00166 
00167         while ((FatNodeType(ParentDcb) == FAT_NTC_DCB) &&
00168             IsListEmpty(&ParentDcb->Dcb.ParentDcbList) &&
00169             (ParentDcb->OpenCount == 0) &&
00170             (ParentDcb->Dcb.DirectoryFile != NULL))
00171         {
00172                 PFILE_OBJECT DirectoryFileObject;
00173 
00174                 DirectoryFileObject = ParentDcb->Dcb.DirectoryFile;
00175 
00176                 DPRINT1("Uninitialize parent Stream Cache Map\n");
00177 
00178                 CcUninitializeCacheMap(DirectoryFileObject, NULL, NULL);
00179 
00180                 ParentDcb->Dcb.DirectoryFile = NULL;
00181 
00182                 ObDereferenceObject(DirectoryFileObject);
00183 
00184                 if (ParentDcb->Dcb.DirectoryFileOpenCount == 0)
00185                 {
00186                     PFCB CurrentDcb;
00187 
00188                     CurrentDcb = ParentDcb;
00189                     ParentDcb = CurrentDcb->ParentFcb;
00190 
00191                     SetFlag(Vcb->State, VCB_STATE_FLAG_DELETED_FCB);
00192 
00193                     FatDeleteFcb(&IrpContext, CurrentDcb);
00194                 }
00195                 else
00196                 {
00197                     break;
00198                 }
00199         }
00200     }
00201 
00202     Status = STATUS_SUCCESS;
00203 
00204 close_done:
00205     /* Closing is done, check if VCB could be closed too */
00206     if (!RecursiveClose)
00207     {
00208         /* One open left - yes, VCB can go away */
00209         if (Vcb->OpenFileCount == 1 &&
00210             !FlagOn(Vcb->State, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS)
00211             && VcbDeleted)
00212         {
00213             FatReleaseVcb(&IrpContext, Vcb );
00214 
00215             SetFlag(IrpContext.Flags, IRPCONTEXT_CANWAIT);
00216 
00217             FatAcquireExclusiveGlobal(&IrpContext);
00218 
00219             FatAcquireExclusiveVcb(&IrpContext, Vcb);
00220 
00221             Vcb->OpenFileCount--;
00222 
00223             VcbDeletedLv = FatCheckForDismount(&IrpContext, Vcb, FALSE);
00224 
00225             FatReleaseGlobal(&IrpContext);
00226 
00227             if (VcbDeleted) *VcbDeleted = VcbDeletedLv;
00228         }
00229         else
00230         {
00231             /* Remove extra referenec */
00232             Vcb->OpenFileCount --;
00233         }
00234 
00235         /* Clear recursion flag if necessary */
00236         if (!VcbDeletedLv)
00237         {
00238             ClearFlag(Vcb->State, VCB_STATE_FLAG_CLOSE_IN_PROGRESS);
00239         }
00240     }
00241 
00242     /* Release VCB if it wasn't deleted */
00243     if (!VcbDeletedLv)
00244         FatReleaseVcb(&IrpContext, Vcb);
00245 
00246     return Status;
00247 }
00248 
00249 NTSTATUS
00250 NTAPI
00251 FatiClose(IN PFAT_IRP_CONTEXT IrpContext,
00252           IN PIRP Irp)
00253 {
00254     PIO_STACK_LOCATION IrpSp;
00255     TYPE_OF_OPEN TypeOfOpen;
00256     PVCB Vcb;
00257     PFCB Fcb;
00258     PCCB Ccb;
00259     BOOLEAN TopLevel, Wait, VcbDeleted = FALSE, DelayedClose = FALSE;
00260     NTSTATUS Status = STATUS_SUCCESS;
00261     PCLOSE_CONTEXT CloseContext = NULL;
00262 
00263     TopLevel = FatIsTopLevelIrp(Irp);
00264 
00265     /* Get current IRP stack location */
00266     IrpSp = IoGetCurrentIrpStackLocation(Irp);
00267 
00268     /* Decode incoming file object */
00269     TypeOfOpen = FatDecodeFileObject(IrpSp->FileObject, &Vcb, &Fcb, &Ccb);
00270 
00271     /* Set CCB read only flag */
00272     if (Ccb && IsFileObjectReadOnly(IrpSp->FileObject))
00273         SetFlag(Ccb->Flags, CCB_READ_ONLY);
00274 
00275     /* It's possible to wait only if we are top level or not a system process */
00276     Wait = TopLevel && (PsGetCurrentProcess() != FatGlobalData.SystemProcess);
00277 
00278     /* Determine if it's a delayed close, by flags first */
00279     if ((TypeOfOpen == UserFileOpen || TypeOfOpen == UserDirectoryOpen) &&
00280         (Fcb->State & FCB_STATE_DELAY_CLOSE) &&
00281         !FatGlobalData.ShutdownStarted)
00282     {
00283         DelayedClose = TRUE;
00284     }
00285 
00286     /* If close is not delayed, try to perform the close operation */
00287     if (!DelayedClose)
00288         Status = FatiCommonClose(Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted);
00289 
00290     /* We have to delay close if either it's defined by a flag or it was not possible
00291        to perform it synchronously */
00292     if (DelayedClose || Status == STATUS_PENDING)
00293     {
00294         DPRINT1("Queuing a pending close, Vcb %p, Fcb %p, Ccb %p\n", Vcb, Fcb, Ccb);
00295 
00296         /* Check if a close context should be allocated */
00297         if (TypeOfOpen == VirtualVolumeFile)
00298         {
00299             ASSERT(Vcb->CloseContext != NULL);
00300             CloseContext = Vcb->CloseContext;
00301             Vcb->CloseContext = NULL;
00302             CloseContext->Free = TRUE;
00303         }
00304         else if (TypeOfOpen == DirectoryFile ||
00305                  TypeOfOpen == EaFile)
00306         {
00307             UNIMPLEMENTED;
00308             //CloseContext = FatAllocateCloseContext(Vcb);
00309             //ASSERT(CloseContext != NULL);
00310             CloseContext->Free = TRUE;
00311         }
00312         else
00313         {
00314             //TODO: FatDeallocateCcbStrings( Ccb );
00315 
00316             /* Set CloseContext to a buffer inside Ccb */
00317             CloseContext = &Ccb->CloseContext;
00318             CloseContext->Free = FALSE;
00319             SetFlag(Ccb->Flags, CCB_CLOSE_CONTEXT);
00320         }
00321 
00322         /* Save all info in the close context */
00323         CloseContext->Vcb = Vcb;
00324         CloseContext->Fcb = Fcb;
00325         CloseContext->TypeOfOpen = TypeOfOpen;
00326 
00327         /* Queue the close */
00328         FatQueueClose(CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->State, FCB_STATE_DELAY_CLOSE)));
00329     }
00330     else
00331     {
00332         /* Close finished right away */
00333         if (TypeOfOpen == VirtualVolumeFile ||
00334             TypeOfOpen == DirectoryFile ||
00335             TypeOfOpen == EaFile)
00336         {
00337                 if (TypeOfOpen == VirtualVolumeFile)
00338                 {
00339                     /* Free close context for the not deleted VCB */
00340                     if (!VcbDeleted)
00341                     {
00342                         CloseContext = Vcb->CloseContext;
00343                         Vcb->CloseContext = NULL;
00344 
00345                         ASSERT(CloseContext != NULL);
00346                     }
00347                 }
00348                 else
00349                 {
00350                     //CloseContext = FatAllocateCloseContext(Vcb);
00351                     DPRINT1("TODO: Allocate close context!\n");
00352                     ASSERT(CloseContext != NULL);
00353                 }
00354 
00355                 /* Free close context */
00356                 if (CloseContext) ExFreePool(CloseContext);
00357         }
00358     }
00359 
00360     /* Complete the request */
00361     FatCompleteRequest(NULL, Irp, Status);
00362 
00363     /* Reset the top level IRP if necessary */
00364     if (TopLevel) IoSetTopLevelIrp(NULL);
00365 
00366     return Status;
00367 }
00368 
00369 NTSTATUS
00370 NTAPI
00371 FatClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
00372 {
00373     PFAT_IRP_CONTEXT IrpContext;
00374     NTSTATUS Status;
00375 
00376     DPRINT("FatClose(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
00377 
00378     /* FatClose works only with a volume device object */
00379     if (DeviceObject == FatGlobalData.DiskDeviceObject)
00380     {
00381         /* Complete the request and return success */
00382         Irp->IoStatus.Status = STATUS_SUCCESS;
00383         Irp->IoStatus.Information = FILE_OPENED;
00384 
00385         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
00386 
00387         return STATUS_SUCCESS;
00388     }
00389 
00390     /* Enter FsRtl critical region */
00391     FsRtlEnterFileSystem();
00392 
00393     /* Build an irp context */
00394     IrpContext = FatBuildIrpContext(Irp, TRUE);
00395 
00396     /* Call internal function */
00397     Status = FatiClose(IrpContext, Irp);
00398 
00399     /* Leave FsRtl critical region */
00400     FsRtlExitFileSystem();
00401 
00402     return Status;
00403 }
00404 
00405 VOID
00406 NTAPI
00407 FatPendingClose(IN PVCB Vcb OPTIONAL)
00408 {
00409     PCLOSE_CONTEXT CloseContext;
00410     PVCB CurrentVcb = NULL;
00411     PVCB LastVcb = NULL;
00412     BOOLEAN FreeContext;
00413     ULONG Loops = 0;
00414 
00415     /* Do the top-level IRP trick */
00416     if (!Vcb) IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
00417 
00418     while ((CloseContext = FatRemoveClose(Vcb, LastVcb)))
00419     {
00420         if (!Vcb)
00421         {
00422             if (!FatGlobalData.ShutdownStarted)
00423             {
00424                 if (CloseContext->Vcb != CurrentVcb)
00425                 {
00426                     Loops = 0;
00427 
00428                     /* Release previous VCB */
00429                     if (CurrentVcb)
00430                         ExReleaseResourceLite(&CurrentVcb->Resource);
00431 
00432                     /* Lock the new VCB */
00433                     CurrentVcb = CloseContext->Vcb;
00434                     (VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
00435                 }
00436                 else
00437                 {
00438                     /* Try to lock */
00439                     if (++Loops >= 20)
00440                     {
00441                         if (ExGetSharedWaiterCount(&CurrentVcb->Resource) +
00442                             ExGetExclusiveWaiterCount(&CurrentVcb->Resource))
00443                         {
00444                             ExReleaseResourceLite(&CurrentVcb->Resource);
00445                             (VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
00446                         }
00447 
00448                         Loops = 0;
00449                     }
00450                 }
00451 
00452                 /* Check open count */
00453                 if (CurrentVcb->OpenFileCount <= 1)
00454                 {
00455                     ExReleaseResourceLite(&CurrentVcb->Resource);
00456                     CurrentVcb = NULL;
00457                 }
00458             }
00459             else if (CurrentVcb)
00460             {
00461                 ExReleaseResourceLite(&CurrentVcb->Resource);
00462                 CurrentVcb = NULL;
00463             }
00464         }
00465 
00466         LastVcb = CurrentVcb;
00467 
00468         /* Remember if we should free the context */
00469         FreeContext = CloseContext->Free;
00470 
00471         FatiCommonClose(CloseContext->Vcb,
00472                         CloseContext->Fcb,
00473                         (FreeContext ? NULL : CONTAINING_RECORD(CloseContext, CCB, CloseContext)),
00474                         CloseContext->TypeOfOpen,
00475                         TRUE,
00476                         NULL);
00477 
00478         /* Free context if necessary */
00479         if (FreeContext) ExFreePool(CloseContext);
00480     }
00481 
00482     /* Release VCB if necessary */
00483     if (CurrentVcb) ExReleaseResourceLite(&CurrentVcb->Resource);
00484 
00485     /* Reset top level IRP */
00486     if (!Vcb) IoSetTopLevelIrp( NULL );
00487 }
00488 
00489 VOID
00490 NTAPI
00491 FatCloseWorker(IN PDEVICE_OBJECT DeviceObject,
00492                IN PVOID Context)
00493 {
00494     FsRtlEnterFileSystem();
00495 
00496     FatPendingClose((PVCB)Context);
00497 
00498     FsRtlExitFileSystem();
00499 }
00500 
00501 VOID
00502 NTAPI
00503 FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
00504               IN BOOLEAN DelayClose)
00505 {
00506     BOOLEAN RunWorker = FALSE;
00507 
00508     /* Acquire the close lists mutex */
00509     ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
00510 
00511     /* Add it to the desired list */
00512     if (DelayClose)
00513     {
00514         InsertTailList(&FatGlobalData.DelayedCloseList,
00515                        &CloseContext->GlobalLinks);
00516         InsertTailList(&CloseContext->Vcb->DelayedCloseList,
00517                        &CloseContext->VcbLinks);
00518 
00519         FatGlobalData.DelayedCloseCount++;
00520 
00521         if (FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount &&
00522             !FatGlobalData.AsyncCloseActive)
00523         {
00524             FatGlobalData.AsyncCloseActive = TRUE;
00525             RunWorker = TRUE;
00526         }
00527     }
00528     else
00529     {
00530         InsertTailList(&FatGlobalData.AsyncCloseList,
00531                        &CloseContext->GlobalLinks);
00532         InsertTailList(&CloseContext->Vcb->AsyncCloseList,
00533                        &CloseContext->VcbLinks);
00534 
00535         FatGlobalData.AsyncCloseCount++;
00536 
00537         if (!FatGlobalData.AsyncCloseActive)
00538         {
00539             FatGlobalData.AsyncCloseActive = TRUE;
00540             RunWorker = TRUE;
00541         }
00542     }
00543 
00544     /* Release the close lists mutex */
00545     ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
00546 
00547     if (RunWorker)
00548         IoQueueWorkItem(FatGlobalData.FatCloseItem, FatCloseWorker, CriticalWorkQueue, NULL);
00549 }
00550 
00551 PCLOSE_CONTEXT
00552 NTAPI
00553 FatRemoveClose(PVCB Vcb OPTIONAL,
00554                PVCB LastVcbHint OPTIONAL)
00555 {
00556     PLIST_ENTRY Entry;
00557     PCLOSE_CONTEXT CloseContext;
00558     BOOLEAN IsWorker = FALSE;
00559 
00560     /* Acquire the close lists mutex */
00561     ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
00562 
00563     if (!Vcb) IsWorker = TRUE;
00564 
00565     if (Vcb == NULL && LastVcbHint != NULL)
00566     {
00567         // TODO: A very special case of overflowing the queue
00568         UNIMPLEMENTED;
00569     }
00570 
00571     /* Usual processing from a worker thread */
00572     if (!Vcb)
00573     {
00574 TryToCloseAgain:
00575 
00576         /* Is there anything in the async close list */
00577         if (!IsListEmpty(&FatGlobalData.AsyncCloseList))
00578         {
00579             Entry = RemoveHeadList(&FatGlobalData.AsyncCloseList);
00580             FatGlobalData.AsyncCloseCount--;
00581 
00582             CloseContext = CONTAINING_RECORD(Entry,
00583                                              CLOSE_CONTEXT,
00584                                              GlobalLinks);
00585 
00586             RemoveEntryList(&CloseContext->VcbLinks);
00587         } else if (!IsListEmpty(&FatGlobalData.DelayedCloseList) &&
00588                    (FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount/2 ||
00589                    FatGlobalData.ShutdownStarted))
00590         {
00591             /* In case of a shutdown or when delayed queue is filled at half - perform closing */
00592             Entry = RemoveHeadList(&FatGlobalData.DelayedCloseList);
00593             FatGlobalData.DelayedCloseCount--;
00594 
00595             CloseContext = CONTAINING_RECORD(Entry,
00596                                              CLOSE_CONTEXT,
00597                                              GlobalLinks);
00598             RemoveEntryList(&CloseContext->VcbLinks);
00599         }
00600         else
00601         {
00602             /* Nothing to close */
00603             CloseContext = NULL;
00604             if (IsWorker) FatGlobalData.AsyncCloseActive = FALSE;
00605         }
00606     }
00607     else
00608     {
00609         if (!IsListEmpty(&Vcb->AsyncCloseList))
00610         {
00611             /* Is there anything in the async close list */
00612             Entry = RemoveHeadList(&Vcb->AsyncCloseList);
00613             FatGlobalData.AsyncCloseCount--;
00614 
00615             CloseContext = CONTAINING_RECORD(Entry,
00616                                              CLOSE_CONTEXT,
00617                                              VcbLinks);
00618 
00619             RemoveEntryList(&CloseContext->GlobalLinks);
00620         }
00621         else if (!IsListEmpty(&Vcb->DelayedCloseList))
00622         {
00623             /* Process delayed close list */
00624             Entry = RemoveHeadList(&Vcb->DelayedCloseList);
00625             FatGlobalData.DelayedCloseCount--;
00626 
00627             CloseContext = CONTAINING_RECORD(Entry,
00628                                              CLOSE_CONTEXT,
00629                                              VcbLinks);
00630 
00631             RemoveEntryList(&CloseContext->GlobalLinks);
00632         }
00633         else if (LastVcbHint)
00634         {
00635             /* Try again */
00636             goto TryToCloseAgain;
00637         }
00638         else
00639         {
00640             /* Nothing to close */
00641             CloseContext = NULL;
00642         }
00643     }
00644 
00645     /* Release the close lists mutex */
00646     ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
00647 
00648     return CloseContext;
00649 }
00650 
00651 /* EOF */

Generated on Sun May 27 2012 04:27:34 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.