Renamed readwrite() to cache_io(), and readwrite_pages() to pages_io().
While we can tolerate the device driver to ignore the bytes argument when we read from the device, we cannot do this for writes - now the code actually takes this into account. Also added a comment about what to do when our own driver is fixed :) Implemented file_cache_sync(). file_cache_set_size() now uses vm_cache::virtual_size instead of the now removed vnode_store::size. Also, it now resizes the vm_cache as well, so that any no longer used pages are freed. write_to_cache() now puts all pages in the modified list, so that they can be written back easily. Improved debug output. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10203 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Vendored
+87
-50
@@ -57,10 +57,11 @@ add_to_iovec(iovec *vecs, int32 &index, int32 max, addr_t address, size_t size)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
readwrite_pages(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
pages_io(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t count,
|
||||||
size_t *_numBytes, bool doWrite)
|
size_t *_numBytes, bool doWrite)
|
||||||
{
|
{
|
||||||
TRACE(("read_pages: ref = %p, offset = %Ld, size = %lu\n", ref, offset, *_numBytes));
|
TRACE(("pages_io: ref = %p, offset = %Ld, size = %lu, %s\n", ref, offset,
|
||||||
|
*_numBytes, doWrite ? "write" : "read"));
|
||||||
|
|
||||||
// translate the iovecs into direct device accesses
|
// translate the iovecs into direct device accesses
|
||||||
file_io_vec fileVecs[16];
|
file_io_vec fileVecs[16];
|
||||||
@@ -79,36 +80,46 @@ readwrite_pages(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t cou
|
|||||||
dprintf("[%lu] offset = %Ld, size = %Ld\n", i, fileVecs[i].offset, fileVecs[i].length);
|
dprintf("[%lu] offset = %Ld, size = %Ld\n", i, fileVecs[i].offset, fileVecs[i].length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// now directly read the data from the device
|
uint32 fileVecIndex;
|
||||||
// the first file_io_vec can be read directly
|
size_t size;
|
||||||
|
|
||||||
size_t size = fileVecs[0].length;
|
if (!doWrite) {
|
||||||
if (size > numBytes)
|
// now directly read the data from the device
|
||||||
size = numBytes;
|
// the first file_io_vec can be read directly
|
||||||
|
|
||||||
if (doWrite)
|
|
||||||
status = vfs_write_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs, count, &size);
|
|
||||||
else
|
|
||||||
status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs, count, &size);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// ToDo: this is a work-around for buggy device drivers!
|
|
||||||
if (size > fileVecs[0].length) {
|
|
||||||
dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
|
|
||||||
size = fileVecs[0].length;
|
size = fileVecs[0].length;
|
||||||
}
|
if (size > numBytes)
|
||||||
|
size = numBytes;
|
||||||
|
|
||||||
ASSERT(size <= fileVecs[0].length);
|
status = vfs_read_pages(ref->device, ref->cookie, fileVecs[0].offset, vecs, count, &size);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
// If the file portion was contiguous, we're already done now
|
// ToDo: this is a work-around for buggy device drivers!
|
||||||
if (size == numBytes)
|
// When our own drivers honour the length, we can:
|
||||||
return B_OK;
|
// a) also use this direct I/O for writes (otherwise, it would overwrite precious data)
|
||||||
|
// b) panic if the term below is true (at least for writes)
|
||||||
|
if (size > fileVecs[0].length) {
|
||||||
|
dprintf("warning: device driver %p doesn't respect total length in read_pages() call!\n", ref->device);
|
||||||
|
size = fileVecs[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
// if we reached the end of the file, we can return as well
|
ASSERT(size <= fileVecs[0].length);
|
||||||
if (size != fileVecs[0].length) {
|
|
||||||
*_numBytes = size;
|
// If the file portion was contiguous, we're already done now
|
||||||
return B_OK;
|
if (size == numBytes)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// if we reached the end of the file, we can return as well
|
||||||
|
if (size != fileVecs[0].length) {
|
||||||
|
*_numBytes = size;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileVecIndex = 1;
|
||||||
|
} else {
|
||||||
|
fileVecIndex = 0;
|
||||||
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Too bad, let's process the rest of the file_io_vecs
|
// Too bad, let's process the rest of the file_io_vecs
|
||||||
@@ -126,7 +137,7 @@ readwrite_pages(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t cou
|
|||||||
|
|
||||||
size_t vecOffset = size;
|
size_t vecOffset = size;
|
||||||
|
|
||||||
for (uint32 fileVecIndex = 1; fileVecIndex < fileVecCount; fileVecIndex++) {
|
for (; fileVecIndex < fileVecCount; fileVecIndex++) {
|
||||||
file_io_vec &fileVec = fileVecs[fileVecIndex];
|
file_io_vec &fileVec = fileVecs[fileVecIndex];
|
||||||
iovec tempVecs[8];
|
iovec tempVecs[8];
|
||||||
uint32 tempCount = 1;
|
uint32 tempCount = 1;
|
||||||
@@ -158,7 +169,7 @@ readwrite_pages(file_cache_ref *ref, off_t offset, const iovec *vecs, size_t cou
|
|||||||
|
|
||||||
size_t bytes = size;
|
size_t bytes = size;
|
||||||
if (doWrite)
|
if (doWrite)
|
||||||
status = vfs_read_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
|
status = vfs_write_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
|
||||||
else
|
else
|
||||||
status = vfs_read_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
|
status = vfs_read_pages(ref->device, ref->cookie, fileVec.offset, tempVecs, tempCount, &bytes);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -212,7 +223,7 @@ read_from_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read file into reserved pages
|
// read file into reserved pages
|
||||||
status_t status = readwrite_pages(ref, offset, vecs, vecCount, &size, false);
|
status_t status = pages_io(ref, offset, vecs, vecCount, &size, false);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// ToDo: remove allocated pages...
|
// ToDo: remove allocated pages...
|
||||||
panic("file_cache: remove allocated pages! read pages failed: %s\n", strerror(status));
|
panic("file_cache: remove allocated pages! read pages failed: %s\n", strerror(status));
|
||||||
@@ -286,7 +297,7 @@ write_to_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, si
|
|||||||
size_t bytesRead = B_PAGE_SIZE;
|
size_t bytesRead = B_PAGE_SIZE;
|
||||||
iovec readVec = { (void *)virtualAddress, B_PAGE_SIZE };
|
iovec readVec = { (void *)virtualAddress, B_PAGE_SIZE };
|
||||||
|
|
||||||
readwrite_pages(ref, offset + pos, &readVec, 1, &bytesRead, false);
|
pages_io(ref, offset + pos, &readVec, 1, &bytesRead, false);
|
||||||
// ToDo: handle errors!
|
// ToDo: handle errors!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,9 +306,13 @@ write_to_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, si
|
|||||||
user_memcpy((void *)(virtualAddress + pageOffset), (void *)buffer, bytes);
|
user_memcpy((void *)(virtualAddress + pageOffset), (void *)buffer, bytes);
|
||||||
buffer += bytes;
|
buffer += bytes;
|
||||||
bufferSize -= bytes;
|
bufferSize -= bytes;
|
||||||
|
|
||||||
|
vm_page_set_state(page, PAGE_STATE_MODIFIED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToDo: we only have to write the pages back immediately if write-back mode
|
||||||
|
// is disabled, which is not possible right now
|
||||||
#if 0
|
#if 0
|
||||||
// write cached pages back to the file if we were asked to do that
|
// write cached pages back to the file if we were asked to do that
|
||||||
status_t status = readwrite_pages(ref, offset, vecs, vecCount, &size, true);
|
status_t status = readwrite_pages(ref, offset, vecs, vecCount, &size, true);
|
||||||
@@ -318,21 +333,26 @@ write_to_cache(file_cache_ref *ref, off_t offset, size_t size, addr_t buffer, si
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make the pages accessible in the cache
|
// make the pages accessible in the cache
|
||||||
for (int32 i = pageIndex; i-- > 0;)
|
for (int32 i = pageIndex; i-- > 0;) {
|
||||||
pages[i]->state = PAGE_STATE_ACTIVE;
|
if (pages[i]->state == PAGE_STATE_BUSY)
|
||||||
|
pages[i]->state = PAGE_STATE_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
readwrite(void *_cacheRef, off_t offset, addr_t bufferBase, size_t *_size, bool doWrite)
|
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;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
vm_cache_ref *cache = ref->cache;
|
vm_cache_ref *cache = ref->cache;
|
||||||
off_t fileSize = ((vnode_store *)cache->cache->store)->size;
|
off_t fileSize = cache->cache->virtual_size;
|
||||||
|
|
||||||
TRACE(("readwrite(ref = %p, offset = %Ld, buffer = %p, size = %lu, %s\n",
|
TRACE(("cache_io(ref = %p, offset = %Ld, buffer = %p, size = %lu, %s)\n",
|
||||||
ref, offset, (void *)bufferBase, *_size, doWrite ? "write" : "read"));
|
ref, offset, (void *)bufferBase, *_size, doWrite ? "write" : "read"));
|
||||||
|
|
||||||
// out of bounds access?
|
// out of bounds access?
|
||||||
@@ -427,7 +447,7 @@ readwrite(void *_cacheRef, off_t offset, addr_t bufferBase, size_t *_size, bool
|
|||||||
extern "C" void *
|
extern "C" void *
|
||||||
file_cache_create(mount_id mountID, vnode_id vnodeID, off_t size, int fd)
|
file_cache_create(mount_id mountID, vnode_id vnodeID, off_t size, int fd)
|
||||||
{
|
{
|
||||||
TRACE(("file_cache create(mountID = %ld, vnodeID = %Ld, size = %Ld, fd = %d)\n", mountID, vnodeID, size, fd));
|
TRACE(("file_cache_create(mountID = %ld, vnodeID = %Ld, size = %Ld, fd = %d)\n", mountID, vnodeID, size, fd));
|
||||||
|
|
||||||
file_cache_ref *ref = new file_cache_ref;
|
file_cache_ref *ref = new file_cache_ref;
|
||||||
if (ref == NULL)
|
if (ref == NULL)
|
||||||
@@ -441,14 +461,14 @@ file_cache_create(mount_id mountID, vnode_id vnodeID, off_t size, int fd)
|
|||||||
if (vfs_get_cookie_from_fd(fd, &ref->cookie) != B_OK)
|
if (vfs_get_cookie_from_fd(fd, &ref->cookie) != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
// get the vnode for the object, this also grabs a ref to it
|
// get the vnode for the object
|
||||||
if (vfs_get_vnode(mountID, vnodeID, &ref->vnode) != B_OK)
|
if (vfs_get_vnode(mountID, vnodeID, &ref->vnode) != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
if (vfs_get_vnode_cache(ref->vnode, (void **)&ref->cache) != B_OK)
|
if (vfs_get_vnode_cache(ref->vnode, (void **)&ref->cache) != B_OK)
|
||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
((vnode_store *)ref->cache->cache->store)->size = size;
|
ref->cache->cache->virtual_size = size;
|
||||||
return ref;
|
return ref;
|
||||||
|
|
||||||
err3:
|
err3:
|
||||||
@@ -469,6 +489,8 @@ file_cache_delete(void *_cacheRef)
|
|||||||
if (ref == NULL)
|
if (ref == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
TRACE(("file_cache_delete(ref = %p)\n", ref));
|
||||||
|
|
||||||
vfs_vnode_release_ref(ref->device);
|
vfs_vnode_release_ref(ref->device);
|
||||||
delete ref;
|
delete ref;
|
||||||
}
|
}
|
||||||
@@ -479,17 +501,27 @@ file_cache_set_size(void *_cacheRef, off_t size)
|
|||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
((vnode_store *)(ref->cache->cache->store))->size = size;
|
TRACE(("file_cache_set_size(ref = %p, size = %Ld)\n", ref, size));
|
||||||
// ToDo: remove all pages outside of the new file size!
|
|
||||||
return B_OK;
|
if (ref == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
mutex_lock(&ref->cache->lock);
|
||||||
|
status_t status = vm_cache_resize(ref->cache, size);
|
||||||
|
mutex_unlock(&ref->cache->lock);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" status_t
|
extern "C" status_t
|
||||||
file_cache_sync(void *_cacheRef)
|
file_cache_sync(void *_cacheRef)
|
||||||
{
|
{
|
||||||
// ToDo: implement me!
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
return B_ERROR;
|
if (ref == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
return vm_cache_write_modified(ref->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -498,7 +530,7 @@ file_cache_read_pages(void *_cacheRef, off_t offset, const iovec *vecs, size_t c
|
|||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
return readwrite_pages(ref, offset, vecs, count, _numBytes, false);
|
return pages_io(ref, offset, vecs, count, _numBytes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -507,7 +539,11 @@ file_cache_write_pages(void *_cacheRef, off_t offset, const iovec *vecs, size_t
|
|||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
return readwrite_pages(ref, offset, vecs, count, _numBytes, true);
|
status_t status = pages_io(ref, offset, vecs, count, _numBytes, true);
|
||||||
|
TRACE(("file_cache_write_pages(ref = %p, offset = %Ld, vecs = %p, count = %lu, bytes = %lu) = %ld\n",
|
||||||
|
ref, offset, vecs, count, *_numBytes, status));
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -516,10 +552,10 @@ file_cache_read(void *_cacheRef, off_t offset, void *bufferBase, size_t *_size)
|
|||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu\n",
|
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu)\n",
|
||||||
ref, offset, bufferBase, *_size));
|
ref, offset, bufferBase, *_size));
|
||||||
|
|
||||||
return readwrite(ref, offset, (addr_t)bufferBase, _size, false);
|
return cache_io(ref, offset, (addr_t)bufferBase, _size, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -528,10 +564,11 @@ file_cache_write(void *_cacheRef, off_t offset, const void *buffer, size_t *_siz
|
|||||||
{
|
{
|
||||||
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
|
||||||
|
|
||||||
TRACE(("file_cache_write(ref = %p, offset = %Ld, buffer = %p, size = %lu\n",
|
status_t status = cache_io(ref, offset, (addr_t)const_cast<void *>(buffer), _size, true);
|
||||||
ref, offset, buffer, *_size));
|
TRACE(("file_cache_write(ref = %p, offset = %Ld, buffer = %p, size = %lu) = %ld\n",
|
||||||
|
ref, offset, buffer, *_size, status));
|
||||||
|
|
||||||
return readwrite(ref, offset, (addr_t)const_cast<void *>(buffer), _size, false);
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user