From efb0a3a853557e69ecf2bc88adc9a69ed08d1514 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 17 Aug 2015 22:13:59 +0200 Subject: [PATCH] EntryCache: Add entry_cache_add_missing() for negative caching. It provides a way for filesystems to cache a lookup failure and therefore prevents repeated lookups of missing entries. This is a common scenario for example in command lookup and compiling, where each directory in PATH or each include directory is searched for the given entry. --- headers/os/drivers/fs_cache.h | 2 ++ headers/private/fs_shell/fssh_api_wrapper.h | 1 + headers/private/fs_shell/fssh_fs_cache.h | 2 ++ .../userlandfs/server/haiku/entry_cache.cpp | 7 ++++++ src/system/kernel/fs/EntryCache.cpp | 10 ++++++-- src/system/kernel/fs/EntryCache.h | 5 ++-- src/system/kernel/fs/vfs.cpp | 24 ++++++++++++++++--- src/tools/fs_shell/vfs.cpp | 9 +++++++ 8 files changed, 53 insertions(+), 7 deletions(-) diff --git a/headers/os/drivers/fs_cache.h b/headers/os/drivers/fs_cache.h index 64667699a5..9a71a5b5e1 100644 --- a/headers/os/drivers/fs_cache.h +++ b/headers/os/drivers/fs_cache.h @@ -104,6 +104,8 @@ extern status_t file_map_translate(void *map, off_t offset, size_t size, /* entry cache */ extern status_t entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID); +extern status_t entry_cache_add_missing(dev_t mountID, ino_t dirID, + const char* name); extern status_t entry_cache_remove(dev_t mountID, ino_t dirID, const char* name); diff --git a/headers/private/fs_shell/fssh_api_wrapper.h b/headers/private/fs_shell/fssh_api_wrapper.h index 337648f2e2..1651b2a041 100644 --- a/headers/private/fs_shell/fssh_api_wrapper.h +++ b/headers/private/fs_shell/fssh_api_wrapper.h @@ -871,6 +871,7 @@ /* entry cache */ #define entry_cache_add fssh_entry_cache_add +#define entry_cache_add_missing fssh_entry_cache_add_missing #define entry_cache_remove fssh_entry_cache_remove //////////////////////////////////////////////////////////////////////////////// diff --git a/headers/private/fs_shell/fssh_fs_cache.h b/headers/private/fs_shell/fssh_fs_cache.h index 87eef13f39..88cc9a392e 100644 --- a/headers/private/fs_shell/fssh_fs_cache.h +++ b/headers/private/fs_shell/fssh_fs_cache.h @@ -126,6 +126,8 @@ extern fssh_status_t fssh_file_map_translate(void *_map, fssh_off_t offset, extern fssh_status_t fssh_entry_cache_add(fssh_dev_t mountID, fssh_ino_t dirID, const char* name, fssh_ino_t nodeID); +extern fssh_status_t fssh_entry_cache_add_missing(fssh_dev_t mountID, + fssh_ino_t dirID, const char* name); extern fssh_status_t fssh_entry_cache_remove(fssh_dev_t mountID, fssh_ino_t dirID, const char* name); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/entry_cache.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/entry_cache.cpp index 8ea12b8158..7aa60ac982 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/haiku/entry_cache.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/haiku/entry_cache.cpp @@ -17,6 +17,13 @@ entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID) } +status_t +entry_cache_add_missing(dev_t mountID, ino_t dirID, const char* name) +{ + return B_OK; +} + + status_t entry_cache_remove(dev_t mountID, ino_t dirID, const char* name) { diff --git a/src/system/kernel/fs/EntryCache.cpp b/src/system/kernel/fs/EntryCache.cpp index e9a6a14db9..63743b8f4c 100644 --- a/src/system/kernel/fs/EntryCache.cpp +++ b/src/system/kernel/fs/EntryCache.cpp @@ -90,7 +90,7 @@ EntryCache::Init() status_t -EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID) +EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID, bool missing) { EntryCacheKey key(dirID, name); @@ -99,6 +99,7 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID) 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; @@ -114,6 +115,7 @@ EntryCache::Add(ino_t dirID, const char* name, ino_t nodeID) entry->node_id = nodeID; entry->dir_id = dirID; + entry->missing = missing; entry->generation = fCurrentGeneration; entry->index = kEntryNotInArray; strcpy(entry->name, name); @@ -155,7 +157,8 @@ EntryCache::Remove(ino_t dirID, const char* name) bool -EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID) +EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID, + bool& _missing) { EntryCacheKey key(dirID, name); @@ -171,6 +174,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID) // The entry is already in the current generation or is being moved to // it by another thread. _nodeID = entry->node_id; + _missing = entry->missing; return true; } @@ -184,6 +188,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID) fGenerations[fCurrentGeneration].entries[index] = entry; entry->index = index; _nodeID = entry->node_id; + _missing = entry->missing; return true; } @@ -201,6 +206,7 @@ EntryCache::Lookup(ino_t dirID, const char* name, ino_t& _nodeID) _AddEntryToCurrentGeneration(entry); _nodeID = entry->node_id; + _missing = entry->missing; return true; } diff --git a/src/system/kernel/fs/EntryCache.h b/src/system/kernel/fs/EntryCache.h index 79a8df0f06..4cbf865915 100644 --- a/src/system/kernel/fs/EntryCache.h +++ b/src/system/kernel/fs/EntryCache.h @@ -36,6 +36,7 @@ struct EntryCacheEntry { ino_t dir_id; int32 generation; int32 index; + bool missing; char name[1]; }; @@ -87,12 +88,12 @@ public: status_t Init(); status_t Add(ino_t dirID, const char* name, - ino_t nodeID); + ino_t nodeID, bool missing); status_t Remove(ino_t dirID, const char* name); bool Lookup(ino_t dirID, const char* name, - ino_t& nodeID); + ino_t& nodeID, bool& missing); const char* DebugReverseLookup(ino_t nodeID, ino_t& _dirID); diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 6e98ac4f5e..68f58c63ec 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -2089,9 +2089,12 @@ static status_t lookup_dir_entry(struct vnode* dir, const char* name, struct vnode** _vnode) { ino_t id; + bool missing; - if (dir->mount->entry_cache.Lookup(dir->id, name, id)) - return get_vnode(dir->device, id, _vnode, true, false); + if (dir->mount->entry_cache.Lookup(dir->id, name, id, missing)) { + return missing ? B_ENTRY_NOT_FOUND + : get_vnode(dir->device, id, _vnode, true, false); + } status_t status = FS_CALL(dir, lookup, name, &id); if (status != B_OK) @@ -4011,7 +4014,22 @@ entry_cache_add(dev_t mountID, ino_t dirID, const char* name, ino_t nodeID) return B_BAD_VALUE; locker.Unlock(); - return mount->entry_cache.Add(dirID, name, nodeID); + return mount->entry_cache.Add(dirID, name, nodeID, false); +} + + +extern "C" status_t +entry_cache_add_missing(dev_t mountID, ino_t dirID, const char* name) +{ + // lookup mount -- the caller is required to make sure that the mount + // won't go away + MutexLocker locker(sMountMutex); + struct fs_mount* mount = find_mount(mountID); + if (mount == NULL) + return B_BAD_VALUE; + locker.Unlock(); + + return mount->entry_cache.Add(dirID, name, -1, true); } diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp index 9308a351da..5137ddd364 100644 --- a/src/tools/fs_shell/vfs.cpp +++ b/src/tools/fs_shell/vfs.cpp @@ -2277,6 +2277,15 @@ fssh_entry_cache_add(fssh_dev_t mountID, fssh_ino_t dirID, const char* name, } +extern "C" fssh_status_t +fssh_entry_cache_add_missing(fssh_dev_t mountID, fssh_ino_t dirID, + const char* name) +{ + // We don't implement an entry cache in the FS shell. + return FSSH_B_OK; +} + + extern "C" fssh_status_t fssh_entry_cache_remove(fssh_dev_t mountID, fssh_ino_t dirID, const char* name) {