Kernel/arch - Fix common division macro to handle numerators around datatype max
[tpg/acess2.git] / KernelLand / Kernel / drv / iocache.c
index 8f73541..d38aa65 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * Acess2 Kernel
- * - IO Cache
+ * - By thePowersGang (John Hodge)
  * 
- * By thePowersGang (John Hodge)
- * 
- * TODO: Convert to use spare physical pages instead
+ * drv/iocache.c
+ * - Block IO Caching
  */
 #define DEBUG  0
 #include <acess.h>
 #include <iocache.h>
+#define IOCACHE_USE_PAGES      1
 
 // === TYPES ===
 typedef struct sIOCache_Ent    tIOCache_Ent;
@@ -26,11 +26,15 @@ struct sIOCache_Ent
 
 struct sIOCache_PageInfo
 {
-       tIOCache_PageInfo       *GlobalNext;
        tIOCache_PageInfo       *CacheNext;
+       tIOCache_PageInfo       *GlobalNext;
        tIOCache        *Owner;
+       Sint64  LastAccess;
+       
        tPAddr  BasePhys;
        Uint64  BaseOffset;
+       Uint32  PresentSectors;
+       Uint32  DirtySectors;
 };
 
 struct sIOCache
@@ -39,31 +43,48 @@ struct sIOCache
         int    SectorSize;
        tMutex  Lock;
         int    Mode;
-       Uint32  ID;
+       void    *ID;
        tIOCache_WriteCallback  Write;
         int    CacheSize;
         int    CacheUsed;
+       #if IOCACHE_USE_PAGES
+       tIOCache_PageInfo       *Pages;
+       #else
        tIOCache_Ent    *Entries;
+       #endif
 };
 
+#if IOCACHE_USE_PAGES
+tIOCache_PageInfo      *IOCache_int_GetPage(tIOCache *Cache, Uint64 Sector, tIOCache_PageInfo **Prev, size_t *Offset);
+#endif
+
 // === GLOBALS ===
 tShortSpinlock glIOCache_Caches;
 tIOCache       *gIOCache_Caches = NULL;
  int   giIOCache_NumCaches = 0;
+#if IOCACHE_USE_PAGES
 tIOCache_PageInfo      *gIOCache_GlobalPages;
+#endif
 
 // === CODE ===
 /**
  * \fn tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
  * \brief Creates a new IO Cache
  */
-tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
+tIOCache *IOCache_Create( tIOCache_WriteCallback Write, void *ID, int SectorSize, int CacheSize )
 {
-       tIOCache        *ret = calloc( 1, sizeof(tIOCache) );
-       
-       // Sanity Check
-       if(!ret)        return NULL;
+       if( CacheSize < 1 )
+               return NULL;
+       if( SectorSize < 512 )
+               return NULL;
+       if( SectorSize > PAGE_SIZE )
+               return NULL;
        
+       // TODO: Check that SectorSize is a power of two        
+
+       tIOCache        *ret = calloc( 1, sizeof(tIOCache) );
+       if(!ret)        return NULL;    
+
        // Fill Structure
        ret->SectorSize = SectorSize;
        ret->Mode = IOCACHE_WRITEBACK;
@@ -81,6 +102,26 @@ tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSiz
        return ret;
 }
 
+#if IOCACHE_USE_PAGES
+tIOCache_PageInfo *IOCache_int_GetPage(tIOCache *Cache, Uint64 Sector, tIOCache_PageInfo **Prev, size_t *Offset)
+{
+       Uint64  wanted_base = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
+       if( Offset )
+               *Offset = (Sector*Cache->SectorSize) % PAGE_SIZE;
+       
+       tIOCache_PageInfo *prev = (void*)&Cache->Pages;
+       for( tIOCache_PageInfo *page = Cache->Pages; page; prev = page, page = page->CacheNext )
+       {
+               if(page->BaseOffset < wanted_base)      continue;
+               if(page->BaseOffset > wanted_base)      break;
+               return page;
+       }
+       if( Prev )
+               *Prev = prev;
+       return NULL;
+}
+#endif
+
 /**
  * \fn int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
  * \brief Read from a cached sector
@@ -106,21 +147,21 @@ int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
 
        #if IOCACHE_USE_PAGES
        tIOCache_PageInfo       *page;
-       size_t  offset = (Sector*Cache->SectorSize) % PAGE_SIZE;
-       Uint64  wanted_base = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
-       for( page = Cache->Pages; page; page = page->CacheNext )
+       size_t  offset;
+       page = IOCache_int_GetPage(Cache, Sector, NULL, &offset);
+       if( page && (page->PresentSectors & (1 << offset/Cache->SectorSize)) )
        {
-               void    *tmp;
-               if(page->BaseOffset < WantedBase)       continue;
-               if(page->BaseOffset > WantedBase)       break;
-               tmp = MM_MapTemp( page->BasePhys );
+               page->LastAccess = now();
+               char *tmp = MM_MapTemp( page->BasePhys );
                memcpy( Buffer, tmp + offset, Cache->SectorSize ); 
                MM_FreeTemp( tmp );
+               Mutex_Release( &Cache->Lock );
+               LEAVE('i', 1);
+               return 1;
        }
        #else   
-       tIOCache_Ent    *ent;
        // Search the list
-       for( ent = Cache->Entries; ent; ent = ent->Next )
+       for( tIOCache_Ent *ent = Cache->Entries; ent; ent = ent->Next )
        {
                // Have we found what we are looking for?
                if( ent->Num == Sector ) {
@@ -145,11 +186,8 @@ int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
  * \fn int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
  * \brief Cache a sector
  */
