diff --git a/src/system/kernel/fs/EntryCache.cpp b/src/system/kernel/fs/EntryCache.cpp index 03a5c9089c..fd01fbd874 100644 --- a/src/system/kernel/fs/EntryCache.cpp +++ b/src/system/kernel/fs/EntryCache.cpp @@ -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; + } }