[EXT2]
authorPierre Schweitzer <pierre@reactos.org>
Fri, 29 Jul 2016 10:29:16 +0000 (10:29 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Fri, 29 Jul 2016 10:29:16 +0000 (10:29 +0000)
Upgrade the driver to release 0.68.

CORE-11714

svn path=/trunk/; revision=72042

14 files changed:
reactos/drivers/filesystems/ext2/inc/ext2fs.h
reactos/drivers/filesystems/ext2/src/block.c
reactos/drivers/filesystems/ext2/src/cleanup.c
reactos/drivers/filesystems/ext2/src/close.c
reactos/drivers/filesystems/ext2/src/create.c
reactos/drivers/filesystems/ext2/src/ext3/generic.c
reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c
reactos/drivers/filesystems/ext2/src/fileinfo.c
reactos/drivers/filesystems/ext2/src/flush.c
reactos/drivers/filesystems/ext2/src/fsctl.c
reactos/drivers/filesystems/ext2/src/init.c
reactos/drivers/filesystems/ext2/src/memory.c
reactos/drivers/filesystems/ext2/src/write.c
reactos/media/doc/README.FSD

index f238840..2b669a3 100644 (file)
@@ -47,7 +47,7 @@
 
 /* STRUCTS & CONSTS******************************************************/
 
-#define EXT2FSD_VERSION                 "0.66"
+#define EXT2FSD_VERSION                 "0.68"
 
 
 /* WDK DEFINITIONS ******************************************************/
@@ -491,6 +491,7 @@ typedef PVOID   PBCB;
 typedef VOID (NTAPI *EXT2_REAPER_RELEASE)(PVOID);
 
 typedef struct _EXT2_REAPER {
+        PETHREAD                Thread;
         KEVENT                  Engine;
         KEVENT                  Wait;
         EXT2_REAPER_RELEASE     Free;
@@ -534,6 +535,7 @@ typedef struct _EXT2_GLOBAL {
     LIST_ENTRY                  VcbList;
 
     /* Cleaning thread related: resource cleaner */
+    EXT2_REAPER                 FcbReaper;
     EXT2_REAPER                 McbReaper;
     EXT2_REAPER                 bhReaper;
 
@@ -647,12 +649,17 @@ typedef struct _EXT2_VCB {
     // Resource for Mcb (Meta data control block)
     ERESOURCE                   McbLock;
 
-    // Entry of Mcb Tree (Root Node)
-    PEXT2_MCB                   McbTree;
+    // List of FCBs for open files on this volume
+    ERESOURCE                   FcbLock;
+    LIST_ENTRY                  FcbList;
+    ULONG                       FcbCount;
 
     // Mcb list
-    LIST_ENTRY                  McbList;
     ULONG                       NumOfMcb;
+    LIST_ENTRY                  McbList;
+
+    // Entry of Mcb Tree (Root Node)
+    PEXT2_MCB                   McbTree;
 
     // Link list to Global
     LIST_ENTRY                  Next;
@@ -663,10 +670,6 @@ typedef struct _EXT2_VCB {
     // Dirty Mcbs of modifications for volume stream
     LARGE_MCB                   Extents;
 
-    // List of FCBs for open files on this volume
-    ULONG                       FcbCount;
-    LIST_ENTRY                  FcbList;
-    KSPIN_LOCK                  FcbLock;
 
     // Share Access for the file object
     SHARE_ACCESS                ShareAccess;
@@ -817,6 +820,7 @@ typedef struct _EXT2_FCB {
 
     // List of FCBs for this volume
     LIST_ENTRY                      Next;
+    LARGE_INTEGER                   TsDrop; /* drop time */
 
     SECTION_OBJECT_POINTERS         SectionObject;
 
@@ -863,7 +867,7 @@ typedef struct _EXT2_FCB {
 #define FCB_FROM_POOL               0x00000001
 #define FCB_PAGE_FILE               0x00000002
 #define FCB_FILE_MODIFIED           0x00000020
-#define FCB_STATE_BUSY              0x00000040
+
 #define FCB_ALLOC_IN_CREATE         0x00000080
 #define FCB_ALLOC_IN_WRITE          0x00000100
 #define FCB_ALLOC_IN_SETINFO        0x00000200
@@ -961,12 +965,10 @@ struct _EXT2_MCB {
 static
 #endif
 __inline ULONG DEC_OBJ_CNT(PULONG _C) {
-    if (*_C > 0) {
-        return InterlockedDecrement(_C);
-    } else {
+    if (*_C <= 0) {
         DbgBreak();
     }
-    return 0;
+    return InterlockedDecrement(_C);
 }
 
 #if EXT2_DEBUG
@@ -1774,7 +1776,7 @@ VOID
 Ext2PutGroup(IN PEXT2_VCB Vcb);
 
 VOID
-Ext2DropGroup(IN PEXT2_VCB Vcb);
+Ext2DropBH(IN PEXT2_VCB Vcb);
 
 BOOLEAN
 Ext2SaveGroup(
@@ -2438,7 +2440,6 @@ struct buffer_head *ext3_bread(struct ext2_icb *icb, struct inode *inode,
 int add_dirent_to_buf(struct ext2_icb *icb, struct dentry *dentry,
                       struct inode *inode, struct ext3_dir_entry_2 *de,
                       struct buffer_head *bh);
-
 #if !defined(__REACTOS__) || defined(_MSC_VER)
 struct ext3_dir_entry_2 *
             do_split(struct ext2_icb *icb, struct inode *dir,
@@ -2523,6 +2524,12 @@ Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext);
 // Memory.c
 //
 
+VOID
+NTAPI
+Ext2FcbReaperThread(
+    PVOID   Context
+);
+
 VOID
 NTAPI
 Ext2McbReaperThread(
@@ -2551,13 +2558,15 @@ Ext2AllocateFcb (
 );
 
 VOID
-Ext2FreeFcb (IN PEXT2_FCB Fcb);
+Ext2UnlinkFcb(IN PEXT2_FCB Fcb);
 
 VOID
-Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
+Ext2FreeFcb (IN PEXT2_FCB Fcb);
+VOID
+Ext2ReleaseFcb (IN PEXT2_FCB Fcb);
 
 VOID
-Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
+Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
 
 PEXT2_CCB
 Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink);
index d063437..bddb55e 100644 (file)
@@ -351,7 +351,7 @@ Ext2ReadWriteBlocks(
 
                 IoBuildPartialMdl( MasterIrp->MdlAddress,
                                    Mdl,
-                                   (PCHAR)MasterIrp->UserBuffer +Extent->Offset,
+                                   (PCHAR)MasterIrp->UserBuffer+Extent->Offset,
                                    Extent->Length );
 
                 IoSetNextIrpStackLocation(Irp);
@@ -568,8 +568,7 @@ Ext2ReadDisk(
                             FALSE );
 
     if (!NT_SUCCESS(Status)) {
-        DEBUG(DL_ERR, ( "Ext2ReadDisk: disk device error.\n"));
-
+        DEBUG(DL_ERR, ("Ext2ReadDisk: disk i/o error: %xh.\n", Status));
         goto errorout;
     }
 
index 005fcb6..f7233af 100644 (file)
@@ -73,14 +73,12 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        VcbResourceAcquired =
-            ExAcquireResourceExclusiveLite(
-                &Vcb->MainResource,
-                TRUE
-            );
-
         if (Fcb->Identifier.Type == EXT2VCB) {
 
+            ExAcquireResourceExclusiveLite(
+                    &Vcb->MainResource, TRUE);
+            VcbResourceAcquired = TRUE;
+
             if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
                 Vcb->LockFile == FileObject ){
 
@@ -103,6 +101,12 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
 
+        FcbResourceAcquired =
+            ExAcquireResourceExclusiveLite(
+                &Fcb->MainResource,
+                TRUE
+            );
+
         if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
             if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                     IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
@@ -135,18 +139,8 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
             }
 
             FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);
-
         }
 
-        ExReleaseResourceLite(&Vcb->MainResource);
-        VcbResourceAcquired = FALSE;
-
-        FcbResourceAcquired =
-            ExAcquireResourceExclusiveLite(
-                &Fcb->MainResource,
-                TRUE
-            );
-
         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
 
@@ -284,6 +278,37 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
             }
         }
 
+        IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
+
+        if (!IsDirectory(Fcb)) {
+
+            if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
+                    (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
+                    (Fcb->SectionObject.DataSectionObject != NULL)) {
+
+                if (!IsVcbReadOnly(Vcb)) {
+                    CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
+                    ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+                }
+
+                /* purge cache if all remaining openings are non-cached */
+                if (Fcb->NonCachedOpenCount > 0 ||
+                    IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
+                    if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
+                        ExReleaseResourceLite(&(Fcb->PagingIoResource));
+                    }
+
+                    /* CcPurge could generate recursive IRP_MJ_CLOSE request */
+                    CcPurgeCacheSection( &Fcb->SectionObject,
+                                         NULL,
+                                         0,
+                                         FALSE );
+                }
+            }
+
+            CcUninitializeCacheMap(FileObject, NULL, NULL);
+        }
+
         if (SymLinkDelete ||
             (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
              Fcb->OpenHandleCount == 0) ) {
@@ -337,35 +362,6 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
             }
         }
 
-        if (!IsDirectory(Fcb)) {
-
-            if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
-                    (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
-                    (Fcb->SectionObject.DataSectionObject != NULL)) {
-
-                if (!IsVcbReadOnly(Vcb)) {
-                    CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
-                    ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
-                }
-
-                /* purge cache if all remaining openings are non-cached */
-                if (Fcb->NonCachedOpenCount > 0) {
-                    if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
-                        ExReleaseResourceLite(&(Fcb->PagingIoResource));
-                    }
-
-                    CcPurgeCacheSection( &Fcb->SectionObject,
-                                         NULL,
-                                         0,
-                                         FALSE );
-                }
-            }
-
-            CcUninitializeCacheMap(FileObject, NULL, NULL);
-        }
-
-        IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
-
         DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
                         Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));
 
index 6403b5c..d8065e6 100644 (file)
@@ -31,11 +31,10 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
     PFILE_OBJECT    FileObject;
     PEXT2_FCB       Fcb = NULL;
     PEXT2_CCB       Ccb = NULL;
+
     BOOLEAN         VcbResourceAcquired = FALSE;
     BOOLEAN         FcbResourceAcquired = FALSE;
-    BOOLEAN         bDeleteVcb = FALSE;
-    BOOLEAN         bBeingClosed = FALSE;
-    BOOLEAN         bSkipLeave = FALSE;
+    BOOLEAN         FcbDerefDeferred = FALSE;
 
     _SEH2_TRY {
 
@@ -55,25 +54,6 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
 
-        if (!ExAcquireResourceExclusiveLite(
-                    &Vcb->MainResource,
-                    TRUE )) {
-            DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
-                           Vcb->OpenHandleCount, Vcb->ReferenceCount));
-
-            Status = STATUS_PENDING;
-            _SEH2_LEAVE;
-        }
-        VcbResourceAcquired = TRUE;
-
-        bSkipLeave = TRUE;
-        if (IsFlagOn(Vcb->Flags, VCB_BEING_CLOSED)) {
-            bBeingClosed = TRUE;
-        } else {
-            SetLongFlag(Vcb->Flags, VCB_BEING_CLOSED);
-            bBeingClosed = FALSE;
-        }
-
         if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
 
             FileObject = NULL;
@@ -92,11 +72,30 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
             Ccb = (PEXT2_CCB) FileObject->FsContext2;
         }
 
-        DEBUG(DL_INF, ( "Ext2Close: (VCB) bBeingClosed = %d Vcb = %p ReferCount = %d\n",
-                        bBeingClosed, Vcb, Vcb->ReferenceCount));
+        DEBUG(DL_INF, ( "Ext2Close: (VCB) Vcb = %p ReferCount = %d\n",
+                         Vcb, Vcb->ReferenceCount));
+
+        /*
+         * WARNING: don't release Vcb resource lock here.
+         *
+         *  CcPurgeCacheSection will lead a recursive irp: IRP_MJ_CLOSE
+         *  which would cause revrese order of lock acquirision:
+         *  1) IRP_MJ_CLEANUP: a) Vcb lock -> b) Fcb lock
+         *  2) IRP_MJ_CLOSE:   c) Vcb lock -> d) Fcb lock
+         */
 
         if (Fcb->Identifier.Type == EXT2VCB) {
 
+            if (!ExAcquireResourceExclusiveLite(
+                            &Vcb->MainResource,
+                            TRUE )) {
+                DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
+                                   Vcb->OpenHandleCount, Vcb->ReferenceCount));
+                Status = STATUS_PENDING;
+                _SEH2_LEAVE;
+            }
+            VcbResourceAcquired = TRUE;
+
             if (Ccb) {
 
                 Ext2DerefXcb(&Vcb->ReferenceCount);
@@ -112,7 +111,7 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
         }
 
         if ( Fcb->Identifier.Type != EXT2FCB ||
-                Fcb->Identifier.Size != sizeof(EXT2_FCB)) {
+             Fcb->Identifier.Size != sizeof(EXT2_FCB)) {
             _SEH2_LEAVE;
         }
 
