sys: FSP_META_CACHE: refactoring and start integration into Fsvol

This commit is contained in:
Bill Zissimopoulos
2016-02-18 11:48:57 -08:00
parent 2c9cd46e4b
commit 3cfdfba64c
4 changed files with 200 additions and 179 deletions

View File

@ -23,8 +23,7 @@ typedef struct
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 Buffer[];
} FSP_META_CACHE_ITEM_BUFFER;
static inline
VOID MetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item)
static inline VOID FspMetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item)
{
LONG RefCount = InterlockedDecrement(&Item->RefCount);
if (0 == RefCount)
@ -35,186 +34,38 @@ VOID MetaCacheDereferenceItem(FSP_META_CACHE_ITEM *Item)
}
}
NTSTATUS MetaCacheCreate(
ULONG MetaCapacity, ULONG ItemSizeMax, PLARGE_INTEGER MetaTimeout,
FSP_META_CACHE **PMetaCache)
{
*PMetaCache = 0;
FSP_META_CACHE *MetaCache;
ULONG BucketCount = (PAGE_SIZE - sizeof *MetaCache) / sizeof MetaCache->ItemBuckets[0];
MetaCache = FspAllocNonPaged(PAGE_SIZE);
if (0 == MetaCache)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(MetaCache, PAGE_SIZE);
KeInitializeSpinLock(&MetaCache->SpinLock);
InitializeListHead(&MetaCache->ItemList);
MetaCache->MetaCapacity = MetaCapacity;
MetaCache->ItemSizeMax = ItemSizeMax;
MetaCache->MetaTimeout = MetaTimeout->QuadPart;
MetaCache->ItemBucketCount = BucketCount;
*PMetaCache = MetaCache;
return STATUS_SUCCESS;
}
VOID MetaCacheDelete(FSP_META_CACHE *MetaCache)
{
MetaCacheInvalidateExpired(MetaCache, (UINT64)-1LL);
FspFree(MetaCache);
}
VOID MetaCacheInvalidateExpired(FSP_META_CACHE *MetaCache, UINT64 ExpirationTime)
{
FSP_META_CACHE_ITEM *Item;
PLIST_ENTRY Head, Entry;
ULONG HashIndex;
KIRQL Irql;
for (;;)
{
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
Item = 0;
Head = &MetaCache->ItemList;
Entry = Head->Flink;
if (Head != Entry)
{
Item = CONTAINING_RECORD(Entry, FSP_META_CACHE_ITEM, ListEntry);
if (Item->ExpirationTime <= ExpirationTime)
{
HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount;
for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex];
*P; P = &(*P)->DictNext)
if (*P == Item)
{
*P = (*P)->DictNext;
break;
}
RemoveEntryList(&Item->ListEntry);
MetaCache->ItemCount--;
}
else
Item = 0;
}
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 == Item)
break;
MetaCacheDereferenceItem(Item);
}
}
PVOID MetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, PULONG PSize)
static inline FSP_META_CACHE_ITEM *FspMetaCacheLookupIndexedItemAtDpcLevel(FSP_META_CACHE *MetaCache,
UINT64 ItemIndex)
{
FSP_META_CACHE_ITEM *Item = 0;
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer;
ULONG HashIndex;
KIRQL Irql;
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
HashIndex = ItemIndex % MetaCache->ItemBucketCount;
ULONG HashIndex = ItemIndex % MetaCache->ItemBucketCount;
for (FSP_META_CACHE_ITEM *ItemX = MetaCache->ItemBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
if (ItemX->ItemIndex == ItemIndex)
{
Item = ItemX;
InterlockedIncrement(&Item->RefCount);
break;
}
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 == Item)
{
if (0 != PSize)
*PSize = 0;
return 0;
}
ItemBuffer = Item->ItemBuffer;
if (0 != PSize)
*PSize = ItemBuffer->Size;
return ItemBuffer->Buffer;
return Item;
}
VOID MetaCacheDereferenceItemBuffer(PVOID Buffer)
static inline VOID FspMetaCacheAddItemAtDpcLevel(FSP_META_CACHE *MetaCache, FSP_META_CACHE_ITEM *Item)
{
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer = (PVOID)((PUINT8)Buffer - sizeof *ItemBuffer);
MetaCacheDereferenceItem(ItemBuffer->Item);
}
UINT64 MetaCacheAddItem(FSP_META_CACHE *MetaCache, PVOID Buffer, ULONG Size)
{
FSP_META_CACHE_ITEM *Item;
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer;
UINT64 ItemIndex = 0;
ULONG HashIndex;
BOOLEAN HasCapacity;
KIRQL Irql;
if (sizeof *ItemBuffer + Size > MetaCache->ItemSizeMax)
return 0;
Item = FspAllocNonPaged(sizeof *Item);
if (0 == Item)
return 0;
ItemBuffer = FspAlloc(sizeof *ItemBuffer + Size);
if (0 == ItemBuffer)
{
FspFree(Item);
return 0;
}
RtlZeroMemory(Item, sizeof *Item);
Item->ItemBuffer = ItemBuffer;
Item->ExpirationTime = KeQueryInterruptTime() + MetaCache->MetaTimeout;
Item->RefCount = 1;
RtlZeroMemory(ItemBuffer, sizeof *ItemBuffer);
ItemBuffer->Item = Item;
ItemBuffer->Size = Size;
RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size);
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
HasCapacity = MetaCache->ItemCount < MetaCache->MetaCapacity;
if (HasCapacity)
{
ItemIndex = MetaCache->ItemIndex;
ItemIndex = (UINT64)-1LL == ItemIndex ? 1 : ItemIndex + 1;
MetaCache->ItemIndex = ItemIndex;
Item->ItemIndex = ItemIndex;
MetaCache->ItemCount++;
InsertTailList(&MetaCache->ItemList, &Item->ListEntry);
HashIndex = ItemIndex % MetaCache->ItemBucketCount;
ULONG HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount;
#if DBG
for (FSP_META_CACHE_ITEM *ItemX = MetaCache->ItemBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
ASSERT(ItemX->ItemIndex != ItemIndex);
for (FSP_META_CACHE_ITEM *ItemX = MetaCache->ItemBuckets[HashIndex]; ItemX; ItemX = ItemX->DictNext)
ASSERT(ItemX->ItemIndex != Item->ItemIndex);
#endif
Item->DictNext = MetaCache->ItemBuckets[HashIndex];
MetaCache->ItemBuckets[HashIndex] = Item;
}
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (!HasCapacity)
{
FspFree(ItemBuffer);
FspFree(Item);
}
return ItemIndex;
Item->DictNext = MetaCache->ItemBuckets[HashIndex];
MetaCache->ItemBuckets[HashIndex] = Item;
InsertTailList(&MetaCache->ItemList, &Item->ListEntry);
MetaCache->ItemCount++;
}
VOID MetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex)
static inline FSP_META_CACHE_ITEM *FspMetaCacheRemoveIndexedItemAtDpcLevel(FSP_META_CACHE *MetaCache,
UINT64 ItemIndex)
{
FSP_META_CACHE_ITEM *Item = 0;
ULONG HashIndex;
KIRQL Irql;
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
HashIndex = ItemIndex % MetaCache->ItemBucketCount;
ULONG HashIndex = ItemIndex % MetaCache->ItemBucketCount;
for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex]; *P; P = &(*P)->DictNext)
if ((*P)->ItemIndex == ItemIndex)
{
@ -224,8 +75,156 @@ VOID MetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex)
MetaCache->ItemCount--;
break;
}
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 != Item)
MetaCacheDereferenceItem(Item);
return Item;
}
static inline FSP_META_CACHE_ITEM *FspMetaCacheRemoveExpiredItemAtDpcLevel(FSP_META_CACHE *MetaCache,
UINT64 ExpirationTime)
{
PLIST_ENTRY Head = &MetaCache->ItemList;
PLIST_ENTRY Entry = Head->Flink;
if (Head == Entry)
return 0;
FSP_META_CACHE_ITEM *Item = CONTAINING_RECORD(Entry, FSP_META_CACHE_ITEM, ListEntry);
if (Item->ExpirationTime > ExpirationTime)
return 0;
ULONG HashIndex = Item->ItemIndex % MetaCache->ItemBucketCount;
for (FSP_META_CACHE_ITEM **P = (PVOID)&MetaCache->ItemBuckets[HashIndex]; *P; P = &(*P)->DictNext)
if (*P == Item)
{
*P = (*P)->DictNext;
break;
}
RemoveEntryList(&Item->ListEntry);
MetaCache->ItemCount--;
return Item;
}
NTSTATUS FspMetaCacheCreate(
ULONG MetaCapacity, ULONG ItemSizeMax, PLARGE_INTEGER MetaTimeout,
FSP_META_CACHE **PMetaCache)
{
*PMetaCache = 0;
if (0 == MetaCapacity || 0 == ItemSizeMax || 0 == MetaTimeout->QuadPart)
return STATUS_SUCCESS;
FSP_META_CACHE *MetaCache;
ULONG BucketCount = (PAGE_SIZE - sizeof *MetaCache) / sizeof MetaCache->ItemBuckets[0];
MetaCache = FspAllocNonPaged(PAGE_SIZE);
if (0 == MetaCache)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(MetaCache, PAGE_SIZE);
KeInitializeSpinLock(&MetaCache->SpinLock);
InitializeListHead(&MetaCache->ItemList);
MetaCache->MetaCapacity = MetaCapacity;
MetaCache->ItemSizeMax = ItemSizeMax;
MetaCache->MetaTimeout = MetaTimeout->QuadPart;
MetaCache->ItemBucketCount = BucketCount;
*PMetaCache = MetaCache;
return STATUS_SUCCESS;
}
VOID FspMetaCacheDelete(FSP_META_CACHE *MetaCache)
{
if (0 == MetaCache)
return;
FspMetaCacheInvalidateExpired(MetaCache, (UINT64)-1LL);
FspFree(MetaCache);
}
VOID FspMetaCacheInvalidateExpired(FSP_META_CACHE *MetaCache, UINT64 ExpirationTime)
{
if (0 == MetaCache)
return;
FSP_META_CACHE_ITEM *Item;
KIRQL Irql;
for (;;)
{
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
Item = FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, ExpirationTime);
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 == Item)
break;
FspMetaCacheDereferenceItem(Item);
}
}
PVOID FspMetaCacheReferenceItemBuffer(FSP_META_CACHE *MetaCache, UINT64 ItemIndex, PULONG PSize)
{
if (0 != PSize)
*PSize = 0;
if (0 == MetaCache || 0 == ItemIndex)
return 0;
FSP_META_CACHE_ITEM *Item = 0;
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer;
KIRQL Irql;
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
Item = FspMetaCacheLookupIndexedItemAtDpcLevel(MetaCache, ItemIndex);
if (0 == Item)
{
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
return 0;
}
InterlockedIncrement(&Item->RefCount);
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
ItemBuffer = Item->ItemBuffer;
if (0 != PSize)
*PSize = ItemBuffer->Size;
return ItemBuffer->Buffer;
}
VOID FspMetaCacheDereferenceItemBuffer(PVOID Buffer)
{
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer = (PVOID)((PUINT8)Buffer - sizeof *ItemBuffer);
FspMetaCacheDereferenceItem(ItemBuffer->Item);
}
UINT64 FspMetaCacheAddItem(FSP_META_CACHE *MetaCache, PVOID Buffer, ULONG Size)
{
if (0 == MetaCache)
return 0;
FSP_META_CACHE_ITEM *Item;
FSP_META_CACHE_ITEM_BUFFER *ItemBuffer;
UINT64 ItemIndex = 0;
KIRQL Irql;
if (sizeof *ItemBuffer + Size > MetaCache->ItemSizeMax)
return 0;
Item = FspAllocNonPaged(sizeof *Item);
if (0 == Item)
return 0;
ItemBuffer = FspAlloc(sizeof *ItemBuffer + Size);
if (0 == ItemBuffer)
{
FspFree(Item);
return 0;
}
RtlZeroMemory(Item, sizeof *Item);
RtlZeroMemory(ItemBuffer, sizeof *ItemBuffer);
Item->ItemBuffer = ItemBuffer;
Item->ExpirationTime = KeQueryInterruptTime() + MetaCache->MetaTimeout;
Item->RefCount = 1;
ItemBuffer->Item = Item;
ItemBuffer->Size = Size;
RtlCopyMemory(ItemBuffer->Buffer, Buffer, Size);
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
if (MetaCache->ItemCount >= MetaCache->MetaCapacity)
FspMetaCacheRemoveExpiredItemAtDpcLevel(MetaCache, (UINT64)-1LL);
ItemIndex = MetaCache->ItemIndex;
ItemIndex = (UINT64)-1LL == ItemIndex ? 1 : ItemIndex + 1;
MetaCache->ItemIndex = Item->ItemIndex = ItemIndex;
FspMetaCacheAddItemAtDpcLevel(MetaCache, Item);
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
return ItemIndex;
}
VOID FspMetaCacheInvalidateItem(FSP_META_CACHE *MetaCache, UINT64 ItemIndex)
{
if (0 == MetaCache || 0 == ItemIndex)
return;
FSP_META_CACHE_ITEM *Item;
KIRQL Irql;
KeAcquireSpinLock(&MetaCache->SpinLock, &Irql);
Item = FspMetaCacheRemoveIndexedItemAtDpcLevel(MetaCache, ItemIndex);
KeReleaseSpinLock(&MetaCache->SpinLock, Irql);
if (0 != Item)
FspMetaCacheDereferenceItem(Item);
}