kernel/EntryCache: Allocate and free entries without locks held.

Avoids some contention, but doesn't seem to speed things up much.

Change-Id: I25be31ba4d91d5013bd09cf8c32635654aed2db2
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9532
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2025-08-05 16:28:21 +00:00
committed by waddlesplash
parent 360544ed44
commit b53996dc7f
+47 -28
View File
@@ -108,44 +108,49 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID, bool missing)
{
EntryCacheKey key(dirID, name);
WriteLocker _(fLock);
if (fGenerationCount == 0)
return B_NO_MEMORY;
EntryCacheEntry* entry = fEntries.Lookup(key);
if (entry != NULL) {
entry->node_id = nodeID;
entry->missing = missing;
if (entry->generation != fCurrentGeneration) {
if (entry->index >= 0) {
fGenerations[entry->generation].entries[entry->index] = NULL;
_AddEntryToCurrentGeneration(entry);
}
}
return B_OK;
}
// Avoid deadlock if system had to wait for free memory
const size_t nameLen = strlen(name);
entry = (EntryCacheEntry*)malloc_etc(sizeof(EntryCacheEntry) + nameLen,
CACHE_DONT_WAIT_FOR_MEMORY);
EntryCacheEntry* entry = (EntryCacheEntry*)malloc(sizeof(EntryCacheEntry) + nameLen);
if (entry == NULL)
return B_NO_MEMORY;
entry->node_id = nodeID;
entry->dir_id = dirID;
entry->hash = EntryCacheKey::Hash(dirID, name);
entry->hash = key.hash;
entry->missing = missing;
entry->generation = fCurrentGeneration;
entry->index = kEntryNotInArray;
entry->generation = -1;
memcpy(entry->name, name, nameLen + 1);
WriteLocker writeLocker(fLock);
if (fGenerationCount == 0) {
free(entry);
return B_NO_MEMORY;
}
EntryCacheEntry* existingEntry = fEntries.Lookup(key);
if (existingEntry != NULL) {
free(entry);
entry = existingEntry;
entry->node_id = nodeID;
entry->missing = missing;
if (entry->generation != fCurrentGeneration) {
if (entry->index >= 0) {
fGenerations[entry->generation].entries[entry->index] = NULL;
writeLocker.Detach();
_AddEntryToCurrentGeneration(entry);
}
}
return B_OK;
}
fEntries.Insert(entry);
writeLocker.Detach();
_AddEntryToCurrentGeneration(entry);
return B_OK;
}
@@ -166,6 +171,7 @@ EntryCache::Remove(ino_t dirID, const char* name)
if (entry->index >= 0) {
// remove the entry from its generation and delete it
fGenerations[entry->generation].entries[entry->index] = NULL;
writeLocker.Unlock();
free(entry);
} else {
// We can't free it, since another thread is about to try to move it
@@ -221,14 +227,16 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID,
if (entry->index == kEntryRemoved) {
// the entry has been removed in the meantime
writeLocker.Unlock();
free(entry);
return false;
}
_AddEntryToCurrentGeneration(entry);
_nodeID = entry->node_id;
_missing = entry->missing;
writeLocker.Detach();
_AddEntryToCurrentGeneration(entry);
return true;
}
@@ -252,7 +260,7 @@ EntryCache::DebugReverseLookup(ino_t nodeID, ino_t& _dirID)
void
EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
{
ASSERT_WRITE_LOCKED_RW_LOCK(&fLock);
WriteLocker locker(fLock, true);
// the generation might not be full yet
int32 index = fGenerations[fCurrentGeneration].next_index++;
@@ -264,6 +272,7 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
}
// we have to clear the oldest generation
EntryCacheEntry* entriesToFree = NULL;
const int32 newGeneration = (fCurrentGeneration + 1) % fGenerationCount;
for (int32 i = 0; i < fGenerations[newGeneration].entries_size; i++) {
EntryCacheEntry* otherEntry = fGenerations[newGeneration].entries[i];
@@ -272,7 +281,9 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
fGenerations[newGeneration].entries[i] = NULL;
fEntries.Remove(otherEntry);
free(otherEntry);
otherEntry->hash_link = entriesToFree;
entriesToFree = otherEntry;
}
// set the new generation and add the entry
@@ -281,4 +292,12 @@ EntryCache::_AddEntryToCurrentGeneration(EntryCacheEntry* entry)
fGenerations[newGeneration].next_index = 1;
entry->generation = newGeneration;
entry->index = 0;
// free the old entries
locker.Unlock();
while (entriesToFree != NULL) {
EntryCacheEntry* next = entriesToFree->hash_link;
free(entriesToFree);
entriesToFree = next;
}
}