@@ -126,68 +125,40 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
 
         Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
 
-        if (!Ccb) {
+        if (Ccb == NULL ||
+            Ccb->Identifier.Type != EXT2CCB ||
+            Ccb->Identifier.Size != sizeof(EXT2_CCB)) {
             Status = STATUS_SUCCESS;
             _SEH2_LEAVE;
         }
 
-        ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
-               (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
-        if (IsFlagOn(Fcb->Flags, FCB_STATE_BUSY)) {
-            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_FILE_BUSY);
-            DEBUG(DL_WRN, ( "Ext2Close: busy bit set: %wZ\n", &Fcb->Mcb->FullName ));
-            Status = STATUS_PENDING;
-            _SEH2_LEAVE;
-        }
-
         DEBUG(DL_INF, ( "Ext2Close: Fcb = %p OpenHandleCount= %u ReferenceCount=%u NonCachedCount=%u %wZ\n",
                         Fcb, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName ));
 
-        if (Ccb) {
-
-            Ext2FreeCcb(Vcb, Ccb);
-
-            if (FileObject) {
-                FileObject->FsContext2 = Ccb = NULL;
-            }
+        Ext2FreeCcb(Vcb, Ccb);
+        if (FileObject) {
+            FileObject->FsContext2 = Ccb = NULL;
         }
 
-        if (0 == Ext2DerefXcb(&Fcb->ReferenceCount)) {
-
-            //
-            // Remove Fcb from Vcb->FcbList ...
-            //
-
-            if (FcbResourceAcquired) {
-                ExReleaseResourceLite(&Fcb->MainResource);
-                FcbResourceAcquired = FALSE;
-            }
-
-            Ext2FreeFcb(Fcb);
+        /* only deref fcb, Ext2ReleaseFcb might lead deadlock */
+        FcbDerefDeferred = TRUE;
+        if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
+            NULL == Fcb->Mcb ||
+            IsFileDeleted(Fcb->Mcb)) {
+            Fcb->TsDrop.QuadPart = 0;
+        } else {
+            KeQuerySystemTime(&Fcb->TsDrop);
+        }
+        Ext2DerefXcb(&Vcb->ReferenceCount);
 
-            if (FileObject) {
-                FileObject->FsContext = Fcb = NULL;
-            }
+        if (FileObject) {
+            FileObject->FsContext = NULL;
         }
 
-        Ext2DerefXcb(&Vcb->ReferenceCount);
         Status = STATUS_SUCCESS;
 
     } _SEH2_FINALLY {
 
-        if (NT_SUCCESS(Status) && Vcb != NULL && IsVcbInited(Vcb)) {
-            /* for Ext2Fsd driver open/close, Vcb is NULL */
-            if ((!bBeingClosed) && (Vcb->ReferenceCount == 0) &&
-                (!IsMounted(Vcb) || IsDispending(Vcb))) {
-                bDeleteVcb = TRUE;
-            }
-        }
-
-        if (bSkipLeave && !bBeingClosed) {
-            ClearFlag(Vcb->Flags, VCB_BEING_CLOSED);
-        }
-
         if (FcbResourceAcquired) {
             ExReleaseResourceLite(&Fcb->MainResource);
         }
@@ -205,17 +176,11 @@ Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
             } else {
 
                 Ext2CompleteIrpContext(IrpContext, Status);
-
-                if (bDeleteVcb) {
-
-                    PVPB Vpb = Vcb->Vpb;
-                    DEBUG(DL_DBG, ( "Ext2Close: Try to free Vcb %p and Vpb %p\n",
-                                    Vcb, Vpb));
-
-                    Ext2CheckDismount(IrpContext, Vcb, FALSE);
-                }
             }
         }
+
+        if (FcbDerefDeferred)
+            Ext2DerefXcb(&Fcb->ReferenceCount);
     } _SEH2_END;
 
     return Status;
