1*46122852SIngo Weinhold /* 2*46122852SIngo Weinhold * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3*46122852SIngo Weinhold * Distributed under the terms of the MIT License. 4*46122852SIngo Weinhold */ 5*46122852SIngo Weinhold 6*46122852SIngo Weinhold 7*46122852SIngo Weinhold #include "CachedDataReader.h" 8*46122852SIngo Weinhold 9*46122852SIngo Weinhold #include <algorithm> 10*46122852SIngo Weinhold 11*46122852SIngo Weinhold #include <package/hpkg/DataOutput.h> 12*46122852SIngo Weinhold 13*46122852SIngo Weinhold #include <util/AutoLock.h> 14*46122852SIngo Weinhold #include <vm/VMCache.h> 15*46122852SIngo Weinhold #include <vm/vm_page.h> 16*46122852SIngo Weinhold 17*46122852SIngo Weinhold #include "DebugSupport.h" 18*46122852SIngo Weinhold 19*46122852SIngo Weinhold 20*46122852SIngo Weinhold using BPackageKit::BHPKG::BBufferDataReader; 21*46122852SIngo Weinhold using BPackageKit::BHPKG::BBufferDataOutput; 22*46122852SIngo Weinhold 23*46122852SIngo Weinhold 24*46122852SIngo Weinhold static inline bool 25*46122852SIngo Weinhold page_physical_number_less(const vm_page* a, const vm_page* b) 26*46122852SIngo Weinhold { 27*46122852SIngo Weinhold return a->physical_page_number < b->physical_page_number; 28*46122852SIngo Weinhold } 29*46122852SIngo Weinhold 30*46122852SIngo Weinhold 31*46122852SIngo Weinhold // #pragma mark - PagesDataOutput 32*46122852SIngo Weinhold 33*46122852SIngo Weinhold 34*46122852SIngo Weinhold struct CachedDataReader::PagesDataOutput : public BDataOutput { 35*46122852SIngo Weinhold PagesDataOutput(vm_page** pages, size_t pageCount) 36*46122852SIngo Weinhold : 37*46122852SIngo Weinhold fPages(pages), 38*46122852SIngo Weinhold fPageCount(pageCount), 39*46122852SIngo Weinhold fInPageOffset(0) 40*46122852SIngo Weinhold { 41*46122852SIngo Weinhold } 42*46122852SIngo Weinhold 43*46122852SIngo Weinhold virtual status_t WriteData(const void* buffer, size_t size) 44*46122852SIngo Weinhold { 45*46122852SIngo Weinhold while (size > 0) { 46*46122852SIngo Weinhold if (fPageCount == 0) 47*46122852SIngo Weinhold return B_BAD_VALUE; 48*46122852SIngo Weinhold 49*46122852SIngo Weinhold size_t toCopy = std::min(size, B_PAGE_SIZE - fInPageOffset); 50*46122852SIngo Weinhold status_t error = vm_memcpy_to_physical( 51*46122852SIngo Weinhold fPages[0]->physical_page_number * B_PAGE_SIZE + fInPageOffset, 52*46122852SIngo Weinhold buffer, toCopy, false); 53*46122852SIngo Weinhold if (error != B_OK) 54*46122852SIngo Weinhold return error; 55*46122852SIngo Weinhold 56*46122852SIngo Weinhold fInPageOffset += toCopy; 57*46122852SIngo Weinhold if (fInPageOffset == B_PAGE_SIZE) { 58*46122852SIngo Weinhold fInPageOffset = 0; 59*46122852SIngo Weinhold fPages++; 60*46122852SIngo Weinhold fPageCount--; 61*46122852SIngo Weinhold } 62*46122852SIngo Weinhold 63*46122852SIngo Weinhold buffer = (const char*)buffer + toCopy; 64*46122852SIngo Weinhold size -= toCopy; 65*46122852SIngo Weinhold } 66*46122852SIngo Weinhold 67*46122852SIngo Weinhold return B_OK; 68*46122852SIngo Weinhold } 69*46122852SIngo Weinhold 70*46122852SIngo Weinhold private: 71*46122852SIngo Weinhold vm_page** fPages; 72*46122852SIngo Weinhold size_t fPageCount; 73*46122852SIngo Weinhold size_t fInPageOffset; 74*46122852SIngo Weinhold }; 75*46122852SIngo Weinhold 76*46122852SIngo Weinhold 77*46122852SIngo Weinhold // #pragma mark - CachedDataReader 78*46122852SIngo Weinhold 79*46122852SIngo Weinhold 80*46122852SIngo Weinhold CachedDataReader::CachedDataReader() 81*46122852SIngo Weinhold : 82*46122852SIngo Weinhold fReader(NULL), 83*46122852SIngo Weinhold fCache(NULL), 84*46122852SIngo Weinhold fCacheLineLockers() 85*46122852SIngo Weinhold { 86*46122852SIngo Weinhold mutex_init(&fLock, "packagefs cached reader"); 87*46122852SIngo Weinhold } 88*46122852SIngo Weinhold 89*46122852SIngo Weinhold 90*46122852SIngo Weinhold CachedDataReader::~CachedDataReader() 91*46122852SIngo Weinhold { 92*46122852SIngo Weinhold if (fCache != NULL) { 93*46122852SIngo Weinhold fCache->Lock(); 94*46122852SIngo Weinhold fCache->ReleaseRefAndUnlock(); 95*46122852SIngo Weinhold } 96*46122852SIngo Weinhold 97*46122852SIngo Weinhold mutex_destroy(&fLock); 98*46122852SIngo Weinhold } 99*46122852SIngo Weinhold 100*46122852SIngo Weinhold 101*46122852SIngo Weinhold status_t 102*46122852SIngo Weinhold CachedDataReader::Init(BAbstractBufferedDataReader* reader, off_t size) 103*46122852SIngo Weinhold { 104*46122852SIngo Weinhold fReader = reader; 105*46122852SIngo Weinhold 106*46122852SIngo Weinhold status_t error = fCacheLineLockers.Init(); 107*46122852SIngo Weinhold if (error != B_OK) 108*46122852SIngo Weinhold RETURN_ERROR(error); 109*46122852SIngo Weinhold 110*46122852SIngo Weinhold error = VMCacheFactory::CreateNullCache(VM_PRIORITY_SYSTEM, 111*46122852SIngo Weinhold fCache); 112*46122852SIngo Weinhold if (error != B_OK) 113*46122852SIngo Weinhold RETURN_ERROR(error); 114*46122852SIngo Weinhold 115*46122852SIngo Weinhold AutoLocker<VMCache> locker(fCache); 116*46122852SIngo Weinhold 117*46122852SIngo Weinhold error = fCache->Resize(size, VM_PRIORITY_SYSTEM); 118*46122852SIngo Weinhold if (error != B_OK) 119*46122852SIngo Weinhold RETURN_ERROR(error); 120*46122852SIngo Weinhold 121*46122852SIngo Weinhold return B_OK; 122*46122852SIngo Weinhold } 123*46122852SIngo Weinhold 124*46122852SIngo Weinhold 125*46122852SIngo Weinhold status_t 126*46122852SIngo Weinhold CachedDataReader::ReadData(off_t offset, void* buffer, size_t size) 127*46122852SIngo Weinhold { 128*46122852SIngo Weinhold BBufferDataOutput output(buffer, size); 129*46122852SIngo Weinhold return ReadDataToOutput(offset, size, &output); 130*46122852SIngo Weinhold } 131*46122852SIngo Weinhold 132*46122852SIngo Weinhold 133*46122852SIngo Weinhold status_t 134*46122852SIngo Weinhold CachedDataReader::ReadDataToOutput(off_t offset, size_t size, 135*46122852SIngo Weinhold BDataOutput* output) 136*46122852SIngo Weinhold { 137*46122852SIngo Weinhold if (offset > fCache->virtual_end 138*46122852SIngo Weinhold || (off_t)size > fCache->virtual_end - offset) { 139*46122852SIngo Weinhold return B_BAD_VALUE; 140*46122852SIngo Weinhold } 141*46122852SIngo Weinhold 142*46122852SIngo Weinhold if (size == 0) 143*46122852SIngo Weinhold return B_OK; 144*46122852SIngo Weinhold 145*46122852SIngo Weinhold while (size > 0) { 146*46122852SIngo Weinhold // the start of the current cache line 147*46122852SIngo Weinhold off_t lineOffset = (offset / kCacheLineSize) * kCacheLineSize; 148*46122852SIngo Weinhold 149*46122852SIngo Weinhold // intersection of request and cache line 150*46122852SIngo Weinhold off_t cacheLineEnd = std::min(lineOffset + (off_t)kCacheLineSize, 151*46122852SIngo Weinhold fCache->virtual_end); 152*46122852SIngo Weinhold size_t requestLineLength 153*46122852SIngo Weinhold = std::min(cacheLineEnd - offset, (off_t)size); 154*46122852SIngo Weinhold 155*46122852SIngo Weinhold // transfer the data of the cache line 156*46122852SIngo Weinhold status_t error = _ReadCacheLine(lineOffset, cacheLineEnd - lineOffset, 157*46122852SIngo Weinhold offset, requestLineLength, output); 158*46122852SIngo Weinhold if (error != B_OK) 159*46122852SIngo Weinhold return error; 160*46122852SIngo Weinhold 161*46122852SIngo Weinhold offset = cacheLineEnd; 162*46122852SIngo Weinhold size -= requestLineLength; 163*46122852SIngo Weinhold } 164*46122852SIngo Weinhold 165*46122852SIngo Weinhold return B_OK; 166*46122852SIngo Weinhold } 167*46122852SIngo Weinhold 168*46122852SIngo Weinhold 169*46122852SIngo Weinhold status_t 170*46122852SIngo Weinhold CachedDataReader::_ReadCacheLine(off_t lineOffset, size_t lineSize, 171*46122852SIngo Weinhold off_t requestOffset, size_t requestLength, BDataOutput* output) 172*46122852SIngo Weinhold { 173*46122852SIngo Weinhold PRINT("CachedDataReader::_ReadCacheLine(%" B_PRIdOFF ", %zu, %" B_PRIdOFF 174*46122852SIngo Weinhold ", %zu, %p\n", lineOffset, lineSize, requestOffset, requestLength, 175*46122852SIngo Weinhold output); 176*46122852SIngo Weinhold 177*46122852SIngo Weinhold CacheLineLocker cacheLineLocker(this, lineOffset); 178*46122852SIngo Weinhold 179*46122852SIngo Weinhold // check whether there are pages of the cache line and the mark them used 180*46122852SIngo Weinhold page_num_t firstPageOffset = lineOffset / B_PAGE_SIZE; 181*46122852SIngo Weinhold page_num_t linePageCount = (lineSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE; 182*46122852SIngo Weinhold vm_page* pages[kPagesPerCacheLine] = {}; 183*46122852SIngo Weinhold 184*46122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 185*46122852SIngo Weinhold 186*46122852SIngo Weinhold page_num_t firstMissing = 0; 187*46122852SIngo Weinhold page_num_t lastMissing = 0; 188*46122852SIngo Weinhold page_num_t missingPages = 0; 189*46122852SIngo Weinhold page_num_t pageOffset = firstPageOffset; 190*46122852SIngo Weinhold 191*46122852SIngo Weinhold VMCachePagesTree::Iterator it = fCache->pages.GetIterator(pageOffset, true, 192*46122852SIngo Weinhold true); 193*46122852SIngo Weinhold while (pageOffset < firstPageOffset + linePageCount) { 194*46122852SIngo Weinhold vm_page* page = it.Next(); 195*46122852SIngo Weinhold page_num_t currentPageOffset; 196*46122852SIngo Weinhold if (page == NULL 197*46122852SIngo Weinhold || page->cache_offset >= firstPageOffset + linePageCount) { 198*46122852SIngo Weinhold page = NULL; 199*46122852SIngo Weinhold currentPageOffset = firstPageOffset + linePageCount; 200*46122852SIngo Weinhold } else 201*46122852SIngo Weinhold currentPageOffset = page->cache_offset; 202*46122852SIngo Weinhold 203*46122852SIngo Weinhold if (pageOffset < currentPageOffset) { 204*46122852SIngo Weinhold // pages are missing 205*46122852SIngo Weinhold if (missingPages == 0) 206*46122852SIngo Weinhold firstMissing = pageOffset; 207*46122852SIngo Weinhold lastMissing = currentPageOffset - 1; 208*46122852SIngo Weinhold missingPages += currentPageOffset - pageOffset; 209*46122852SIngo Weinhold 210*46122852SIngo Weinhold for (; pageOffset < currentPageOffset; pageOffset++) 211*46122852SIngo Weinhold pages[pageOffset - firstPageOffset] = NULL; 212*46122852SIngo Weinhold } 213*46122852SIngo Weinhold 214*46122852SIngo Weinhold if (page != NULL) { 215*46122852SIngo Weinhold pages[pageOffset++ - firstPageOffset] = page; 216*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 217*46122852SIngo Weinhold vm_page_set_state(page, PAGE_STATE_UNUSED); 218*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(page); 219*46122852SIngo Weinhold } 220*46122852SIngo Weinhold } 221*46122852SIngo Weinhold 222*46122852SIngo Weinhold cacheLocker.Unlock(); 223*46122852SIngo Weinhold 224*46122852SIngo Weinhold if (missingPages > 0) { 225*46122852SIngo Weinhold // TODO: If the missing pages range doesn't intersect with the request, just 226*46122852SIngo Weinhold // satisfy the request and don't read anything at all. 227*46122852SIngo Weinhold // There are pages of the cache line missing. We have to allocate fresh 228*46122852SIngo Weinhold // ones. 229*46122852SIngo Weinhold 230*46122852SIngo Weinhold // reserve 231*46122852SIngo Weinhold vm_page_reservation reservation; 232*46122852SIngo Weinhold if (!vm_page_try_reserve_pages(&reservation, missingPages, 233*46122852SIngo Weinhold VM_PRIORITY_SYSTEM)) { 234*46122852SIngo Weinhold _DiscardPages(pages, firstMissing - firstPageOffset, missingPages); 235*46122852SIngo Weinhold 236*46122852SIngo Weinhold // fall back to uncached transfer 237*46122852SIngo Weinhold return fReader->ReadDataToOutput(requestOffset, requestLength, 238*46122852SIngo Weinhold output); 239*46122852SIngo Weinhold } 240*46122852SIngo Weinhold 241*46122852SIngo Weinhold // Allocate the missing pages and remove the already existing pages in 242*46122852SIngo Weinhold // the range from the cache. We're going to read/write the whole range 243*46122852SIngo Weinhold // anyway. 244*46122852SIngo Weinhold for (pageOffset = firstMissing; pageOffset <= lastMissing; 245*46122852SIngo Weinhold pageOffset++) { 246*46122852SIngo Weinhold page_num_t index = pageOffset - firstPageOffset; 247*46122852SIngo Weinhold if (pages[index] == NULL) { 248*46122852SIngo Weinhold pages[index] = vm_page_allocate_page(&reservation, 249*46122852SIngo Weinhold PAGE_STATE_UNUSED); 250*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(pages[index]); 251*46122852SIngo Weinhold } else { 252*46122852SIngo Weinhold cacheLocker.Lock(); 253*46122852SIngo Weinhold fCache->RemovePage(pages[index]); 254*46122852SIngo Weinhold cacheLocker.Unlock(); 255*46122852SIngo Weinhold } 256*46122852SIngo Weinhold } 257*46122852SIngo Weinhold 258*46122852SIngo Weinhold missingPages = lastMissing - firstMissing + 1; 259*46122852SIngo Weinhold 260*46122852SIngo Weinhold // add the pages to the cache 261*46122852SIngo Weinhold cacheLocker.Lock(); 262*46122852SIngo Weinhold 263*46122852SIngo Weinhold for (pageOffset = firstMissing; pageOffset <= lastMissing; 264*46122852SIngo Weinhold pageOffset++) { 265*46122852SIngo Weinhold page_num_t index = pageOffset - firstPageOffset; 266*46122852SIngo Weinhold fCache->InsertPage(pages[index], (off_t)pageOffset * B_PAGE_SIZE); 267*46122852SIngo Weinhold } 268*46122852SIngo Weinhold 269*46122852SIngo Weinhold cacheLocker.Unlock(); 270*46122852SIngo Weinhold 271*46122852SIngo Weinhold // read in the missing pages 272*46122852SIngo Weinhold status_t error = _ReadIntoPages(pages, firstMissing - firstPageOffset, 273*46122852SIngo Weinhold missingPages); 274*46122852SIngo Weinhold if (error != B_OK) { 275*46122852SIngo Weinhold ERROR("CachedDataReader::_ReadCacheLine(): Failed to read into " 276*46122852SIngo Weinhold "cache (offset: %" B_PRIdOFF ", length: %" B_PRIuSIZE "), " 277*46122852SIngo Weinhold "trying uncached read (offset: %" B_PRIdOFF ", length: %" 278*46122852SIngo Weinhold B_PRIuSIZE ")\n", (off_t)firstMissing * B_PAGE_SIZE, 279*46122852SIngo Weinhold (size_t)missingPages * B_PAGE_SIZE, requestOffset, 280*46122852SIngo Weinhold requestLength); 281*46122852SIngo Weinhold 282*46122852SIngo Weinhold _DiscardPages(pages, firstMissing - firstPageOffset, missingPages); 283*46122852SIngo Weinhold 284*46122852SIngo Weinhold // Try again using an uncached transfer 285*46122852SIngo Weinhold return fReader->ReadDataToOutput(requestOffset, requestLength, 286*46122852SIngo Weinhold output); 287*46122852SIngo Weinhold } 288*46122852SIngo Weinhold } 289*46122852SIngo Weinhold 290*46122852SIngo Weinhold // write data to output 291*46122852SIngo Weinhold status_t error = _WritePages(pages, requestOffset - lineOffset, 292*46122852SIngo Weinhold requestLength, output); 293*46122852SIngo Weinhold _CachePages(pages, 0, linePageCount); 294*46122852SIngo Weinhold return error; 295*46122852SIngo Weinhold } 296*46122852SIngo Weinhold 297*46122852SIngo Weinhold 298*46122852SIngo Weinhold /*! Frees all pages in given range of the \a pages array. 299*46122852SIngo Weinhold \c NULL entries in the range are OK. All non \c NULL entries must refer 300*46122852SIngo Weinhold to pages with \c PAGE_STATE_UNUSED. The pages may belong to \c fCache or 301*46122852SIngo Weinhold may not have a cache. 302*46122852SIngo Weinhold \c fCache must not be locked. 303*46122852SIngo Weinhold */ 304*46122852SIngo Weinhold void 305*46122852SIngo Weinhold CachedDataReader::_DiscardPages(vm_page** pages, size_t firstPage, 306*46122852SIngo Weinhold size_t pageCount) 307*46122852SIngo Weinhold { 308*46122852SIngo Weinhold PRINT("%p->CachedDataReader::_DiscardPages(%" B_PRIuSIZE ", %" B_PRIuSIZE 309*46122852SIngo Weinhold ")\n", this, firstPage, pageCount); 310*46122852SIngo Weinhold 311*46122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 312*46122852SIngo Weinhold 313*46122852SIngo Weinhold for (size_t i = firstPage; i < firstPage + pageCount; i++) { 314*46122852SIngo Weinhold vm_page* page = pages[i]; 315*46122852SIngo Weinhold if (page == NULL) 316*46122852SIngo Weinhold continue; 317*46122852SIngo Weinhold 318*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 319*46122852SIngo Weinhold 320*46122852SIngo Weinhold ASSERT_PRINT(page->State() == PAGE_STATE_UNUSED, 321*46122852SIngo Weinhold "page: %p @! page -m %p", page, page); 322*46122852SIngo Weinhold 323*46122852SIngo Weinhold if (page->Cache() != NULL) 324*46122852SIngo Weinhold fCache->RemovePage(page); 325*46122852SIngo Weinhold 326*46122852SIngo Weinhold vm_page_free(NULL, page); 327*46122852SIngo Weinhold } 328*46122852SIngo Weinhold } 329*46122852SIngo Weinhold 330*46122852SIngo Weinhold 331*46122852SIngo Weinhold /*! Marks all pages in the given range of the \a pages array cached. 332*46122852SIngo Weinhold There must not be any \c NULL entries in the given array range. All pages 333*46122852SIngo Weinhold must belong to \c cache and have state \c PAGE_STATE_UNUSED. 334*46122852SIngo Weinhold \c fCache must not be locked. 335*46122852SIngo Weinhold */ 336*46122852SIngo Weinhold void 337*46122852SIngo Weinhold CachedDataReader::_CachePages(vm_page** pages, size_t firstPage, 338*46122852SIngo Weinhold size_t pageCount) 339*46122852SIngo Weinhold { 340*46122852SIngo Weinhold PRINT("%p->CachedDataReader::_CachePages(%" B_PRIuSIZE ", %" B_PRIuSIZE 341*46122852SIngo Weinhold ")\n", this, firstPage, pageCount); 342*46122852SIngo Weinhold 343*46122852SIngo Weinhold AutoLocker<VMCache> cacheLocker(fCache); 344*46122852SIngo Weinhold 345*46122852SIngo Weinhold for (size_t i = firstPage; i < firstPage + pageCount; i++) { 346*46122852SIngo Weinhold vm_page* page = pages[i]; 347*46122852SIngo Weinhold ASSERT(page != NULL); 348*46122852SIngo Weinhold ASSERT_PRINT(page->State() == PAGE_STATE_UNUSED 349*46122852SIngo Weinhold && page->Cache() == fCache, 350*46122852SIngo Weinhold "page: %p @! page -m %p", page, page); 351*46122852SIngo Weinhold 352*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_START(page); 353*46122852SIngo Weinhold vm_page_set_state(page, PAGE_STATE_CACHED); 354*46122852SIngo Weinhold DEBUG_PAGE_ACCESS_END(page); 355*46122852SIngo Weinhold } 356*46122852SIngo Weinhold } 357*46122852SIngo Weinhold 358*46122852SIngo Weinhold 359*46122852SIngo Weinhold /*! Writes the contents of pages in \c pages to \a output. 360*46122852SIngo Weinhold \param pages The pages array. 361*46122852SIngo Weinhold \param pagesRelativeOffset The offset relative to \a pages[0] where to 362*46122852SIngo Weinhold start writing from. 363*46122852SIngo Weinhold \param requestLength The number of bytes to write. 364*46122852SIngo Weinhold \param output The output to which the data shall be written. 365*46122852SIngo Weinhold \return \c B_OK, if writing went fine, another error code otherwise. 366*46122852SIngo Weinhold */ 367*46122852SIngo Weinhold status_t 368*46122852SIngo Weinhold CachedDataReader::_WritePages(vm_page** pages, size_t pagesRelativeOffset, 369*46122852SIngo Weinhold size_t requestLength, BDataOutput* output) 370*46122852SIngo Weinhold { 371*46122852SIngo Weinhold PRINT("%p->CachedDataReader::_WritePages(%" B_PRIuSIZE ", %" B_PRIuSIZE 372*46122852SIngo Weinhold ", %p)\n", this, pagesRelativeOffset, requestLength, output); 373*46122852SIngo Weinhold 374*46122852SIngo Weinhold size_t firstPage = pagesRelativeOffset / B_PAGE_SIZE; 375*46122852SIngo Weinhold size_t endPage = (pagesRelativeOffset + requestLength + B_PAGE_SIZE - 1) 376*46122852SIngo Weinhold / B_PAGE_SIZE; 377*46122852SIngo Weinhold 378*46122852SIngo Weinhold // fallback to copying individual pages 379*46122852SIngo Weinhold size_t inPageOffset = pagesRelativeOffset % B_PAGE_SIZE; 380*46122852SIngo Weinhold for (size_t i = firstPage; i < endPage; i++) { 381*46122852SIngo Weinhold // map the page 382*46122852SIngo Weinhold void* handle; 383*46122852SIngo Weinhold addr_t address; 384*46122852SIngo Weinhold status_t error = vm_get_physical_page( 385*46122852SIngo Weinhold pages[i]->physical_page_number * B_PAGE_SIZE, &address, 386*46122852SIngo Weinhold &handle); 387*46122852SIngo Weinhold if (error != B_OK) 388*46122852SIngo Weinhold return error; 389*46122852SIngo Weinhold 390*46122852SIngo Weinhold // write the page's data 391*46122852SIngo Weinhold size_t toCopy = std::min(B_PAGE_SIZE - inPageOffset, requestLength); 392*46122852SIngo Weinhold error = output->WriteData((uint8*)(address + inPageOffset), toCopy); 393*46122852SIngo Weinhold 394*46122852SIngo Weinhold // unmap the page 395*46122852SIngo Weinhold vm_put_physical_page(address, handle); 396*46122852SIngo Weinhold 397*46122852SIngo Weinhold if (error != B_OK) 398*46122852SIngo Weinhold return error; 399*46122852SIngo Weinhold 400*46122852SIngo Weinhold inPageOffset = 0; 401*46122852SIngo Weinhold requestLength -= toCopy; 402*46122852SIngo Weinhold } 403*46122852SIngo Weinhold 404*46122852SIngo Weinhold return B_OK; 405*46122852SIngo Weinhold } 406*46122852SIngo Weinhold 407*46122852SIngo Weinhold 408*46122852SIngo Weinhold status_t 409*46122852SIngo Weinhold CachedDataReader::_ReadIntoPages(vm_page** pages, size_t firstPage, 410*46122852SIngo Weinhold size_t pageCount) 411*46122852SIngo Weinhold { 412*46122852SIngo Weinhold PagesDataOutput output(pages + firstPage, pageCount); 413*46122852SIngo Weinhold 414*46122852SIngo Weinhold off_t firstPageOffset = (off_t)pages[firstPage]->cache_offset 415*46122852SIngo Weinhold * B_PAGE_SIZE; 416*46122852SIngo Weinhold generic_size_t requestLength = std::min( 417*46122852SIngo Weinhold firstPageOffset + (off_t)pageCount * B_PAGE_SIZE, 418*46122852SIngo Weinhold fCache->virtual_end) 419*46122852SIngo Weinhold - firstPageOffset; 420*46122852SIngo Weinhold 421*46122852SIngo Weinhold return fReader->ReadDataToOutput(firstPageOffset, requestLength, &output); 422*46122852SIngo Weinhold } 423*46122852SIngo Weinhold 424*46122852SIngo Weinhold 425*46122852SIngo Weinhold void 426*46122852SIngo Weinhold CachedDataReader::_LockCacheLine(CacheLineLocker* lineLocker) 427*46122852SIngo Weinhold { 428*46122852SIngo Weinhold MutexLocker locker(fLock); 429*46122852SIngo Weinhold 430*46122852SIngo Weinhold CacheLineLocker* otherLineLocker 431*46122852SIngo Weinhold = fCacheLineLockers.Lookup(lineLocker->Offset()); 432*46122852SIngo Weinhold if (otherLineLocker == NULL) { 433*46122852SIngo Weinhold fCacheLineLockers.Insert(lineLocker); 434*46122852SIngo Weinhold return; 435*46122852SIngo Weinhold } 436*46122852SIngo Weinhold 437*46122852SIngo Weinhold // queue and wait 438*46122852SIngo Weinhold otherLineLocker->Queue().Add(lineLocker); 439*46122852SIngo Weinhold lineLocker->Wait(fLock); 440*46122852SIngo Weinhold } 441*46122852SIngo Weinhold 442*46122852SIngo Weinhold 443*46122852SIngo Weinhold void 444*46122852SIngo Weinhold CachedDataReader::_UnlockCacheLine(CacheLineLocker* lineLocker) 445*46122852SIngo Weinhold { 446*46122852SIngo Weinhold MutexLocker locker(fLock); 447*46122852SIngo Weinhold 448*46122852SIngo Weinhold fCacheLineLockers.Remove(lineLocker); 449*46122852SIngo Weinhold 450*46122852SIngo Weinhold if (CacheLineLocker* nextLineLocker = lineLocker->Queue().RemoveHead()) { 451*46122852SIngo Weinhold nextLineLocker->Queue().MoveFrom(&lineLocker->Queue()); 452*46122852SIngo Weinhold fCacheLineLockers.Insert(nextLineLocker); 453*46122852SIngo Weinhold nextLineLocker->WakeUp(); 454*46122852SIngo Weinhold } 455*46122852SIngo Weinhold } 456