Changeset 26271

Show
Ignore:
Timestamp:
07/05/08 21:07:31 (5 months ago)
Author:
bonefish
Message:

* Turned most of the vm_cache_*() functions into VMCache methods.
* Changed the VMCache ref count and locking concept. References can only

be acquired or released with the cache locked. A cache is destroyed
when it has no more references when being unlocked. Unlocking is also
the point when a cache is merged with its only consumer. It must have
ref count 1 in this case.

* Removed VMCache::busy. It is no longer needed due to the ref

count/locking changes. Merging only happens when no one else has
reference to the cache. This also simplifies fault_find_page().

Location:
haiku/branches/developer/bonefish/vm
Files:
8 modified

Legend:

Unmodified
Added
Removed
  • haiku/branches/developer/bonefish/vm/headers/private/kernel/vm_cache.h

    r26175 r26271  
    1616struct kernel_args; 
    1717 
    18 //typedef struct vm_store vm_store; 
    19  
    2018 
    2119#ifdef __cplusplus 
     
    2422 
    2523status_t vm_cache_init(struct kernel_args *args); 
    26 void vm_cache_acquire_ref(struct VMCache *cache); 
    27 void vm_cache_release_ref(struct VMCache *cache); 
    28 struct VMCache *vm_cache_acquire_page_cache_ref(struct vm_page *page); 
    29 struct vm_page *vm_cache_lookup_page(struct VMCache *cache, off_t page); 
    30 void vm_cache_insert_page(struct VMCache *cache, struct vm_page *page, 
    31         off_t offset); 
    32 void vm_cache_remove_page(struct VMCache *cache, struct vm_page *page); 
    33 void vm_cache_remove_consumer(struct VMCache *cache, struct VMCache *consumer); 
    34 void vm_cache_add_consumer_locked(struct VMCache *cache, 
    35         struct VMCache *consumer); 
    36 status_t vm_cache_write_modified(struct VMCache *cache, bool fsReenter); 
    37 status_t vm_cache_set_minimal_commitment_locked(struct VMCache *cache, 
    38         off_t commitment); 
    39 status_t vm_cache_resize(struct VMCache *cache, off_t newSize); 
    40 status_t vm_cache_insert_area_locked(struct VMCache *cache, vm_area *area); 
    41 status_t vm_cache_remove_area(struct VMCache *cache, struct vm_area *area); 
     24struct VMCache *vm_cache_acquire_locked_page_cache(struct vm_page *page, 
     25        bool dontWait); 
    4226 
    4327#ifdef __cplusplus 
  • haiku/branches/developer/bonefish/vm/headers/private/kernel/vm_types.h

    r26250 r26271  
    1414#include <condition_variable.h> 
    1515#include <kernel.h> 
     16#include <lock.h> 
    1617#include <util/DoublyLinkedQueue.h> 
    1718 
     
    176177        virtual void            Delete(); 
    177178 
     179                        bool            Lock() 
     180                                                        { return mutex_lock(&fLock) == B_OK; } 
     181                        bool            TryLock() 
     182                                                        { return mutex_trylock(&fLock) == B_OK; } 
     183                        bool            SwitchLock(mutex* from) 
     184                                                        { return mutex_switch_lock(from, &fLock) == B_OK; } 
     185                        void            Unlock(); 
     186                        void            AssertLocked() 
     187                                                        { ASSERT_LOCKED_MUTEX(&fLock); } 
     188 
     189                        void            AcquireRefLocked(); 
     190                        void            AcquireRef(); 
     191                        void            ReleaseRefLocked(); 
     192                        void            ReleaseRef(); 
     193                        void            ReleaseRefAndUnlock() 
     194                                                        { ReleaseRefLocked(); Unlock(); } 
     195 
     196                        vm_page*        LookupPage(off_t offset); 
     197                        void            InsertPage(vm_page* page, off_t offset); 
     198                        void            RemovePage(vm_page* page); 
     199 
     200                        void            AddConsumer(VMCache* consumer); 
     201 
     202                        status_t        InsertAreaLocked(vm_area* area); 
     203                        status_t        RemoveArea(vm_area* area); 
     204 
     205                        status_t        WriteModified(bool fsReenter); 
     206                        status_t        SetMinimalCommitment(off_t commitment); 
     207                        status_t        Resize(off_t newSize); 
     208 
     209                        // for debugging only 
     210                        mutex*          GetLock() 
     211                                                        { return &fLock; } 
     212                        int32           RefCount() const 
     213                                                        { return fRefCount; } 
     214 
    178215        // backing store operations 
    179216        virtual status_t        Commit(off_t size); 
     
    193230        virtual void            ReleaseStoreRef(); 
    194231 
     232private: 
     233        inline  bool            _IsMergeable() const; 
     234 
     235                        void            _MergeWithOnlyConsumer(); 
     236                        void            _RemoveConsumer(VMCache* consumer); 
     237 
     238 
    195239public: 
    196         mutex                           lock; 
    197240        struct vm_area          *areas; 
    198         vint32                          ref_count; 
    199241        struct list_link        consumer_link; 
    200242        struct list                     consumers; 
     
    209251        uint32                          temporary : 1; 
    210252        uint32                          scan_skip : 1; 
    211         uint32                          busy : 1; 
    212         uint32                          type : 5; 
     253        uint32                          type : 6; 
    213254 
    214255#if DEBUG_CACHE_LIST 
     
    216257        struct VMCache*         debug_next; 
    217258#endif 
     259 
     260private: 
     261        int32                           fRefCount; 
     262        mutex                           fLock; 
    218263}; 
    219264 
  • haiku/branches/developer/bonefish/vm/src/system/kernel/cache/file_cache.cpp

    r26250 r26271  
    120120        if (vm_low_memory_state() != B_NO_LOW_MEMORY) { 
    121121                vm_cache *cache = ref->cache; 
    122                 mutex_lock(&cache->lock); 
     122                cache->Lock(); 
    123123 
    124124                if (list_is_empty(&cache->consumers) && cache->areas == NULL 
     
    145145                                        if (page->state != PAGE_STATE_MODIFIED 
    146146                                                && page->state != PAGE_STATE_BUSY) { 
    147                                                 vm_cache_remove_page(cache, page); 
     147                                                cache->RemovePage(page); 
    148148                                                vm_page_set_state(page, PAGE_STATE_FREE); 
    149149                                                left--; 
     
    152152                        } 
    153153                } 
    154                 mutex_unlock(&cache->lock); 
     154                cache->Unlock(); 
    155155        } 
    156156 
     
    195195                busyConditions[pageIndex - 1].Publish(page, "page"); 
    196196 
    197                 vm_cache_insert_page(cache, page, offset + pos); 
     197                cache->InsertPage(page, offset + pos); 
    198198 
    199199                addr_t virtualAddress; 
     
    207207 
    208208        push_access(ref, offset, bufferSize, false); 
    209         mutex_unlock(&cache->lock); 
     209        cache->Unlock(); 
    210210        vm_page_unreserve_pages(lastReservedPages); 
    211211 
     
    228228                } 
    229229 
    230                 mutex_lock(&cache->lock); 
     230                cache->Lock(); 
    231231 
    232232                for (int32 i = 0; i < pageIndex; i++) { 
    233233                        busyConditions[i].Unpublish(); 
    234                         vm_cache_remove_page(cache, pages[i]); 
     234                        cache->RemovePage(pages[i]); 
    235235                        vm_page_set_state(pages[i], PAGE_STATE_FREE); 
    236236                } 
     
    262262 
    263263        reserve_pages(ref, reservePages, false); 
    264         mutex_lock(&cache->lock); 
     264        cache->Lock(); 
    265265 
    266266        // make the pages accessible in the cache 
     
    291291 
    292292        push_access(ref, offset, bufferSize, false); 
    293         mutex_unlock(&ref->cache->lock); 
     293        ref->cache->Unlock(); 
    294294        vm_page_unreserve_pages(lastReservedPages); 
    295295 
     
    299299                reserve_pages(ref, reservePages, false); 
    300300 
    301         mutex_lock(&ref->cache->lock); 
     301        ref->cache->Lock(); 
    302302 
    303303        return status; 
     
    339339                busyConditions[pageIndex - 1].Publish(page, "page"); 
    340340 
    341                 vm_cache_insert_page(ref->cache, page, offset + pos); 
     341                ref->cache->InsertPage(page, offset + pos); 
    342342 
    343343                addr_t virtualAddress; 
     
    350350 
    351351        push_access(ref, offset, bufferSize, true); 
    352         mutex_unlock(&ref->cache->lock); 
     352        ref->cache->Unlock(); 
    353353        vm_page_unreserve_pages(lastReservedPages); 
    354354 
     
    432432                reserve_pages(ref, reservePages, true); 
    433433 
    434         mutex_lock(&ref->cache->lock); 
     434        ref->cache->Lock(); 
    435435 
    436436        // unmap the pages again 
     
    481481 
    482482        push_access(ref, offset, bufferSize, true); 
    483         mutex_unlock(&ref->cache->lock); 
     483        ref->cache->Unlock(); 
    484484        vm_page_unreserve_pages(lastReservedPages); 
    485485 
     
    509509                reserve_pages(ref, reservePages, true); 
    510510 
    511         mutex_lock(&ref->cache->lock); 
     511        ref->cache->Lock(); 
    512512 
    513513        return status; 
     
    605605 
    606606        reserve_pages(ref, lastReservedPages, doWrite); 
    607         MutexLocker locker(cache->lock); 
     607        AutoLocker<VMCache> locker(cache); 
    608608 
    609609        while (bytesLeft > 0) { 
    610610                // check if this page is already in memory 
    611                 vm_page *page = vm_cache_lookup_page(cache, offset); 
     611                vm_page *page = cache->LookupPage(offset); 
    612612                if (page != NULL) { 
    613613                        // The page may be busy - since we need to unlock the cache sometime 
     
    970970        TRACE(("file_cache_delete(ref = %p)\n", ref)); 
    971971 
    972         vm_cache_release_ref(ref->cache); 
     972        ref->cache->ReleaseRef(); 
    973973        delete ref; 
    974974} 
     
    985985                return B_OK; 
    986986 
    987         MutexLocker _(ref->cache->lock); 
     987        AutoLocker<VMCache> _(ref->cache); 
    988988 
    989989        off_t offset = ref->cache->virtual_end; 
     
    995995                size = newSize - offset; 
    996996 
    997         return vm_cache_resize(ref->cache, newSize); 
     997        return ref->cache->Resize(newSize); 
    998998} 
    999999 
     
    10061006                return B_BAD_VALUE; 
    10071007 
    1008         return vm_cache_write_modified(ref->cache, true); 
     1008        return ref->cache->WriteModified(true); 
    10091009} 
    10101010 
  • haiku/branches/developer/bonefish/vm/src/system/kernel/fs/vfs.cpp

    r26250 r26271  
    771771        // if we have a vm_cache attached, remove it 
    772772        if (vnode->cache) 
    773                 vm_cache_release_ref(vnode->cache); 
     773                vnode->cache->ReleaseRef(); 
    774774 
    775775        vnode->cache = NULL; 
     
    10601060 
    10611061                if (vnode->cache != NULL) 
    1062                         vm_cache_write_modified(vnode->cache, false); 
     1062                        vnode->cache->WriteModified(false); 
    10631063 
    10641064                dec_vnode_ref_count(vnode, true, false); 
     
    39213921{ 
    39223922        if (vnode->cache != NULL) { 
    3923                 vm_cache_acquire_ref(vnode->cache); 
     3923                vnode->cache->AcquireRef(); 
    39243924                *_cache = vnode->cache; 
    39253925                return B_OK; 
     
    39473947        } 
    39483948 
     3949        mutex_unlock(&sVnodeMutex); 
     3950 
    39493951        if (status == B_OK) { 
    3950                 vm_cache_acquire_ref(vnode->cache); 
     3952                vnode->cache->AcquireRef(); 
    39513953                *_cache = vnode->cache; 
    39523954        } 
    39533955 
    3954         mutex_unlock(&sVnodeMutex); 
    39553956        return status; 
    39563957} 
     
    67066707 
    67076708                        if (vnode->cache != NULL) 
    6708                                 vm_cache_write_modified(vnode->cache, false); 
     6709                                vnode->cache->WriteModified(false); 
    67096710 
    67106711                        // the next vnode might change until we lock the vnode list again, 
  • haiku/branches/developer/bonefish/vm/src/system/kernel/vm/vm.cpp

    r26250 r26271  
    12401240                if (cache->areas == area && area->cache_next == NULL 
    12411241                        && list_is_empty(&cache->consumers)) { 
    1242                         status_t error = vm_cache_resize(cache, newSize); 
     1242                        status_t error = cache->Resize(newSize); 
    12431243                        if (error != B_OK) 
    12441244                                return error; 
     
    12991299 
    13001300        // We need a cache reference for the new area. 
    1301         vm_cache_acquire_ref(cache); 
     1301        cache->AcquireRefLocked(); 
    13021302 
    13031303        if (_secondArea != NULL) 
     
    13731373                addressSpace, cache, *_virtualAddress, offset, size, addressSpec, 
    13741374                wiring, protection, _area, areaName)); 
    1375         ASSERT_LOCKED_MUTEX(&cache->lock); 
     1375        cache->AssertLocked(); 
    13761376 
    13771377        vm_area *area = create_area_struct(addressSpace, areaName, wiring, 
     
    13941394                        goto err1; 
    13951395 
    1396                 mutex_lock(&newCache->lock); 
     1396                newCache->Lock(); 
    13971397                newCache->temporary = 1; 
    13981398                newCache->scan_skip = cache->scan_skip; 
     
    14001400                newCache->virtual_end = offset + size; 
    14011401 
    1402                 vm_cache_add_consumer_locked(cache, newCache); 
     1402                cache->AddConsumer(newCache); 
    14031403 
    14041404                cache = newCache; 
    14051405        } 
    14061406 
    1407         status = vm_cache_set_minimal_commitment_locked(cache, size); 
     1407        status = cache->SetMinimalCommitment(size); 
    14081408        if (status != B_OK) 
    14091409                goto err2; 
     
    14331433 
    14341434        // point the cache back to the area 
    1435         vm_cache_insert_area_locked(cache, area); 
     1435        cache->InsertAreaLocked(area); 
    14361436        if (mapping == REGION_PRIVATE_MAP) 
    1437                 mutex_unlock(&cache->lock); 
     1437                cache->Unlock(); 
    14381438 
    14391439        // insert the area in the global area hash table 
     
    14521452                // We created this cache, so we must delete it again. Note, that we 
    14531453                // need to temporarily unlock the source cache or we'll otherwise 
    1454                 // deadlock, since vm_cache_remove_consumer will try to lock it too. 
    1455                 mutex_unlock(&cache->lock); 
    1456                 mutex_unlock(&sourceCache->lock); 
    1457                 vm_cache_release_ref(cache); 
    1458                 mutex_lock(&sourceCache->lock); 
     1454                // deadlock, since VMCache::_RemoveConsumer() will try to lock it, too. 
     1455                sourceCache->Unlock(); 
     1456                cache->ReleaseRefAndUnlock(); 
     1457                sourceCache->Lock(); 
    14591458        } 
    14601459err1: 
     
    16421641        } 
    16431642 
    1644         mutex_lock(&cache->lock); 
     1643        cache->Lock(); 
    16451644 
    16461645        status = map_backing_store(addressSpace, cache, address, 0, size, 
     
    16481647                unmapAddressRange, kernel); 
    16491648 
    1650         mutex_unlock(&cache->lock); 
    1651  
    16521649        if (status < B_OK) { 
    1653                 vm_cache_release_ref(cache); 
     1650                cache->ReleaseRefAndUnlock(); 
    16541651                goto err1; 
    16551652        } 
     1653 
     1654        cache->Unlock(); 
    16561655 
    16571656        locker.DegradeToReadLock(); 
     
    16711670 
    16721671                        // Allocate and map all pages for this area 
    1673                         mutex_lock(&cache->lock); 
     1672                        cache->Lock(); 
    16741673 
    16751674                        off_t offset = 0; 
     
    16921691                                } 
    16931692 
    1694                                 vm_cache_insert_page(cache, page, offset); 
     1693                                cache->InsertPage(page, offset); 
    16951694                                vm_map_page(area, page, address, protection); 
    16961695                        } 
    16971696 
    1698                         mutex_unlock(&cache->lock); 
     1697                        cache->Unlock(); 
    16991698                        vm_page_unreserve_pages(reservePages); 
    17001699                        break; 
     
    17121711                                panic("ALREADY_WIRED flag used outside kernel startup\n"); 
    17131712 
    1714                         mutex_lock(&cache->lock); 
     1713                        cache->Lock(); 
    17151714                        map->ops->lock(map); 
    17161715 
     
    17351734                                        // TODO: needs to be atomic on all platforms! 
    17361735                                vm_page_set_state(page, PAGE_STATE_WIRED); 
    1737                                 vm_cache_insert_page(cache, page, offset); 
     1736                                cache->InsertPage(page, offset); 
    17381737                        } 
    17391738 
    17401739                        map->ops->unlock(map); 
    1741                         mutex_unlock(&cache->lock); 
     1740                        cache->Unlock(); 
    17421741                        break; 
    17431742                } 
     
    17551754 
    17561755                        vm_page_reserve_pages(reservePages); 
    1757                         mutex_lock(&cache->lock); 
     1756                        cache->Lock(); 
    17581757                        map->ops->lock(map); 
    17591758 
     
    17731772                                        // TODO: needs to be atomic on all platforms! 
    17741773                                vm_page_set_state(page, PAGE_STATE_WIRED); 
    1775                                 vm_cache_insert_page(cache, page, offset); 
     1774                                cache->InsertPage(page, offset); 
    17761775                        } 
    17771776 
    17781777                        map->ops->unlock(map); 
    1779                         mutex_unlock(&cache->lock); 
     1778                        cache->Unlock(); 
    17801779                        vm_page_unreserve_pages(reservePages); 
    17811780                        break; 
     
    18451844        cache->virtual_end = size; 
    18461845 
    1847         mutex_lock(&cache->lock); 
     1846        cache->Lock(); 
    18481847 
    18491848        status = map_backing_store(locker.AddressSpace(), cache, _address, 
     
    18511850                REGION_NO_PRIVATE_MAP, &area, name, false, true); 
    18521851 
    1853         mutex_unlock(&cache->lock); 
    1854  
    18551852        if (status < B_OK) 
    1856                 vm_cache_release_ref(cache); 
     1853                cache->ReleaseRefLocked(); 
     1854 
     1855        cache->Unlock(); 
    18571856 
    18581857        if (status >= B_OK && (addressSpec & B_MTR_MASK) != 0) { 
     
    19181917        cache->virtual_end = size; 
    19191918 
    1920         mutex_lock(&cache->lock); 
     1919        cache->Lock(); 
    19211920 
    19221921        status = map_backing_store(locker.AddressSpace(), cache, address, 0, size, 
     
    19241923                false, true); 
    19251924 
    1926         mutex_unlock(&cache->lock); 
    1927  
    19281925        if (status < B_OK) { 
    1929                 vm_cache_release_ref(cache); 
     1926                cache->ReleaseRefAndUnlock(); 
    19301927                return status; 
    19311928        } 
     1929 
     1930        cache->Unlock(); 
    19321931 
    19331932        area->cache_type = CACHE_TYPE_NULL; 
     
    20062005                return status; 
    20072006 
    2008         mutex_lock(&cache->lock); 
     2007        cache->Lock();