index a72da5a..251343f 100644 (file)
@@ -698,13 +698,14 @@ Ext2CreateFile(
     ULONG               CreateDisposition;
 
     BOOLEAN             bParentFcbCreated = FALSE;
-
 #ifndef __REACTOS__
     BOOLEAN             bDir = FALSE;
 #endif
     BOOLEAN             bFcbAllocated = FALSE;
     BOOLEAN             bCreated = FALSE;
+
     BOOLEAN             bMainResourceAcquired = FALSE;
+    BOOLEAN             bFcbLockAcquired = FALSE;
 
     BOOLEAN             OpenDirectory;
     BOOLEAN             OpenTargetDirectory;
@@ -776,14 +777,14 @@ Ext2CreateFile(
 
         if (ParentFcb) {
             ParentMcb = ParentFcb->Mcb;
-            SetLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
             Ext2ReferMcb(ParentMcb);
+            ParentFcb = NULL;
         }
 
         if (FileName.Length == 0) {
 
-            if (ParentFcb) {
-                Mcb = ParentFcb->Mcb;
+            if (ParentMcb) {
+                Mcb = ParentMcb;
                 Ext2ReferMcb(Mcb);
                 Status = STATUS_SUCCESS;
                 goto McbExisting;
@@ -811,7 +812,7 @@ Ext2CreateFile(
         RtlZeroMemory(FileName.Buffer, FileName.MaximumLength);
         RtlCopyMemory(FileName.Buffer, IrpSp->FileObject->FileName.Buffer, FileName.Length);
 
-        if (ParentFcb && FileName.Buffer[0] == L'\\') {
+        if (IrpSp->FileObject->RelatedFileObject && FileName.Buffer[0] == L'\\') {
             Status = STATUS_INVALID_PARAMETER;
             _SEH2_LEAVE;
         }
@@ -952,9 +953,9 @@ Dissecting:
                 _SEH2_LEAVE;
             }
 
-            /* clear BUSY bit from original ParentFcb */
-            if (ParentFcb) {
-                ClearLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
+            if (!bFcbLockAcquired) {
+                ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+                bFcbLockAcquired = TRUE;
             }
 
             /* get the ParentFcb, allocate it if needed ... */
@@ -966,9 +967,13 @@ Dissecting:
                     _SEH2_LEAVE;
                 }
                 bParentFcbCreated = TRUE;
-                Ext2ReferXcb(&ParentFcb->ReferenceCount);
             }
-            SetLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
+            Ext2ReferXcb(&ParentFcb->ReferenceCount);
+
+            if (bFcbLockAcquired) {
+                ExReleaseResourceLite(&Vcb->FcbLock);
+                bFcbLockAcquired = FALSE;
+            }
 
             // We need to create a new one ?
             if ((CreateDisposition == FILE_CREATE ) ||
@@ -1157,6 +1162,12 @@ Dissecting:
         }
 
 Openit:
+
+        if (!bFcbLockAcquired) {
+            ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+            bFcbLockAcquired = TRUE;
+        }
+
         /* Mcb should already be referred and symlink is too */
         if (Mcb) {
 
@@ -1221,10 +1232,15 @@ Openit:
         }
 
         if (Fcb) {
-
             /* grab Fcb's reference first to avoid the race between
                Ext2Close  (it could free the Fcb we are accessing) */
             Ext2ReferXcb(&Fcb->ReferenceCount);
+        }
+
+        ExReleaseResourceLite(&Vcb->FcbLock);
+        bFcbLockAcquired = FALSE;
+
+        if (Fcb) {
 
             ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
             bMainResourceAcquired = TRUE;
@@ -1565,6 +1581,9 @@ Openit:
 
     } _SEH2_FINALLY {
 
+        if (bFcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+        }
 
         if (ParentMcb) {
             Ext2DerefMcb(ParentMcb);
@@ -1606,29 +1625,24 @@ Openit:
 
                 Ext2FreeCcb(Vcb, Ccb);
             }
-        }
-
-        if (Fcb && Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
-
-            if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
 
-                LARGE_INTEGER Size;
-                ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
-                _SEH2_TRY {
-                    Size.QuadPart = 0;
-                    Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
-                } _SEH2_FINALLY {
-                    ExReleaseResourceLite(&Fcb->PagingIoResource);
-                } _SEH2_END;
-            }
+            if (Fcb != NULL) {
+
+                if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
+                    LARGE_INTEGER Size;
+                    ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
+                    _SEH2_TRY {
+                        Size.QuadPart = 0;
+                        Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
+                    } _SEH2_FINALLY {
+                        ExReleaseResourceLite(&Fcb->PagingIoResource);
+                    } _SEH2_END;
+                }
 
-            if (bCreated) {
-                Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
+                if (bCreated) {
+                    Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
+                }
             }
-
-            Ext2FreeFcb(Fcb);
-            Fcb = NULL;
-            bMainResourceAcquired = FALSE;
         }
 
         if (bMainResourceAcquired) {
@@ -1641,14 +1655,12 @@ Openit:
             Ext2FreePool(FileName.Buffer, EXT2_FNAME_MAGIC);
         }
 
-        /* dereference parent Fcb, free it if it goes to zero */
+        /* dereference Fcb and parent */
+        if (Fcb) {
+            Ext2ReleaseFcb(Fcb);
+        }
         if (ParentFcb) {
-            ClearLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
-            if (bParentFcbCreated) {
-                if (Ext2DerefXcb(&ParentFcb->ReferenceCount) == 0) {
-                    Ext2FreeFcb(ParentFcb);
-                }
-            }
+            Ext2ReleaseFcb(ParentFcb);
         }
 
         /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer
index 9bc2747..4e38352 100644 (file)
@@ -48,9 +48,6 @@ Ext2LoadSuper(IN PEXT2_VCB      Vcb,
                  bVerify );
 
     if (!NT_SUCCESS(Status)) {
-
-        DEBUG(DL_ERR, ( "Ext2ReadDisk: disk device error.\n"));
-
         Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
         Ext2Sb = NULL;
     }
@@ -209,7 +206,7 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
 
 
 VOID
-Ext2DropGroup(IN PEXT2_VCB Vcb)
+Ext2DropBH(IN PEXT2_VCB Vcb)
 {
     struct ext3_sb_info *sbi = &Vcb->sbi;
     LARGE_INTEGER        timeout;
@@ -220,17 +217,26 @@ Ext2DropGroup(IN PEXT2_VCB Vcb)
         return;
 
     _SEH2_TRY {
+
+        /* acquire bd lock to avoid bh creation */
+        ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
         SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
-        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
         Ext2PutGroup(Vcb);
+
+        while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+            struct buffer_head *bh;
+            PLIST_ENTRY         l;
+            l = RemoveHeadList(&Vcb->bd.bd_bh_free);
+            bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
+            ASSERT(0 == atomic_read(&bh->b_count));
+            free_buffer_head(bh);
+        }
+
     } _SEH2_FINALLY {
-        ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+        ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
     } _SEH2_END;
 
-    timeout.QuadPart = (LONGLONG)-10*1000*1000;
-    KeWaitForSingleObject(&Vcb->bd.bd_bh_notify,
-                           Executive, KernelMode,
-                           FALSE, &timeout);
     ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
 }
 
index 3d47033..c23557e 100644 (file)
@@ -1099,77 +1099,6 @@ out:
        return err;
 }
 
-static int ext4_ext_shrink_indepth(void *icb,
-                                  handle_t *handle,
-                                  struct inode *inode,
-                                  unsigned int flags,
-                                  int *shrinked)
-{
-       struct ext4_extent_header *eh, *neh;
-       struct ext4_extent_idx *ix;
-       struct buffer_head *bh = NULL;
-       ext4_fsblk_t block;
-       int err = 0, depth = ext_depth(inode);
-       int neh_entries;
-       *shrinked = 0;
-
-       if (!depth)
-               return 0;
-
-       eh = ext_inode_hdr(inode);
-       if (le16_to_cpu(eh->eh_entries) != 1)
-               return 0;
-
-       ix = EXT_FIRST_INDEX(eh);
-       block = ext4_idx_pblock(ix);
-       bh = extents_bread(inode->i_sb, block);
-       if (!bh)
-               goto out;
-
-       /* set size of new block */
-       neh = ext_block_hdr(bh);
-       neh_entries = le16_to_cpu(neh->eh_entries);
-       if (!neh->eh_depth &&
-           neh_entries > ext4_ext_space_root(inode, 0))
-               goto out;
-
-       if (neh->eh_depth &&
-           neh_entries > ext4_ext_space_root_idx(inode, 0))
-               goto out;
-
-       /* old root could have indexes or leaves
-        * so calculate e_max right way */
-       if (neh->eh_depth)
-               eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
-       else
-               eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
-
-       eh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
-       eh->eh_entries = neh_entries;
-       if (neh->eh_depth) {
-               memmove(EXT_FIRST_INDEX(eh),
-                       EXT_FIRST_INDEX(neh),
-                       sizeof(struct ext4_extent_idx) * neh_entries);
-       } else {
-               memmove(EXT_FIRST_EXTENT(eh),
-                       EXT_FIRST_EXTENT(neh),
-                       sizeof(struct ext4_extent) * neh_entries);
-       }
-       le16_add_cpu(&eh->eh_depth, -1);
-
-       ext4_mark_inode_dirty(icb, handle, inode);
-       *shrinked = 1;
-out:
-       if (bh)
-               extents_brelse(bh);
-
-       if (*shrinked)
-               ext4_free_blocks(icb, handle, inode, NULL,
-                                block, 1, flags);
-
-       return err;
-}
-
 /*
  * ext4_ext_create_new_leaf:
  * finds empty index and adds new leaf.
@@ -1427,25 +1356,29 @@ found_extent:
  * with leaves.
  */
 ext4_lblk_t
-ext4_ext_next_allocated_block(struct ext4_ext_path *path, int at)
+ext4_ext_next_allocated_block(struct ext4_ext_path *path)
 {
-       if (at == 0 && !path->p_ext && !path->p_idx)
+       int depth;
+
+       depth = path->p_depth;
+
+       if (depth == 0 && path->p_ext == NULL)
                return EXT_MAX_BLOCKS;
 
-       while (at >= 0) {
-               if (at == path->p_depth) {
+       while (depth >= 0) {
+               if (depth == path->p_depth) {
                        /* leaf */
-                       if (path[at].p_ext &&
-                               path[at].p_ext !=
-                                       EXT_LAST_EXTENT(path[at].p_hdr))
-                         return le32_to_cpu(path[at].p_ext[1].ee_block);
+                       if (path[depth].p_ext &&
+                                       path[depth].p_ext !=
+                                       EXT_LAST_EXTENT(path[depth].p_hdr))
+                               return le32_to_cpu(path[depth].p_ext[1].ee_block);
                } else {
                        /* index */
-                       if (path[at].p_idx !=
-                                       EXT_LAST_INDEX(path[at].p_hdr))
-                         return le32_to_cpu(path[at].p_idx[1].ei_block);
+                       if (path[depth].p_idx !=
+                                       EXT_LAST_INDEX(path[depth].p_hdr))
+                               return le32_to_cpu(path[depth].p_idx[1].ei_block);
                }
-               at--;
+               depth--;
        }
 
        return EXT_MAX_BLOCKS;
@@ -1482,14 +1415,12 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path)
 
 /*
  * ext4_ext_correct_indexes:
- * if leaf/node gets modified and modified extent/index
- * is first in the leaf/node,
+ * if leaf gets modified and modified extent is first in the leaf,
  * then we have to correct all indexes above.
+ * TODO: do we need to correct tree in all cases?
  */
-static int ext4_ext_correct_indexes(void *icb, handle_t *handle,
-                                   struct inode *inode,
-                                   struct ext4_ext_path *path,
-                                   int at)
+static int ext4_ext_correct_indexes(void *icb, handle_t *handle, struct inode *inode,
+               struct ext4_ext_path *path)
 {
        struct ext4_extent_header *eh;
        int depth = ext_depth(inode);
@@ -1497,49 +1428,49 @@ static int ext4_ext_correct_indexes(void *icb, handle_t *handle,
        __le32 border;
        int k, err = 0;
 
-       assert(at >= 0);
-       if (!at)
-               return 0;
-
-       if (depth == at) {
-               eh = path[at].p_hdr;
-               ex = path[at].p_ext;
-
-               if (ex == NULL || eh == NULL)
-                       return -EIO;
-
-               if (at == 0) {
-                       /* there is no tree at all */
-                       return 0;
-               }
+       eh = path[depth].p_hdr;
+       ex = path[depth].p_ext;
 
-               if (ex != EXT_FIRST_EXTENT(eh)) {
-                       /* we correct tree if first leaf got modified only */
-                       return 0;
-               }
+       if (unlikely(ex == NULL || eh == NULL)) {
+               EXT4_ERROR_INODE(inode,
+                               "ex %p == NULL or eh %p == NULL", ex, eh);
+               return -EIO;
+       }
 
-               k = at - 1;
-               border = path[at].p_ext->ee_block;
-               path[k].p_idx->ei_block = border;
-               err = ext4_ext_dirty(icb, handle, inode, path + k);
-               if (err)
-                       return err;
+       if (depth == 0) {
+               /* there is no tree at all */
+               return 0;
+       }
 
-       } else {
-               border = path[at].p_idx->ei_block;
-               k = at;
+       if (ex != EXT_FIRST_EXTENT(eh)) {
+               /* we correct tree if first leaf got modified only */
+               return 0;
        }
 
-       while (k) {
+       /*
+        * TODO: we need correction if border is smaller than current one
+        */
+       k = depth - 1;
+       border = path[depth].p_ext->ee_block;
+       err = ext4_ext_get_access(icb, handle, inode, path + k);
+       if (err)
+               return err;
+       path[k].p_idx->ei_block = border;
+       err = ext4_ext_dirty(icb, handle, inode, path + k);
+       if (err)
+               return err;
+
+       while (k--) {
                /* change all left-side indexes */
-               if (path[k].p_idx != EXT_FIRST_INDEX(path[k].p_hdr))
+               if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
                        break;
-               path[k-1].p_idx->ei_block = border;
-               err = ext4_ext_dirty(icb, handle, inode, path + k-1);
+               err = ext4_ext_get_access(icb, handle, inode, path + k);
+               if (err)
+                       break;
+               path[k].p_idx->ei_block = border;
+               err = ext4_ext_dirty(icb, handle, inode, path + k);
                if (err)
                        break;
-
-               k--;
        }
 
        return err;
@@ -1914,11 +1845,9 @@ merge:
        if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
                ext4_ext_try_to_merge(icb, handle, inode, path, nearex);
 
-       depth = ext_depth(inode);
 
        /* time to correct all indexes above */
-       err = ext4_ext_correct_indexes(icb, handle,
-                       inode, path, depth);
+       err = ext4_ext_correct_indexes(icb, handle, inode, path);
        if (err)
                goto cleanup;
 
@@ -1952,351 +1881,156 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
        return ret;
 }
 
-static void ext4_ext_remove_blocks(
-               void *icb,
-               handle_t *handle,
-               struct inode *inode, struct ext4_extent *ex,
-               ext4_lblk_t from, ext4_lblk_t to)
+static int ext4_remove_blocks(void *icb, handle_t *handle, struct inode *inode,
+               struct ext4_extent *ex,
+               unsigned long from, unsigned long to)
 {
-       int len = to - from + 1;
-       ext4_lblk_t num;
-       ext4_fsblk_t start;
-       num = from - le32_to_cpu(ex->ee_block);
-       start = ext4_ext_pblock(ex) + num;
-       ext_debug("Freeing %lu at %I64u, %d\n", from, start, len);
-       ext4_free_blocks(icb, handle, inode, NULL,
-                        start, len, 0);
-}
-
-static int ext4_ext_remove_idx(void *icb,
-               handle_t *handle,
-               struct inode *inode,
-               struct ext4_ext_path *path,
-               int depth)
-{
-       int err, i = depth;
-       ext4_fsblk_t leaf;
-
-       /* free index block */
-       leaf = ext4_idx_pblock(path[i].p_idx);
-
-       if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) {
-               int len = EXT_LAST_INDEX(path[i].p_hdr) - path[i].p_idx;
-               memmove(path[i].p_idx, path[i].p_idx + 1,
-                       len * sizeof(struct ext4_extent_idx));
-       }
-
-       le16_add_cpu(&path[i].p_hdr->eh_entries, -1);
-       err = ext4_ext_dirty(icb, handle, inode, path + i);
-       if (err)
-               return err;
-
-       ext_debug("IDX: Freeing %lu at %I64u, %d\n",
-               le32_to_cpu(path[i].p_idx->ei_block), leaf, 1);
-       ext4_free_blocks(icb, handle, inode, NULL,
-                        leaf, 1, 0);
-       return err;
-}
-
-static int ext4_ext_amalgamate(void *icb,
-                              handle_t *handle,
-                              struct inode *inode,
-                              struct ext4_ext_path *path,
-                              int at)
-{
-       int new_entries, right_entries;
-       int depth = ext_depth(inode);
-       struct ext4_ext_path *right_path = NULL;
-       ext4_lblk_t now;
-       int ret = 0;
-       if (!at)
-               return 0;
-
-       now = ext4_ext_next_allocated_block(path, at - 1);
-       if (now == EXT_MAX_BLOCKS)
-               goto out;
-
-       right_path = ext4_find_extent(inode, now, NULL, 0);
-       if (IS_ERR(right_path)) {
-               ret = PTR_ERR(right_path);
-               right_path = NULL;
-               goto out;
-       }
+       struct buffer_head *bh;
+       int i;
 
-       right_entries = le16_to_cpu(right_path[at].p_hdr->eh_entries);
-       new_entries = le16_to_cpu(path[at].p_hdr->eh_entries) +
-                     right_entries;
-       if (new_entries > path[at].p_hdr->eh_max) {
-               ret = 0;
-               goto out;
-       }
-       if (at == depth) {
-               struct ext4_extent *last_ex = EXT_LAST_EXTENT(path[at].p_hdr);
-               memmove(last_ex + 1,
-                       EXT_FIRST_EXTENT(right_path[at].p_hdr),
-                       right_entries * sizeof(struct ext4_extent));
+       if (from >= le32_to_cpu(ex->ee_block)
+                       && to == le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) {
+               /* tail removal */
+               unsigned long num, start;
+               num = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - from;
+               start = ext4_ext_pblock(ex) + ext4_ext_get_actual_len(ex) - num;
+               ext4_free_blocks(icb, handle, inode, NULL, start, num, 0);
+       } else if (from == le32_to_cpu(ex->ee_block)
+                       && to <= le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) {
        } else {
-               struct ext4_extent_idx *last_ix = EXT_LAST_INDEX(path[at].p_hdr);
-               memmove(last_ix + 1,
-                       EXT_FIRST_INDEX(right_path[at].p_hdr),
-                       right_entries * sizeof(struct ext4_extent_idx));
        }
-       path[at].p_hdr->eh_entries = cpu_to_le16(new_entries);
-       right_path[at].p_hdr->eh_entries = 0;
-       ext4_ext_dirty(icb, handle, inode, path + at);
-
-       /*
-        * remove the empty node from index block above.
-        */
-       depth = at;
-       while (depth > 0) {
-               struct ext4_extent_header *eh = right_path[depth].p_hdr;
-               if (eh->eh_entries == 0 && right_path[depth].p_bh != NULL) {
-                       ext4_ext_drop_refs(right_path + depth);
-                       ret = ext4_ext_remove_idx(icb, handle, inode, right_path, depth - 1);
-                       if (ret)
-                               goto out;
-
-               } else
-                       break;
-
-               depth--;
-       }
-       ret = ext4_ext_correct_indexes(icb, handle,
-                       inode, right_path, depth);
-out:
-       if (right_path) {
-               ext4_ext_drop_refs(right_path);
-               kfree(right_path);
-       }
-
-       return ret;
-}
-
-static int ext4_ext_balance(void *icb,
-                           handle_t *handle,
-                           struct inode *inode,
-                           struct ext4_ext_path **path,
-                           int at)
-{
-       int ret, shrinked = 0;
-       int depth = at;
-
-       while (depth > 0) {
-               ret = ext4_ext_amalgamate(icb, handle,
-                               inode, *path, depth);
-               if (ret)
-                       goto out;
-
-               depth--;
-       }
-       do {
-               ret = ext4_ext_shrink_indepth(icb, handle,
-                               inode, 0, &shrinked);
-       } while (!ret && shrinked);
-
-out:
-       return ret;
+       return 0;
 }
 
 /*
- * NOTE: After removal, path should not be reused.
+ * routine removes index from the index block
+ * it's used in truncate case only. thus all requests are for
+ * last index in the block only
  */
-int ext4_ext_remove_extent(void *icb,
-               handle_t *handle,
-               struct inode *inode, struct ext4_ext_path **path)
+int ext4_ext_rm_idx(void *icb, handle_t *handle, struct inode *inode,
+               struct ext4_ext_path *path)
 {
-       int len;
-       int err = 0;
-       ext4_lblk_t start;
-       uint16_t new_entries;
-       int depth = ext_depth(inode);
-       struct ext4_extent *ex = (*path)[depth].p_ext,
-                          *ex2 = ex + 1;
-       struct ext4_extent_header *eh = (*path)[depth].p_hdr;
-       if (!ex)
-               return -EINVAL;
-
-       start = le32_to_cpu(ex->ee_block);
-       len = ext4_ext_get_actual_len(ex);
-       new_entries = le16_to_cpu(eh->eh_entries) - 1;
-
-       ext4_ext_remove_blocks(icb, handle,
-                       inode, ex, start, start + len - 1);
-       if (ex2 <= EXT_LAST_EXTENT(eh))
-               memmove(ex, ex2,
-                       (EXT_LAST_EXTENT(eh) - ex2 + 1) * sizeof(struct ext4_extent));
-       eh->eh_entries = cpu_to_le16(new_entries);
-
-       ext4_ext_dirty(icb, handle, inode, (*path) + depth);
-
-       /*
-        * If the node is free, then we should
-        * remove it from index block above.
-        */
-       while (depth > 0) {
-               eh = (*path)[depth].p_hdr;
-               if (eh->eh_entries == 0 && (*path)[depth].p_bh != NULL) {
-                       ext4_ext_drop_refs((*path) + depth);
-                       err = ext4_ext_remove_idx(icb, handle,
-                                       inode, *path, depth - 1);
-                       if (err)
-                               break;
-
-               } else
-                       break;
-
-               depth--;
-       }
-       err = ext4_ext_correct_indexes(icb, handle,
-                       inode, *path, depth);
-
-       if ((*path)->p_hdr->eh_entries == 0) {
-               /*
-                * truncate to zero freed all the tree,
-                * so we need to correct eh_depth
-                */
-               ext_inode_hdr(inode)->eh_depth = 0;
-               ext_inode_hdr(inode)->eh_max =
-                       cpu_to_le16(ext4_ext_space_root(inode, 0));
-               err = ext4_ext_dirty(icb, handle, inode, *path);
-       }
-       err = ext4_ext_balance(icb, handle, inode, path, depth);
+       int err;
+       ext4_fsblk_t leaf;
 
+       /* free index block */
+       path--;
+       leaf = ext4_idx_pblock(path->p_idx);
+       BUG_ON(path->p_hdr->eh_entries == 0);
+       if ((err = ext4_ext_get_access(icb, handle, inode, path)))
+               return err;
+       path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
+       if ((err = ext4_ext_dirty(icb, handle, inode, path)))
+               return err;
+       ext4_free_blocks(icb, handle, inode, NULL, leaf, 1, 0);
        return err;
 }
 
-int __ext4_ext_truncate(void *icb,
-                       handle_t *handle,
-                       struct inode *inode,
-                       ext4_lblk_t from, ext4_lblk_t to)
+static int
+ext4_ext_rm_leaf(void *icb, handle_t *handle, struct inode *inode,
+               struct ext4_ext_path *path, unsigned long start)
 {
-       int depth = ext_depth(inode), ret = -EIO;
+       int err = 0, correct_index = 0;
+       int depth = ext_depth(inode), credits;
+       struct ext4_extent_header *eh;
+       unsigned a, b, block, num;
+       unsigned long ex_ee_block;
+       unsigned short ex_ee_len;
        struct ext4_extent *ex;
-       struct ext4_ext_path *path = NULL, *npath;
-       ext4_lblk_t now = from;
-
-       if (to < from)
-               return -EINVAL;
-
-       npath = ext4_find_extent(inode, from, &path, 0);
-       if (IS_ERR(npath))
-               goto out;
 
-       path = npath;
-       ex = path[depth].p_ext;
-       if (!ex)
-               goto out;
-
-       if (from < le32_to_cpu(ex->ee_block) &&
-           to < le32_to_cpu(ex->ee_block)) {
-               ret = 0;
-               goto out;
-       }
-       /* If we do remove_space inside the range of an extent */
-       if ((le32_to_cpu(ex->ee_block) < from) &&
-           (to < le32_to_cpu(ex->ee_block) +
-                       ext4_ext_get_actual_len(ex) - 1)) {
-
-               struct ext4_extent newex;
-               int unwritten = ext4_ext_is_unwritten(ex);
-               ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
-               int len = ext4_ext_get_actual_len(ex);
-               ext4_fsblk_t newblock =
-                       to + 1 - ee_block + ext4_ext_pblock(ex);
-
-               ex->ee_len = cpu_to_le16(from - ee_block);
-               if (unwritten)
-                       ext4_ext_mark_unwritten(ex);
+       /* the header must be checked already in ext4_ext_remove_space() */
+       if (!path[depth].p_hdr)
+               path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
+       eh = path[depth].p_hdr;
+       BUG_ON(eh == NULL);
+
+       /* find where to start removing */
+       ex = EXT_LAST_EXTENT(eh);
+
+       ex_ee_block = le32_to_cpu(ex->ee_block);
+       ex_ee_len = ext4_ext_get_actual_len(ex);
+
+       while (ex >= EXT_FIRST_EXTENT(eh) &&
+                       ex_ee_block + ex_ee_len > start) {
+               path[depth].p_ext = ex;
+
+               a = ex_ee_block > start ? ex_ee_block : start;
+               b = (unsigned long long)ex_ee_block + ex_ee_len - 1 < 
+                       EXT_MAX_BLOCKS ? ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCKS;
+
+
+               if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) {
+                       block = 0;
+                       num = 0;
+                       BUG();
+               } else if (a != ex_ee_block) {
+                       /* remove tail of the extent */
+                       block = ex_ee_block;
+                       num = a - block;
+               } else if (b != ex_ee_block + ex_ee_len - 1) {
+                       /* remove head of the extent */
+                       block = a;
+                       num = b - a;
+                       /* there is no "make a hole" API yet */
+                       BUG();
+               } else {
+                       /* remove whole extent: excellent! */
+                       block = ex_ee_block;
+                       num = 0;
+                       BUG_ON(a != ex_ee_block);
+                       BUG_ON(b != ex_ee_block + ex_ee_len - 1);
+               }
 
-               ext4_ext_dirty(icb, handle, inode, path + depth);
+               /* at present, extent can't cross block group */
+               /* leaf + bitmap + group desc + sb + inode */
+               credits = 5;
+               if (ex == EXT_FIRST_EXTENT(eh)) {
+                       correct_index = 1;
+                       credits += (ext_depth(inode)) + 1;
+               }
 
-               ext4_ext_remove_blocks(icb, handle,
-                               inode,
-                               ex, from, to);
+               /*handle = ext4_ext_journal_restart(icb, handle, credits);*/
+               /*if (IS_ERR(icb, handle)) {*/
+               /*err = PTR_ERR(icb, handle);*/
+               /*goto out;*/
+               /*}*/
 
-               newex.ee_block = cpu_to_le32(to + 1);
-               newex.ee_len = cpu_to_le16(ee_block + len - 1 - to);
-               ext4_ext_store_pblock(&newex, newblock);
-               if (unwritten)
-                       ext4_ext_mark_unwritten(&newex);
+               err = ext4_ext_get_access(icb, handle, inode, path + depth);
+               if (err)
+                       goto out;
 
-               ret = ext4_ext_insert_extent(icb, handle,
-                               inode, &path, &newex, 0);
-               goto out;
-       }
-       if (le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 < from) {
-               now = ext4_ext_next_allocated_block(path, depth);
-               npath = ext4_find_extent(inode, now, &path, 0);
-               if (IS_ERR(npath))
+               err = ext4_remove_blocks(icb, handle, inode, ex, a, b);
+               if (err)
                        goto out;
 
-               path = npath;
-               ex = path[depth].p_ext;
-       }
-       while (ex &&
-              le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 >= now &&
-              le32_to_cpu(ex->ee_block) <= to) {
-               int len, new_len = 0;
-               int unwritten;
-               ext4_lblk_t start, new_start;
-               ext4_fsblk_t newblock;
-
-               new_start = start = le32_to_cpu(ex->ee_block);
-               len = ext4_ext_get_actual_len(ex);
-               newblock = ext4_ext_pblock(ex);
-               if (start < from) {
-                       len -= from - start;
-                       new_len = from - start;
-                       start = from;
-               } else {
-                       if (start + len - 1 > to) {
-                               new_len = start + len - 1 - to;
-                               len -= new_len;
-                               new_start = to + 1;
-                               newblock += to + 1 - start;
-                       }
+               if (num == 0) {
+                       /* this extent is removed entirely mark slot unused */
+                       ext4_ext_store_pblock(ex, 0);
+                       eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
                }
 
-               now = ext4_ext_next_allocated_block(path, depth);
-               if (!new_len) {
-                       ret = ext4_ext_remove_extent(icb, handle,
-                                       inode, &path);
-                       if (ret)
-                               goto out;
-
-               } else {
-                       ext4_ext_remove_blocks(icb, handle,
-                               inode,
-                               ex, start, start + len - 1);
-                       ex->ee_block = cpu_to_le32(new_start);
-                       unwritten = ext4_ext_is_unwritten(ex);
-                       ex->ee_len = cpu_to_le16(new_len);
-                       ext4_ext_store_pblock(ex, newblock);
-                       if (unwritten)
-                               ext4_ext_mark_unwritten(ex);
+               ex->ee_block = cpu_to_le32(block);
+               ex->ee_len = cpu_to_le16(num);
 
-                       ext4_ext_dirty(icb, handle,
-                               inode, path + depth);
-               }
-               npath = ext4_find_extent(inode, now, &path, 0);
-               if (IS_ERR(npath))
+               err = ext4_ext_dirty(icb, handle, inode, path + depth);
+               if (err)
                        goto out;
 
-               path = npath;
-               depth = ext_depth(inode);
-               ex = path[depth].p_ext;
-       }
-out:
-       if (path) {
-               ext4_ext_drop_refs(path);
-               kfree(path);
+               ex--;
+               ex_ee_block = le32_to_cpu(ex->ee_block);
+               ex_ee_len = ext4_ext_get_actual_len(ex);
        }
 
-       if (IS_ERR(npath))
-               ret = PTR_ERR(npath);
+       if (correct_index && eh->eh_entries)
+               err = ext4_ext_correct_indexes(icb, handle, inode, path);
 
-       return ret;
+       /* if this leaf is free, then we should
+        * remove it from index block above */
+       if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
+               err = ext4_ext_rm_idx(icb, handle, inode, path + depth);
+
+out:
+       return err;
 }
 
 /*
@@ -2438,6 +2172,140 @@ fix_extent_len:
        return err;
 }
 
+/*
+ * returns 1 if current index have to be freed (even partial)
+ */
+#ifndef __REACTOS__
+static int inline
+#else
+inline int
+#endif
+ext4_ext_more_to_rm(struct ext4_ext_path *path)
+{
+       BUG_ON(path->p_idx == NULL);
+
+       if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
+               return 0;
+
+       /*
+        * if truncate on deeper level happened it it wasn't partial
+        * so we have to consider current index for truncation
+        */
+       if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block)
+               return 0;
+       return 1;
+}
+
+int ext4_ext_remove_space(void *icb, struct inode *inode, unsigned long start)
+{
+       struct super_block *sb = inode->i_sb;
+       int depth = ext_depth(inode);
+       struct ext4_ext_path *path;
+       handle_t *handle = NULL;
+       int i = 0, err = 0;
+
+       /* probably first extent we're gonna free will be last in block */
+       /*handle = ext4_journal_start(inode, depth + 1);*/
+       /*if (IS_ERR(icb, handle))*/
+       /*return PTR_ERR(icb, handle);*/
+
+       /*
+        * we start scanning from right side freeing all the blocks
+        * after i_size and walking into the deep
+        */
+       path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
+       if (path == NULL) {
+               ext4_journal_stop(icb, handle);
+               return -ENOMEM;
+       }
+       memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
+       path[0].p_hdr = ext_inode_hdr(inode);
+       if (ext4_ext_check_inode(inode)) {
+               err = -EIO;
+               goto out;
+       }
+       path[0].p_depth = depth;
+
+       while (i >= 0 && err == 0) {
+               if (i == depth) {
+                       /* this is leaf block */
+                       err = ext4_ext_rm_leaf(icb, handle, inode, path, start);
+                       /* root level have p_bh == NULL, extents_brelse() eats this */
+                       extents_brelse(path[i].p_bh);
+                       path[i].p_bh = NULL;
+                       i--;
+                       continue;
+               }
+
+               /* this is index block */
+               if (!path[i].p_hdr) {
+                       path[i].p_hdr = ext_block_hdr(path[i].p_bh);
+               }
+
+               if (!path[i].p_idx) {
+                       /* this level hasn't touched yet */
+                       path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
+                       path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
+               } else {
+                       /* we've already was here, see at next index */
+                       path[i].p_idx--;
+               }
+
+               if (ext4_ext_more_to_rm(path + i)) {
+                       struct buffer_head *bh;
+                       /* go to the next level */
+                       memset(path + i + 1, 0, sizeof(*path));
+                       bh = read_extent_tree_block(inode, ext4_idx_pblock(path[i].p_idx), path[0].p_depth - (i + 1), 0);
+                       if (IS_ERR(bh)) {
+                               /* should we reset i_size? */
+                               err = -EIO;
+                               break;
+                       }
+                       path[i+1].p_bh = bh;
+
+                       /* put actual number of indexes to know is this
+                        * number got changed at the next iteration */
+                       path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
+                       i++;
+               } else {
+                       /* we finish processing this index, go up */
+                       if (path[i].p_hdr->eh_entries == 0 && i > 0) {
+                               /* index is empty, remove it
+                                * handle must be already prepared by the
+                                * truncatei_leaf() */
+                               err = ext4_ext_rm_idx(icb, handle, inode, path + i);
+                       }
+                       /* root level have p_bh == NULL, extents_brelse() eats this */
+                       extents_brelse(path[i].p_bh);
+                       path[i].p_bh = NULL;
+                       i--;
+               }
+       }
+
+       /* TODO: flexible tree reduction should be here */
+       if (path->p_hdr->eh_entries == 0) {
+               /*
+                * truncate to zero freed all the tree
+                * so, we need to correct eh_depth
+                */
+               err = ext4_ext_get_access(icb, handle, inode, path);
+               if (err == 0) {
+                       ext_inode_hdr(inode)->eh_depth = 0;
+                       ext_inode_hdr(inode)->eh_max =
+                               cpu_to_le16(ext4_ext_space_root(inode, 0));
+                       err = ext4_ext_dirty(icb, handle, inode, path);
+               }
+       }
+out:
+       if (path) {
+               ext4_ext_drop_refs(path);
+               kfree(path);
+       }
+       ext4_journal_stop(icb, handle);
+
+       return err;
+}
+
 int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode)
 {
        struct ext4_extent_header *eh;
@@ -2576,7 +2444,7 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f
 
        /* find next allocated block so that we know how many
         * blocks we can allocate without ovelapping next extent */
-       next = ext4_ext_next_allocated_block(path, depth);
+       next = ext4_ext_next_allocated_block(path);
        BUG_ON(next <= iblock);
        allocated = next - iblock;
        if (flags & EXT4_GET_BLOCKS_PRE_IO && max_blocks > EXT_UNWRITTEN_MAX_LEN)
@@ -2639,8 +2507,7 @@ out2:
 
 int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start)
 {
-       int ret = __ext4_ext_truncate(icb, NULL, inode,
-                       start, EXT_MAX_BLOCKS);
+    int ret = ext4_ext_remove_space(icb, inode, start);
 
        /* Save modifications on i_blocks field of the inode. */
        if (!ret)
index dff7195..cfc016b 100644 (file)
@@ -504,7 +504,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
     ULONG                   Length;
     PVOID                   Buffer;
 
-    BOOLEAN                 VcbMainResourceAcquired = FALSE;
     BOOLEAN                 FcbMainResourceAcquired = FALSE;
     BOOLEAN                 FcbPagingIoResourceAcquired = FALSE;
 
@@ -542,18 +541,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
             _SEH2_LEAVE;
         }
 
-        /* we need grab Vcb in case it's rename or sethardlink */
-        if (FileInformationClass == FileRenameInformation ||
-            FileInformationClass == FileLinkInformation) {
-            if (!ExAcquireResourceExclusiveLite(
-                        &Vcb->MainResource,
-                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
-                Status = STATUS_PENDING;
-                _SEH2_LEAVE;
-            }
-            VcbMainResourceAcquired = TRUE;
-        }
-
         if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
             Status = STATUS_ACCESS_DENIED;
             _SEH2_LEAVE;
@@ -1047,10 +1034,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
             ExReleaseResourceLite(&Fcb->MainResource);
         }
 
-        if (VcbMainResourceAcquired) {
-            ExReleaseResourceLite(&Vcb->MainResource);
-        }
-
         if (!IrpContext->ExceptionInProgress) {
             if (Status == STATUS_PENDING ||
                     Status == STATUS_CANT_WAIT ) {
@@ -1347,8 +1330,7 @@ Ext2SetRenameInfo(
     BOOLEAN                 bMove = FALSE;
     BOOLEAN                 bTargetRemoved = FALSE;
 
-    BOOLEAN                 bNewTargetDcb = FALSE;
-    BOOLEAN                 bNewParentDcb = FALSE;
+    BOOLEAN                 bFcbLockAcquired = FALSE;
 
     PFILE_RENAME_INFORMATION    FRI;
 
@@ -1435,16 +1417,17 @@ Ext2SetRenameInfo(
         bMove = TRUE;
     }
 
+    if (!bFcbLockAcquired) {
+        ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+        bFcbLockAcquired = TRUE;
+    }
+
     TargetDcb = TargetMcb->Fcb;
     if (TargetDcb == NULL) {
         TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
-        if (TargetDcb) {
-            Ext2ReferXcb(&TargetDcb->ReferenceCount);
-            bNewTargetDcb = TRUE;
-        }
     }
     if (TargetDcb) {
-        SetLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+        Ext2ReferXcb(&TargetDcb->ReferenceCount);
     }
 
     ParentMcb = Mcb->Parent;
@@ -1454,15 +1437,16 @@ Ext2SetRenameInfo(
 
         if (ParentDcb == NULL) {
             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
-            if (ParentDcb) {
-                Ext2ReferXcb(&ParentDcb->ReferenceCount);
-                bNewParentDcb = TRUE;
-            }
-        }
-        if (ParentDcb) {
-            SetLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
         }
     }
+    if (ParentDcb) {
+        Ext2ReferXcb(&ParentDcb->ReferenceCount);
+    }
+
+    if (bFcbLockAcquired) {
+        ExReleaseResourceLite(&Vcb->FcbLock);
+        bFcbLockAcquired = FALSE;
+    }
 
     if (!TargetDcb || !ParentDcb) {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -1625,40 +1609,25 @@ Ext2SetRenameInfo(
                  FILE_NOTIFY_CHANGE_DIR_NAME :
                  FILE_NOTIFY_CHANGE_FILE_NAME ),
                 FILE_ACTION_RENAMED_NEW_NAME  );
-
         }
     }
 
 errorout:
 
+    if (bFcbLockAcquired) {
+        ExReleaseResourceLite(&Vcb->FcbLock);
+        bFcbLockAcquired = FALSE;
+    }
+
     if (NewEntry)
         Ext2FreeEntry(NewEntry);
 
     if (TargetDcb) {
-        if (ParentDcb && ParentDcb->Inode->i_ino != TargetDcb->Inode->i_ino) {
-            ClearLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
-        }
-        ClearLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+        Ext2ReleaseFcb(TargetDcb);
     }
 
-    if (bNewTargetDcb) {
-        ASSERT(TargetDcb != NULL);
-        if (Ext2DerefXcb(&TargetDcb->ReferenceCount) == 0) {
-            Ext2FreeFcb(TargetDcb);
-            TargetDcb = NULL;
-        } else {
-            DEBUG(DL_RES, ( "Ext2SetRenameInfo: TargetDcb is resued by other threads.\n"));
-        }
-    }
-
-    if (bNewParentDcb) {
-        ASSERT(ParentDcb != NULL);
-        if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
-            Ext2FreeFcb(ParentDcb);
-            ParentDcb = NULL;
-        } else {
-            DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
-        }
+    if (ParentDcb) {
+        Ext2ReleaseFcb(ParentDcb);
     }
 
     if (ExistingMcb)
@@ -1698,8 +1667,8 @@ Ext2SetLinkInfo(
 
     BOOLEAN                 ReplaceIfExists;
     BOOLEAN                 bTargetRemoved = FALSE;
-    BOOLEAN                 bNewTargetDcb = FALSE;
-    BOOLEAN                 bNewParentDcb = FALSE;
+
+    BOOLEAN                 bFcbLockAcquired = FALSE;
 
     PFILE_LINK_INFORMATION  FLI;
 
@@ -1781,17 +1750,15 @@ Ext2SetLinkInfo(
         }
     }
 
+    ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+    bFcbLockAcquired = TRUE;
+
     TargetDcb = TargetMcb->Fcb;
     if (TargetDcb == NULL) {
         TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
-        if (TargetDcb) {
-            Ext2ReferXcb(&TargetDcb->ReferenceCount);
-            bNewTargetDcb = TRUE;
-        }
     }
-
     if (TargetDcb) {
-        SetLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+        Ext2ReferXcb(&TargetDcb->ReferenceCount);
     }
 
     ParentMcb = Mcb->Parent;
@@ -1801,15 +1768,16 @@ Ext2SetLinkInfo(
 
         if (ParentDcb == NULL) {
             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
-            if (ParentDcb) {
-                Ext2ReferXcb(&ParentDcb->ReferenceCount);
-                bNewParentDcb = TRUE;
-            }
-        }
-        if (ParentDcb) {
-            SetLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
         }
     }
+    if (ParentDcb) {
+        Ext2ReferXcb(&ParentDcb->ReferenceCount);
+    }
+
+    if (bFcbLockAcquired) {
+        ExReleaseResourceLite(&Vcb->FcbLock);
+        bFcbLockAcquired = FALSE;
+    }
 
     if (!TargetDcb || !ParentDcb) {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -1887,31 +1855,17 @@ Ext2SetLinkInfo(
 
 errorout:
 
-    if (TargetDcb) {
-        if (ParentDcb && ParentDcb->Inode->i_ino != TargetDcb->Inode->i_ino) {
-            ClearLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
-        }
-        ClearLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+    if (bFcbLockAcquired) {
+        ExReleaseResourceLite(&Vcb->FcbLock);
+        bFcbLockAcquired = FALSE;
     }
 
-    if (bNewTargetDcb) {
-        ASSERT(TargetDcb != NULL);
-        if (Ext2DerefXcb(&TargetDcb->ReferenceCount) == 0) {
-            Ext2FreeFcb(TargetDcb);
-            TargetDcb = NULL;
-        } else {
-            DEBUG(DL_RES, ( "Ext2SetLinkInfo: TargetDcb is resued by other threads.\n"));
-        }
+    if (TargetDcb) {
+        Ext2ReleaseFcb(TargetDcb);
     }
 
-    if (bNewParentDcb) {
-        ASSERT(ParentDcb != NULL);
-        if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
-            Ext2FreeFcb(ParentDcb);
-            ParentDcb = NULL;
-        } else {
-            DEBUG(DL_RES, ( "Ext2SeLinkInfo: ParentDcb is resued by other threads.\n"));
-        }
+    if (ParentDcb) {
+        Ext2ReleaseFcb(ParentDcb);
     }
 
     if (ExistingMcb)
@@ -1957,7 +1911,7 @@ Ext2DeleteFile(
     LARGE_INTEGER   Size;
     LARGE_INTEGER   SysTime;
 
-    BOOLEAN         bNewDcb = FALSE;
+    BOOLEAN         bFcbLockAcquired = FALSE;
 
     DEBUG(DL_INF, ( "Ext2DeleteFile: File %wZ (%xh) will be deleted!\n",
                     &Mcb->FullName, Mcb->Inode.i_ino));
@@ -1979,16 +1933,22 @@ Ext2DeleteFile(
         ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
         VcbResourceAcquired = TRUE;
 
+        ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+        bFcbLockAcquired = TRUE;
+
         if (!(Dcb = Mcb->Parent->Fcb)) {
             Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent);
-            if (Dcb) {
-                Ext2ReferXcb(&Dcb->ReferenceCount);
-                bNewDcb = TRUE;
-            }
+        }
+        if (Dcb) {
+            Ext2ReferXcb(&Dcb->ReferenceCount);
+        }
+
+        if (bFcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+            bFcbLockAcquired = FALSE;
         }
 
         if (Dcb) {
-            SetLongFlag(Dcb->Flags, FCB_STATE_BUSY);
             DcbResourceAcquired =
                 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
 
@@ -2090,21 +2050,18 @@ Ext2DeleteFile(
             ExReleaseResourceLite(&Dcb->MainResource);
         }
 
-        if (Dcb) {
-            ClearLongFlag(Dcb->Flags, FCB_STATE_BUSY);
-            if (bNewDcb) {
-                if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
-                    Ext2FreeFcb(Dcb);
-                } else {
-                    DEBUG(DL_ERR, ( "Ext2DeleteFile: Dcb %wZ used by other threads.\n",
-                                    &Mcb->FullName ));
-                }
-            }
+        if (bFcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
         }
+
         if (VcbResourceAcquired) {
             ExReleaseResourceLite(&Vcb->MainResource);
         }
 
+        if (Dcb) {
+            Ext2ReleaseFcb(Dcb);
+        }
+
         Ext2DerefMcb(Mcb);
     } _SEH2_END;
 
index 3359a11..d57a3b1 100644 (file)
@@ -81,14 +81,21 @@ Ext2FlushVolume (
 
     DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
 
-    /* discard buffer_headers for group_desc */
-    Ext2DropGroup(Vcb);
-
     ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
     ExReleaseResourceLite(&Vcb->PagingIoResource);
 
+    /* acquire gd lock to avoid gd/bh creation */
+    ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+
+    /* discard buffer_headers for group_desc */
+    Ext2DropBH(Vcb);
+
+    /* do flushing */
     CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
 
+    /* release gd lock */
+    ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+
     return IoStatus.Status;
 }
 
index a7c5677..731e018 100644 (file)
@@ -1582,8 +1582,6 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
     PEXT2_MCB           Mcb = NULL;
 
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
-    BOOLEAN             bNewParentDcb = FALSE;
-    BOOLEAN             MainResourceAcquired = FALSE;
     
     PVOID               InputBuffer;
     ULONG               InputBufferLength;
@@ -1600,6 +1598,8 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
     PCHAR               OemNameBuffer = NULL;
     int                 OemNameLength = 0, i;
 
+    BOOLEAN             MainResourceAcquired = FALSE;
+    BOOLEAN             FcbLockAcquired = FALSE;
 
     _SEH2_TRY {
 
@@ -1614,19 +1614,26 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
         Irp = IrpContext->Irp;
         IrpSp = IoGetCurrentIrpStackLocation(Irp);
 
+        ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+        FcbLockAcquired = TRUE;
+
         ParentMcb = Mcb->Parent;
         ParentDcb = ParentMcb->Fcb;
         if (ParentDcb == NULL) {
             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
-            if (ParentDcb) {
-                Ext2ReferXcb(&ParentDcb->ReferenceCount);
-                bNewParentDcb = TRUE;
-            }
+        }
+        if (ParentDcb) {
+            Ext2ReferXcb(&ParentDcb->ReferenceCount);
         }
 
         if (!Mcb)
             _SEH2_LEAVE;
 
+        if (FcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+            FcbLockAcquired = FALSE;
+        }
+
         if (!ExAcquireResourceSharedLite(
                     &Fcb->MainResource,
                     IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
@@ -1702,6 +1709,11 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
 
     } _SEH2_FINALLY {
 
+        if (FcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+            FcbLockAcquired = FALSE;
+        }
+
         if (MainResourceAcquired) {
             ExReleaseResourceLite(&Fcb->MainResource);
         }
@@ -1719,16 +1731,6 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
                 FILE_ACTION_MODIFIED );
         }
 
-        if (bNewParentDcb) {
-            ASSERT(ParentDcb != NULL);
-            if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
-                Ext2FreeFcb(ParentDcb);
-                ParentDcb = NULL;
-            } else {
-                DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
-            }
-        }
-
         if (!_SEH2_AbnormalTermination()) {
             if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
                 Status = Ext2QueueRequest(IrpContext);
@@ -1736,6 +1738,10 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
                 Ext2CompleteIrpContext(IrpContext, Status);
             }
         }
+
+        if (ParentDcb) {
+            Ext2ReleaseFcb(ParentDcb);
+        }
     } _SEH2_END;
     
     return Status;
@@ -1786,13 +1792,14 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
     PEXT2_CCB           Ccb = NULL;
     PEXT2_MCB           Mcb = NULL;
 
+    PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
+    PEXT2_MCB           ParentMcb = NULL;
+
     NTSTATUS            Status = STATUS_UNSUCCESSFUL;
-    BOOLEAN             bNewParentDcb = FALSE;
-    BOOLEAN             bFcbAllocated = FALSE;
+
+    BOOLEAN             FcbLockAcquired = FALSE;
     BOOLEAN             MainResourceAcquired = FALSE;
     
-    PEXT2_FCB           ParentDcb = NULL;   /* Dcb of it's current parent */
-    PEXT2_MCB           ParentMcb = NULL;
 
     _SEH2_TRY {
 
@@ -1805,14 +1812,16 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
         Mcb = IrpContext->Fcb->Mcb;
         Irp = IrpContext->Irp;
 
+        ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+        FcbLockAcquired = TRUE;
+
         ParentMcb = Mcb->Parent;
         ParentDcb = ParentMcb->Fcb;
         if (ParentDcb == NULL) {
             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
-            if (ParentDcb) {
-                Ext2ReferXcb(&ParentDcb->ReferenceCount);
-                bNewParentDcb = TRUE;
-            }
+        }
+        if (ParentDcb) {
+            Ext2ReferXcb(&ParentDcb->ReferenceCount);
         }
 
         if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
@@ -1820,15 +1829,19 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
             Status = STATUS_NOT_A_REPARSE_POINT;
             _SEH2_LEAVE;
         }
-        
+
         Fcb = Ext2AllocateFcb (Vcb, Mcb);
         if (Fcb) {
-            bFcbAllocated = TRUE;
+            Ext2ReferXcb(&Fcb->ReferenceCount);
         } else {
             Status = STATUS_INSUFFICIENT_RESOURCES;
             _SEH2_LEAVE;
         }
-        Ext2ReferXcb(&Fcb->ReferenceCount);
+
+        if (FcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+            FcbLockAcquired = FALSE;
+        }
 
         if (!ExAcquireResourceSharedLite(
                     &Fcb->MainResource,
@@ -1848,6 +1861,10 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
 
     } _SEH2_FINALLY {
 
+        if (FcbLockAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+        }
+
         if (MainResourceAcquired) {
             ExReleaseResourceLite(&Fcb->MainResource);
         }
@@ -1862,16 +1879,6 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
 
         }
         
-        if (bNewParentDcb) {
-            ASSERT(ParentDcb != NULL);
-            if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
-                Ext2FreeFcb(ParentDcb);
-                ParentDcb = NULL;
-            } else {
-                DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
-            }
-        }
-
         if (!_SEH2_AbnormalTermination()) {
             if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
                 Status = Ext2QueueRequest(IrpContext);
@@ -1879,11 +1886,13 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
                 Ext2CompleteIrpContext(IrpContext, Status);
             }
         }
-        
-        if (bFcbAllocated) {
-            if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
-                Ext2FreeFcb(Fcb);
-            }
+
+        if (ParentDcb) {
+            Ext2ReleaseFcb(ParentDcb);
+        }
+
+        if (Fcb) {
+            Ext2ReleaseFcb(Fcb);
         }
     } _SEH2_END;
     
@@ -2450,13 +2459,7 @@ Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
         } else {
 
             Status = STATUS_WRONG_VOLUME;
-            if (VcbResourceAcquired) {
-                ExReleaseResourceLite(&Vcb->MainResource);
-                VcbResourceAcquired = FALSE;
-            }
             Ext2PurgeVolume(Vcb, FALSE);
-            VcbResourceAcquired =
-                ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
 
             SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
             ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
@@ -2607,8 +2610,9 @@ Ext2CheckDismount (
     ExAcquireResourceExclusiveLite(
         &Vcb->MainResource, TRUE );
 
-    if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
-            (IrpContext->RealDevice == Vcb->RealDevice)) {
+    if (IrpContext && 
+        IrpContext->MajorFunction == IRP_MJ_CREATE &&
+        IrpContext->RealDevice == Vcb->RealDevice) {
         UnCleanCount = 2;
     } else {
         UnCleanCount = 1;
@@ -2696,59 +2700,44 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
                  IN BOOLEAN  FlushBeforePurge )
 {
     PEXT2_FCB       Fcb;
-    LIST_ENTRY      FcbList;
-    PLIST_ENTRY     ListEntry;
-    PFCB_LIST_ENTRY FcbListEntry;
+    LIST_ENTRY      List, *Next;
+
     BOOLEAN         VcbResourceAcquired = FALSE;
+    BOOLEAN         FcbResourceAcquired = FALSE;
+    BOOLEAN         gdResourceAcquired = FALSE;
+
     _SEH2_TRY {
 
         ASSERT(Vcb != NULL);
         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
 
-        VcbResourceAcquired =
-            ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+        ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+        VcbResourceAcquired = TRUE;
 
         if (IsVcbReadOnly(Vcb)) {
             FlushBeforePurge = FALSE;
         }
 
-        /* discard buffer_headers for group_desc */
-        Ext2DropGroup(Vcb);
-
-        FcbListEntry= NULL;
-        InitializeListHead(&FcbList);
+        InitializeListHead(&List);
 
-        for (ListEntry = Vcb->FcbList.Flink;
-                ListEntry != &Vcb->FcbList;
-                ListEntry = ListEntry->Flink  ) {
-
-            Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
+        ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+        FcbResourceAcquired = TRUE;
 
-            DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", &Fcb->Mcb->FullName, Fcb->ReferenceCount));
+        while (!IsListEmpty(&Vcb->FcbList)) {
 
-            FcbListEntry = Ext2AllocatePool(
-                               PagedPool,
-                               sizeof(FCB_LIST_ENTRY),
-                               EXT2_FLIST_MAGIC
-                           );
+            Next = RemoveHeadList(&Vcb->FcbList);
+            Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
 
-            if (FcbListEntry) {
-                FcbListEntry->Fcb = Fcb;
-                Ext2ReferXcb(&Fcb->ReferenceCount);
-                InsertTailList(&FcbList, &FcbListEntry->Next);
-            } else {
-                DEBUG(DL_ERR, ( "Ext2PurgeVolume: failed to allocate FcbListEntry ...\n"));
-            }
+            DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n",
+                            &Fcb->Mcb->FullName, Fcb->ReferenceCount));
+            InsertTailList(&List, &Fcb->Next);
         }
 
-        while (!IsListEmpty(&FcbList)) {
-
-            ListEntry = RemoveHeadList(&FcbList);
+        while (!IsListEmpty(&List)) {
 
-            FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
-
-            Fcb = FcbListEntry->Fcb;
+            Next = RemoveHeadList(&List);
+            Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
 
             if (ExAcquireResourceExclusiveLite(
                         &Fcb->MainResource,
@@ -2756,16 +2745,28 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
 
                 Ext2PurgeFile(Fcb, FlushBeforePurge);
 
-                if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
-                    Ext2FreeFcb(Fcb);
+                if (Fcb->ReferenceCount <= 1) {
+                    Fcb->TsDrop.QuadPart = 0;
+                    InsertHeadList(&Vcb->FcbList, &Fcb->Next);
                 } else {
-                    ExReleaseResourceLite(&Fcb->MainResource);
+                    InsertTailList(&Vcb->FcbList, &Fcb->Next);
                 }
+                ExReleaseResourceLite(&Fcb->MainResource);
             }
+        }
 
-            Ext2FreePool(FcbListEntry, EXT2_FLIST_MAGIC);
+        if (FcbResourceAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+            FcbResourceAcquired = FALSE;
         }
 
+        /* acquire bd lock to avoid bh creation */
+        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+        gdResourceAcquired = TRUE;
+
+        /* discard buffer_headers for group_desc */
+        Ext2DropBH(Vcb);
+
         if (FlushBeforePurge) {
             ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
             ExReleaseResourceLite(&Vcb->PagingIoResource);
@@ -2777,11 +2778,6 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
             MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
         }
 
-        if (VcbResourceAcquired) {
-            ExReleaseResourceLite(&Vcb->MainResource);
-            VcbResourceAcquired = FALSE;
-        }
-
         if (Vcb->SectionObject.DataSectionObject) {
             CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
         }
@@ -2790,6 +2786,14 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
 
     } _SEH2_FINALLY {
 
+        if (gdResourceAcquired) {
+            ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+        }
+
+        if (FcbResourceAcquired) {
+            ExReleaseResourceLite(&Vcb->FcbLock);
+        }
+
         if (VcbResourceAcquired) {
             ExReleaseResourceLite(&Vcb->MainResource);
         }
@@ -2811,30 +2815,23 @@ Ext2PurgeFile ( IN PEXT2_FCB Fcb,
 
 
     if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
-
         DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
                         &Fcb->Mcb->FullName));
-
         ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
         ExReleaseResourceLite(&Fcb->PagingIoResource);
-
         CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
         ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
     }
 
     if (Fcb->SectionObject.ImageSectionObject) {
-
         DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
                         &Fcb->Mcb->FullName));
-
         MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
     }
 
     if (Fcb->SectionObject.DataSectionObject) {
-
         DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
                         &Fcb->Mcb->FullName));
-
         CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
     }
 
index f9a8023..eb0dfc8 100644 (file)
@@ -197,7 +197,7 @@ Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath)
      * 1 writing support
      */
     QueryTable[i].Flags = 0;
-    QueryTable[0].Name = WRITING_SUPPORT;
+    QueryTable[i].Name = WRITING_SUPPORT;
     QueryTable[i].DefaultType = REG_NONE;
     QueryTable[i].DefaultLength = 0;
     QueryTable[i].DefaultData = NULL;
@@ -431,6 +431,7 @@ Ext2EresourceAlignmentChecking()
     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaInode) & 7) == 0);
     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaBlock) & 7) == 0);
     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0);
