146122852SIngo Weinhold /* 246122852SIngo Weinhold * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 346122852SIngo Weinhold * Distributed under the terms of the MIT License. 446122852SIngo Weinhold */ 546122852SIngo Weinhold 646122852SIngo Weinhold 746122852SIngo Weinhold #include "CachedDataReader.h" 846122852SIngo Weinhold 946122852SIngo Weinhold #include <algorithm> 1046122852SIngo Weinhold 1100dfae0bSAdrien Destugues #include <package/hpkg/BufferDataOutput.h> 1246122852SIngo Weinhold 1346122852SIngo Weinhold #include <util/AutoLock.h> 1446122852SIngo Weinhold #include <vm/VMCache.h> 1546122852SIngo Weinhold #include <vm/vm_page.h> 1646122852SIngo Weinhold 1746122852SIngo Weinhold #include "DebugSupport.h" 1846122852SIngo Weinhold 1946122852SIngo Weinhold 2046122852SIngo Weinhold using BPackageKit::BHPKG::BBufferDataReader; 2146122852SIngo Weinhold using BPackageKit::BHPKG::BBufferDataOutput; 2246122852SIngo Weinhold 2346122852SIngo Weinhold 2446122852SIngo Weinhold static inline bool 2546122852SIngo Weinhold page_physical_number_less(const vm_page* a, const vm_page* b) 2646122852SIngo Weinhold { 2746122852SIngo Weinhold return a->physical_page_number < b->physical_page_number; 2846122852SIngo Weinhold } 2946122852SIngo Weinhold 3046122852SIngo Weinhold 3146122852SIngo Weinhold // #pragma mark - PagesDataOutput 3246122852SIngo Weinhold 3346122852SIngo Weinhold 349af2105dSAdrien Destugues struct CachedDataReader::PagesDataOutput : public BDataIO { 3546122852SIngo Weinhold PagesDataOutput(vm_page** pages, size_t pageCount) 3646122852SIngo Weinhold : 3746122852SIngo Weinhold fPages(pages), 3846122852SIngo Weinhold fPageCount(pageCount), 3946122852SIngo Weinhold fInPageOffset(0) 4046122852SIngo Weinhold { 4146122852SIngo Weinhold } 4246122852SIngo Weinhold 43*4c235c74SIngo Weinhold virtual status_t Write(const void* buffer, size_t size) 4446122852SIngo Weinhold { 4546122852SIngo Weinhold while (size > 0) { 4646122852SIngo Weinhold if (fPageCount == 0) 4746122852SIngo Weinhold return B_BAD_VALUE; 4846122852SIngo Weinhold 4946122852SIngo Weinhold size_t toCopy = std::min(size, B_PAGE_SIZE - fInPageOffset); 5046122852SIngo Weinhold status_t error = vm_memcpy_to_physical( 5146122852SIngo Weinhold fPages[0]->physical_page_number * B_PAGE_SIZE + fInPageOffset, 5246122852SIngo Weinhold buffer, toCopy, false); 53*4c235c74SIngo Weinhold if (error != B_OK) 5446122852SIngo Weinhold return error; 5546122852SIngo Weinhold 5646122852SIngo Weinhold fInPageOffset += toCopy; 5746122852SIngo Weinhold if (fInPageOffset == B_PAGE_SIZE) { 5846122852SIngo Weinhold fInPageOffset = 0; 5946122852SIngo Weinhold fPages++; 6046122852SIngo Weinhold fPageCount--; 6146122852SIngo Weinhold } 6246122852SIngo Weinhold 6346122852SIngo Weinhold buffer = (const char*)buffer + toCopy; 6446122852SIngo Weinhold size -= toCopy; 6546122852SIngo Weinhold } 6646122852SIngo Weinhold 67*4c235c74SIngo Weinhold return B_OK; 6846122852SIngo Weinhold } 6946122852SIngo Weinhold 709af2105dSAdrien Destugues virtual ssize_t Read(void* buffer, size_t size) 719af2105dSAdrien Destugues { 729af2105dSAdrien Destugues return B_NOT_SUPPORTED; 739af2105dSAdrien Destugues } 749af2105dSAdrien Destugues 7546122852SIngo Weinhold private: 7646122852SIngo Weinhold vm_page** fPages; 7746122852SIngo Weinhold size_t fPageCount; 7846122852SIngo Weinhold size_t fInPageOffset; 7946122852SIngo Weinhold }; 8046122852SIngo Weinhold 8146122852SIngo Weinhold 8246122852SIngo Weinhold // #pragma mark - CachedDataReader 8346122852SIngo Weinhold 8446122852SIngo Weinhold 8546122852SIngo Weinhold CachedDataReader::CachedDataReader() 8646122852SIngo Weinhold : 8746122852SIngo Weinhold fReader(NULL), 8846122852SIngo Weinhold fCache(NULL), 8946122852SIngo Weinhold fCacheLineLockers() 9046122852SIngo Weinhold { 9146122852SIngo Weinhold mutex_init(&fLock, "packagefs cached reader"); 9246122852SIngo Weinhold } 9346122852SIngo Weinhold 9446122852SIngo Weinhold 9546122852SIngo Weinhold CachedDataReader::~CachedDataReader() 9646122852SIngo Weinhold { 9746122852SIngo Weinhold if (fCache != NULL) { 9846122852SIngo Weinhold fCache->Lock(); 9946122852SIngo Weinhold fCache->ReleaseRefAndUnlock(); 10046122852SIngo Weinhold } 10146122852SIngo Weinhold 10246122852SIngo Weinhold mutex_destroy(&fLock); 10346122852SIngo Weinhold } 10446122852SIngo Weinhold 10546122852SIngo Weinhold 10646122852SIngo Weinhold status_t 10746122852SIngo Weinhold CachedDataReader::Init(BAbstractBufferedDataReader* reader, off_t size) 10846122852SIngo Weinhold { 10946122852SIngo Weinhold fReader = reader; 11046122852SIngo Weinhold 11146122852SIngo Weinhold status_t error = fCacheLineLockers.Init(); 11246122852SIngo Weinhold if (error != B_OK) 11346122852SIngo Weinhold RETURN_ERROR(error); 11446122852SIngo Weinhold 11546122852SIngo Weinhold error = VMCacheFactory::CreateNullCache(VM_PRIORITY_SYSTEM, 11646122852SIngo Weinhold fCache); 11746122852SIngo Weinhold if (error != B_OK) 11846122852SIngo Weinhold RETURN_ERROR(error); 11946122852SIngo Weinhold 12046122852SIngo Weinhold AutoLocker<VMCache> locker(fCache); 12146122852SIngo Weinhold 12246122852SIngo Weinhold error = fCache->Resize(size, VM_PRIORITY_SYSTEM); 12346122852SIngo Weinhold if (error != B_OK) 12446122852SIngo Weinhold RETURN_ERROR(error); 12546122852SIngo Weinhold 12646122852SIngo Weinhold return B_OK; 12746122852SIngo Weinhold } 12846122852SIngo Weinhold 12946122852SIngo Weinhold 13046122852SIngo Weinhold status_t 13146122852SIngo Weinhold CachedDataReader::ReadData(off_t offset, void* buffer, size_t size) 13246122852SIngo Weinhold { 13346122852SIngo Weinhold BBufferDataOutput output(buffer, size); 13446122852SIngo Weinhold return ReadDataToOutput(offset, size, &output); 13546122852SIngo Weinhold } 13646122852SIngo Weinhold 13746122852SIngo Weinhold 13846122852SIngo Weinhold status_t 13946122852SIngo Weinhold CachedDataReader::ReadDataToOutput(off_t offset, size_t size, 1409af2105dSAdrien Destugues BDataIO* output) 14146122852SIngo Weinhold { 14246122852SIngo Weinhold if (offset > fCache->virtual_end 14346122852SIngo Weinhold || (off_t)size > fCache->virtual_end - offset) { 14446122852SIngo Weinhold return B_BAD_VALUE; 14546122852SIngo Weinhold } 14646122852SIngo Weinhold 14746122852SIngo Weinhold if (size == 0) 14846122852SIngo Weinhold return B_OK; 14946122852SIngo Weinhold 15046122852SIngo Weinhold while (size > 0) { 15146122852SIngo Weinhold // the start of the current cache line 15246122852SIngo Weinhold off_t lineOffset = (offset / kCacheLineSize) * kCacheLineSize; 15346122852SIngo Weinhold 15446122852SIngo Weinhold // intersection of request and cache line 15546122852SIngo Weinhold off_t cacheLineEnd = std::min(lineOffset + (off_t)kCacheLineSize, 15646122852SIngo Weinhold fCache->virtual_end); 15746122852SIngo Weinhold size_t requestLineLength 15846122852SIngo Weinhold = std::min(cacheLineEnd - offset, (off_t)size); 15946122852SIngo Weinhold 16046122852SIngo Weinhold // transfer the data of the cache line 16146122852SIngo Weinhold status_t error = _ReadCacheLine(lineOffset, cacheLineEnd - lineOffset, 16246122852SIngo Weinhold offset, requestLineLength, output); 163*4c235c74SIngo Weinhold if (error != B_OK) 16446122852SIngo Weinhold return error; 16546122852SIngo Weinhold 16646122852SIngo Weinhold offset = cacheLineEnd; 16746122852SIngo Weinhold size -= requestLineLength; 16846122852SIngo Weinhold } 16946122852SIngo Weinhold 17046122852SIngo Weinhold return B_OK; 17146122852SIngo Weinhold } 17246122852SIngo Weinhold 17346122852SIngo Weinhold 17446122852SIngo Weinhold status_t 17546122852SIngo Weinhold CachedDataReader::_ReadCacheLine(off_t lineOffset, size_t lineSize, 1769af2105dSAdrien Destugues off_t requestOffset, size_t requestLength, BDataIO* output) 17746122852SIngo Weinhold { 17846122852SIngo Weinhold PRINT("CachedDataReader::_ReadCacheLine(%" B_PRIdOFF ", %zu, %" B_PRIdOFF 17946122852SIngo Weinhold ", %zu, %p\n", lineOffset, lineSize, requestOffset, requestLength, 18046122852SIngo Weinhold output); 18146122852SIngo Weinhold 18246122852SIngo Weinhold CacheLineLocker cacheLineLocker(this, lineOffset); 18346122852SIngo Weinhold 18446122852SIngo Weinhold // check whether there are pages of the cache line and the mark them used 18546122852SIngo Weinhold page_num_t firstPageOffset = lineOffset / B_PAGE_SIZE; 18646122852SIngo Weinhold page_num_t linePageCount = (lineSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE; 18746122852SIngo Weinhold vm_page* pages[kPagesPerCacheLine] = {}; 18846122852SIngo Weinhold 18946122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 19046122852SIngo Weinhold 19146122852SIngo Weinhold page_num_t firstMissing = 0; 19246122852SIngo Weinhold page_num_t lastMissing = 0; 19346122852SIngo Weinhold page_num_t missingPages = 0; 19446122852SIngo Weinhold page_num_t pageOffset = firstPageOffset; 19546122852SIngo Weinhold 19646122852SIngo Weinhold VMCachePagesTree::Iterator it = fCache->pages.GetIterator(pageOffset, true, 19746122852SIngo Weinhold true); 19846122852SIngo Weinhold while (pageOffset < firstPageOffset + linePageCount) { 19946122852SIngo Weinhold vm_page* page = it.Next(); 20046122852SIngo Weinhold page_num_t currentPageOffset; 20146122852SIngo Weinhold if (page == NULL 20246122852SIngo Weinhold || page->cache_offset >= firstPageOffset + linePageCount) { 20346122852SIngo Weinhold page = NULL; 20446122852SIngo Weinhold currentPageOffset = firstPageOffset + linePageCount; 20546122852SIngo Weinhold } else 20646122852SIngo Weinhold currentPageOffset = page->cache_offset; 20746122852SIngo Weinhold 20846122852SIngo Weinhold if (pageOffset < currentPageOffset) { 20946122852SIngo Weinhold // pages are missing 21046122852SIngo Weinhold if (missingPages == 0) 21146122852SIngo Weinhold firstMissing = pageOffset; 21246122852SIngo Weinhold lastMissing = currentPageOffset - 1; 21346122852SIngo Weinhold missingPages += currentPageOffset - pageOffset; 21446122852SIngo Weinhold 21546122852SIngo Weinhold for (; pageOffset < currentPageOffset; pageOffset++) 21646122852SIngo Weinhold pages[pageOffset - firstPageOffset] = NULL; 21746122852SIngo Weinhold } 21846122852SIngo Weinhold 21946122852SIngo Weinhold if (page != NULL) { 22046122852SIngo Weinhold pages[pageOffset++ - firstPageOffset] = page; 22146122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 22246122852SIngo Weinhold vm_page_set_state(page, PAGE_STATE_UNUSED); 22346122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(page); 22446122852SIngo Weinhold } 22546122852SIngo Weinhold } 22646122852SIngo Weinhold 22746122852SIngo Weinhold cacheLocker.Unlock(); 22846122852SIngo Weinhold 22946122852SIngo Weinhold if (missingPages > 0) { 23046122852SIngo Weinhold // TODO: If the missing pages range doesn't intersect with the request, just 23146122852SIngo Weinhold // satisfy the request and don't read anything at all. 23246122852SIngo Weinhold // There are pages of the cache line missing. We have to allocate fresh 23346122852SIngo Weinhold // ones. 23446122852SIngo Weinhold 23546122852SIngo Weinhold // reserve 23646122852SIngo Weinhold vm_page_reservation reservation; 23746122852SIngo Weinhold if (!vm_page_try_reserve_pages(&reservation, missingPages, 23846122852SIngo Weinhold VM_PRIORITY_SYSTEM)) { 23946122852SIngo Weinhold _DiscardPages(pages, firstMissing - firstPageOffset, missingPages); 24046122852SIngo Weinhold 24146122852SIngo Weinhold // fall back to uncached transfer 24246122852SIngo Weinhold return fReader->ReadDataToOutput(requestOffset, requestLength, 24346122852SIngo Weinhold output); 24446122852SIngo Weinhold } 24546122852SIngo Weinhold 24646122852SIngo Weinhold // Allocate the missing pages and remove the already existing pages in 24746122852SIngo Weinhold // the range from the cache. We're going to read/write the whole range 24846122852SIngo Weinhold // anyway. 24946122852SIngo Weinhold for (pageOffset = firstMissing; pageOffset <= lastMissing; 25046122852SIngo Weinhold pageOffset++) { 25146122852SIngo Weinhold page_num_t index = pageOffset - firstPageOffset; 25246122852SIngo Weinhold if (pages[index] == NULL) { 25346122852SIngo Weinhold pages[index] = vm_page_allocate_page(&reservation, 25446122852SIngo Weinhold PAGE_STATE_UNUSED); 25546122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(pages[index]); 25646122852SIngo Weinhold } else { 25746122852SIngo Weinhold cacheLocker.Lock(); 25846122852SIngo Weinhold fCache->RemovePage(pages[index]); 25946122852SIngo Weinhold cacheLocker.Unlock(); 26046122852SIngo Weinhold } 26146122852SIngo Weinhold } 26246122852SIngo Weinhold 26346122852SIngo Weinhold missingPages = lastMissing - firstMissing + 1; 26446122852SIngo Weinhold 26546122852SIngo Weinhold // add the pages to the cache 26646122852SIngo Weinhold cacheLocker.Lock(); 26746122852SIngo Weinhold 26846122852SIngo Weinhold for (pageOffset = firstMissing; pageOffset <= lastMissing; 26946122852SIngo Weinhold pageOffset++) { 27046122852SIngo Weinhold page_num_t index = pageOffset - firstPageOffset; 27146122852SIngo Weinhold fCache->InsertPage(pages[index], (off_t)pageOffset * B_PAGE_SIZE); 27246122852SIngo Weinhold } 27346122852SIngo Weinhold 27446122852SIngo Weinhold cacheLocker.Unlock(); 27546122852SIngo Weinhold 27646122852SIngo Weinhold // read in the missing pages 27746122852SIngo Weinhold status_t error = _ReadIntoPages(pages, firstMissing - firstPageOffset, 27846122852SIngo Weinhold missingPages); 27946122852SIngo Weinhold if (error != B_OK) { 28046122852SIngo Weinhold ERROR("CachedDataReader::_ReadCacheLine(): Failed to read into " 28146122852SIngo Weinhold "cache (offset: %" B_PRIdOFF ", length: %" B_PRIuSIZE "), " 28246122852SIngo Weinhold "trying uncached read (offset: %" B_PRIdOFF ", length: %" 28346122852SIngo Weinhold B_PRIuSIZE ")\n", (off_t)firstMissing * B_PAGE_SIZE, 28446122852SIngo Weinhold (size_t)missingPages * B_PAGE_SIZE, requestOffset, 28546122852SIngo Weinhold requestLength); 28646122852SIngo Weinhold 28746122852SIngo Weinhold _DiscardPages(pages, firstMissing - firstPageOffset, missingPages); 28846122852SIngo Weinhold 28946122852SIngo Weinhold // Try again using an uncached transfer 29046122852SIngo Weinhold return fReader->ReadDataToOutput(requestOffset, requestLength, 29146122852SIngo Weinhold output); 29246122852SIngo Weinhold } 29346122852SIngo Weinhold } 29446122852SIngo Weinhold 29546122852SIngo Weinhold // write data to output 29646122852SIngo Weinhold status_t error = _WritePages(pages, requestOffset - lineOffset, 29746122852SIngo Weinhold requestLength, output); 29846122852SIngo Weinhold _CachePages(pages, 0, linePageCount); 29946122852SIngo Weinhold return error; 30046122852SIngo Weinhold } 30146122852SIngo Weinhold 30246122852SIngo Weinhold 30346122852SIngo Weinhold /*! Frees all pages in given range of the \a pages array. 30446122852SIngo Weinhold \c NULL entries in the range are OK. All non \c NULL entries must refer 30546122852SIngo Weinhold to pages with \c PAGE_STATE_UNUSED. The pages may belong to \c fCache or 30646122852SIngo Weinhold may not have a cache. 30746122852SIngo Weinhold \c fCache must not be locked. 30846122852SIngo Weinhold */ 30946122852SIngo Weinhold void 31046122852SIngo Weinhold CachedDataReader::_DiscardPages(vm_page** pages, size_t firstPage, 31146122852SIngo Weinhold size_t pageCount) 31246122852SIngo Weinhold { 31346122852SIngo Weinhold PRINT("%p->CachedDataReader::_DiscardPages(%" B_PRIuSIZE ", %" B_PRIuSIZE 31446122852SIngo Weinhold ")\n", this, firstPage, pageCount); 31546122852SIngo Weinhold 31646122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 31746122852SIngo Weinhold 31846122852SIngo Weinhold for (size_t i = firstPage; i < firstPage + pageCount; i++) { 31946122852SIngo Weinhold vm_page* page = pages[i]; 32046122852SIngo Weinhold if (page == NULL) 32146122852SIngo Weinhold continue; 32246122852SIngo Weinhold 32346122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 32446122852SIngo Weinhold 32546122852SIngo Weinhold ASSERT_PRINT(page->State() == PAGE_STATE_UNUSED, 32646122852SIngo Weinhold "page: %p @! page -m %p", page, page); 32746122852SIngo Weinhold 32846122852SIngo Weinhold if (page->Cache() != NULL) 32946122852SIngo Weinhold fCache->RemovePage(page); 33046122852SIngo Weinhold 33146122852SIngo Weinhold vm_page_free(NULL, page); 33246122852SIngo Weinhold } 33346122852SIngo Weinhold } 33446122852SIngo Weinhold 33546122852SIngo Weinhold 33646122852SIngo Weinhold /*! Marks all pages in the given range of the \a pages array cached. 33746122852SIngo Weinhold There must not be any \c NULL entries in the given array range. All pages 33846122852SIngo Weinhold must belong to \c cache and have state \c PAGE_STATE_UNUSED. 33946122852SIngo Weinhold \c fCache must not be locked. 34046122852SIngo Weinhold */ 34146122852SIngo Weinhold void 34246122852SIngo Weinhold CachedDataReader::_CachePages(vm_page** pages, size_t firstPage, 34346122852SIngo Weinhold size_t pageCount) 34446122852SIngo Weinhold { 34546122852SIngo Weinhold PRINT("%p->CachedDataReader::_CachePages(%" B_PRIuSIZE ", %" B_PRIuSIZE 34646122852SIngo Weinhold ")\n", this, firstPage, pageCount); 34746122852SIngo Weinhold 34846122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 34946122852SIngo Weinhold 35046122852SIngo Weinhold for (size_t i = firstPage; i < firstPage + pageCount; i++) { 35146122852SIngo Weinhold vm_page* page = pages[i]; 35246122852SIngo Weinhold ASSERT(page != NULL); 35346122852SIngo Weinhold ASSERT_PRINT(page->State() == PAGE_STATE_UNUSED 35446122852SIngo Weinhold && page->Cache() == fCache, 35546122852SIngo Weinhold "page: %p @! page -m %p", page, page); 35646122852SIngo Weinhold 35746122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 35846122852SIngo Weinhold vm_page_set_state(page, PAGE_STATE_CACHED); 35946122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(page); 36046122852SIngo Weinhold } 36146122852SIngo Weinhold } 36246122852SIngo Weinhold 36346122852SIngo Weinhold 36446122852SIngo Weinhold /*! Writes the contents of pages in \c pages to \a output. 36546122852SIngo Weinhold \param pages The pages array. 36646122852SIngo Weinhold \param pagesRelativeOffset The offset relative to \a pages[0] where to 36746122852SIngo Weinhold start writing from. 36846122852SIngo Weinhold \param requestLength The number of bytes to write. 36946122852SIngo Weinhold \param output The output to which the data shall be written. 37046122852SIngo Weinhold \return \c B_OK, if writing went fine, another error code otherwise. 37146122852SIngo Weinhold */ 37246122852SIngo Weinhold status_t 37346122852SIngo Weinhold CachedDataReader::_WritePages(vm_page** pages, size_t pagesRelativeOffset, 3749af2105dSAdrien Destugues size_t requestLength, BDataIO* output) 37546122852SIngo Weinhold { 37646122852SIngo Weinhold PRINT("%p->CachedDataReader::_WritePages(%" B_PRIuSIZE ", %" B_PRIuSIZE 37746122852SIngo Weinhold ", %p)\n", this, pagesRelativeOffset, requestLength, output); 37846122852SIngo Weinhold 37946122852SIngo Weinhold size_t firstPage = pagesRelativeOffset / B_PAGE_SIZE; 38046122852SIngo Weinhold size_t endPage = (pagesRelativeOffset + requestLength + B_PAGE_SIZE - 1) 38146122852SIngo Weinhold / B_PAGE_SIZE; 38246122852SIngo Weinhold 38346122852SIngo Weinhold // fallback to copying individual pages 38446122852SIngo Weinhold size_t inPageOffset = pagesRelativeOffset % B_PAGE_SIZE; 38546122852SIngo Weinhold for (size_t i = firstPage; i < endPage; i++) { 38646122852SIngo Weinhold // map the page 38746122852SIngo Weinhold void* handle; 38846122852SIngo Weinhold addr_t address; 38946122852SIngo Weinhold status_t error = vm_get_physical_page( 39046122852SIngo Weinhold pages[i]->physical_page_number * B_PAGE_SIZE, &address, 39146122852SIngo Weinhold &handle); 39246122852SIngo Weinhold if (error != B_OK) 39346122852SIngo Weinhold return error; 39446122852SIngo Weinhold 39546122852SIngo Weinhold // write the page's data 39646122852SIngo Weinhold size_t toCopy = std::min(B_PAGE_SIZE - inPageOffset, requestLength); 3979af2105dSAdrien Destugues error = output->Write((uint8*)(address + inPageOffset), toCopy); 39846122852SIngo Weinhold 39946122852SIngo Weinhold // unmap the page 40046122852SIngo Weinhold vm_put_physical_page(address, handle); 40146122852SIngo Weinhold 402*4c235c74SIngo Weinhold if (error != B_OK) 40346122852SIngo Weinhold return error; 40446122852SIngo Weinhold 40546122852SIngo Weinhold inPageOffset = 0; 40646122852SIngo Weinhold requestLength -= toCopy; 40746122852SIngo Weinhold } 40846122852SIngo Weinhold 40946122852SIngo Weinhold return B_OK; 41046122852SIngo Weinhold } 41146122852SIngo Weinhold 41246122852SIngo Weinhold 41346122852SIngo Weinhold status_t 41446122852SIngo Weinhold CachedDataReader::_ReadIntoPages(vm_page** pages, size_t firstPage, 41546122852SIngo Weinhold size_t pageCount) 41646122852SIngo Weinhold { 41746122852SIngo Weinhold PagesDataOutput output(pages + firstPage, pageCount); 41846122852SIngo Weinhold 41946122852SIngo Weinhold off_t firstPageOffset = (off_t)pages[firstPage]->cache_offset 42046122852SIngo Weinhold * B_PAGE_SIZE; 42146122852SIngo Weinhold generic_size_t requestLength = std::min( 42246122852SIngo Weinhold firstPageOffset + (off_t)pageCount * B_PAGE_SIZE, 42346122852SIngo Weinhold fCache->virtual_end) 42446122852SIngo Weinhold - firstPageOffset; 42546122852SIngo Weinhold 42646122852SIngo Weinhold return fReader->ReadDataToOutput(firstPageOffset, requestLength, &output); 42746122852SIngo Weinhold } 42846122852SIngo Weinhold 42946122852SIngo Weinhold 43046122852SIngo Weinhold void 43146122852SIngo Weinhold CachedDataReader::_LockCacheLine(CacheLineLocker* lineLocker) 43246122852SIngo Weinhold { 43346122852SIngo Weinhold MutexLocker locker(fLock); 43446122852SIngo Weinhold 43546122852SIngo Weinhold CacheLineLocker* otherLineLocker 43646122852SIngo Weinhold = fCacheLineLockers.Lookup(lineLocker->Offset()); 43746122852SIngo Weinhold if (otherLineLocker == NULL) { 43846122852SIngo Weinhold fCacheLineLockers.Insert(lineLocker); 43946122852SIngo Weinhold return; 44046122852SIngo Weinhold } 44146122852SIngo Weinhold 44246122852SIngo Weinhold // queue and wait 44346122852SIngo Weinhold otherLineLocker->Queue().Add(lineLocker); 44446122852SIngo Weinhold lineLocker->Wait(fLock); 44546122852SIngo Weinhold } 44646122852SIngo Weinhold 44746122852SIngo Weinhold 44846122852SIngo Weinhold void 44946122852SIngo Weinhold CachedDataReader::_UnlockCacheLine(CacheLineLocker* lineLocker) 45046122852SIngo Weinhold { 45146122852SIngo Weinhold MutexLocker locker(fLock); 45246122852SIngo Weinhold 45346122852SIngo Weinhold fCacheLineLockers.Remove(lineLocker); 45446122852SIngo Weinhold 45546122852SIngo Weinhold if (CacheLineLocker* nextLineLocker = lineLocker->Queue().RemoveHead()) { 45646122852SIngo Weinhold nextLineLocker->Queue().MoveFrom(&lineLocker->Queue()); 45746122852SIngo Weinhold fCacheLineLockers.Insert(nextLineLocker); 45846122852SIngo Weinhold nextLineLocker->WakeUp(); 45946122852SIngo Weinhold } 46046122852SIngo Weinhold } 461