os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_fatcache.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfat32\sl_fatcache.cpp
    15 // FAT12 and FAT16 cache implementation
    16 // 
    17 //
    18 
    19 /**
    20  @file
    21 */
    22 
    23 #include "sl_std.h"
    24 #include "sl_fatcache.h"
    25 
    26 
    27 //#################################################################################################################################
    28 //  CFatCacheBase implementation
    29 //  Base class for all types of FAT cache
    30 //#################################################################################################################################
    31 
    32 CFatCacheBase::~CFatCacheBase()
    33     {
    34     Close(ETrue); //-- deallocate cache's memory discarding any dirty data
    35     }
    36 
    37 CFatCacheBase::CFatCacheBase()
    38     {
    39     iCurrentFatNo = KInvalidFatNo;
    40     SetDirty(EFalse);
    41     }
    42 
    43 
    44 /**
    45     FAT cache initialisation.
    46 
    47     @param  aOwner pointer to the owning FAT mount
    48 */
    49 void CFatCacheBase::InitialiseL(CFatMountCB* aOwner)
    50     {
    51     ASSERT(aOwner);
    52     
    53     Close(ETrue); //-- deallocate cache's memory discarding any dirty data
    54     
    55     //-- populate parameters from the owning mount
    56     iFatType = aOwner->FatType();
    57     __ASSERT_ALWAYS((iFatType == EFat12 || iFatType == EFat16 || iFatType == EFat32), User::Leave(KErrCorrupt));  
    58     
    59     ipDrive = &aOwner->DriveInterface();
    60     iFatStartPos = aOwner->FirstFatSector() << aOwner->SectorSizeLog2(); 
    61     iFatSize = aOwner->FatSizeInBytes();
    62     iNumFATs = (TUint16)aOwner->NumberOfFats();
    63     iFatSecSzLog2   = (TUint16)aOwner->SectorSizeLog2(); 
    64     iFatClustSzLog2 = (TUint16)aOwner->ClusterSizeLog2();
    65 
    66     __ASSERT_ALWAYS(iNumFATs >=1, User::Leave(KErrCorrupt));
    67 
    68     __PRINT3(_L("#-CFatCacheBase::InitialiseL() FatStart:%u, FatSz:%d, drv:%d"),iFatStartPos, iFatSize, aOwner->DriveNumber());
    69     }
    70 
    71 //-----------------------------------------------------------------------------
    72 /**
    73     This method shall be called to check if we are allowed to invalidate dirty cache, i.e. discard non-flushed data.
    74     The behaviour is hardcoded (see KAllowInvalidateDirtyCache constant)
    75 
    76     @return ETrue if invalidating dirty cache is allowed. Otherwise panics the current thread
    77 */
    78 TBool CFatCacheBase::CheckInvalidatingDirtyCache() const
    79     {
    80     
    81     //-- If not EFalse, invalidating dirty cache (pages) is allowed. This shall be OK, because
    82     //-- invalidating the cache is required only after direct media writes to the FAT by RawWrite, which can corrupt it anyway. 
    83     TBool KAllowInvalidateDirtyCache = ETrue;
    84     
    85     if(!IsDirty())
    86         return KAllowInvalidateDirtyCache;        
    87 
    88     __PRINT(_L("#-CFatCacheBase::Invalidating dirty cache !"));
    89     
    90     if(!KAllowInvalidateDirtyCache)
    91         {
    92         __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
    93         }
    94 
    95     return KAllowInvalidateDirtyCache;        
    96     }
    97 
    98 //-----------------------------------------------------------------------------
    99 
   100 /**
   101     Read portion of raw data from 1st FAT copy.
   102     
   103     @param  aPos   media position in the _FIRST_ FAT to start reading with
   104     @param  aLen   number of bytes to read
   105     @param  aData  data descriptor
   106 
   107     @return standard error code.
   108 */
   109 TInt CFatCacheBase::ReadFatData(TUint32 aPos, TUint32 aLen, TDes8& aData) const
   110     {
   111     //__PRINT2(_L("#-CFatCacheNew::ReadFatData() pos:%u, Len:%d"), aPos, aLen);
   112 
   113     //-- this method can pick up data corresponding to invalid FAT entries, like FAT[0], FAT[1] and
   114     //-- the last portion beyond FAT because of read granularity. This isn't a problem, because the data there
   115     //-- won't be written on disk.
   116     ASSERT(aPos >= FatStartPos()); 
   117 
   118     return ipDrive->ReadNonCritical(aPos, aLen, aData);
   119     }
   120 
   121 //-----------------------------------------------------------------------------
   122 
   123 /** 
   124     Writes data to the FAT table, which number is set in iCurrentFatNo member variable. 
   125     @param  aPos   data media position in the _FIRST_ FAT copy
   126     @param  aData  data descriptor
   127     @return standard error code.
   128 */
   129 TInt CFatCacheBase::WriteFatData(TUint32 aPos, const TDesC8& aData) const
   130     {
   131     //__PRINT3(_L("#-CFatCacheBase::WriteFatData() pos:%u, Len:%d, FAT:%d"), aPos, aData.Length(), iCurrentFatNo);
   132 
   133 #ifdef _DEBUG    
   134     //-- FAT[0] and FAT[1] entries are reserved and we must not write data there. It's up to the caller of this method to
   135     //-- calculate correct data position in FAT
   136     TInt reserved_Entries_Offset=0;
   137     switch(iFatType)
   138         {
   139         case EFat32: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat32Entry); break;  //-- FAT32  
   140         case EFat16: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat16Entry); break;  //-- FAT16  
   141         case EFat12: reserved_Entries_Offset = 3;   break;                                         //-- FAT12
   142         default: ASSERT(0); break;
   143         }
   144     ASSERT(aPos >= FatStartPos()+reserved_Entries_Offset);
   145     ASSERT((aPos+aData.Length()) <= FatStartPos()+FatSize());
   146     ASSERT(iCurrentFatNo < iNumFATs);
   147 #endif    
   148 
   149     //-- goto the required FAT copy. iCurrentFatNo shall contain FAT number we are writing to.
   150     aPos+=iCurrentFatNo*FatSize(); 
   151 
   152     return ipDrive->WriteCritical(aPos, aData);
   153     }
   154 
   155 //-----------------------------------------------------------------------------
   156 /** 
   157     get a pointer to the CFatBitCache interface. 
   158     @return NULL because it is not present here 
   159 */
   160 CFatBitCache* CFatCacheBase::BitCacheInterface() 
   161     {
   162     return NULL;
   163     }
   164     
   165 
   166 //#################################################################################################################################
   167 //  CFatPagedCacheBase implementation
   168 //  Base class for all paged FAT caches
   169 //#################################################################################################################################
   170 
   171 CFatPagedCacheBase::CFatPagedCacheBase()
   172                :CFatCacheBase() 
   173     {
   174     }
   175 
   176 
   177 //#################################################################################################################################
   178 //  CFatCachePageBase implementation
   179 //  Base class for FAT cache pages (FAT16 fixed and FAT32 LRU)
   180 //#################################################################################################################################
   181 
   182 CFatCachePageBase::CFatCachePageBase(CFatPagedCacheBase& aCache)
   183                   :iCache(aCache)
   184     {
   185     ASSERT(IsPowerOf2(aCache.PageSize()));
   186     iStartIndexInFAT = KMaxTUint;
   187 
   188     //-- calculate number of FAT entries in the page, it depends on FAT type
   189     switch(aCache.FatType())
   190         {
   191         case EFat32:
   192             iFatEntriesInPage = PageSize() >> KFat32EntrySzLog2;
   193         break;
   194     
   195         case EFat16:
   196             iFatEntriesInPage = PageSize() >> KFat16EntrySzLog2;
   197         break;
   198     
   199         default:
   200             ASSERT(0);
   201             Fault(EFatCache_BadFatType);
   202         break;
   203 
   204         };
   205 
   206     SetState(EInvalid); 
   207     }
   208 
   209 CFatCachePageBase::~CFatCachePageBase()
   210     {
   211     iData.Close();
   212     }
   213 
   214 //-----------------------------------------------------------------------------
   215 /**
   216     Mark the page as "invalid". I.e containing inalid data.
   217     On the first read/write access to such page it will be re-read from the media
   218 
   219     @param aIgnoreDirtyData if ETrue, it is allowed to ignore the fact that the page contains dirty (not flushed) data.
   220 */
   221 void CFatCachePageBase::Invalidate(TBool aIgnoreDirtyData /*= EFalse*/)
   222     {
   223     if(!aIgnoreDirtyData && IsDirty())
   224         {
   225         __PRINT1(_L("#-CFatCachePageBase::Invalidate() dirty page! FAT idx:%d"), iStartIndexInFAT);
   226         __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
   227         }
   228 
   229     iDirtySectors.Clear(); //-- clear dirty sectors bitmap
   230     SetState(EInvalid);
   231     }
   232 
   233 //-----------------------------------------------------------------------------
   234 /**
   235     Flush all dirty page sectors to the media and mark the page as "clean" if required.
   236     If the page is "clean" i.e doesn't contain changed data, does nothing.
   237 
   238     @param  aKeepDirty  if ETrue, the "dirty" flag isn't reset after page flushing.
   239 */
   240 void CFatCachePageBase::FlushL(TBool aKeepDirty)
   241     {
   242     if(!IsDirty())
   243         return;
   244 
   245     if(!IsValid())
   246         {
   247         __PRINT1(_L("#-CFatCachePageBase::FlushL() Invalid page! FAT idx:%d"), iStartIndexInFAT);
   248         ASSERT(0);
   249         User::Leave(KErrCorrupt);
   250         return;
   251         }
   252 
   253     //__PRINT1(_L("#-CFatCachePageBase::FlushL() FAT idx:%d"), iStartIndexInFAT);
   254 
   255     //-- write dirty FAT sectors  to the media one by one. 
   256     //-- merging adjacent dirty subsectors into larger clusters and writing them at once looks like a good idea, but
   257     //-- in reality it showed FAT performance degradation, at least on MMC/SD media.
   258     
   259     const TInt MaxSectors = iCache.SectorsInPage();
   260     
   261     for(TInt i=0; i<MaxSectors; ++i)
   262         {
   263         if(iDirtySectors[i])
   264             {
   265             DoWriteSectorL(i);
   266             }
   267         }
   268 
   269     //-- All data flushed; mark page as clean if it isn't required not to do.
   270     if(!aKeepDirty)
   271         SetClean(); 
   272 
   273     }
   274 
   275 
   276 //#################################################################################################################################
   277 //  CFat16FixedCache implementation
   278 //  Fixed cache (caches all FAT16) but organised as an array of pages
   279 //#################################################################################################################################
   280 
   281 CFat16FixedCache::CFat16FixedCache()
   282                  :CFatPagedCacheBase(),iPages(1) //-- array granularity is 1
   283     {
   284     }
   285 
   286 //-----------------------------------------------------------------------------
   287 /**
   288     FAT16 fixed cache factory function.
   289     @param  aOwner              pointer to the owning FAT mount
   290     @param  aFatSize            size of the FAT table in bytes
   291     @param  aRdGranularityLog2  Log2(read granularity)
   292     @param  aWrGranularityLog2  Log2(write granularity)
   293 
   294     @return pointer to the constructed object.
   295 */
   296 CFat16FixedCache* CFat16FixedCache::NewL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
   297     {
   298     __PRINT(_L("#-CFat16FixedCache::NewL()"));
   299 
   300     CFat16FixedCache* pSelf = NULL;
   301     pSelf = new (ELeave) CFat16FixedCache;
   302 
   303     CleanupStack::PushL(pSelf);
   304     pSelf->InitialiseL(aOwner, aFatSize, aRdGranularityLog2, aWrGranularityLog2);
   305     CleanupStack::Pop();
   306     
   307     return pSelf;
   308     }
   309 
   310 //-----------------------------------------------------------------------------
   311 /**
   312     FAT16 fixed cache initialisation.
   313     @param  aOwner              pointer to the owning FAT mount
   314     @param  aFatSize            size of the FAT table in bytes
   315     @param  aRdGranularityLog2  Log2(read granularity)
   316     @param  aWrGranularityLog2  Log2(write granularity)
   317 */
   318 void CFat16FixedCache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
   319     {
   320     const TUint32 ReadGranularity = Pow2(aRdGranularityLog2);
   321     const TUint32 WriteGranularity = Pow2(aWrGranularityLog2);
   322 
   323     __PRINT3(_L("#-CFat16FixedCache::InitialiseL FatSz:%u, RdGr:%d, WrGr:%d"),aFatSize, ReadGranularity, WriteGranularity);
   324     (void)ReadGranularity;
   325     (void)WriteGranularity;
   326 
   327     TBool bParamsValid = (aRdGranularityLog2 >= aWrGranularityLog2) && (aWrGranularityLog2 >= KDefSectorSzLog2);
   328     __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));
   329 
   330     CFatPagedCacheBase::InitialiseL(aOwner);
   331     
   332     ASSERT(FatType() == EFat16);
   333 
   334     //-- See FAT specs, and round up the limit to the FAT sector boundary
   335     const TUint32 KMaxFat16Size = ((65524*sizeof(TFat16Entry)+FAT_SectorSz()-1) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2(); 
   336     const TUint32 KMinFat16Size = 4086*sizeof(TFat16Entry);  //-- See FAT specs
   337     
   338     bParamsValid = aFatSize >= KMinFat16Size && aFatSize <= KMaxFat16Size;
   339 	__ASSERT_ALWAYS(bParamsValid, User::Leave(KErrCorrupt));
   340 
   341     //-- cache page size is (2^aRdGranularityLog2) bytes and consists of 2^(aRdGranularityLog2-aWrGranularity) sectors.
   342     iPageSizeLog2 = aRdGranularityLog2;
   343     iSectorSizeLog2 = aWrGranularityLog2; //-- Log2(number of sectors in cache page)
   344     
   345     __ASSERT_ALWAYS(SectorsInPage() < KMaxSectorsInPage, Fault(EFatCache_BadGranularity));
   346 
   347     const TUint numPages = (aFatSize+(PageSize()-1)) >> iPageSizeLog2;
   348     __PRINT1(_L("#-CFat16FixedCache Num Pages:%d"), numPages);
   349 
   350     //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
   351     for(TUint i=0; i<numPages; ++i)
   352         iPages.Append(NULL);
   353     
   354     }
   355 
   356 
   357 //-----------------------------------------------------------------------------
   358 /**
   359     Close the cache and deallocate its memory.
   360     @param  aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.  
   361 */
   362 void CFat16FixedCache::Close(TBool aDiscardDirtyData)
   363     {
   364     __PRINT1(_L("#-CFat16FixedCache::Close(%d)"), aDiscardDirtyData);
   365 
   366     TInt cnt = iPages.Count();
   367     while(cnt--)
   368         {//-- delete pages
   369         CFat16FixedCachePage *pPage = iPages[cnt];
   370         if(pPage && (pPage->IsDirty()))
   371             {//-- trying to destroy the cache that has dirty pages
   372             __PRINT1(_L("#-CFat16FixedCache::Close() The page is dirty! Start idx:%d"), pPage->StartFatIndex());
   373             if(!aDiscardDirtyData)
   374                 {
   375                 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
   376                 }
   377             //-- ignore this fact if requested.
   378             }
   379         
   380         delete pPage;
   381         }
   382 
   383     iPages.Close();
   384     SetDirty(EFalse);
   385     }
   386 
   387 //-----------------------------------------------------------------------------
   388 /**
   389     Read FAT entry from the cache. 
   390 
   391     @param  aIndex FAT entry index to read
   392     @return FAT entry value at the index "aIndex" 
   393 */
   394 TUint32 CFat16FixedCache::ReadEntryL(TUint32 aIndex)
   395     {
   396     //__PRINT1(_L("#-CFat16FixedCache::ReadEntryL() FAT idx:%d"), aIndex);
   397     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat16EntrySzLog2));
   398 
   399     //-- calculate page index in the array
   400     const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
   401     CFat16FixedCachePage *pPage = iPages[pgIdx];
   402     
   403     TUint32 entry = KMaxTUint;
   404 
   405     if(!pPage)
   406         {//-- page at this position isn't allocated yet
   407         pPage = CFat16FixedCachePage::NewL(*this);
   408         iPages[pgIdx] = pPage;
   409         
   410         //-- read the page from media
   411         entry = pPage->ReadFromMediaL(aIndex);
   412         }
   413     else
   414         {//-- get cached entry from the page
   415         TBool bRes = pPage->ReadCachedEntryL(aIndex, entry);
   416         ASSERT(bRes);
   417         (void)bRes;
   418         }
   419 
   420     return entry;
   421     }
   422 
   423 //-----------------------------------------------------------------------------
   424 /**
   425     Write FAT entry to the cache. 
   426     Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
   427 
   428     @param  aIndex FAT entry index
   429     @param  aEntry FAT entry value
   430 */
   431 void CFat16FixedCache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
   432     {
   433     //__PRINT2(_L("#-CFat16FixedCache::WriteEntryL() FAT idx:%d, val:%d"), aIndex, aEntry);
   434 
   435     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat16EntrySzLog2));
   436 
   437     SetDirty(ETrue);
   438 
   439     //-- calculate page index in the array
   440     const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
   441     CFat16FixedCachePage *pPage = iPages[pgIdx];
   442 
   443     if(!pPage)
   444         {//-- page at this position isn't allocated yet
   445         pPage = CFat16FixedCachePage::NewL(*this);
   446         iPages[pgIdx] = pPage;
   447         
   448         //-- read the page from media
   449         pPage->ReadFromMediaL(aIndex);
   450         }
   451 
   452     //-- overwrite entry in cache
   453     TBool bRes = pPage->WriteCachedEntryL(aIndex, aEntry);
   454     ASSERT(bRes);
   455     (void)bRes;
   456     }
   457 
   458 /**
   459     A debug method that asserts that the cache is really clean
   460 */
   461 void CFat16FixedCache::AssertCacheReallyClean() const
   462     {
   463 #ifdef _DEBUG 
   464         for(TUint i=0; i<NumPages(); ++i)
   465         {
   466             CFat16FixedCachePage* pPage = iPages[i];
   467             if(pPage && pPage->IsDirty())
   468                 {
   469                 __PRINT(_L("#-CFat16FixedCache::AssertCacheReallyClean()"));
   470                 ASSERT(0);
   471                 }
   472         }
   473 #endif   
   474     }
   475 
   476 
   477 //-----------------------------------------------------------------------------
   478 /**
   479     Flushes all dirty data to the media.
   480 */
   481 void CFat16FixedCache::FlushL()
   482     {
   483     if(!IsDirty())
   484         {
   485         AssertCacheReallyClean();
   486         return;
   487         }
   488 
   489 
   490     //-- flush dirty data to all copies of FAT
   491     for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
   492         {
   493         const TInt nPages = NumPages();
   494         for(TInt i=0; i<nPages; ++i)
   495             {
   496             const TBool keepDirty = iCurrentFatNo < (NumFATs() - 1);
   497 
   498             CFat16FixedCachePage* pPage = iPages[i];
   499             if(pPage)
   500                 pPage->FlushL(keepDirty);
   501             }
   502        
   503         }
   504    
   505     iCurrentFatNo = KInvalidFatNo;
   506     SetDirty(EFalse);
   507     }
   508 
   509 //-----------------------------------------------------------------------------
   510 /**
   511     Invalidate whole cache. All pages will be marked as invalid and will be re-read from the media on first access to them.
   512     @return always KErrNone
   513 */
   514 TInt CFat16FixedCache::Invalidate()
   515     {
   516     __PRINT(_L("#-CFat16FixedCache::Invalidate()"));
   517     const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
   518 
   519     //-- iterate through the array of pages marking invalidating every page
   520     TInt cnt = iPages.Count();
   521     while(cnt--)
   522         {//-- delete pages
   523         CFat16FixedCachePage *pPage = iPages[cnt];
   524         if(pPage)
   525             pPage->Invalidate(bIgnoreDirtyData);
   526         }
   527 
   528 
   529     SetDirty(EFalse);
   530 
   531     return KErrNone;
   532     }
   533 
   534 //-----------------------------------------------------------------------------
   535 /**
   536     Invalidate FAT cache pages that contain FAT entries from aStartIndex to (aStartIndex+aNumEntries)
   537     These pages will be marked as invalid and will be re-read from the media on first access to them.
   538     
   539     @param  aStartIndex FAT start index of the region being invalidated
   540     @param  aNumEntries number of entries to invalidate
   541     @return always KErrNone
   542 */
   543 TInt CFat16FixedCache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
   544     {
   545     __PRINT2(_L("#-CFat16FixedCache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
   546     ASSERT(aStartIndex >= KFatFirstSearchCluster &&  aStartIndex < (FatSize() >> KFat16EntrySzLog2));
   547 
   548     if(!aNumEntries)
   549         {
   550         ASSERT(0);
   551         return KErrNone;
   552         }
   553 
   554     const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
   555     const TUint startPgIdx  = aStartIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
   556     const TUint nPagesToInv = 1+(aNumEntries >> (PageSizeLog2()-KFat16EntrySzLog2));
   557 
   558     TUint i;
   559     //-- invalidate pages that contain [aStartIndex ... aStartIndex+aNumEntries] entries
   560     for(i=0; i<nPagesToInv; ++i)
   561         {
   562         const TUint pageIdx = i+startPgIdx;
   563         if(pageIdx >= NumPages())
   564             break;
   565         
   566         CFat16FixedCachePage* pPage = iPages[pageIdx];
   567         if(pPage)
   568             pPage->Invalidate(bIgnoreDirtyData);
   569         } 
   570 
   571     SetDirty(EFalse);
   572    
   573     //-- check if the cache still has dirty pages
   574     for(i=0; i<NumPages(); ++i)
   575         {
   576         CFat16FixedCachePage* pPage = iPages[i];
   577         if(pPage && pPage->IsDirty()) 
   578             {
   579             SetDirty(ETrue);
   580             break;
   581             }      
   582         }
   583 
   584     return KErrNone;
   585     }
   586 
   587 //#################################################################################################################################
   588 //  CFat16FixedCachePage implementation
   589 //  Page for the FAT16 fixed cache
   590 //#################################################################################################################################
   591 
   592 //-----------------------------------------------------------------------------
   593 
   594 CFat16FixedCachePage::CFat16FixedCachePage(CFatPagedCacheBase& aCache)
   595                      :CFatCachePageBase(aCache)
   596     {
   597     ASSERT(IsPowerOf2(EntriesInPage()));
   598     }
   599 
   600 
   601 /**
   602     Factory function.
   603     @param aCache reference to the owning cache.
   604     @return pointer to the constructed object or NULL on error
   605 */
   606 CFat16FixedCachePage* CFat16FixedCachePage::NewL(CFatPagedCacheBase& aCache)
   607     {
   608     CFat16FixedCachePage* pSelf = NULL;
   609     pSelf = new (ELeave) CFat16FixedCachePage(aCache);
   610 
   611     CleanupStack::PushL(pSelf);
   612     
   613     pSelf->iData.CreateMaxL(aCache.PageSize()); //-- allocate memory for the page
   614    
   615     CleanupStack::Pop();
   616 
   617     return pSelf;
   618     }
   619 
   620 
   621 //-----------------------------------------------------------------------------
   622 /**
   623     Read FAT16 entry from the cache. 
   624     
   625     1. If page's data are valid, just extracts data from the page buffer.
   626     2. If page's data are invalid firstly reads data from the media and goto 1
   627     
   628     @param  aFatIndex entry's absolute FAT index (from the FAT start)
   629     @param  aResult on sucess there will be FAT16 entry value
   630     @return ETrue, because FAT16 cache pages never get eviched.
   631 */
   632 TBool CFat16FixedCachePage::ReadCachedEntryL (TUint32 aFatIndex, TUint32& aResult)
   633     {
   634     if(IsValid())
   635         {//-- read entry directly from page buffer, the cached data are valid
   636         aResult = (*GetEntryPtr(aFatIndex)) & KFat16EntryMask;
   637         }
   638     else
   639         {//-- aFatIndex belongs to this page, but the page is invalid and needs to be read from the media
   640         //__PRINT(_L("#-CFat16FixedCachePage::ReadCachedEntry() The page is invalid, reading from the media"));
   641         aResult = ReadFromMediaL(aFatIndex);
   642         }
   643 
   644     return ETrue;
   645     }
   646 
   647 //-----------------------------------------------------------------------------
   648 
   649 /**
   650     Writes FAT cache page sector to the media (to all copies of the FAT)
   651     @param  aSector sector number winthin this page
   652 */
   653 void CFat16FixedCachePage::DoWriteSectorL(TUint32 aSector)
   654     {
   655     //__PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorL() startSec:%d, cnt:%d"), aSector);
   656 
   657     ASSERT(aSector < iCache.SectorsInPage());
   658 
   659     TInt offset = 0;
   660 
   661     if(iStartIndexInFAT == 0 && aSector == 0)
   662         {//-- this is the very beginning of FAT16. We must skip FAT[0] & FAT[1] entries and do not write them to media.    
   663         offset = KFatFirstSearchCluster << KFat16EntrySzLog2; 
   664         }    
   665     
   666     const TUint8* pData = iData.Ptr()+offset+(aSector << iCache.SectorSizeLog2());
   667     
   668     TUint32 dataLen = (1 << iCache.SectorSizeLog2()) - offset;
   669 
   670     const TUint32 mediaPosStart = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2) + (aSector << iCache.SectorSizeLog2()) + offset; 
   671     const TUint32 mediaPosEnd = mediaPosStart + dataLen; 
   672 
   673     //-- check if we are going to write beyond FAT. It can happen if the write granularity is bigger that the sector size.
   674     const TUint32 posFatEnd = iCache.FatStartPos() + iCache.FatSize();
   675     if(mediaPosEnd > posFatEnd)
   676         {//-- correct the leength of the data to write.
   677         dataLen -= (mediaPosEnd-posFatEnd);
   678         }
   679 
   680     TPtrC8 ptrData(pData, dataLen); //-- source data descriptor 
   681 
   682     TInt nRes = iCache.WriteFatData(mediaPosStart, ptrData);
   683     
   684     if(nRes != KErrNone)
   685         {
   686         __PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorsL() failed! code:%d"), nRes);
   687         User::Leave(nRes);
   688         }
   689 
   690     }
   691 
   692 //-----------------------------------------------------------------------------
   693 /**
   694     Write FAT16 entry at aFatIndex to the cache. Note that the data are not written to the media, only to the cache page.
   695     Corresponding page sector is marked as dirty and will be flushed on FlushL() call later.
   696 
   697     1. If page's data are valid, copies data to the page buffer and marks sector as dirty.
   698     2. If page's data are invalid, firstly reads data from the media and goto 1
   699 
   700     @param  aFatIndex entry's absolute FAT index (from the FAT start)
   701     @param  aFatEntry FAT16 entry value
   702     @return ETrue because FAT16 cache pages never get eviched.
   703 */
   704 TBool CFat16FixedCachePage::WriteCachedEntryL(TUint32 aFatIndex, TUint32 aFatEntry)
   705     {
   706     
   707     ASSERT(IsEntryCached(aFatIndex));
   708 
   709     if(!IsValid())
   710         {//-- we are trying to write data to the page that has invalid data. //-- read the data from the media first.
   711         ReadFromMediaL(aFatIndex);
   712         }
   713 
   714     TFat16Entry* pEntry = GetEntryPtr(aFatIndex);
   715     
   716     const TFat16Entry orgEntry = *pEntry;
   717     *pEntry = (TFat16Entry)((orgEntry & ~KFat16EntryMask) | (aFatEntry & KFat16EntryMask));
   718     
   719     //-- mark corresponding sector of the cache page as dirty
   720     const TUint entryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
   721     const TUint dirtySectorNum   = entryIndexInPage >> (iCache.SectorSizeLog2() - KFat16EntrySzLog2);
   722 
   723     ASSERT(dirtySectorNum < iCache.SectorsInPage());
   724 
   725     iDirtySectors.SetBit(dirtySectorNum);
   726     SetState(EDirty); //-- mark page as dirty.
   727 
   728     return ETrue;
   729     }
   730 
   731 //-----------------------------------------------------------------------------
   732 
   733 /**
   734     Get a pointer to the FAT16 entry in the page buffer.
   735     The page 's data shall be valid and the entry shall belong to this page.
   736     
   737     @param aFatIndex absolute FAT index (from the FAT start) of the entry
   738     @return pointer to the FAT16 entry in the page buffer.
   739 */
   740 TFat16Entry* CFat16FixedCachePage::GetEntryPtr(TUint32 aFatIndex) const
   741     {
   742     ASSERT(IsValid() && IsEntryCached(aFatIndex));
   743 
   744     const TUint KEntryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
   745     TFat16Entry* pEntry = ((TFat16Entry*)iData.Ptr()) + KEntryIndexInPage;
   746 
   747     return  pEntry;
   748     }
   749 
   750 //-----------------------------------------------------------------------------
   751 /**
   752     Read the FAT16 cache page from the media and returns required FAT16 entry.    
   753 
   754     @param  aFatIndex entry's absolute FAT index (from the FAT start)
   755     @return entry value at aFatIndex.
   756 */
   757 TUint32 CFat16FixedCachePage::ReadFromMediaL(TUint32 aFatIndex)
   758     {
   759     //__PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() FAT idx:%d"), aFatIndex);
   760     const TUint KFat16EntriesInPageLog2 = iCache.PageSizeLog2()-KFat16EntrySzLog2; //-- number of FAT16 entries in page is always a power of 2
   761 
   762     //-- find out index in FAT this page starts from
   763     iStartIndexInFAT = (aFatIndex >> KFat16EntriesInPageLog2) << KFat16EntriesInPageLog2;
   764     SetState(EInvalid); //-- mark the page as invalid just in case if the read fails.
   765 
   766     //-- read page from the media
   767     const TUint32 pageStartPos = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2);
   768     
   769     TInt nRes = iCache.ReadFatData(pageStartPos, iCache.PageSize(), iData);
   770     if(nRes != KErrNone)
   771         {
   772         __PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() failed! code:%d"), nRes);
   773         User::Leave(nRes);
   774         }
   775 
   776     SetClean(); //-- mark this page as clean
   777 
   778     const TFat16Entry entry = (TFat16Entry)((*GetEntryPtr(aFatIndex)) & KFat16EntryMask);
   779 
   780     return entry;
   781     }
   782 
   783 
   784 //-----------------------------------------------------------------------------
   785 
   786 //#################################################################################################################################
   787 //  CFat12Cache implementation
   788 //  FAT12 non-paged fixed cache. This cache consists from only 1 page, logically divided up to 32 sectors (write granularity unit)
   789 //#################################################################################################################################
   790 
   791 CFat12Cache::CFat12Cache()
   792             :CFatCacheBase()
   793     {
   794     }
   795 
   796 //-----------------------------------------------------------------------------
   797 /**
   798     FAT12 fixed cache factory function.
   799     @param  aOwner              pointer to the owning FAT mount
   800     @param  aFatSize            size of the FAT table in bytes
   801 
   802     @return pointer to the constructed object.
   803 */
   804 CFat12Cache* CFat12Cache::NewL(CFatMountCB* aOwner, TUint32 aFatSize)
   805     {
   806     __PRINT(_L("#-CFat12Cache::NewL()"));
   807     CFat12Cache* pSelf = NULL;
   808     pSelf = new (ELeave) CFat12Cache;
   809 
   810     CleanupStack::PushL(pSelf);
   811     pSelf->InitialiseL(aOwner, aFatSize);
   812     CleanupStack::Pop();
   813     
   814     return pSelf;
   815     }
   816 
   817 //-----------------------------------------------------------------------------
   818 /**
   819     FAT16 fixed cache initialisation.
   820     @param  aOwner              pointer to the owning FAT mount
   821     @param  aFatSize            size of the FAT table in bytes
   822 */
   823 void CFat12Cache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize)
   824     {
   825     __PRINT1(_L("#-CFat12Cache::InitialiseL FatSz:%u"),aFatSize);
   826 
   827     CFatCacheBase::InitialiseL(aOwner);
   828     ASSERT(FatType() == EFat12);
   829 
   830     //-- see FAT specs; 4084 is a max. number of clusters, fat12 entry is 1.5 bytes; but we need to round up FAT12 size to the sector size
   831     const TUint32 KMaxFat12Size = ( ((TUint32)(4084*1.5+FAT_SectorSz()-1)) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
   832     const TUint32 KMinFat12Size = FAT_SectorSz();  //-- 1 FAT sector
   833 	__ASSERT_ALWAYS(aFatSize >= KMinFat12Size && aFatSize <= KMaxFat12Size, User::Leave(KErrCorrupt));
   834     (void)KMaxFat12Size;
   835     (void)KMinFat12Size;
   836 
   837     //-- as soon as FAT12 max size is 4084 entries or 6126 bytes, the cache is contiguous and divided 
   838     //-- to logical sectors (write granularity). 
   839 
   840     //-- calculate number write cache sector in the cache
   841     iSectorsInCache = (aFatSize + (FAT_SectorSz()-1)) >> FAT_SectorSzLog2();
   842     __ASSERT_ALWAYS(NumSectors() <= KMaxSectorsInCache, Fault(EFatCache_BadGranularity));
   843 
   844     //-- round up cache size to write granularity (sector size)
   845     const TUint32 cacheSize = NumSectors() << FAT_SectorSzLog2();
   846     
   847     //-- create buffer for the whole FAT12
   848     iData.CreateMaxL(cacheSize);
   849 
   850     //-- this will read whole FAT into the cache 
   851     User::LeaveIfError(Invalidate()); 
   852     }
   853 
   854 //-----------------------------------------------------------------------------
   855 /**
   856     Close the cache and deallocate its memory.
   857     @param  aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.  
   858 */
   859 void CFat12Cache::Close(TBool aDiscardDirtyData)
   860     {
   861     __PRINT1(_L("#-CFat12Cache::Close(%d)"), aDiscardDirtyData);    
   862     
   863     for(TUint32 i=0; i<NumSectors(); ++i)
   864         {
   865         if(iDirtySectors[i])
   866             {//-- trying to destroy the cache that has dirty sectors
   867             __PRINT1(_L("#-CFat12Cache::Close() The cache is dirty! cache sector:%d"), i);
   868             if(!aDiscardDirtyData)
   869                 {
   870                 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
   871                 }
   872             //-- ignore this fact if requested.
   873             }
   874         }
   875 
   876     iData.Close();
   877     SetDirty(EFalse);
   878     }
   879 
   880 //-----------------------------------------------------------------------------
   881 /**
   882     Read FAT entry from the cache. 
   883 
   884     @param  aIndex FAT entry index to read
   885     @return FAT entry value at the index "aIndex" 
   886 */
   887 TUint32 CFat12Cache::ReadEntryL(TUint32 aIndex)
   888     {
   889     //__PRINT1(_L("#-CFat12Cache::ReadEntryL() FAT idx:%d"), aIndex);
   890     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
   891 
   892     TUint32 entry;
   893 
   894     if(aIndex & 0x01)
   895         {//-- odd index
   896         --aIndex;
   897         const TUint32 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
   898         Mem::Copy(&entry, iData.Ptr()+byteIdx, 2); 
   899         entry >>= 4;   
   900         }
   901     else
   902         {//-- even index
   903         const TUint32 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
   904         Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
   905         }
   906 
   907     entry &= KFat12EntryMask; 
   908 
   909     return entry;
   910     }
   911 
   912 //-----------------------------------------------------------------------------
   913 /**
   914     Write FAT entry to the cache. 
   915     Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
   916 
   917     @param  aIndex FAT entry index
   918     @param  aEntry FAT entry value
   919 */
   920 void CFat12Cache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
   921     {
   922     //__PRINT2(_L("#-CFat12Cache::WriteEntryL() FAT idx:%d, entry:%u"), aIndex, aEntry);
   923     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
   924 
   925     aEntry &= KFat12EntryMask; 
   926  
   927     TUint32 byteIdx = 0;
   928     TUint8 tmp;
   929 
   930     if(aIndex & 0x01)
   931         {//-- odd index
   932         --aIndex;
   933         byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
   934         tmp = (TUint8)(iData[byteIdx] & 0x0F); //-- we modifying a higher nibble 
   935         tmp |= (TUint8) ((aEntry & 0x0F)<<4);
   936         iData[byteIdx] = tmp;
   937 
   938         iData[byteIdx+1] = (TUint8)(aEntry >> 4);  
   939         }
   940     else
   941         {//-- even index
   942         byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
   943         iData[byteIdx] = (TUint8)aEntry;  
   944 
   945         const TUint32 nextIdx = byteIdx+1;
   946         tmp = (TUint8)(iData[nextIdx] & 0xF0); //-- we modifying a lower nibble 
   947         tmp |= (TUint8)((aEntry >> 8) & 0x0F);
   948         iData[nextIdx] = tmp;
   949 
   950         }
   951 
   952     //-- mark changed sectors dirty. We modified 2 bytes at [byteIdx] and [byteIdx+1]
   953     iDirtySectors.SetBit(byteIdx >> FAT_SectorSzLog2());
   954     iDirtySectors.SetBit((byteIdx+1) >> FAT_SectorSzLog2());
   955 
   956     SetDirty(ETrue);
   957     }
   958 
   959 //-----------------------------------------------------------------------------
   960 /**
   961     A debug method that asserts that the cache is really clean
   962 */
   963 void CFat12Cache::AssertCacheReallyClean() const
   964     {
   965 #ifdef _DEBUG 
   966     if(iDirtySectors.HasBitsSet())
   967         {
   968         __PRINT(_L("#-CFat12Cache::AssertCacheReallyClean()"));
   969         ASSERT(0);
   970         }
   971 
   972 #endif   
   973     }
   974 
   975 //-----------------------------------------------------------------------------
   976 /**
   977     Flushes all dirty data to the media.
   978     Walks through all sectors in this cache and flushes dirty ones.
   979 */
   980 void CFat12Cache::FlushL()
   981     {
   982     if(!IsDirty())
   983         {
   984         AssertCacheReallyClean();
   985         return;
   986         }
   987 
   988     //-- write all dirty sectors to the media (into all copies of FAT)
   989     for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
   990         {
   991         for(TUint secNo=0; secNo<NumSectors(); ++secNo)
   992             {
   993             if(iDirtySectors[secNo])
   994                 {//-- this sector is dirty, write it to the media
   995 
   996                 TInt offset = 0;
   997                 if(secNo == 0)
   998                     {//-- this is a first sector in FAT. We must skip FAT[0] & FAT[1] entries and do not write them to the media.    
   999                     offset = 3; //-- 2 FAT12 entries
  1000                     }
  1001 
  1002                 const TUint32 secPos = secNo << FAT_SectorSzLog2(); //-- relative sector position in FAT
  1003                 const TUint8* pData = iData.Ptr()+offset+secPos;    //-- pointer to the data in cache buffer
  1004                 const TUint32 len = FAT_SectorSz() - offset;          
  1005                 TPtrC8 ptrData(pData, len);                         //-- source data descriptor 
  1006                 const TUint32 mediaPos = FatStartPos() + secPos + offset;
  1007                 
  1008                 TInt nRes = WriteFatData(mediaPos, ptrData);
  1009 
  1010                 if(nRes != KErrNone)
  1011                     {
  1012                     __PRINT1(_L("#-CFat12Cache::FlushL() failed! code:%d"), nRes);
  1013                     User::Leave(nRes);
  1014                     }
  1015 
  1016                 }//if(iDirtySectors[secNo])
  1017             }
  1018 
  1019         }
  1020 
  1021     iCurrentFatNo = KInvalidFatNo;
  1022 
  1023     //-- mark the cache as clean
  1024     iDirtySectors.Clear();
  1025     SetDirty(EFalse);
  1026     
  1027     }
  1028 
  1029 //-----------------------------------------------------------------------------
  1030 /**
  1031     Invalidates whole cache. Because FAT12 is tiny, just re-reads data from the media to the cache
  1032     @return Media read result code.
  1033 */
  1034 TInt CFat12Cache::Invalidate()
  1035     {
  1036     __PRINT(_L("#-CFat12Cache::Invalidate()"));
  1037     CheckInvalidatingDirtyCache();
  1038     
  1039     //-- read whole cache from the media
  1040     const TUint32 posStart = FatStartPos();
  1041     const TUint32 len      = NumSectors() << FAT_SectorSzLog2();
  1042      
  1043     TInt nRes = ReadFatData(posStart, len, iData);
  1044     if(nRes != KErrNone)
  1045         return nRes;
  1046 
  1047     //-- mark the cache as clean
  1048     SetDirty(EFalse);
  1049     iDirtySectors.Clear();
  1050 
  1051     return KErrNone;
  1052     }
  1053 
  1054 //-----------------------------------------------------------------------------
  1055 /**
  1056     Invalidate wholes cache. Because FAT12 is tiny, just re-reads data from the media to the cache
  1057     @param  aStartIndex ignored
  1058     @param  aNumEntries ignored
  1059     @return Media read result code.
  1060 */
  1061 TInt CFat12Cache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
  1062     {
  1063     __PRINT2(_L("#-CFat12Cache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
  1064     ASSERT(aStartIndex >= KFatFirstSearchCluster &&  aStartIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
  1065     (void)aStartIndex;
  1066     (void)aNumEntries;
  1067 
  1068     //-- just re-read all FAT12, it is just 6K max and isn't worth calculating invalid sectors
  1069     return Invalidate();
  1070     }
  1071 
  1072 
  1073 
  1074 
  1075 
  1076 
  1077 
  1078 
  1079 
  1080 
  1081 
  1082 
  1083 
  1084 
  1085 
  1086 
  1087 
  1088 
  1089 
  1090 
  1091 
  1092 
  1093 
  1094 
  1095 
  1096 
  1097 
  1098 
  1099 
  1100 
  1101 
  1102 
  1103 
  1104 
  1105 
  1106 
  1107 
  1108 
  1109 
  1110 
  1111 
  1112 
  1113