+    CL_ASSERT((FIELD_OFFSET(EXT2_VCB, FcbLock) & 7) == 0);
     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, bd.bd_bh_lock) & 7) == 0);
     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, sbi.s_gd_lock) & 7) == 0);
     CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0);
@@ -555,11 +556,19 @@ DriverEntry (
         goto errorout;
     }
 
+    Status= Ext2StartReaper(
+                &Ext2Global->FcbReaper,
+                Ext2FcbReaperThread);
+    if (!NT_SUCCESS(Status)) {
+        goto errorout;
+    }
+
     /* start resource reaper thread */
     Status= Ext2StartReaper(
                 &Ext2Global->McbReaper,
                 Ext2McbReaperThread);
     if (!NT_SUCCESS(Status)) {
+        Ext2StopReaper(&Ext2Global->FcbReaper);
         goto errorout;
     }
 
@@ -567,6 +576,7 @@ DriverEntry (
                 &Ext2Global->bhReaper,
                 Ext2bhReaperThread);
     if (!NT_SUCCESS(Status)) {
+        Ext2StopReaper(&Ext2Global->FcbReaper);
         Ext2StopReaper(&Ext2Global->McbReaper);
         goto errorout;
     }
index 60055a6..8cd9a9f 100644 (file)
@@ -18,15 +18,11 @@ extern PEXT2_GLOBAL Ext2Global;
 /* DEFINITIONS *************************************************************/
 
 #ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, Ext2AllocateFcb)
