rem: cache_io(void *_cacheRef, off_t offset, addr_t bufferBase, size_t *_size, bool doWrite)
add: cache_io(void *_cacheRef, off_t offset, addr_t buffer, size_t *_size, bool doWrite)
context: cache_io(void *_cacheRef, off_t offset, addr_t bufferBase, size_t *_size, bool doWrite){	if (_cacheRef == NULL)		panic("cache_io() called with NULL ref!\n");	file_cache_ref *ref = (file_cache_ref *)_cacheRef;	vm_cache_ref *cache = ref->cache;	off_t fileSize = cache->cache->virtual_size;	TRACE(("cache_io(ref = %p, offset = %Ld, buffer = %p, size = %lu, %s)\n",		ref, offset, (void *)bufferBase, *_size, doWrite ? "write" : "read"));	// out of bounds access?	if (offset >= fileSize || offset < 0) {		*_size = 0;		return B_OK;	}	int32 pageOffset = offset & (B_PAGE_SIZE - 1);	size_t size = *_size;	offset -= pageOffset;	if (offset + pageOffset + size > fileSize) {		// adapt size to be within the file's offsets		size = fileSize - pageOffset - offset;		*_size = size;	}	size_t bytesLeft = size, lastLeft = size;	addr_t buffer = bufferBase;	off_t lastOffset = offset;	mutex_lock(&cache->lock);	for (; bytesLeft > 0; offset += B_PAGE_SIZE) {		// check if this page is already in memory		addr_t virtualAddress;	restart:		vm_page *page = vm_cache_lookup_page(cache, offset);		if (page != NULL && page->state == PAGE_STATE_BUSY) {			// ToDo: don't wait forever!			mutex_unlock(&cache->lock);			snooze(20000);			mutex_lock(&cache->lock);			goto restart;		}		TRACE(("lookup page from offset %Ld: %p\n", offset, page));		if (page != NULL			&& vm_get_physical_page(page->ppn * B_PAGE_SIZE,					&virtualAddress, PHYSICAL_PAGE_CAN_WAIT) == B_OK) {			// it is, so let's satisfy the first part of the request, if we have to			if (bufferBase != buffer) {				size_t requestSize = buffer - bufferBase;				status_t status;				if (doWrite) {					status = write_to_cache(ref, lastOffset + pageOffset,						requestSize, bufferBase, requestSize);				} else {					status = read_into_cache(ref, lastOffset + pageOffset,						requestSize, bufferBase, requestSize);				}				if (status != B_OK) {					vm_put_physical_page(virtualAddress);					mutex_unlock(&cache->lock);					return B_IO_ERROR;				}				bufferBase += requestSize;			}			// and copy the contents of the page already in memory			if (doWrite) {				user_memcpy((void *)(virtualAddress + pageOffset), (void *)buffer,					min_c(size_t(B_PAGE_SIZE - pageOffset), bytesLeft));			} else {				user_memcpy((void *)buffer, (void *)(virtualAddress + pageOffset),					min_c(size_t(B_PAGE_SIZE - pageOffset), bytesLeft));			}			vm_put_physical_page(virtualAddress);			bufferBase += B_PAGE_SIZE - pageOffset;			pageOffset = 0;			if (bytesLeft <= B_PAGE_SIZE) {				// we've read the last page, so we're done!				mutex_unlock(&cache->lock);				return B_OK;			}			// prepare a potential gap request			lastOffset = offset + B_PAGE_SIZE;			lastLeft = bytesLeft - B_PAGE_SIZE;		}		if (bytesLeft <= B_PAGE_SIZE)			break;		buffer += B_PAGE_SIZE;		bytesLeft -= B_PAGE_SIZE;	}	// fill the last remainding bytes of the request (either write or read)	lastOffset += pageOffset;	status_t status;	if (doWrite)		status = write_to_cache(ref, lastOffset, lastLeft, bufferBase, lastLeft);	else		status = read_into_cache(ref, lastOffset, lastLeft, bufferBase, lastLeft);	mutex_unlock(&cache->lock);	return status;}