From ad1ca231acba6e83b2c3f199a6465f4e29282b08 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 26 Jun 2013 18:15:48 +0800 Subject: [PATCH] KernelLand - Better node chaching code --- KernelLand/Kernel/include/vfs.h | 17 ++- KernelLand/Kernel/vfs/nodecache.c | 143 ++++++------------ KernelLand/Modules/Filesystems/Ext2/ext2.c | 2 +- .../Modules/Filesystems/Ext2/ext2_common.h | 2 +- KernelLand/Modules/Filesystems/NTFS/common.h | 4 +- KernelLand/Modules/Filesystems/NTFS/dir.c | 1 + KernelLand/Modules/Filesystems/NTFS/io.c | 9 +- KernelLand/Modules/Filesystems/NTFS/main.c | 19 ++- 8 files changed, 86 insertions(+), 111 deletions(-) diff --git a/KernelLand/Kernel/include/vfs.h b/KernelLand/Kernel/include/vfs.h index d2cdf204..f7666137 100644 --- a/KernelLand/Kernel/include/vfs.h +++ b/KernelLand/Kernel/include/vfs.h @@ -496,12 +496,17 @@ extern int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState); * fast cleanup when a filesystem is unmounted. * \{ */ + +typedef struct sInodeCache tInodeCache; + +typedef void (*tInode_CleanUpNode)(tVFS_Node *Node); + /** * \fn int Inode_GetHandle(void) * \brief Gets a unique handle to the Node Cache * \return A unique handle for use for the rest of the Inode_* functions */ -extern int Inode_GetHandle(void); +extern tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode); /** * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode) * \brief Gets an inode from the node cache @@ -509,7 +514,7 @@ extern int Inode_GetHandle(void); * \param Inode Value of the Inode field of the ::tVFS_Node you want * \return A pointer to the cached node */ -extern tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode); +extern tVFS_Node *Inode_GetCache(tInodeCache *Handle, Uint64 Inode); /** * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node) * \brief Caches a node in the Node Cache @@ -517,8 +522,8 @@ extern tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode); * \param Node A pointer to the node to be cached (a copy is taken) * \return A pointer to the node in the node cache */ -extern tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node); -extern tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size); +extern tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node); +extern tVFS_Node *Inode_CacheNodeEx(tInodeCache *Handle, tVFS_Node *Node, size_t Size); /** * \fn int Inode_UncacheNode(int Handle, Uint64 Inode) * \brief Dereferences (and removes if needed) a node from the cache @@ -526,13 +531,13 @@ extern tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size); * \param Inode Value of the Inode field of the ::tVFS_Node you want to remove * \return -1: Error (not present), 0: Not freed, 1: Freed */ -extern int Inode_UncacheNode(int Handle, Uint64 Inode); +extern int Inode_UncacheNode(tInodeCache *Handle, Uint64 Inode); /** * \fn void Inode_ClearCache(int Handle) * \brief Clears the cache for a handle * \param Handle A handle returned by Inode_GetHandle() */ -extern void Inode_ClearCache(int Handle); +extern void Inode_ClearCache(tInodeCache *Handle); /** * \} diff --git a/KernelLand/Kernel/vfs/nodecache.c b/KernelLand/Kernel/vfs/nodecache.c index aee1826e..5fdebb6b 100644 --- a/KernelLand/Kernel/vfs/nodecache.c +++ b/KernelLand/Kernel/vfs/nodecache.c @@ -15,33 +15,30 @@ typedef struct sCachedInode { struct sCachedInode *Next; tVFS_Node Node; } tCachedInode; -typedef struct sInodeCache { +struct sInodeCache +{ struct sInodeCache *Next; - int Handle; + tInode_CleanUpNode CleanUpNode; tCachedInode *FirstNode; // Sorted List Uint64 MaxCached; // Speeds up Searching -} tInodeCache; - -// === PROTOTYPES === -tInodeCache *Inode_int_GetFSCache(int Handle); +}; // === GLOBALS === - int gVFS_NextInodeHandle = 1; tShortSpinlock glVFS_InodeCache; tInodeCache *gVFS_InodeCache = NULL; // === CODE === -/** - * \fn int Inode_GetHandle() - */ -int Inode_GetHandle() + +// Create a new inode cache +tInodeCache *Inode_GetHandle(tInode_CleanUpNode CleanUpNode) { tInodeCache *ent; ent = malloc( sizeof(tInodeCache) ); ent->MaxCached = 0; - ent->Handle = gVFS_NextInodeHandle++; - ent->Next = NULL; ent->FirstNode = NULL; + ent->Next = NULL; + ent->FirstNode = NULL; + ent->CleanUpNode = CleanUpNode; // Add to list SHORTLOCK( &glVFS_InodeCache ); @@ -49,26 +46,21 @@ int Inode_GetHandle() gVFS_InodeCache = ent; SHORTREL( &glVFS_InodeCache ); - return ent->Handle; + return ent; } /** * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode) * \brief Gets a node from the cache */ -tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode) +tVFS_Node *Inode_GetCache(tInodeCache *Cache, Uint64 Inode) { - tInodeCache *cache; tCachedInode *ent; - cache = Inode_int_GetFSCache(Handle); - if(!cache) return NULL; - - if(Inode > cache->MaxCached) return NULL; + if(Inode > Cache->MaxCached) return NULL; // Search Cache - ent = cache->FirstNode; - for( ; ent; ent = ent->Next ) + for( ent = Cache->FirstNode; ent; ent = ent->Next ) { if(ent->Node.Inode < Inode) continue; if(ent->Node.Inode > Inode) return NULL; @@ -82,27 +74,23 @@ tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode) /** * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node) */ -tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node) +tVFS_Node *Inode_CacheNode(tInodeCache *Handle, tVFS_Node *Node) { return Inode_CacheNodeEx(Handle, Node, sizeof(*Node)); } -tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size) +tVFS_Node *Inode_CacheNodeEx(tInodeCache *Cache, tVFS_Node *Node, size_t Size) { - tInodeCache *cache; - tCachedInode *newEnt, *ent, *prev = NULL; + tCachedInode *newEnt, *prev = NULL; ASSERT(Size >= sizeof(tVFS_Node)); - - cache = Inode_int_GetFSCache(Handle); - if(!cache) return NULL; - if(Node->Inode > cache->MaxCached) - cache->MaxCached = Node->Inode; + if(Node->Inode > Cache->MaxCached) + Cache->MaxCached = Node->Inode; // Search Cache - ent = cache->FirstNode; - for( ; ent; prev = ent, ent = ent->Next ) + tCachedInode *ent; + for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next ) { if(ent->Node.Inode < Node->Inode) continue; if(ent->Node.Inode == Node->Inode) { @@ -119,7 +107,7 @@ tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size) if( prev ) prev->Next = newEnt; else - cache->FirstNode = newEnt; + Cache->FirstNode = newEnt; newEnt->Node.ReferenceCount = 1; LOG("Cached %llx as %p", Node->Inode, &newEnt->Node); @@ -131,28 +119,20 @@ tVFS_Node *Inode_CacheNodeEx(int Handle, tVFS_Node *Node, size_t Size) * \fn void Inode_UncacheNode(int Handle, Uint64 Inode) * \brief Dereferences/Removes a cached node */ -int Inode_UncacheNode(int Handle, Uint64 Inode) +int Inode_UncacheNode(tInodeCache *Cache, Uint64 Inode) { - tInodeCache *cache; tCachedInode *ent, *prev; - cache = Inode_int_GetFSCache(Handle); - if(!cache) { - Log_Notice("Inode", "Invalid cache handle %i used", Handle); - return -1; - } + ENTER("pHandle XInode", Cache, Inode); - ENTER("iHandle XInode", Handle, Inode); - - if(Inode > cache->MaxCached) { + if(Inode > Cache->MaxCached) { LEAVE('i', -1); return -1; } // Search Cache - ent = cache->FirstNode; prev = NULL; - for( ; ent; prev = ent, ent = ent->Next ) + for( ent = Cache->FirstNode; ent; prev = ent, ent = ent->Next ) { if(ent->Node.Inode < Inode) continue; if(ent->Node.Inode > Inode) { @@ -176,15 +156,17 @@ int Inode_UncacheNode(int Handle, Uint64 Inode) if( prev ) prev->Next = ent->Next; else - cache->FirstNode = ent->Next; - if(ent->Node.Inode == cache->MaxCached) + Cache->FirstNode = ent->Next; + if(ent->Node.Inode == Cache->MaxCached) { - if(ent != cache->FirstNode && prev) - cache->MaxCached = prev->Node.Inode; + if(ent != Cache->FirstNode && prev) + Cache->MaxCached = prev->Node.Inode; else - cache->MaxCached = 0; + Cache->MaxCached = 0; } - + + if(Cache->CleanUpNode) + Cache->CleanUpNode(&ent->Node); if(ent->Node.Data) free(ent->Node.Data); free(ent); @@ -203,63 +185,38 @@ int Inode_UncacheNode(int Handle, Uint64 Inode) * \fn void Inode_ClearCache(int Handle) * \brief Removes a cache */ -void Inode_ClearCache(int Handle) +void Inode_ClearCache(tInodeCache *Cache) { - tInodeCache *cache; tInodeCache *prev = NULL; tCachedInode *ent, *next; // Find the cache - for( - cache = gVFS_InodeCache; - cache && cache->Handle < Handle; - prev = cache, cache = cache->Next - ); - if(!cache || cache->Handle != Handle) return; + for( prev = (void*)&gVFS_InodeCache; prev && prev->Next != Cache; prev = prev->Next ) + ; + if( !prev ) { + // Oops? + return; + } // Search Cache - ent = cache->FirstNode; - while( ent ) + for( ent = Cache->FirstNode; ent; ent = next ) { - ent->Node.ReferenceCount = 1; next = ent->Next; + ent->Node.ReferenceCount = 1; + // Usually has the side-effect of freeing this node + // TODO: Ensure that node is freed if(ent->Node.Type && ent->Node.Type->Close) ent->Node.Type->Close( &ent->Node ); - free(ent); - - ent = next; + else + free(ent); } // Free Cache if(prev == NULL) - gVFS_InodeCache = cache->Next; + gVFS_InodeCache = Cache->Next; else - prev->Next = cache->Next; - free(cache); + prev->Next = Cache->Next; + free(Cache); } -/** - * \fn tInodeCache *Inode_int_GetFSCache(int Handle) - * \brief Gets a cache given it's handle - */ -tInodeCache *Inode_int_GetFSCache(int Handle) -{ - tInodeCache *cache = gVFS_InodeCache; - // Find Cache - for( ; cache; cache = cache->Next ) - { - if(cache->Handle > Handle) continue; - if(cache->Handle < Handle) { - Warning("Inode_int_GetFSCache - Handle %i not in cache\n", Handle); - return NULL; - } - break; - } - if(!cache) { - Warning("Inode_int_GetFSCache - Handle %i not in cache [NULL]\n", Handle); - return NULL; - } - - return cache; -} diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2.c b/KernelLand/Modules/Filesystems/Ext2/ext2.c index 4d13f1ed..516fe0b9 100644 --- a/KernelLand/Modules/Filesystems/Ext2/ext2.c +++ b/KernelLand/Modules/Filesystems/Ext2/ext2.c @@ -139,7 +139,7 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) disk->GroupCount = groupCount; // Get an inode cache handle - disk->CacheID = Inode_GetHandle(); + disk->CacheID = Inode_GetHandle(NULL); // Get Block Size if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) { diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2_common.h b/KernelLand/Modules/Filesystems/Ext2/ext2_common.h index b4c9547a..04fcae41 100644 --- a/KernelLand/Modules/Filesystems/Ext2/ext2_common.h +++ b/KernelLand/Modules/Filesystems/Ext2/ext2_common.h @@ -13,7 +13,7 @@ // === STRUCTURES === typedef struct { int FD; - int CacheID; + tInodeCache *CacheID; tVFS_Node RootNode; tExt2_SuperBlock SuperBlock; diff --git a/KernelLand/Modules/Filesystems/NTFS/common.h b/KernelLand/Modules/Filesystems/NTFS/common.h index e8dbe7d0..3ef81097 100644 --- a/KernelLand/Modules/Filesystems/NTFS/common.h +++ b/KernelLand/Modules/Filesystems/NTFS/common.h @@ -40,7 +40,7 @@ struct sNTFS_Directory struct sNTFS_Disk { int FD; - int CacheHandle; + tInodeCache *InodeCache; int ClusterSize; @@ -50,8 +50,6 @@ struct sNTFS_Disk tNTFS_Attrib *MFTDataAttr; tNTFS_Attrib *MFTBitmapAttr; - int InodeCache; - tNTFS_Directory RootDir; }; diff --git a/KernelLand/Modules/Filesystems/NTFS/dir.c b/KernelLand/Modules/Filesystems/NTFS/dir.c index dc5fb7c3..5697252b 100644 --- a/KernelLand/Modules/Filesystems/NTFS/dir.c +++ b/KernelLand/Modules/Filesystems/NTFS/dir.c @@ -273,6 +273,7 @@ tVFS_Node *NTFS_int_CreateNode(tNTFS_Disk *Disk, Uint64 MFTEntry) ret = &types.tpl_file.Node; ret->Type = &gNTFS_FileType; types.tpl_file.Data = NTFS_GetAttrib(Disk, MFTEntry, NTFS_FileAttrib_Data, "", 0); + ret->Size = types.tpl_file.Data->DataSize; } ret->Inode = MFTEntry; ret->ImplPtr = Disk; diff --git a/KernelLand/Modules/Filesystems/NTFS/io.c b/KernelLand/Modules/Filesystems/NTFS/io.c index d0f70889..014dc70b 100644 --- a/KernelLand/Modules/Filesystems/NTFS/io.c +++ b/KernelLand/Modules/Filesystems/NTFS/io.c @@ -14,8 +14,13 @@ size_t NTFS_ReadFile(tVFS_Node *Node, Uint64 Offset, size_t Length, void *Buffer, Uint Flags) { tNTFS_File *File = (void*)Node; - - return NTFS_ReadAttribData(File->Data, Offset, Length, Buffer); + + ENTER("XNode->Inode XOffset xLength pBuffer xFlags", + Node->Inode, Offset, Length, Buffer, Flags); + + size_t ret = NTFS_ReadAttribData(File->Data, Offset, Length, Buffer); + LEAVE('x', ret); + return ret; } diff --git a/KernelLand/Modules/Filesystems/NTFS/main.c b/KernelLand/Modules/Filesystems/NTFS/main.c index 4586e12e..3b17e17e 100644 --- a/KernelLand/Modules/Filesystems/NTFS/main.c +++ b/KernelLand/Modules/Filesystems/NTFS/main.c @@ -137,7 +137,7 @@ tVFS_Node *NTFS_InitDevice(const char *Device, const char **Options) //NTFS_DumpEntry(disk, 0); // $MFT //NTFS_DumpEntry(disk, 3); // $VOLUME - disk->InodeCache = Inode_GetHandle(); + disk->InodeCache = Inode_GetHandle(NTFS_FreeNode); disk->MFTDataAttr = NULL; disk->MFTDataAttr = NTFS_GetAttrib(disk, 0, NTFS_FileAttrib_Data, "", 0); @@ -223,6 +223,9 @@ int NTFS_int_ApplyUpdateSequence(void *Buffer, size_t BufLen, const Uint16 *Sequ tNTFS_FILE_Header *NTFS_GetMFT(tNTFS_Disk *Disk, Uint32 MFTEntry) { + // TODO: Cache MFT allocation for short-term + + // tNTFS_FILE_Header *ret = malloc( Disk->MFTRecSize ); if(!ret) { Log_Warning("FS_NTFS", "malloc() fail!"); @@ -332,8 +335,12 @@ tNTFS_Attrib *NTFS_GetAttrib(tNTFS_Disk *Disk, Uint32 MFTEntry, int Type, const if( attr->Type != Type ) continue; if( Name ) { - LOG("Name check = '%s'", Name); + if( attr->NameOffset + attr->NameLength*2 > attr->Size ) { + break; + } const void *name16 = (char*)attr + attr->NameOffset; + LOG("Name check: '%s' == '%.*ls'", + Name, attr->NameLength, name16); if( UTF16_CompareWithUTF8(attr->NameLength, name16, Name) != 0 ) continue ; } @@ -345,11 +352,10 @@ tNTFS_Attrib *NTFS_GetAttrib(tNTFS_Disk *Disk, Uint32 MFTEntry, int Type, const ASSERT(attr->NameOffset % 1 == 0); Uint16 *name16 = (Uint16*)attr + attr->NameOffset/2; size_t namelen = UTF16_ConvertToUTF8(0, NULL, attr->NameLength, name16); - size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen*4); + size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen); tNTFS_Attrib *ret = malloc( sizeof(tNTFS_Attrib) + namelen + 1 + edatalen ); if(!ret) { - LEAVE('n'); - return NULL; + goto _error; } if( attr->NonresidentFlag ) ret->Name = (void*)(ret + 1); @@ -396,12 +402,15 @@ tNTFS_Attrib *NTFS_GetAttrib(tNTFS_Disk *Disk, Uint32 MFTEntry, int Type, const { ret->DataSize = edatalen; memcpy(ret->ResidentData, (char*)attr + attr->Resident.AttribOfs, edatalen); + Debug_HexDump("GetAttrib Resident", ret->ResidentData, edatalen); } + NTFS_ReleaseMFT(Disk, MFTEntry, hdr); LEAVE('p', ret); return ret; } +_error: NTFS_ReleaseMFT(Disk, MFTEntry, hdr); LEAVE('n'); return NULL; -- 2.20.1