-int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
+int IOCache_Add( tIOCache *Cache, Uint64 Sector, const void *Buffer )
 {
-       tIOCache_Ent    *ent, *prev;
-       tIOCache_Ent    *new;
-       tIOCache_Ent    *oldest = NULL, *oldestPrev;
        
        // Sanity Check!
        if(!Cache || !Buffer)
@@ -163,6 +201,76 @@ int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
        }
        
        // Search the list
+       #if IOCACHE_USE_PAGES
+       char    *page_map;
+       size_t  offset;
+       tIOCache_PageInfo *prev;
+       tIOCache_PageInfo *page = IOCache_int_GetPage(Cache, Sector, &prev, &offset);
+       if( page )
+       {
+               Uint32  mask = (1 << offset/Cache->SectorSize);
+                int    ret = !(page->PresentSectors & mask);
+               if( ret )
+               {
+                       page_map = MM_MapTemp( page->BasePhys );
+                       memcpy( page_map + offset, Buffer, Cache->SectorSize ); 
+                       MM_FreeTemp( page_map );
+                       page->PresentSectors |= mask;
+               }
+               Mutex_Release( &Cache->Lock );
+               return ret;
+       }
+       else if( Cache->CacheUsed <= Cache->CacheSize )
+       {
+               page = malloc( sizeof(tIOCache_PageInfo) );
+               page->BasePhys = MM_AllocPhys();
+               page_map = MM_MapTemp( page->BasePhys );
+               
+               page->GlobalNext = gIOCache_GlobalPages;
+               gIOCache_GlobalPages = page;
+       }
+       else
+       {
+               tIOCache_PageInfo *oldest = Cache->Pages, *oldestPrev = NULL;
+               for( tIOCache_PageInfo *ent = Cache->Pages; ent; prev = ent, ent = ent->CacheNext )
+               {
+                       if( ent->LastAccess < oldest->LastAccess ) {
+                               oldest = ent;
+                               oldestPrev = prev;
+                       }
+               }
+               // Remove oldest from list
+               *(oldestPrev ? &oldestPrev->CacheNext : &Cache->Pages) = oldest->CacheNext;
+               page = oldest;
+               page_map = MM_MapTemp( page->BasePhys );
+               // Flush
+               if( page->DirtySectors && Cache->Mode != IOCACHE_VIRTUAL )
+               {
+                       for( int i = 0; i < PAGE_SIZE/Cache->SectorSize; i ++ )
+                               Cache->Write(Cache->ID, page->BaseOffset/Cache->SectorSize+i,
+                                       page_map + i * Cache->SectorSize);
+               }
+       }
+
+       // Create a new page
+       page->CacheNext = prev->CacheNext;
+       prev->CacheNext = page;
+       
+       page->Owner = Cache;
+       page->LastAccess = now();
+       
+       page->BaseOffset = (Sector*Cache->SectorSize) & ~(PAGE_SIZE-1);
+       page->PresentSectors = 0;
+       page->DirtySectors = 0;
+       
+       memcpy( page_map + offset, Buffer, Cache->SectorSize ); 
+
+       MM_FreeTemp(page_map);
+       
+       #else
+       tIOCache_Ent    *ent, *prev;
+       tIOCache_Ent    *new;
+       tIOCache_Ent    *oldest = NULL, *oldestPrev;
        prev = (tIOCache_Ent*)&Cache->Entries;
        for( ent = Cache->Entries; ent; prev = ent, ent = ent->Next )
        {
@@ -225,6 +333,7 @@ int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
        // Append to list
        prev->Next = new;
        Cache->CacheUsed ++;
+       #endif
        
        // Release Spinlock
        Mutex_Release( &Cache->Lock );
@@ -237,10 +346,8 @@ int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
  * \fn int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
  * \brief Read from a cached sector
  */
-int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
+int IOCache_Write( tIOCache *Cache, Uint64 Sector, const void *Buffer )
 {
-       tIOCache_Ent    *ent;
-       
        // Sanity Check!
        if(!Cache || !Buffer)
                return -1;
@@ -251,8 +358,32 @@ int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
                return -1;
        }
        
+       #if IOCACHE_USE_PAGES
+       tIOCache_PageInfo       *page;
+       size_t  offset;
+       page = IOCache_int_GetPage(Cache, Sector, NULL, &offset);
+       if( page && (page->PresentSectors & (1 << offset/Cache->SectorSize)) )
+       {
+               
+               page->LastAccess = now();
+               char *tmp = MM_MapTemp( page->BasePhys );
+               memcpy( tmp + offset, Buffer, Cache->SectorSize );
+               MM_FreeTemp( tmp );
+               
+               if(Cache->Mode == IOCACHE_WRITEBACK) {
+                       Cache->Write(Cache->ID, Sector, Buffer);
+               }
+               else {
+                       page->DirtySectors |= (1 << offset/Cache->SectorSize);
+               }
+               
+               Mutex_Release( &Cache->Lock );
+               LEAVE('i', 1);
+               return 1;
+       }
+       #else   
        // Search the list
-       for( ent = Cache->Entries; ent; ent = ent->Next )
+       for( tIOCache_Ent &ent = Cache->Entries; ent; ent = ent->Next )
        {
                // Have we found what we are looking for?
                if( ent->Num == Sector ) {
@@ -271,6 +402,7 @@ int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
                // it's not there
                if(ent->Num > Sector)   break;
        }
+       #endif
        
        Mutex_Release( &Cache->Lock );
        return 0;
@@ -282,8 +414,6 @@ int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
  */
 void IOCache_Flush( tIOCache *Cache )
 {
-       tIOCache_Ent    *ent;
-       
        if( Cache->Mode == IOCACHE_VIRTUAL )    return;
        
        // Lock
@@ -294,11 +424,26 @@ void IOCache_Flush( tIOCache *Cache )
        }
        
        // Write All
-       for( ent = Cache->Entries; ent; ent = ent->Next )
+       #if IOCACHE_USE_PAGES
+       for( tIOCache_PageInfo *page = Cache->Pages; page; page = page->CacheNext )
+       {
+               // Flush
+               char *page_map = MM_MapTemp( page->BasePhys );
+               if( page->DirtySectors && Cache->Mode != IOCACHE_VIRTUAL )
+               {
+                       for( int i = 0; i < PAGE_SIZE/Cache->SectorSize; i ++ )
+                               Cache->Write(Cache->ID, page->BaseOffset/Cache->SectorSize+i,
+                                       page_map + i * Cache->SectorSize);
+               }
+               MM_FreeTemp(page_map);
+       }
+       #else
+       for( tIOCache_Ent *ent = Cache->Entries; ent; ent = ent->Next )
        {
                Cache->Write(Cache->ID, ent->Num, ent->Data);
                ent->LastWrite = 0;
        }
+       #endif
        
        Mutex_Release( &Cache->Lock );
 }
@@ -309,30 +454,7 @@ void IOCache_Flush( tIOCache *Cache )
  */
 void IOCache_Destroy( tIOCache *Cache )
 {
-       tIOCache_Ent    *ent, *prev = NULL;
-       
-       // Lock
-       Mutex_Acquire( &Cache->Lock );
-       if(Cache->CacheSize == 0) {
-               Mutex_Release( &Cache->Lock );
-               return;
-       }
-       
-       // Free All
-       for(ent = Cache->Entries;
-               ent;
-               prev = ent, ent = ent->Next, free(prev) )
-       {
-               if( Cache->Mode != IOCACHE_VIRTUAL )
-               {
-                       Cache->Write(Cache->ID, ent->Num, ent->Data);
-                       ent->LastWrite = 0;
-               }
-       }
-       
-       Cache->CacheSize = 0;
-       
-       Mutex_Release( &Cache->Lock );
+       IOCache_Flush(Cache);
        
        // Remove from list
        SHORTLOCK( &glIOCache_Caches );

UCC git Repository :: git.ucc.asn.au