Author: arty
Date: Wed Feb 29 09:18:01 2012
New Revision: 55914
URL:
http://svn.reactos.org/svn/reactos?rev=55914&view=rev
Log:
[FSRTL]
Import code from Pierre Schweitzer's fsrtl branch.
- Large MCB and MCB
- Change notification
Added:
trunk/reactos/ntoskrnl/fsrtl/mcb.c (with props)
Modified:
trunk/reactos/ntoskrnl/CMakeLists.txt
trunk/reactos/ntoskrnl/fsrtl/fsrtlpc.c
trunk/reactos/ntoskrnl/fsrtl/largemcb.c
trunk/reactos/ntoskrnl/fsrtl/notify.c
trunk/reactos/ntoskrnl/include/internal/fsrtl.h
Modified: trunk/reactos/ntoskrnl/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/CMakeLists.txt?re…
==============================================================================
--- trunk/reactos/ntoskrnl/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/CMakeLists.txt [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -119,6 +119,7 @@
fsrtl/fsfilter.c
fsrtl/fsrtlpc.c
fsrtl/largemcb.c
+ fsrtl/mcb.c
fsrtl/name.c
fsrtl/notify.c
fsrtl/oplock.c
Modified: trunk/reactos/ntoskrnl/fsrtl/fsrtlpc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/fsrtlpc.c?r…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/fsrtlpc.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/fsrtlpc.c [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -169,6 +169,8 @@
IFS_POOL_TAG,
0);
+ FsRtlInitializeLargeMcbs();
+
/* Allocate the Resource Buffer */
FsRtlPagingIoResources = FsRtlAllocatePoolWithTag(NonPagedPool,
FSRTL_MAX_RESOURCES *
Modified: trunk/reactos/ntoskrnl/fsrtl/largemcb.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/largemcb.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/largemcb.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/largemcb.c [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -2,20 +2,138 @@
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/fsrtl/largemcb.c
- * PURPOSE: Mapping Control Block (MCB) support for File System Drivers
+ * PURPOSE: Large Mapped Control Block (MCB) support for File System Drivers
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ * Pierre Schweitzer (heis_spiter(a)hotmail.com)
+ * Art Yerkes (art.yerkes(a)gmail.com)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
-#define NDEBUG
+//#define NDEBUG
#include <debug.h>
+/* GLOBALS *******************************************************************/
+
+#define GET_LIST_HEAD(x) ((PLIST_ENTRY)(&((PRTL_GENERIC_TABLE)x)[1]))
+
+PAGED_LOOKASIDE_LIST FsRtlFirstMappingLookasideList;
+NPAGED_LOOKASIDE_LIST FsRtlFastMutexLookasideList;
+
+typedef struct _LARGE_MCB_MAPPING_ENTRY
+{
+ LARGE_INTEGER RunStartVbn;
+ LARGE_INTEGER SectorCount;
+ LARGE_INTEGER StartingLbn;
+ LIST_ENTRY Sequence;
+} LARGE_MCB_MAPPING_ENTRY, *PLARGE_MCB_MAPPING_ENTRY;
+
+static PVOID NTAPI McbMappingAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
+{
+ PVOID Result;
+ PBASE_MCB Mcb = (PBASE_MCB)Table->TableContext;
+ Result = ExAllocatePoolWithTag(Mcb->PoolType, Bytes, 'LMCB');
+ DPRINT("McbMappingAllocate(%d) => %p\n", Bytes, Result);
+ return Result;
+}
+
+static VOID NTAPI McbMappingFree(PRTL_GENERIC_TABLE Table, PVOID Buffer)
+{
+ DPRINT("McbMappingFree(%p)\n", Buffer);
+ ExFreePoolWithTag(Buffer, 'LMCB');
+}
+
+static RTL_GENERIC_COMPARE_RESULTS NTAPI McbMappingCompare
+(RTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
+{
+ PLARGE_MCB_MAPPING_ENTRY A = PtrA, B = PtrB;
+ return
+ (A->RunStartVbn.QuadPart + A->SectorCount.QuadPart <
+ B->RunStartVbn.QuadPart) ? GenericLessThan :
+ (A->RunStartVbn.QuadPart >
+ B->RunStartVbn.QuadPart + B->SectorCount.QuadPart) ?
+ GenericGreaterThan : GenericEqual;
+}
+
/* PUBLIC FUNCTIONS **********************************************************/
/*
- * @unimplemented
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlAddBaseMcbEntry(IN PBASE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Lbn,
+ IN LONGLONG SectorCount)
+{
+ LARGE_MCB_MAPPING_ENTRY Node;
+ PLARGE_MCB_MAPPING_ENTRY Existing = NULL;
+ BOOLEAN NewElement = FALSE;
+
+ Node.RunStartVbn.QuadPart = Vbn;
+ Node.StartingLbn.QuadPart = Lbn;
+ Node.SectorCount.QuadPart = SectorCount;
+
+ while (!NewElement)
+ {
+ DPRINT("Inserting %x:%x\n", Node.RunStartVbn.LowPart,
Node.SectorCount.LowPart);
+ Existing = RtlInsertElementGenericTable
+ (Mcb->Mapping, &Node, sizeof(Node), &NewElement);
+ DPRINT("Existing %x\n", Existing);
+ if (!Existing) break;
+
+ DPRINT("NewElement %d\n", NewElement);
+ if (!NewElement)
+ {
+ // We merge the existing runs
+ LARGE_INTEGER StartVbn, FinalVbn;
+ DPRINT("Existing: %x:%x\n",
+ Existing->RunStartVbn.LowPart, Node.SectorCount.LowPart);
+ if (Existing->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart)
+ {
+ StartVbn = Existing->RunStartVbn;
+ Node.StartingLbn = Existing->StartingLbn;
+ }
+ else
+ {
+ StartVbn = Node.RunStartVbn;
+ }
+ DPRINT("StartVbn %x\n", StartVbn.LowPart);
+ if (Existing->RunStartVbn.QuadPart + Existing->SectorCount.QuadPart >
+ Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart)
+ {
+ FinalVbn.QuadPart =
+ Existing->RunStartVbn.QuadPart + Existing->SectorCount.QuadPart;
+ }
+ else
+ {
+ FinalVbn.QuadPart =
+ Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart;
+ }
+ DPRINT("FinalVbn %x\n", FinalVbn.LowPart);
+ Node.RunStartVbn.QuadPart = StartVbn.QuadPart;
+ Node.SectorCount.QuadPart = FinalVbn.QuadPart - StartVbn.QuadPart;
+ RemoveHeadList(&Existing->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Existing);
+ Mcb->PairCount--;
+ }
+ else
+ {
+ DPRINT("Mapping added %x\n", Existing);
+ Mcb->MaximumPairCount++;
+ Mcb->PairCount++;
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Existing->Sequence);
+ }
+ }
+
+ DPRINT("!!Existing %d\n", !!Existing);
+ return !!Existing;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -24,30 +142,57 @@
IN LONGLONG Lbn,
IN LONGLONG SectorCount)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlAddMcbEntry(IN PMCB Mcb,
- IN VBN Vbn,
- IN LBN Lbn,
- IN ULONG SectorCount)
-{
- /* Call the newer function */
- return FsRtlAddLargeMcbEntry(&Mcb->
- DummyFieldThatSizesThisStructureCorrectly,
- (LONGLONG)Vbn,
- (LONGLONG)Lbn,
- (LONGLONG)SectorCount);
+ BOOLEAN Result;
+
+ DPRINT("Mcb %x Vbn %x Lbn %x SectorCount %x\n", Mcb, Vbn, Lbn, SectorCount);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ Result = FsRtlAddBaseMcbEntry(&(Mcb->BaseMcb),
+ Vbn,
+ Lbn,
+ SectorCount);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
}
/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlGetNextBaseMcbEntry(IN PBASE_MCB Mcb,
+ IN ULONG RunIndex,
+ OUT PLONGLONG Vbn,
+ OUT PLONGLONG Lbn,
+ OUT PLONGLONG SectorCount)
+{
+ ULONG i = 0;
+ BOOLEAN Result = FALSE;
+ PLARGE_MCB_MAPPING_ENTRY Entry;
+ for (Entry = (PLARGE_MCB_MAPPING_ENTRY)
+ RtlEnumerateGenericTable(Mcb->Mapping, TRUE);
+ Entry && i < RunIndex;
+ Entry = (PLARGE_MCB_MAPPING_ENTRY)
+ RtlEnumerateGenericTable(Mcb->Mapping, FALSE), i++);
+ if (Entry)
+ {
+ Result = TRUE;
+ if (Vbn)
+ *Vbn = Entry->RunStartVbn.QuadPart;
+ if (Lbn)
+ *Lbn = Entry->StartingLbn.QuadPart;
+ if (SectorCount)
+ *SectorCount = Entry->SectorCount.QuadPart;
+ }
+
+ return Result;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -57,55 +202,78 @@
OUT PLONGLONG Lbn,
OUT PLONGLONG SectorCount)
{
- KeBugCheck(FILE_SYSTEM);
- *Vbn = 0;
- *Lbn = 0;
- *SectorCount= 0;
- return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlGetNextMcbEntry(IN PMCB Mcb,
- IN ULONG RunIndex,
- OUT PVBN Vbn,
- OUT PLBN Lbn,
- OUT PULONG SectorCount)
-{
- BOOLEAN Return = FALSE;
- LONGLONG llVbn;
- LONGLONG llLbn;
- LONGLONG llSectorCount;
-
- /* Call the Large version */
- Return = FsRtlGetNextLargeMcbEntry(
- &Mcb->DummyFieldThatSizesThisStructureCorrectly,
- RunIndex,
- &llVbn,
- &llLbn,
- &llSectorCount);
-
- /* Return the lower 32 bits */
- *Vbn = (ULONG)llVbn;
- *Lbn = (ULONG)llLbn;
- *SectorCount = (ULONG)llSectorCount;
-
- /* And return the original value */
- return Return;
-}
-
-/*
- * @unimplemented
+ BOOLEAN Result;
+
+ DPRINT("FsRtlGetNextLargeMcbEntry Mcb %x RunIndex %x\n", Mcb, RunIndex);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ Result = FsRtlGetNextBaseMcbEntry(&(Mcb->BaseMcb),
+ RunIndex,
+ Vbn,
+ Lbn,
+ SectorCount);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlInitializeBaseMcb(IN PBASE_MCB Mcb,
+ IN POOL_TYPE PoolType)
+{
+ Mcb->PairCount = 0;
+
+ if (PoolType == PagedPool)
+ {
+ Mcb->Mapping =
ExAllocateFromPagedLookasideList(&FsRtlFirstMappingLookasideList);
+ }
+ else
+ {
+ Mcb->Mapping = ExAllocatePoolWithTag(PoolType |
POOL_RAISE_IF_ALLOCATION_FAILURE,
+ sizeof(RTL_GENERIC_TABLE) + sizeof(LIST_ENTRY),
+ 'FSBC');
+ }
+
+ Mcb->PoolType = PoolType;
+ Mcb->MaximumPairCount = MAXIMUM_PAIR_COUNT;
+ RtlInitializeGenericTable
+ (Mcb->Mapping,
+ (PRTL_GENERIC_COMPARE_ROUTINE)McbMappingCompare,
+ McbMappingAllocate,
+ McbMappingFree,
+ Mcb);
+ InitializeListHead(GET_LIST_HEAD(Mcb->Mapping));
+}
+
+/*
+ * @implemented
*/
VOID
NTAPI
FsRtlInitializeLargeMcb(IN PLARGE_MCB Mcb,
IN POOL_TYPE PoolType)
{
- KeBugCheck(FILE_SYSTEM);
+ Mcb->GuardedMutex =
ExAllocateFromNPagedLookasideList(&FsRtlFastMutexLookasideList);
+
+ KeInitializeGuardedMutex(Mcb->GuardedMutex);
+
+ _SEH2_TRY
+ {
+ FsRtlInitializeBaseMcb(&(Mcb->BaseMcb), PoolType);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
+ Mcb->GuardedMutex);
+ Mcb->GuardedMutex = NULL;
+ }
+ _SEH2_END;
}
/*
@@ -113,16 +281,80 @@
*/
VOID
NTAPI
-FsRtlInitializeMcb(IN PMCB Mcb,
- IN POOL_TYPE PoolType)
-{
- /* Call the newer function */
- FsRtlInitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
- PoolType);
+FsRtlInitializeLargeMcbs(VOID)
+{
+ /* Initialize the list for the MCB */
+ ExInitializePagedLookasideList(&FsRtlFirstMappingLookasideList,
+ NULL,
+ NULL,
+ POOL_RAISE_IF_ALLOCATION_FAILURE,
+ sizeof(RTL_GENERIC_TABLE) + sizeof(LIST_ENTRY),
+ IFS_POOL_TAG,
+ 0); /* FIXME: Should be 4 */
+
+ /* Initialize the list for the guarded mutex */
+ ExInitializeNPagedLookasideList(&FsRtlFastMutexLookasideList,
+ NULL,
+ NULL,
+ POOL_RAISE_IF_ALLOCATION_FAILURE,
+ sizeof(KGUARDED_MUTEX),
+ IFS_POOL_TAG,
+ 0); /* FIXME: Should be 32 */
}
/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupBaseMcbEntry(IN PBASE_MCB Mcb,
+ IN LONGLONG Vbn,
+ OUT PLONGLONG Lbn OPTIONAL,
+ OUT PLONGLONG SectorCountFromLbn OPTIONAL,
+ OUT PLONGLONG StartingLbn OPTIONAL,
+ OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
+ OUT PULONG Index OPTIONAL)
+{
+ BOOLEAN Result = FALSE;
+ LARGE_MCB_MAPPING_ENTRY ToLookup;
+ PLARGE_MCB_MAPPING_ENTRY Entry;
+
+ ToLookup.RunStartVbn.QuadPart = Vbn;
+ ToLookup.SectorCount.QuadPart = 1;
+
+ Entry = RtlLookupElementGenericTable(Mcb->Mapping, &ToLookup);
+ if (!Entry)
+ {
+ // Find out if we have a following entry. The spec says we should return
+ // found with Lbn == -1 when we're beneath the largest map.
+ ToLookup.SectorCount.QuadPart = (1ull<<62) - ToLookup.RunStartVbn.QuadPart;
+ Entry = RtlLookupElementGenericTable(Mcb->Mapping, &ToLookup);
+ if (Entry)
+ {
+ Result = TRUE;
+ if (Lbn) *Lbn = ~0ull;
+ }
+ else
+ {
+ Result = FALSE;
+ }
+ }
+ else
+ {
+ LARGE_INTEGER Offset;
+ Offset.QuadPart = Vbn - Entry->RunStartVbn.QuadPart;
+ Result = TRUE;
+ if (Lbn) *Lbn = Entry->StartingLbn.QuadPart + Offset.QuadPart;
+ if (SectorCountFromLbn) *SectorCountFromLbn = Entry->SectorCount.QuadPart -
Offset.QuadPart;
+ if (StartingLbn) *StartingLbn = Entry->StartingLbn.QuadPart;
+ if (SectorCountFromStartingLbn) *SectorCountFromStartingLbn =
Entry->SectorCount.QuadPart;
+ }
+
+ return Result;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -134,14 +366,61 @@
OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
OUT PULONG Index OPTIONAL)
{
- KeBugCheck(FILE_SYSTEM);
- *Lbn = 0;
- *SectorCountFromLbn = 0;
- return FALSE;
+ BOOLEAN Result;
+
+ DPRINT("FsRtlLookupLargeMcbEntry Mcb %x Vbn %x\n", Mcb, (ULONG)Vbn);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ Result = FsRtlLookupBaseMcbEntry(&(Mcb->BaseMcb),
+ Vbn,
+ Lbn,
+ SectorCountFromLbn,
+ StartingLbn,
+ SectorCountFromStartingLbn,
+ Index);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
}
/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastBaseMcbEntryAndIndex(IN PBASE_MCB OpaqueMcb,
+ IN OUT PLONGLONG LargeVbn,
+ IN OUT PLONGLONG LargeLbn,
+ IN OUT PULONG Index)
+{
+ ULONG i = 0;
+ BOOLEAN Result = FALSE;
+ PLIST_ENTRY ListEntry;
+ PLARGE_MCB_MAPPING_ENTRY Entry;
+ PLARGE_MCB_MAPPING_ENTRY CountEntry;
+
+ ListEntry = GET_LIST_HEAD(OpaqueMcb->Mapping);
+ if (!IsListEmpty(ListEntry))
+ {
+ Entry = CONTAINING_RECORD(ListEntry->Flink, LARGE_MCB_MAPPING_ENTRY, Sequence);
+ Result = TRUE;
+ *LargeVbn = Entry->RunStartVbn.QuadPart;
+ *LargeLbn = Entry->StartingLbn.QuadPart;
+
+ for (i = 0, CountEntry = RtlEnumerateGenericTable(OpaqueMcb->Mapping, TRUE);
+ CountEntry != Entry;
+ CountEntry = RtlEnumerateGenericTable(OpaqueMcb->Mapping, FALSE));
+
+ *Index = i;
+ }
+
+ return Result;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -150,15 +429,49 @@
OUT PLONGLONG LargeLbn,
OUT PULONG Index)
{
- KeBugCheck(FILE_SYSTEM);
- *LargeVbn = 0;
- *LargeLbn = 0;
- *Index = 0;
- return FALSE;
+ BOOLEAN Result;
+
+ DPRINT("FsRtlLookupLastLargeMcbEntryAndIndex %x\n", OpaqueMcb);
+
+ KeAcquireGuardedMutex(OpaqueMcb->GuardedMutex);
+ Result = FsRtlLookupLastBaseMcbEntryAndIndex(&(OpaqueMcb->BaseMcb),
+ LargeVbn,
+ LargeLbn,
+ Index);
+ KeReleaseGuardedMutex(OpaqueMcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
}
/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastBaseMcbEntry(IN PBASE_MCB Mcb,
+ OUT PLONGLONG Vbn,
+ OUT PLONGLONG Lbn)
+{
+ BOOLEAN Result = FALSE;
+ PLIST_ENTRY ListEntry;
+ PLARGE_MCB_MAPPING_ENTRY Entry;
+
+ ListEntry = GET_LIST_HEAD(Mcb->Mapping);
+ if (!IsListEmpty(ListEntry))
+ {
+ Entry = CONTAINING_RECORD(ListEntry->Flink, LARGE_MCB_MAPPING_ENTRY, Sequence);
+ Result = TRUE;
+ *Vbn = Entry->RunStartVbn.QuadPart;
+ *Lbn = Entry->StartingLbn.QuadPart;
+ }
+
+ return Result;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -166,68 +479,19 @@
OUT PLONGLONG Vbn,
OUT PLONGLONG Lbn)
{
- KeBugCheck(FILE_SYSTEM);
- return(FALSE);
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupLastMcbEntry(IN PMCB Mcb,
- OUT PVBN Vbn,
- OUT PLBN Lbn)
-{
- BOOLEAN Return = FALSE;
- LONGLONG llVbn = 0;
- LONGLONG llLbn = 0;
-
- /* Call the Large version */
- Return = FsRtlLookupLastLargeMcbEntry(
- &Mcb->DummyFieldThatSizesThisStructureCorrectly,
- &llVbn,
- &llLbn);
-
- /* Return the lower 32-bits */
- *Vbn = (ULONG)llVbn;
- *Lbn = (ULONG)llLbn;
-
- /* And return the original value */
- return Return;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-FsRtlLookupMcbEntry(IN PMCB Mcb,
- IN VBN Vbn,
- OUT PLBN Lbn,
- OUT PULONG SectorCount OPTIONAL,
- OUT PULONG Index)
-{
- BOOLEAN Return = FALSE;
- LONGLONG llLbn;
- LONGLONG llSectorCount;
-
- /* Call the Large version */
- Return = FsRtlLookupLargeMcbEntry(&Mcb->
- DummyFieldThatSizesThisStructureCorrectly,
- (LONGLONG)Vbn,
- &llLbn,
- &llSectorCount,
- NULL,
- NULL,
- Index);
-
- /* Return the lower 32-bits */
- *Lbn = (ULONG)llLbn;
- if (SectorCount) *SectorCount = (ULONG)llSectorCount;
-
- /* And return the original value */
- return Return;
+ BOOLEAN Result;
+
+ DPRINT("FsRtlLookupLastLargeMcbEntry Mcb %x\n", Mcb);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ Result = FsRtlLookupLastBaseMcbEntry(&(Mcb->BaseMcb),
+ Vbn,
+ Lbn);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
}
/*
@@ -235,33 +499,131 @@
*/
ULONG
NTAPI
+FsRtlNumberOfRunsInBaseMcb(IN PBASE_MCB Mcb)
+{
+ /* Return the count */
+ return Mcb->PairCount;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
FsRtlNumberOfRunsInLargeMcb(IN PLARGE_MCB Mcb)
{
ULONG NumberOfRuns;
+
+ DPRINT("FsRtlNumberOfRunsInLargeMcb Mcb %x\n", Mcb);
/* Read the number of runs while holding the MCB lock */
KeAcquireGuardedMutex(Mcb->GuardedMutex);
NumberOfRuns = Mcb->BaseMcb.PairCount;
KeReleaseGuardedMutex(Mcb->GuardedMutex);
+ DPRINT("Done %d\n", NumberOfRuns);
+
/* Return the count */
return NumberOfRuns;
}
/*
- * @implemented
- */
-ULONG
-NTAPI
-FsRtlNumberOfRunsInMcb (IN PMCB Mcb)
-{
- /* Call the newer function */
- return FsRtlNumberOfRunsInLargeMcb(
- &Mcb->DummyFieldThatSizesThisStructureCorrectly);
-}
-
-/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlRemoveBaseMcbEntry(IN PBASE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG SectorCount)
+{
+ LARGE_MCB_MAPPING_ENTRY Node;
+ PLARGE_MCB_MAPPING_ENTRY Element;
+
+ Node.RunStartVbn.QuadPart = Vbn;
+ Node.SectorCount.QuadPart = SectorCount;
+
+ while ((Element = RtlLookupElementGenericTable(Mcb->Mapping, &Node)))
+ {
+ // Must split
+ if (Element->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart &&
+ Element->SectorCount.QuadPart > Node.SectorCount.QuadPart)
+ {
+ LARGE_MCB_MAPPING_ENTRY Upper, Reinsert;
+ PLARGE_MCB_MAPPING_ENTRY Reinserted, Inserted;
+ LARGE_INTEGER StartHole = Node.RunStartVbn;
+ LARGE_INTEGER EndHole;
+ EndHole.QuadPart = Node.RunStartVbn.QuadPart + Node.SectorCount.QuadPart;
+ Upper.RunStartVbn.QuadPart = EndHole.QuadPart;
+ Upper.StartingLbn.QuadPart =
+ Element->StartingLbn.QuadPart +
+ EndHole.QuadPart -
+ Element->RunStartVbn.QuadPart;
+ Upper.SectorCount.QuadPart =
+ Element->SectorCount.QuadPart -
+ (EndHole.QuadPart - Element->RunStartVbn.QuadPart);
+ Reinsert = *Element;
+ Reinsert.SectorCount.QuadPart =
+ Element->RunStartVbn.QuadPart - StartHole.QuadPart;
+ RemoveEntryList(&Element->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+ Mcb->PairCount--;
+
+ Reinserted = RtlInsertElementGenericTable
+ (Mcb->Mapping, &Reinsert, sizeof(Reinsert), NULL);
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+ Mcb->PairCount++;
+
+ Inserted = RtlInsertElementGenericTable
+ (Mcb->Mapping, &Upper, sizeof(Upper), NULL);
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Inserted->Sequence);
+ Mcb->PairCount++;
+ }
+ else if (Element->RunStartVbn.QuadPart < Node.RunStartVbn.QuadPart)
+ {
+ LARGE_MCB_MAPPING_ENTRY NewElement;
+ PLARGE_MCB_MAPPING_ENTRY Reinserted;
+ LARGE_INTEGER StartHole = Node.RunStartVbn;
+ NewElement.RunStartVbn = Element->RunStartVbn;
+ NewElement.StartingLbn = Element->StartingLbn;
+ NewElement.SectorCount.QuadPart = StartHole.QuadPart -
Element->StartingLbn.QuadPart;
+
+ RemoveEntryList(&Element->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+ Mcb->PairCount--;
+
+ Reinserted = RtlInsertElementGenericTable
+ (Mcb->Mapping, &NewElement, sizeof(NewElement), NULL);
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+ Mcb->PairCount++;
+ }
+ else
+ {
+ LARGE_MCB_MAPPING_ENTRY NewElement;
+ PLARGE_MCB_MAPPING_ENTRY Reinserted;
+ LARGE_INTEGER EndHole = Element->RunStartVbn;
+ LARGE_INTEGER EndRun;
+ EndRun.QuadPart = Element->RunStartVbn.QuadPart +
Element->SectorCount.QuadPart;
+ NewElement.RunStartVbn = EndHole;
+ NewElement.StartingLbn.QuadPart = Element->StartingLbn.QuadPart +
+ (EndHole.QuadPart - Element->RunStartVbn.QuadPart);
+ NewElement.SectorCount.QuadPart = EndRun.QuadPart - EndHole.QuadPart;
+
+ RemoveEntryList(&Element->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+ Mcb->PairCount--;
+
+ Reinserted = RtlInsertElementGenericTable
+ (Mcb->Mapping, &NewElement, sizeof(NewElement), NULL);
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &Reinserted->Sequence);
+ Mcb->PairCount++;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
*/
VOID
NTAPI
@@ -269,7 +631,15 @@
IN LONGLONG Vbn,
IN LONGLONG SectorCount)
{
- KeBugCheck(FILE_SYSTEM);
+ DPRINT("FsRtlRemoveLargeMcbEntry Mcb %x, Vbn %x, SectorCount %x\n", Mcb,
(ULONG)Vbn, (ULONG)SectorCount);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ FsRtlRemoveBaseMcbEntry(&(Mcb->BaseMcb),
+ Vbn,
+ SectorCount);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done\n");
}
/*
@@ -277,29 +647,157 @@
*/
VOID
NTAPI
-FsRtlRemoveMcbEntry(IN PMCB Mcb,
- IN VBN Vbn,
- IN ULONG SectorCount)
-{
- /* Call the large function */
- FsRtlRemoveLargeMcbEntry(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
- (LONGLONG)Vbn,
- (LONGLONG)SectorCount);
-}
-
-/*
- * @unimplemented
+FsRtlResetBaseMcb(IN PBASE_MCB Mcb)
+{
+ PLARGE_MCB_MAPPING_ENTRY Element;
+
+ while (RtlNumberGenericTableElements(Mcb->Mapping) &&
+ (Element = (PLARGE_MCB_MAPPING_ENTRY)RtlGetElementGenericTable(Mcb->Mapping,
0)))
+ {
+ RtlDeleteElementGenericTable(Mcb->Mapping, Element);
+ }
+
+ Mcb->PairCount = 0;
+ Mcb->MaximumPairCount = 0;
+}
+
+/*
+ * @implemented
*/
VOID
NTAPI
FsRtlResetLargeMcb(IN PLARGE_MCB Mcb,
IN BOOLEAN SelfSynchronized)
{
- KeBugCheck(FILE_SYSTEM);
+ if (!SelfSynchronized)
+ {
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ }
+
+ FsRtlResetBaseMcb(&Mcb->BaseMcb);
+
+
+ if (!SelfSynchronized)
+ {
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+ }
+}
+
+#define MCB_BUMP_NO_MORE 0
+#define MCB_BUMP_AGAIN 1
+
+static ULONG NTAPI McbBump(PBASE_MCB Mcb, PLARGE_MCB_MAPPING_ENTRY FixedPart)
+{
+ LARGE_MCB_MAPPING_ENTRY Reimagined;
+ PLARGE_MCB_MAPPING_ENTRY Found = NULL;
+
+ DPRINT("McbBump %x (%x:%x)\n", Mcb, FixedPart->RunStartVbn.LowPart,
FixedPart->SectorCount.LowPart);
+
+ Reimagined = *FixedPart;
+ while ((Found = RtlLookupElementGenericTable(Mcb->Mapping, &Reimagined)))
+ {
+ Reimagined = *Found;
+ Reimagined.RunStartVbn.QuadPart =
+ FixedPart->RunStartVbn.QuadPart + FixedPart->SectorCount.QuadPart;
+ DPRINT("Reimagined %x\n", Reimagined.RunStartVbn.LowPart);
+ }
+
+ DPRINT("Found %x\n", Found);
+ if (!Found) return MCB_BUMP_NO_MORE;
+ DPRINT1
+ ("Moving %x-%x to %x because %x-%x overlaps\n",
+ Found->RunStartVbn.LowPart,
+ Found->RunStartVbn.LowPart + Found->SectorCount.QuadPart,
+ Reimagined.RunStartVbn.LowPart + Reimagined.SectorCount.LowPart,
+ Reimagined.RunStartVbn.LowPart,
+ Reimagined.RunStartVbn.LowPart + Reimagined.SectorCount.LowPart);
+ Found->RunStartVbn.QuadPart = Reimagined.RunStartVbn.QuadPart +
Reimagined.SectorCount.QuadPart;
+ Found->StartingLbn.QuadPart = Reimagined.StartingLbn.QuadPart +
Reimagined.SectorCount.QuadPart;
+
+ DPRINT("Again\n");
+ return MCB_BUMP_AGAIN;
}
/*
* @unimplemented
+ */
+BOOLEAN
+NTAPI
+FsRtlSplitBaseMcb(IN PBASE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Amount)
+{
+ ULONG Result;
+ LARGE_MCB_MAPPING_ENTRY Node;
+ PLARGE_MCB_MAPPING_ENTRY Existing = NULL;
+
+ Node.RunStartVbn.QuadPart = Vbn;
+ Node.SectorCount.QuadPart = 0;
+
+ Existing = RtlLookupElementGenericTable(Mcb->Mapping, &Node);
+
+ if (Existing)
+ {
+ // We're in the middle of a run
+ LARGE_MCB_MAPPING_ENTRY UpperPart;
+ LARGE_MCB_MAPPING_ENTRY LowerPart;
+ PLARGE_MCB_MAPPING_ENTRY InsertedUpper;
+
+ UpperPart.RunStartVbn.QuadPart = Node.RunStartVbn.QuadPart + Amount;
+ UpperPart.SectorCount.QuadPart = Existing->RunStartVbn.QuadPart +
+ (Existing->SectorCount.QuadPart - Node.RunStartVbn.QuadPart);
+ UpperPart.StartingLbn.QuadPart = Existing->StartingLbn.QuadPart +
+ (Node.RunStartVbn.QuadPart - Existing->RunStartVbn.QuadPart);
+ LowerPart.RunStartVbn.QuadPart = Existing->RunStartVbn.QuadPart;
+ LowerPart.SectorCount.QuadPart = Node.RunStartVbn.QuadPart -
Existing->RunStartVbn.QuadPart;
+ LowerPart.StartingLbn.QuadPart = Existing->StartingLbn.QuadPart;
+
+ Node = UpperPart;
+
+ DPRINT("Loop: %x\n", Node.RunStartVbn.LowPart);
+ while ((Result = McbBump(Mcb, &Node)) == MCB_BUMP_AGAIN)
+ {
+ DPRINT("Node: %x\n", Node.RunStartVbn.LowPart);
+ }
+ DPRINT("Done\n");
+
+ if (Result == MCB_BUMP_NO_MORE)
+ {
+ Node = *Existing;
+ RemoveHeadList(&Existing->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Existing);
+ Mcb->PairCount--;
+
+ // Adjust the element we found.
+ Existing->SectorCount = LowerPart.SectorCount;
+
+ InsertedUpper = RtlInsertElementGenericTable
+ (Mcb->Mapping, &UpperPart, sizeof(UpperPart), NULL);
+ if (!InsertedUpper)
+ {
+ // Just make it like it was
+ Existing->SectorCount = Node.SectorCount;
+ return FALSE;
+ }
+ InsertHeadList(GET_LIST_HEAD(Mcb->Mapping), &InsertedUpper->Sequence);
+ Mcb->PairCount++;
+ }
+ else
+ {
+ Node.RunStartVbn.QuadPart = Vbn;
+ Node.SectorCount.QuadPart = Amount;
+ while ((Result = McbBump(Mcb, &Node)) == MCB_BUMP_AGAIN);
+ return Result == MCB_BUMP_NO_MORE;
+ }
+ }
+
+ DPRINT("Done\n");
+
+ return TRUE;
+}
+
+/*
+ * @implemented
*/
BOOLEAN
NTAPI
@@ -307,19 +805,62 @@
IN LONGLONG Vbn,
IN LONGLONG Amount)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ BOOLEAN Result;
+
+ DPRINT("FsRtlSplitLargeMcb %x, Vbn %x, Amount %x\n", Mcb, (ULONG)Vbn,
(ULONG)Amount);
+
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ Result = FsRtlSplitBaseMcb(&(Mcb->BaseMcb),
+ Vbn,
+ Amount);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+
+ DPRINT("Done %d\n", Result);
+
+ return Result;
}
/*
* @unimplemented
+ */
+VOID
+NTAPI
+FsRtlTruncateBaseMcb(IN PBASE_MCB Mcb,
+ IN LONGLONG Vbn)
+{
+ if (!Vbn)
+ {
+ FsRtlResetBaseMcb(Mcb);
+ }
+ else
+ {
+ LARGE_MCB_MAPPING_ENTRY Truncate;
+ PLARGE_MCB_MAPPING_ENTRY Found;
+ Truncate.RunStartVbn.QuadPart = Vbn;
+ Truncate.SectorCount.QuadPart = (1ull<<62) - Truncate.RunStartVbn.QuadPart;
+ while ((Found = RtlLookupElementGenericTable(Mcb->Mapping, &Truncate)))
+ {
+ RemoveEntryList(&Found->Sequence);
+ RtlDeleteElementGenericTable(Mcb->Mapping, Found);
+ Mcb->PairCount--;
+ }
+ }
+}
+
+/*
+ * @implemented
*/
VOID
NTAPI
FsRtlTruncateLargeMcb(IN PLARGE_MCB Mcb,
IN LONGLONG Vbn)
{
- KeBugCheck(FILE_SYSTEM);
+ DPRINT("FsRtlTruncateLargeMcb %x Vbn %x\n", Mcb, (ULONG)Vbn);
+ KeAcquireGuardedMutex(Mcb->GuardedMutex);
+ FsRtlTruncateBaseMcb(&(Mcb->BaseMcb),
+ Vbn);
+ KeReleaseGuardedMutex(Mcb->GuardedMutex);
+ DPRINT("Done\n");
}
/*
@@ -327,32 +868,33 @@
*/
VOID
NTAPI
-FsRtlTruncateMcb (IN PMCB Mcb,
- IN VBN Vbn)
-{
- /* Call the newer function */
- FsRtlTruncateLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
- (LONGLONG)Vbn);
-}
-
-/*
- * @unimplemented
+FsRtlUninitializeBaseMcb(IN PBASE_MCB Mcb)
+{
+ FsRtlResetBaseMcb(Mcb);
+
+ if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount ==
MAXIMUM_PAIR_COUNT))
+ {
+ ExFreeToPagedLookasideList(&FsRtlFirstMappingLookasideList,
+ Mcb->Mapping);
+ }
+ else
+ {
+ ExFreePoolWithTag(Mcb->Mapping, 'FSBC');
+ }
+}
+
+/*
+ * @implemented
*/
VOID
NTAPI
FsRtlUninitializeLargeMcb(IN PLARGE_MCB Mcb)
{
- KeBugCheck(FILE_SYSTEM);
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-FsRtlUninitializeMcb(IN PMCB Mcb)
-{
- /* Call the newer function */
- FsRtlUninitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly);
-}
-
+ if (Mcb->GuardedMutex)
+ {
+ ExFreeToNPagedLookasideList(&FsRtlFastMutexLookasideList,
+ Mcb->GuardedMutex);
+ FsRtlUninitializeBaseMcb(&(Mcb->BaseMcb));
+ }
+}
+
Added: trunk/reactos/ntoskrnl/fsrtl/mcb.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/mcb.c?rev=5…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/mcb.c (added)
+++ trunk/reactos/ntoskrnl/fsrtl/mcb.c [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -1,0 +1,190 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/fsrtl/mcb.c
+ * PURPOSE: Mapped Control Block (MCB) support for File System Drivers
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlAddMcbEntry(IN PMCB Mcb,
+ IN VBN Vbn,
+ IN LBN Lbn,
+ IN ULONG SectorCount)
+{
+ /* Call the newer function */
+ return FsRtlAddLargeMcbEntry(&Mcb->
+ DummyFieldThatSizesThisStructureCorrectly,
+ (LONGLONG)Vbn,
+ (LONGLONG)Lbn,
+ (LONGLONG)SectorCount);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlGetNextMcbEntry(IN PMCB Mcb,
+ IN ULONG RunIndex,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount)
+{
+ BOOLEAN Return = FALSE;
+ LONGLONG llVbn;
+ LONGLONG llLbn;
+ LONGLONG llSectorCount;
+
+ /* Call the Large version */
+ Return = FsRtlGetNextLargeMcbEntry(
+ &Mcb->DummyFieldThatSizesThisStructureCorrectly,
+ RunIndex,
+ &llVbn,
+ &llLbn,
+ &llSectorCount);
+
+ /* Return the lower 32 bits */
+ *Vbn = (ULONG)llVbn;
+ *Lbn = (ULONG)llLbn;
+ *SectorCount = (ULONG)llSectorCount;
+
+ /* And return the original value */
+ return Return;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlInitializeMcb(IN PMCB Mcb,
+ IN POOL_TYPE PoolType)
+{
+ /* Call the newer function */
+ FsRtlInitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
+ PoolType);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupLastMcbEntry(IN PMCB Mcb,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn)
+{
+ BOOLEAN Return = FALSE;
+ LONGLONG llVbn = 0;
+ LONGLONG llLbn = 0;
+
+ /* Call the Large version */
+ Return = FsRtlLookupLastLargeMcbEntry(
+ &Mcb->DummyFieldThatSizesThisStructureCorrectly,
+ &llVbn,
+ &llLbn);
+
+ /* Return the lower 32-bits */
+ *Vbn = (ULONG)llVbn;
+ *Lbn = (ULONG)llLbn;
+
+ /* And return the original value */
+ return Return;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+FsRtlLookupMcbEntry(IN PMCB Mcb,
+ IN VBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount OPTIONAL,
+ OUT PULONG Index)
+{
+ BOOLEAN Return = FALSE;
+ LONGLONG llLbn;
+ LONGLONG llSectorCount;
+
+ /* Call the Large version */
+ Return = FsRtlLookupLargeMcbEntry(&Mcb->
+ DummyFieldThatSizesThisStructureCorrectly,
+ (LONGLONG)Vbn,
+ &llLbn,
+ &llSectorCount,
+ NULL,
+ NULL,
+ Index);
+
+ /* Return the lower 32-bits */
+ *Lbn = (ULONG)llLbn;
+ if (SectorCount) *SectorCount = (ULONG)llSectorCount;
+
+ /* And return the original value */
+ return Return;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+NTAPI
+FsRtlNumberOfRunsInMcb(IN PMCB Mcb)
+{
+ /* Call the newer function */
+ return FsRtlNumberOfRunsInLargeMcb(
+ &Mcb->DummyFieldThatSizesThisStructureCorrectly);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlRemoveMcbEntry(IN PMCB Mcb,
+ IN VBN Vbn,
+ IN ULONG SectorCount)
+{
+ /* Call the large function */
+ FsRtlRemoveLargeMcbEntry(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
+ (LONGLONG)Vbn,
+ (LONGLONG)SectorCount);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlTruncateMcb(IN PMCB Mcb,
+ IN VBN Vbn)
+{
+ /* Call the newer function */
+ FsRtlTruncateLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly,
+ (LONGLONG)Vbn);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+FsRtlUninitializeMcb(IN PMCB Mcb)
+{
+ /* Call the newer function */
+ FsRtlUninitializeLargeMcb(&Mcb->DummyFieldThatSizesThisStructureCorrectly);
+}
Propchange: trunk/reactos/ntoskrnl/fsrtl/mcb.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/fsrtl/notify.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/notify.c?re…
==============================================================================
--- trunk/reactos/ntoskrnl/fsrtl/notify.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/fsrtl/notify.c [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -12,6 +12,68 @@
#define NDEBUG
#include <debug.h>
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PNOTIFY_CHANGE
+FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList,
+ IN PVOID FsContext)
+{
+ PLIST_ENTRY NextEntry;
+ PNOTIFY_CHANGE NotifyChange;
+
+ if (!IsListEmpty(NotifyList))
+ {
+ /* Browse the notifications list to find the matching entry */
+ for (NextEntry = NotifyList->Flink;
+ NextEntry != NotifyList;
+ NextEntry = NextEntry->Flink)
+ {
+ NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
+ /* If the current record matches with the given context, it's the good
one */
+ if (NotifyChange->FsContext == FsContext)
+ {
+ return NotifyChange;
+ }
+ }
+ }
+ return NULL;
+}
+
+VOID
+FORCEINLINE
+FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
+{
+ ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
+
+ /* Only acquire fast mutex if it's not already acquired by the current thread */
+ if (RealNotifySync->OwningThread != CurrentThread)
+ {
+ ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
+ RealNotifySync->OwningThread = CurrentThread;
+ }
+ /* Whatever the case, keep trace of the attempt to acquire fast mutex */
+ RealNotifySync->OwnerCount++;
+}
+
+VOID
+FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange,
+ IN NTSTATUS Status)
+{
+}
+
+VOID
+FORCEINLINE
+FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
+{
+ RealNotifySync->OwnerCount--;
+ /* Release the fast mutex only if no other instance needs it */
+ if (!RealNotifySync->OwnerCount)
+ {
+ ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
+ RealNotifySync->OwningThread = (ULONG_PTR)0;
+ }
+}
+
/* PUBLIC FUNCTIONS **********************************************************/
/*++
@@ -44,8 +106,7 @@
*
* @return None
*
- * @remarks This function only redirects to FsRtlNotifyFullChangeDirectory.
- * So, it's better to call the entire function.
+ * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
*
*--*/
VOID
@@ -58,32 +119,33 @@
IN ULONG CompletionFilter,
IN PIRP NotifyIrp)
{
- FsRtlNotifyFullChangeDirectory(NotifySync,
- NotifyList,
- FsContext,
- FullDirectoryName,
- WatchTree,
- TRUE,
- CompletionFilter,
- NotifyIrp,
- NULL,
- NULL);
+ FsRtlNotifyFilterChangeDirectory(NotifySync,
+ NotifyList,
+ FsContext,
+ FullDirectoryName,
+ WatchTree,
+ TRUE,
+ CompletionFilter,
+ NotifyIrp,
+ NULL,
+ NULL,
+ NULL);
}
/*++
* @name FsRtlNotifyCleanup
- * @unimplemented
+ * @implemented
*
* Called by FSD when all handles to FileObject (identified by FsContext) are closed
*
* @param NotifySync
- * FILLME
- *
- * @param NotifyList
- * FILLME
+ * Synchronization object pointer
+ *
+ * @param NotifyList
+ * Notify list pointer (to head)
*
* @param FsContext
- * FILLME
+ * Used to identify the notify structure
*
* @return None
*
@@ -96,7 +158,67 @@
IN PLIST_ENTRY NotifyList,
IN PVOID FsContext)
{
- KeBugCheck(FILE_SYSTEM);
+ PNOTIFY_CHANGE NotifyChange;
+ PREAL_NOTIFY_SYNC RealNotifySync;
+ PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
+
+ /* Get real structure hidden behind the opaque pointer */
+ RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
+
+ /* Acquire the fast mutex */
+ FsRtlNotifyAcquireFastMutex(RealNotifySync);
+
+ _SEH2_TRY
+ {
+ /* Find if there's a matching notification with the FsContext */
+ NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext);
+ if (NotifyChange)
+ {
+ /* Mark it as to know that cleanup is in process */
+ NotifyChange->Flags |= CLEANUP_IN_PROCESS;
+
+ /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP
status */
+ if (!IsListEmpty(NotifyChange->NotifyIrps))
+ {
+ FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_NOTIFY_CLEANUP);
+ }
+ /* Remove from the list */
+ RemoveEntryList(NotifyChange->NotifyList);
+
+ /* Downcrease reference number and if 0 is reached, it's time to do
complete cleanup */
+ if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
+ {
+ /* In case there was an allocated buffer, free it */
+ if (NotifyChange->AllocatedBuffer)
+ {
+ PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess,
NotifyChange->ThisBufferLength);
+ ExFreePool(NotifyChange->AllocatedBuffer);
+ }
+
+ /* In case there the string was set, get the captured subject security
context */
+ if (NotifyChange->FullDirectoryName)
+ {
+ SubjectContext = NotifyChange->SubjectContext;
+ }
+
+ /* Finally, free the notification, as it's not needed anymore */
+ ExFreePool(NotifyChange);
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ /* Release fast mutex */
+ FsRtlNotifyReleaseFastMutex(RealNotifySync);
+
+ /* If the subject security context was captured, release and free it */
+ if (SubjectContext)
+ {
+ SeReleaseSubjectContext(SubjectContext);
+ ExFreePool(SubjectContext);
+ }
+ }
+ _SEH2_END;
}
/*++
@@ -219,43 +341,46 @@
/*++
* @name FsRtlNotifyFullChangeDirectory
- * @unimplemented
- *
- * FILLME
- *
- * @param NotifySync
- * FILLME
- *
- * @param NotifyList
- * FILLME
+ * @implemented
+ *
+ * Lets FSD know if changes occures in the specified directory.
+ *
+ * @param NotifySync
+ * Synchronization object pointer
+ *
+ * @param NotifyList
+ * Notify list pointer (to head)
*
* @param FsContext
- * FILLME
+ * Used to identify the notify structure
*
* @param FullDirectoryName
- * FILLME
+ * String (A or W) containing the full directory name
*
* @param WatchTree
- * FILLME
+ * True to notify changes in subdirectories too
*
* @param IgnoreBuffer
- * FILLME
+ * True to reenumerate directory. It's ignored it NotifyIrp is null
*
* @param CompletionFilter
- * FILLME
- *
- * @param Irp
- * FILLME
+ * Used to define types of changes to notify
+ *
+ * @param NotifyIrp
+ * IRP pointer to complete notify operation. It can be null
*
* @param TraverseCallback
- * FILLME
+ * Pointer to a callback function. It's called each time a change is
+ * done in a subdirectory of the main directory. It's ignored it NotifyIrp
+ * is null
*
* @param SubjectContext
- * FILLME
- *
- * @return None
- *
- * @remarks None
+ * Pointer to pass to SubjectContext member of TraverseCallback.
+ * It's freed after use. It's ignored it NotifyIrp is null
+ *
+ * @return None
+ *
+ * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
*
*--*/
VOID
@@ -267,49 +392,60 @@
IN BOOLEAN WatchTree,
IN BOOLEAN IgnoreBuffer,
IN ULONG CompletionFilter,
- IN PIRP Irp,
+ IN PIRP NotifyIrp,
IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL,
IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
{
- KeBugCheck(FILE_SYSTEM);
+ FsRtlNotifyFilterChangeDirectory(NotifySync,
+ NotifyList,
+ FsContext,
+ FullDirectoryName,
+ WatchTree,
+ IgnoreBuffer,
+ CompletionFilter,
+ NotifyIrp,
+ TraverseCallback,
+ SubjectContext,
+ NULL);
}
/*++
* @name FsRtlNotifyFullReportChange
- * @unimplemented
- *
- * FILLME
- *
- * @param NotifySync
- * FILLME
- *
- * @param NotifyList
- * FILLME
+ * @implemented
+ *
+ * Complets the pending notify IRPs.
+ *
+ * @param NotifySync
+ * Synchronization object pointer
+ *
+ * @param NotifyList
+ * Notify list pointer (to head)
*
* @param FullTargetName
- * FILLME
+ * String (A or W) containing the full directory name that changed
*
* @param TargetNameOffset
- * FILLME
+ * Offset, in FullTargetName, of the final component that is in the changed
directory
*
* @param StreamName
- * FILLME
+ * String (A or W) containing a stream name
*
* @param NormalizedParentName
- * FILLME
+ * String (A or W) containing the full directory name that changed with long
names
*
* @param FilterMatch
- * FILLME
+ * Flags that will be compared to the completion filter
*
* @param Action
- * FILLME
+ * Action code to store in user's buffer
*
* @param TargetContext
- * FILLME
- *
- * @return None
- *
- * @remarks None
+ * Pointer to a callback function. It's called each time a change is
+ * done in a subdirectory of the main directory.
+ *
+ * @return None
+ *
+ * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
*
*--*/
VOID
@@ -324,54 +460,73 @@
IN ULONG Action,
IN PVOID TargetContext)
{
- KeBugCheck(FILE_SYSTEM);
+ FsRtlNotifyFilterReportChange(NotifySync,
+ NotifyList,
+ FullTargetName,
+ TargetNameOffset,
+ StreamName,
+ NormalizedParentName,
+ FilterMatch,
+ Action,
+ TargetContext,
+ NULL);
}
/*++
* @name FsRtlNotifyInitializeSync
- * @unimplemented
- *
- * FILLME
- *
- * @param NotifySync
- * FILLME
- *
- * @return None
- *
- * @remarks None
+ * @implemented
+ *
+ * Allocates the internal structure associated with notifications.
+ *
+ * @param NotifySync
+ * Opaque pointer. It will receive the address of the allocated internal
structure.
+ *
+ * @return None
+ *
+ * @remarks This function raise an exception in case of a failure.
*
*--*/
VOID
NTAPI
FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync)
{
- KeBugCheck(FILE_SYSTEM);
+ PREAL_NOTIFY_SYNC RealNotifySync;
+
+ *NotifySync = NULL;
+
+ RealNotifySync = ExAllocatePoolWithTag(NonPagedPool |
POOL_RAISE_IF_ALLOCATION_FAILURE,
+ sizeof(REAL_NOTIFY_SYNC), TAG('F',
'S', 'N', 'S'));
+ ExInitializeFastMutex(&(RealNotifySync->FastMutex));
+ RealNotifySync->OwningThread = 0;
+ RealNotifySync->OwnerCount = 0;
+
+ *NotifySync = RealNotifySync;
}
/*++
* @name FsRtlNotifyReportChange
- * @unimplemented
- *
- * FILLME
- *
- * @param NotifySync
- * FILLME
- *
- * @param NotifyList
- * FILLME
+ * @implemented
+ *
+ * Complets the pending notify IRPs.
+ *
+ * @param NotifySync
+ * Synchronization object pointer
+ *
+ * @param NotifyList
+ * Notify list pointer (to head)
*
* @param FullTargetName
- * FILLME
+ * String (A or W) containing the full directory name that changed
*
* @param FileNamePartLength
- * FILLME
+ * Length of the final component that is in the changed directory
*
* @param FilterMatch
- * FILLME
- *
- * @return None
- *
- * @remarks None
+ * Flags that will be compared to the completion filter
+ *
+ * @return None
+ *
+ * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
*
*--*/
VOID
@@ -382,11 +537,20 @@
IN PUSHORT FileNamePartLength,
IN ULONG FilterMatch)
{
- KeBugCheck(FILE_SYSTEM);
-}
-
-/*++
- * @name FsRtlCurrentBatchOplock
+ FsRtlNotifyFilterReportChange(NotifySync,
+ NotifyList,
+ FullTargetName,
+ FullTargetName->Length - *FileNamePartLength,
+ NULL,
+ NULL,
+ FilterMatch,
+ 0,
+ NULL,
+ NULL);
+}
+
+/*++
+ * @name FsRtlNotifyUninitializeSync
* @implemented
*
* Uninitialize a NOTIFY_SYNC object
@@ -404,6 +568,10 @@
NTAPI
FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync)
{
- KeBugCheck(FILE_SYSTEM);
-}
-
+ if (*NotifySync)
+ {
+ ExFreePoolWithTag(*NotifySync, TAG('F', 'S', 'N',
'S'));
+ *NotifySync = NULL;
+ }
+}
+
Modified: trunk/reactos/ntoskrnl/include/internal/fsrtl.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/fsrtl.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/fsrtl.h [iso-8859-1] Wed Feb 29 09:18:01 2012
@@ -5,6 +5,10 @@
* PURPOSE: Internal header for the File System Runtime Library
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
*/
+
+#ifndef TAG
+#define TAG(w,x,y,z) (((w)<<24)|((x)<<16)|((y)<<8)|(z))
+#endif
//
// Define this if you want debugging support
@@ -36,7 +40,7 @@
if (x & FsRtlpTraceLevel) DbgPrint(__VA_ARGS__)
#endif
#else
-#define FSTRACE(x, fmt, ...) DPRINT(fmt, ##__VA_ARGS__)
+#define FSTRACE(x, ...) DPRINT(__VA_ARGS__)
#endif
//
@@ -45,11 +49,67 @@
#define FSRTL_MAX_RESOURCES 16
//
+// Number of maximum pair count per MCB
+//
+#define MAXIMUM_PAIR_COUNT 15
+
+//
+// Notifications flags
+//
+#define CLEANUP_IN_PROCESS 4
+
+//
+// Internal structure for NOTIFY_SYNC
+//
+typedef struct _REAL_NOTIFY_SYNC
+{
+ FAST_MUTEX FastMutex;
+ ULONG_PTR OwningThread;
+ ULONG OwnerCount;
+} REAL_NOTIFY_SYNC, * PREAL_NOTIFY_SYNC;
+
+//
+// Internal structure for notifications
+//
+typedef struct _NOTIFY_CHANGE
+{
+ PREAL_NOTIFY_SYNC NotifySync;
+ PVOID FsContext;
+ PVOID StreamID;
+ PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback;
+ PSECURITY_SUBJECT_CONTEXT SubjectContext;
+ PSTRING FullDirectoryName;
+ PLIST_ENTRY NotifyList;
+ PLIST_ENTRY NotifyIrps;
+ PFILTER_REPORT_CHANGE FilterCallback;
+ USHORT Flags;
+ UCHAR CharacterSize;
+ ULONG CompletionFilter;
+ PVOID AllocatedBuffer;
+ PVOID Buffer;
+ ULONG BufferLength;
+ ULONG ThisBufferLength;
+ ULONG DataLength;
+ ULONG LastEntry;
+ ULONG ReferenceCount;
+ PEPROCESS OwningProcess;
+} NOTIFY_CHANGE, *PNOTIFY_CHANGE;
+
+//
+// Internal structure for MCB Mapping pointer
+//
+typedef struct _INT_MAPPING
+{
+ VBN Vbn;
+ LBN Lbn;
+} INT_MAPPING, *PINT_MAPPING;
+
+//
// Initialization Routines
//
-BOOLEAN
+VOID
NTAPI
-FsRtlInitSystem(
+FsRtlInitializeLargeMcbs(
VOID
);
@@ -62,6 +122,12 @@
IN PFILE_OBJECT FileObject
);
+BOOLEAN
+NTAPI
+FsRtlInitSystem(
+ VOID
+);
+
//
// Global data inside the File System Runtime Library
//