Added functions file_cache_{disable,enable}(). They allow to disable

actual caching in the file cache, i.e. all reads and writes go directly
to the underlying device. The implementation is not quite complete,
since the VM can still add pages to the cache when the file is mmap()ed,
which can lead to inconsistencies.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26779 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-08-04 03:15:50 +00:00
parent 2f462cb8e9
commit 7491000f20
6 changed files with 158 additions and 0 deletions
+2
View File
@@ -73,6 +73,8 @@ extern void block_cache_put(void *_cache, off_t blockNumber);
/* file cache */
extern void *file_cache_create(dev_t mountID, ino_t vnodeID, off_t size);
extern void file_cache_delete(void *_cacheRef);
extern void file_cache_enable(void *_cacheRef);
extern status_t file_cache_disable(void *_cacheRef);
extern status_t file_cache_set_size(void *_cacheRef, off_t size);
extern status_t file_cache_sync(void *_cache);
@@ -828,6 +828,8 @@
/* file cache */
#define file_cache_create fssh_file_cache_create
#define file_cache_delete fssh_file_cache_delete
#define file_cache_enable fssh_file_cache_enable
#define file_cache_disable fssh_file_cache_disable
#define file_cache_set_size fssh_file_cache_set_size
#define file_cache_sync fssh_file_cache_sync
+2
View File
@@ -88,6 +88,8 @@ extern void fssh_block_cache_put(void *_cache,
extern void * fssh_file_cache_create(fssh_mount_id mountID,
fssh_vnode_id vnodeID, fssh_off_t size);
extern void fssh_file_cache_delete(void *_cacheRef);
extern void fssh_file_cache_enable(void *_cacheRef);
extern fssh_status_t fssh_file_cache_disable(void *_cacheRef);
extern fssh_status_t fssh_file_cache_set_size(void *_cacheRef,
fssh_off_t size);
extern fssh_status_t fssh_file_cache_sync(void *_cache);
+92
View File
@@ -49,6 +49,7 @@ struct file_cache_ref {
// significant 31 bits, and make this uint32 (one bit for
// write vs. read)
int32 last_access_index;
uint16 disabled_count;
bool last_access_was_write;
};
@@ -58,6 +59,7 @@ typedef status_t (*cache_func)(file_cache_ref *ref, void *cookie, off_t offset,
static struct cache_module_info *sCacheModule;
static const uint8 kZeroBuffer[4096] = {};
// #pragma mark -
@@ -885,6 +887,7 @@ file_cache_create(dev_t mountID, ino_t vnodeID, off_t size)
memset(ref->last_access, 0, sizeof(ref->last_access));
ref->last_access_index = 0;
ref->disabled_count = 0;
// TODO: delay vm_cache creation until data is
// requested/written for the first time? Listing lots of
@@ -930,6 +933,52 @@ file_cache_delete(void *_cacheRef)
}
extern "C" void
file_cache_enable(void *_cacheRef)
{
file_cache_ref *ref = (file_cache_ref*)_cacheRef;
AutoLocker<VMCache> _(ref->cache);
if (ref->disabled_count == 0) {
panic("Unbalanced file_cache_enable()!");
return;
}
ref->disabled_count--;
}
extern "C" status_t
file_cache_disable(void *_cacheRef)
{
// TODO: This function only removes all pages from the cache and prevents
// that the file cache functions add any new ones until re-enabled. The
// VM (on page fault) can still add pages, if the file is mmap()ed. We
// should mark the cache to prevent shared mappings of the file and fix
// the page fault code to deal correctly with private mappings (i.e. only
// insert pages in consumer caches).
file_cache_ref *ref = (file_cache_ref*)_cacheRef;
AutoLocker<VMCache> _(ref->cache);
// If already disabled, there's nothing to do for us.
if (ref->disabled_count > 0) {
ref->disabled_count++;
return B_OK;
}
// The file cache is not yet disabled. We need to evict all cached pages.
status_t error = ref->cache->FlushAndRemoveAllPages();
if (error != B_OK)
return error;
ref->disabled_count++;
return B_OK;
}
extern "C" status_t
file_cache_set_size(void *_cacheRef, off_t newSize)
{
@@ -974,6 +1023,14 @@ file_cache_read(void *_cacheRef, void *cookie, off_t offset, void *buffer,
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu)\n",
ref, offset, buffer, *_size));
if (ref->disabled_count > 0) {
// Caching is disabled -- read directly from the file.
iovec vec;
vec.iov_base = buffer;
vec.iov_len = *_size;
return vfs_read_pages(ref->vnode, cookie, offset, &vec, 1, 0, _size);
}
return cache_io(ref, cookie, offset, (addr_t)buffer, _size, false);
}
@@ -984,6 +1041,41 @@ file_cache_write(void *_cacheRef, void *cookie, off_t offset,
{
file_cache_ref *ref = (file_cache_ref *)_cacheRef;
if (ref->disabled_count > 0) {
// Caching is disabled -- write directly to the file.
if (buffer != NULL) {
iovec vec;
vec.iov_base = (void*)buffer;
vec.iov_len = *_size;
return vfs_write_pages(ref->vnode, cookie, offset, &vec, 1, 0,
_size);
}
// NULL buffer -- use a dummy buffer to write zeroes
// TODO: This is not particularly efficient!
iovec vec;
vec.iov_base = (void*)kZeroBuffer;
vec.iov_len = sizeof(kZeroBuffer);
size_t size = *_size;
while (size > 0) {
size_t toWrite = min_c(size, vec.iov_len);
size_t written = toWrite;
status_t error = vfs_write_pages(ref->vnode, cookie, offset, &vec,
1, 0, &written);
if (error != B_OK)
return error;
if (written == 0)
break;
offset += written;
size -= written;
}
*_size -= size;
return B_OK;
}
status_t status = cache_io(ref, cookie, offset,
(addr_t)const_cast<void *>(buffer), _size, true);
+45
View File
@@ -792,6 +792,51 @@ VMCache::Resize(off_t newSize)
}
status_t
VMCache::FlushAndRemoveAllPages()
{
while (page_count > 0) {
// write back modified pages
status_t error = WriteModified();
if (error != B_OK)
return error;
// remove pages
for (VMCachePagesTree::Iterator it = pages.GetIterator();
vm_page* page = it.Next();) {
if (page->state == PAGE_STATE_BUSY) {
// wait for page to become unbusy
ConditionVariableEntry entry;
entry.Add(page);
Unlock();
entry.Wait();
Lock();
// restart from the start of the list
it = pages.GetIterator();
continue;
}
// skip modified pages -- they will be written back in the next
// iteration
if (page->state == PAGE_STATE_MODIFIED)
continue;
// We can't remove mapped pages.
if (page->wired_count > 0 || !page->mappings.IsEmpty())
return B_BUSY;
RemovePage(page);
vm_page_free(this, page);
// Note: When iterating through a IteratableSplayTree
// removing the current node is safe.
}
}
return B_OK;
}
status_t
VMCache::Commit(off_t size)
{
+15
View File
@@ -281,6 +281,21 @@ fssh_file_cache_delete(void *_cacheRef)
}
void
fssh_file_cache_enable(void *_cacheRef)
{
fssh_panic("fssh_file_cache_enable() called");
}
fssh_status_t
fssh_file_cache_disable(void *_cacheRef)
{
fssh_panic("fssh_file_cache_disable() called");
return FSSH_B_ERROR;
}
fssh_status_t
fssh_file_cache_set_size(void *_cacheRef, fssh_off_t size)
{