-#pragma alloc_text(PAGE, Ext2FreeFcb)
 #pragma alloc_text(PAGE, Ext2AllocateInode)
 #pragma alloc_text(PAGE, Ext2DestroyInode)
 #pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
 #pragma alloc_text(PAGE, Ext2CheckSetBlock)
 #pragma alloc_text(PAGE, Ext2InitializeVcb)
-#pragma alloc_text(PAGE, Ext2FreeCcb)
-#pragma alloc_text(PAGE, Ext2AllocateCcb)
 #pragma alloc_text(PAGE, Ext2TearDownStream)
 #pragma alloc_text(PAGE, Ext2DestroyVcb)
 #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
@@ -139,6 +135,8 @@ Ext2AllocateFcb (
 {
     PEXT2_FCB Fcb;
 
+    ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
+
     Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
               &(Ext2Global->Ext2FcbLookasideList));
 
@@ -201,84 +199,121 @@ Ext2AllocateFcb (
 }
 
 VOID
-Ext2FreeFcb (IN PEXT2_FCB Fcb)
+Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
 {
-    PEXT2_VCB   Vcb = Fcb->Vcb;
+    PEXT2_VCB  Vcb = Fcb->Vcb;
+    PEXT2_MCB  Mcb;
 
-    ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
-           (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-    ASSERT((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
-           (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB)));
+    ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+    Mcb = Fcb->Mcb;
 
-#ifndef _WIN2K_TARGET_
-    FsRtlTeardownPerStreamContexts(&Fcb->Header);
-#endif
+    DEBUG(DL_ERR, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
+                    Fcb, Mcb ? &Mcb->FullName : NULL));
 
-    if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
-        (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+    if ((Mcb != NULL) && 
+        (Mcb->Identifier.Type == EXT2MCB) &&
+        (Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
 
-        ASSERT (Fcb->Mcb->Fcb == Fcb);
-        if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
+        ASSERT (Mcb->Fcb == Fcb);
+        if (IsMcbSpecialFile(Mcb) ||
+            IsFileDeleted(Mcb)) {
 
             ASSERT(!IsRoot(Fcb));
-            Ext2RemoveMcb(Fcb->Vcb, Fcb->Mcb);
-            Fcb->Mcb->Fcb = NULL;
+            Ext2RemoveMcb(Vcb, Mcb);
+            Mcb->Fcb = NULL;
 
-            Ext2UnlinkMcb(Vcb, Fcb->Mcb);
-            Ext2DerefMcb(Fcb->Mcb);
-            Ext2LinkHeadMcb(Vcb, Fcb->Mcb);
+            Ext2UnlinkMcb(Vcb, Mcb);
+            Ext2DerefMcb(Mcb);
+            Ext2LinkHeadMcb(Vcb, Mcb);
 
         } else {
-
-            Fcb->Mcb->Fcb = NULL;
-            Ext2DerefMcb(Fcb->Mcb);
+            Mcb->Fcb = NULL;
+            Ext2DerefMcb(Mcb);
         }
-
-    } else {
-        DbgBreak();
+        Fcb->Mcb = NULL;
     }
 
-    Ext2RemoveFcb(Fcb->Vcb, Fcb);
+    ExReleaseResourceLite(&Vcb->McbLock);
+}
 
-    FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
-    FsRtlUninitializeOplock(&Fcb->Oplock);
-    ExDeleteResourceLite(&Fcb->MainResource);
-    ExDeleteResourceLite(&Fcb->PagingIoResource);
+VOID
+Ext2FreeFcb (IN PEXT2_FCB Fcb)
+{
+    PEXT2_VCB   Vcb = Fcb->Vcb;
 
-    DEBUG(DL_RES, ( "Ext2FreeFcb: Fcb (%p) is being released: %wZ.\n",
-                    Fcb, &Fcb->Mcb->FullName));
+    _SEH2_TRY {
 
-    Fcb->Identifier.Type = 0;
-    Fcb->Identifier.Size = 0;
+        ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
+               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+        ASSERT(0 == Fcb->ReferenceCount);
 
-    ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
-    DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
-}
+#ifndef _WIN2K_TARGET_
+        FsRtlTeardownPerStreamContexts(&Fcb->Header);
+#endif
 
-/* Insert Fcb to Vcb->FcbList queue */
+        FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
+        FsRtlUninitializeOplock(&Fcb->Oplock);
+        ExDeleteResourceLite(&Fcb->MainResource);
+        ExDeleteResourceLite(&Fcb->PagingIoResource);
+
+        Fcb->Identifier.Type = 0;
+        Fcb->Identifier.Size = 0;
+
+        ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
+        DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
+
+        if (0 == Ext2DerefXcb(&Vcb->ReferenceCount)) {
+            if (!IsMounted(Vcb) || IsDispending(Vcb)) {
+                Ext2CheckDismount(NULL, Vcb, FALSE);
+            }
+        }
+
+    } _SEH2_FINALLY {
+    } _SEH2_END;
+}
 
 VOID
-Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
+Ext2ReleaseFcb (IN PEXT2_FCB Fcb)
 {
-    ExInterlockedInsertTailList(&Vcb->FcbList, &Fcb->Next, &Vcb->FcbLock);
-    Ext2ReferXcb(&Vcb->FcbCount);
+    PEXT2_VCB   Vcb = Fcb->Vcb;
+    PEXT2_MCB   Mcb;
+
+    if (0 != Ext2DerefXcb(&Fcb->ReferenceCount))
+        return;
+
+    ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+    ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
+
+    Mcb = Fcb->Mcb;
+    RemoveEntryList(&Fcb->Next);
+
+    if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
+        NULL == Mcb || IsFileDeleted(Mcb)) {
+        InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+        Fcb->TsDrop.QuadPart = 0;
+    } else {
+        InsertTailList(&Vcb->FcbList, &Fcb->Next);
+        KeQuerySystemTime(&Fcb->TsDrop);
+    }
+    ExReleaseResourceLite(&Fcb->MainResource);
+    ExReleaseResourceLite(&Vcb->FcbLock);
+
+    if ((Vcb->FcbCount >> 6) > (ULONG)(Ext2Global->MaxDepth)) {
+        KeSetEvent(&Ext2Global->FcbReaper.Wait, 0, FALSE);
+    }
 }
 
-/* Remove Fcb from Vcb->FcbList queue */
+/* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
 
 VOID
-Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
+Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
 {
-    KIRQL   irql;
+    ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
 
-    KeAcquireSpinLock(&Vcb->FcbLock, &irql);
-    RemoveEntryList(&(Fcb->Next));
-    if (Vcb->FcbCount > 0) {
-        Ext2DerefXcb(&Vcb->FcbCount);
-    } else {
-        DbgBreak();
-    }
-    KeReleaseSpinLock(&Vcb->FcbLock, irql);
+    KeQuerySystemTime(&Fcb->TsDrop);
+    Ext2ReferXcb(&Vcb->FcbCount);
+    Ext2ReferXcb(&Vcb->ReferenceCount);
+    InsertTailList(&Vcb->FcbList, &Fcb->Next);
 }
 
 PEXT2_CCB
@@ -321,7 +356,6 @@ VOID
 Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
 {
     ASSERT(Ccb != NULL);
-
     ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
            (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
 
@@ -2334,7 +2368,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
 
         /* initialize Fcb list head */
         InitializeListHead(&Vcb->FcbList);
-        KeInitializeSpinLock(&Vcb->FcbLock);
+        ExInitializeResourceLite(&Vcb->FcbLock);
 
         /* initialize Mcb list head  */
         InitializeListHead(&(Vcb->McbList));
@@ -2783,7 +2817,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
 
     Ext2CleanupAllMcbs(Vcb);
 
-    Ext2DropGroup(Vcb);
+    Ext2DropBH(Vcb);
 
     if (Vcb->bd.bd_bh_cache)
         kmem_cache_destroy(Vcb->bd.bd_bh_cache);
@@ -2805,6 +2839,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
     ObDereferenceObject(Vcb->TargetDeviceObject);
 
     ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
+    ExDeleteResourceLite(&Vcb->FcbLock);
     ExDeleteResourceLite(&Vcb->McbLock);
     ExDeleteResourceLite(&Vcb->MetaInode);
     ExDeleteResourceLite(&Vcb->MetaBlock);
@@ -2994,6 +3029,8 @@ Ext2McbReaperThread(
 
     _SEH2_TRY {
 
+        Reaper->Thread = PsGetCurrentThread();
+
         /* wake up DirverEntry */
         KeSetEvent(&Reaper->Engine, 0, FALSE);
 
@@ -3097,24 +3134,26 @@ Ext2McbReaperThread(
 }
 
 
-/* get the first Mcb record in Vcb->McbList */
+/* get buffer heads from global Vcb BH list */
 
 BOOLEAN
 Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
 {
     struct buffer_head *bh = NULL;
-    PLIST_ENTRY list = NULL;
-    LARGE_INTEGER now;
-    BOOLEAN       wake = FALSE;
+    PLIST_ENTRY      next = NULL;
+    LARGE_INTEGER   now;
+    BOOLEAN         wake = FALSE;
 
     KeQuerySystemTime(&now);
 
     ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
     while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
-        list = RemoveHeadList(&Vcb->bd.bd_bh_free);
-        bh = CONTAINING_RECORD(list, struct buffer_head, b_link);
+        next = RemoveHeadList(&Vcb->bd.bd_bh_free);
+        bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
         if (atomic_read(&bh->b_count)) {
             InitializeListHead(&bh->b_link);
+            /* to be inserted by brelse */
             continue;
         }
 
@@ -3127,6 +3166,7 @@ Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
             break;
         }
     }
+
     wake = IsListEmpty(&Vcb->bd.bd_bh_free);
     ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
 
@@ -3154,6 +3194,8 @@ Ext2bhReaperThread(
 
     _SEH2_TRY {
 
+        Reaper->Thread = PsGetCurrentThread();
+
         /* wake up DirverEntry */
         KeSetEvent(&Reaper->Engine, 0, FALSE);
 
@@ -3191,8 +3233,7 @@ Ext2bhReaperThread(
                  Link = Link->Flink ) {
 
                 Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
-                if (Ext2QueryUnusedBH(Vcb, &List))
-                    NonWait = TRUE;
+                NonWait = Ext2QueryUnusedBH(Vcb, &List);
             }
             if (GlobalAcquired) {
                 ExReleaseResourceLite(&Ext2Global->Resource);
@@ -3221,6 +3262,146 @@ Ext2bhReaperThread(
     PsTerminateSystemThread(STATUS_SUCCESS);
 }
 
+/* get unused Fcbs to free */
+
+BOOLEAN
+Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
+{
+    PEXT2_FCB       Fcb;
+    PLIST_ENTRY     next = NULL;
+    LARGE_INTEGER   now;
+
+    ULONG           count = 0;
+    ULONG           tries = 0;
+    BOOLEAN         wake = FALSE;
+    BOOLEAN         retry = TRUE;
+
+    KeQuerySystemTime(&now);
+
+    ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+
+again:
+
+    while (!IsListEmpty(&Vcb->FcbList)) {
+
+        next = RemoveHeadList(&Vcb->FcbList);
+        Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
+
+        if (Fcb->ReferenceCount > 0) {
+            InsertTailList(&Vcb->FcbList, &Fcb->Next);
+            break;
+        }
+
+        retry = FALSE;
+
+        if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
+            InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+            break;
+        }
+
+        Ext2UnlinkFcb(Fcb);
+        Ext2DerefXcb(&Vcb->FcbCount);
+        InsertTailList(list, &Fcb->Next);
+        if (++count >= Ext2Global->MaxDepth) {
+            break;
+        }
+    }
+
+    if (retry) {
+        if (++tries < (Vcb->FcbCount >> 4) )
+            goto again;
+    }
+
+    ExReleaseResourceLite(&Vcb->FcbLock);
+
+    return 0;
+}
+
+/* Reaper thread to release Fcb */
+VOID NTAPI
+Ext2FcbReaperThread(
+    PVOID   Context
+)
+{
+    PEXT2_REAPER    Reaper = Context;
+    PEXT2_VCB       Vcb = NULL;
+    LIST_ENTRY      List, *Link;
+    LARGE_INTEGER   Timeout;
+
+    BOOLEAN         GlobalAcquired = FALSE;
+    BOOLEAN         DidNothing = FALSE;
+    BOOLEAN         NonWait = FALSE;
+
+    _SEH2_TRY {
+
+        Reaper->Thread = PsGetCurrentThread();
+
+        /* wake up DirverEntry */
+        KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+        /* now process looping */
+        while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+            /* wait until it is waken or it times out */
+            if (NonWait) {
+                Timeout.QuadPart = (LONGLONG)-10*1000*100;
+                NonWait = FALSE;
+            } else if (DidNothing) {
+                Timeout.QuadPart = Timeout.QuadPart * 2;
+            } else {
+                Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
+            }
+            KeWaitForSingleObject(
+                &Reaper->Wait,
+                Executive,
+                KernelMode,
+                FALSE,
+                &Timeout
+            );
+
+            if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+                break;
+
+            InitializeListHead(&List);
+
+            /* acquire global exclusive lock */
+            ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+            GlobalAcquired = TRUE;
+            /* search all Vcb to get unused resources freed to system */
+            for (Link  = Ext2Global->VcbList.Flink;
+                 Link != &(Ext2Global->VcbList);
+                 Link  = Link->Flink ) {
+
+                Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+                NonWait = Ext2QueryUnusedFcb(Vcb, &List);
+            }
+            if (GlobalAcquired) {
+                ExReleaseResourceLite(&Ext2Global->Resource);
+                GlobalAcquired = FALSE;
+            }
+
+            DidNothing = IsListEmpty(&List);
+            while (!IsListEmpty(&List)) {
+                PEXT2_FCB  Fcb;
+                Link = RemoveHeadList(&List);
+                Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
+                ASSERT(0 == Fcb->ReferenceCount);
+                Ext2FreeFcb(Fcb);
+            }
+        }
+
+    } _SEH2_FINALLY {
+
+        if (GlobalAcquired) {
+            ExReleaseResourceLite(&Ext2Global->Resource);
+        }
+
+        KeSetEvent(&Reaper->Engine, 0, FALSE);
+    } _SEH2_END;
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
 NTSTATUS
 Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
 {
index 1100140..6dec4c4 100644 (file)
@@ -91,7 +91,10 @@ Ext2FloppyFlush(IN PVOID Parameter)
         ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
         ExReleaseResourceLite(&Vcb->PagingIoResource);
 
+        ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+        Ext2DropBH(Vcb);
         CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL);
+        ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
     }
 
     IoSetTopLevelIrp(NULL);
index c1605bc..42c9d7d 100644 (file)
@@ -7,7 +7,7 @@ reactos/drivers/filesystems/btrfs           # Synced to 0.5
 
 The following FSD are shared with: http://www.ext2fsd.com/
 
-reactos/drivers/filesystems/ext2            # Synced to 0.66
+reactos/drivers/filesystems/ext2            # Synced to 0.68
 
 The following FSD are shared with: http://www.acc.umu.se/~bosse/