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