mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-29 13:48:21 +00:00
page cache rewrite
This commit is contained in:
+1
-1
@@ -301,4 +301,4 @@ static void abc_init_routine(void) {
|
||||
__assert(abc_block_cache);
|
||||
}
|
||||
|
||||
INIT_ROUTINE_DEFINE(abc, INIT_ROUTINE_FLAGS_NONE, abc_init_routine, scheduler, trie);
|
||||
INIT_ROUTINE_DEFINE(abc, INIT_ROUTINE_FLAGS_NONE, abc_init_routine, mm_cache, scheduler, trie);
|
||||
|
||||
+4
-21
@@ -1822,7 +1822,6 @@ static int ext2_getpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
static int ext2_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
// only regular files get cached
|
||||
__assert(node->type == V_TYPE_REGULAR);
|
||||
size_t writec;
|
||||
iovec_t iovec = {
|
||||
.addr = MAKE_HHDM(mm_get_page_address(page)),
|
||||
.len = PAGE_SIZE
|
||||
@@ -1830,21 +1829,8 @@ static int ext2_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
|
||||
iovec_iterator_t iovec_iterator;
|
||||
iovec_iterator_init(&iovec_iterator, &iovec, 1);
|
||||
int error = VOP_WRITE(node, &iovec_iterator, PAGE_SIZE, offset, 0, &writec, NULL);
|
||||
|
||||
// its possible that writec is zero here. the condition where this is possible is when
|
||||
// the file is truncated after the check in the page sync function but before it actually is
|
||||
// written back to disk. therefore, we check that the page IS infact truncated if this happens.
|
||||
// if it isn't, something else happened and its not safe to continue.
|
||||
//
|
||||
// TODO: since this check will likely be copied between different filesystem drivers, it could be interesting to have
|
||||
// ext2_putpage take in a (size_t *) pointer and have this check be in whatever function calls VOP_PUTPAGE.
|
||||
|
||||
if (writec == 0) {
|
||||
__assert(page->flags & PAGE_FLAGS_TRUNCATED);
|
||||
}
|
||||
|
||||
return error;
|
||||
size_t writec;
|
||||
return VOP_WRITE(node, &iovec_iterator, PAGE_SIZE, offset, 0, &writec, NULL);
|
||||
}
|
||||
|
||||
static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode_t *targetdir, char *newname, int flags) {
|
||||
@@ -1964,13 +1950,11 @@ static int ext2_rename(vnode_t *sourcedir, vnode_t *source, char *oldname, vnode
|
||||
}
|
||||
|
||||
static int ext2_sync(vnode_t *vnode) {
|
||||
int e = mm_cache_sync_vnode(vnode, 0, UINT64_MAX);
|
||||
int e = mm_cache_sync_vnode(vnode);
|
||||
ext2fs_t *fs = (ext2fs_t *)vnode->vfs;
|
||||
abc_sync(&fs->abc);
|
||||
// TODO don't sync the entire disk but rather only the inodes and blocks
|
||||
VOP_LOCK(fs->backing);
|
||||
int e2 = mm_cache_sync_vnode(fs->backing, 0, UINT64_MAX);
|
||||
VOP_UNLOCK(fs->backing);
|
||||
int e2 = mm_cache_sync_vnode(fs->backing);
|
||||
// only the first errors are reported
|
||||
return e ? e : e2;
|
||||
}
|
||||
@@ -2007,7 +1991,6 @@ static int ext2_inactive(vnode_t *vnode) {
|
||||
__assert(hashtable_remove(&fs->inodetable, &node->id, sizeof(node->id)) == 0);
|
||||
MUTEX_RELEASE(&fs->inodetablelock);
|
||||
|
||||
mm_cache_truncate(vnode, 0);
|
||||
freeinode(fs, &node->inode, node->id);
|
||||
|
||||
slab_free(nodecache, node);
|
||||
|
||||
@@ -200,9 +200,7 @@ static int fatfs_unmount(vfs_t *vfs) {
|
||||
static int fatfs_sync(vfs_t *vfs) {
|
||||
fatfs_t *fatfs = (fatfs_t *)vfs;
|
||||
abc_sync(&fatfs->abc);
|
||||
VOP_LOCK(fatfs->backing);
|
||||
int error = mm_cache_sync_vnode(fatfs->backing, 0, UINT64_MAX);
|
||||
VOP_UNLOCK(fatfs->backing);
|
||||
int error = mm_cache_sync_vnode(fatfs->backing);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -264,19 +262,16 @@ static int fatfs_syncvnode(vnode_t *vnode) {
|
||||
fatnode_t *fatnode = (fatnode_t *)vnode;
|
||||
|
||||
// sync file data
|
||||
int e = mm_cache_sync_vnode(vnode, 0, UINT64_MAX);
|
||||
int e = mm_cache_sync_vnode(vnode);
|
||||
abc_sync(&fs->abc);
|
||||
|
||||
VOP_LOCK(fs->backing);
|
||||
// sync the dent
|
||||
int e2 = 0;
|
||||
if (fatnode->dent_disk_offset)
|
||||
e2 = mm_cache_sync_vnode(fs->backing, fatnode->dent_disk_offset, sizeof(fatfs_dent_t));
|
||||
e2 = mm_cache_sync_vnode(fs->backing);
|
||||
|
||||
// and sync the fats
|
||||
int e3 = mm_cache_sync_vnode(fs->backing, fs->fat_offset, fs->fat_size * fs->fat_count);
|
||||
|
||||
VOP_UNLOCK(fs->backing);
|
||||
int e3 = mm_cache_sync_vnode(fs->backing);
|
||||
|
||||
// only the first errors are reported
|
||||
if (e)
|
||||
@@ -391,7 +386,6 @@ static int fatfs_read(vnode_t *vnode, iovec_iterator_t *iovec_iterator, size_t s
|
||||
static int fatfs_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
// only regular files get cached
|
||||
__assert(node->type == V_TYPE_REGULAR);
|
||||
size_t write_count;
|
||||
iovec_t iovec = {
|
||||
.addr = MAKE_HHDM(mm_get_page_address(page)),
|
||||
.len = PAGE_SIZE
|
||||
@@ -399,23 +393,11 @@ static int fatfs_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
|
||||
iovec_iterator_t iovec_iterator;
|
||||
iovec_iterator_init(&iovec_iterator, &iovec, 1);
|
||||
int error = VOP_WRITE(node, &iovec_iterator, PAGE_SIZE, offset, 0, &write_count, NULL);
|
||||
|
||||
// its possible that write_count is zero here. the condition where this is possible is when
|
||||
// the file is truncated after the check in the page sync function but before it actually is
|
||||
// written back to disk. therefore, we check that the page IS infact truncated if this happens.
|
||||
// if it isn't, something else happened and its not safe to continue.
|
||||
//
|
||||
// TODO: since this check will likely be copied between different filesystem drivers, it could be interesting to have
|
||||
// fatfs_putpage take in a (size_t *) pointer and have this check be in whatever function calls VOP_PUTPAGE.
|
||||
|
||||
if (write_count == 0) {
|
||||
__assert(page->flags & PAGE_FLAGS_TRUNCATED);
|
||||
}
|
||||
|
||||
return error;
|
||||
size_t write_count;
|
||||
return VOP_WRITE(node, &iovec_iterator, PAGE_SIZE, offset, 0, &write_count, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int fatfs_getpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
// only regular files get cached
|
||||
__assert(node->type == V_TYPE_REGULAR);
|
||||
@@ -970,7 +952,6 @@ static int fatfs_inactive(vnode_t *vnode) {
|
||||
__assert(!"fatfs VOP_INACTIVE() with hardlink count >0 is currently unimplemented");
|
||||
} else {
|
||||
// unlinked file having resources released when kernel refcount hits zero
|
||||
mm_cache_truncate(vnode, 0);
|
||||
fatfs_resize_file(fatfs, fatnode, 0);
|
||||
}
|
||||
|
||||
|
||||
+42
-6
@@ -224,6 +224,36 @@ static int tmpfs_root(vfs_t *vfs, vnode_t **vnode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmpfs_rw(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, size_t *done, bool write) {
|
||||
*done = 0;
|
||||
while (*done < size) {
|
||||
uintmax_t current_offset = offset + *done;
|
||||
uintmax_t page_offset = current_offset / PAGE_SIZE * PAGE_SIZE;
|
||||
size_t page_start = current_offset % PAGE_SIZE;
|
||||
size_t copy_size = min(PAGE_SIZE - page_start, size - *done);
|
||||
|
||||
page_t *page;
|
||||
int error = mm_cache_get_page(node, page_offset, 0, &page);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
void *address = MAKE_HHDM(mm_get_page_address(page));
|
||||
if (write)
|
||||
error = iovec_iterator_copy_to_buffer(iovec_iterator, (void *)((uintptr_t)address + page_start), copy_size);
|
||||
else
|
||||
error = iovec_iterator_copy_from_buffer(iovec_iterator, (void *)((uintptr_t)address + page_start), copy_size);
|
||||
mm_release_page(FROM_HHDM(address));
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
*done += copy_size;
|
||||
}
|
||||
|
||||
if (write && *done)
|
||||
((tmpfsnode_t *)node)->attr.mtime = timekeeper_time();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmpfs_read(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) {
|
||||
if (node->type == V_TYPE_DIR)
|
||||
return EISDIR;
|
||||
@@ -231,7 +261,13 @@ static int tmpfs_read(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t si
|
||||
if (node->type != V_TYPE_REGULAR)
|
||||
return EINVAL;
|
||||
|
||||
__assert(!"tmpfs_read is handled by the page cache");
|
||||
tmpfsnode_t *tmpfsnode = (tmpfsnode_t *)node;
|
||||
if (offset >= tmpfsnode->attr.size) {
|
||||
*readc = 0;
|
||||
return 0;
|
||||
}
|
||||
size = min(size, tmpfsnode->attr.size - offset);
|
||||
return tmpfs_rw(node, iovec_iterator, size, offset, readc, false);
|
||||
}
|
||||
|
||||
static int tmpfs_write(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) {
|
||||
@@ -241,7 +277,10 @@ static int tmpfs_write(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t s
|
||||
if (node->type != V_TYPE_REGULAR)
|
||||
return EINVAL;
|
||||
|
||||
__assert(!"tmpfs_read is handled by the page cache");
|
||||
if (size + offset < offset)
|
||||
return EOVERFLOW;
|
||||
__assert(size + offset <= ((tmpfsnode_t *)node)->attr.size);
|
||||
return tmpfs_rw(node, iovec_iterator, size, offset, writec, true);
|
||||
}
|
||||
|
||||
static int tmpfs_access(vnode_t *vnode, mode_t mode, cred_t *cred) {
|
||||
@@ -501,9 +540,6 @@ static int tmpfs_inactive(vnode_t *node) {
|
||||
arch_e9_puts("tmpfs_inactive\n");
|
||||
tmpfsnode_t *tmp_node = (tmpfsnode_t *)node;
|
||||
__assert(tmp_node->attr.nlinks == (node->type == V_TYPE_DIR ? 1 : 0));
|
||||
if (node->type == V_TYPE_REGULAR) {
|
||||
mm_cache_truncate(node, 0);
|
||||
}
|
||||
freenode(tmp_node);
|
||||
return 0;
|
||||
}
|
||||
@@ -535,7 +571,7 @@ static int tmpfs_getpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
void *phyhhdm = MAKE_HHDM(phy);
|
||||
|
||||
mm_hold_page(phy);
|
||||
page->flags |= PAGE_FLAGS_PINNED;
|
||||
__atomic_fetch_or(&page->flags, PAGE_FLAGS_PINNED, __ATOMIC_RELAXED);
|
||||
memset(phyhhdm, 0, PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+24
-48
@@ -152,6 +152,9 @@ int vfs_sync(void) {
|
||||
}
|
||||
|
||||
void vfs_inactive(vnode_t *vnode) {
|
||||
if (vfs_iscacheable(vnode))
|
||||
mm_cache_truncate(vnode, 0);
|
||||
|
||||
if (vnode->type == V_TYPE_SOCKET && vnode->socketbinding) {
|
||||
localsock_leavebinding(vnode);
|
||||
} else if (vnode->type == V_TYPE_FIFO && vnode->fifobinding) {
|
||||
@@ -438,33 +441,14 @@ static void bytestopages(uintmax_t offset, size_t size, uintmax_t *pageoffset, s
|
||||
*pagecount = toppage - *pageoffset;
|
||||
}
|
||||
|
||||
static int writenocache(vnode_t *node, page_t *page, uintmax_t pageoffset) {
|
||||
// don't keep the pages in the cache!
|
||||
// if its a file, do the proper filesystem sync.
|
||||
// if its a block device, sync only the page we just dirtied
|
||||
VOP_LOCK(node);
|
||||
int e;
|
||||
if (node->type == V_TYPE_REGULAR)
|
||||
e = VOP_SYNC(node);
|
||||
else
|
||||
e = mm_cache_sync_vnode(node, pageoffset, PAGE_SIZE);
|
||||
VOP_UNLOCK(node);
|
||||
|
||||
// try to turn it into anonymous memory
|
||||
mm_cache_evict(page);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, size_t *written, int flags) {
|
||||
int err = 0;
|
||||
if (vfs_iscacheable(node)) {
|
||||
bool cacheable = vfs_iscacheable(node);
|
||||
if (cacheable) {
|
||||
*written = 0;
|
||||
// can't write a size 0 buffer
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
// overflow
|
||||
if (size + offset < offset)
|
||||
return EINVAL;
|
||||
|
||||
@@ -502,7 +486,9 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size
|
||||
|
||||
size = min(size + offset, bytesize) - offset;
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheable && (flags & V_FFLAGS_NOCACHE) == 0) {
|
||||
uintmax_t pageoffset, pagecount, startoffset;
|
||||
bytestopages(offset, size, &pageoffset, &pagecount, &startoffset);
|
||||
page_t *page = NULL;
|
||||
@@ -525,15 +511,10 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size
|
||||
mm_cache_make_dirty(page);
|
||||
*written += writesize;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE)
|
||||
err = writenocache(node, page, pageoffset * PAGE_SIZE);
|
||||
|
||||
pageoffset += 1;
|
||||
pagecount -= 1;
|
||||
|
||||
mm_release_page(FROM_HHDM(address));
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
for (uintmax_t offset = 0; offset < pagecount * PAGE_SIZE; offset += PAGE_SIZE) {
|
||||
@@ -554,30 +535,30 @@ int vfs_write_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size
|
||||
mm_cache_make_dirty(page);
|
||||
*written += writesize;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE)
|
||||
err = writenocache(node, page, pageoffset * PAGE_SIZE + offset);
|
||||
|
||||
mm_release_page(FROM_HHDM(address));
|
||||
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
MUTEX_RELEASE(&node->size_lock);
|
||||
if (flags & V_FFLAG_MUST_SYNC)
|
||||
err = mm_cache_sync_vnode(node);
|
||||
|
||||
} else {
|
||||
// special file, just write as its not being cached
|
||||
// Non-cacheable objects and direct I/O bypass the page cache.
|
||||
VOP_LOCK(node);
|
||||
err = VOP_WRITE(node, iovec_iterator, size, offset, flags, written, getcred());
|
||||
VOP_UNLOCK(node);
|
||||
}
|
||||
|
||||
leave:
|
||||
if (cacheable)
|
||||
MUTEX_RELEASE(&node->size_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int vfs_read_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, size_t *bytesread, int flags) {
|
||||
int err = 0;
|
||||
if (vfs_iscacheable(node)) {
|
||||
bool cacheable = vfs_iscacheable(node);
|
||||
if (cacheable) {
|
||||
*bytesread = 0;
|
||||
// can't read 0 bytes from the cache
|
||||
if (size == 0)
|
||||
@@ -615,7 +596,9 @@ int vfs_read_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size,
|
||||
goto leave;
|
||||
|
||||
size = min(size + offset, nodesize) - offset;
|
||||
}
|
||||
|
||||
if (cacheable && (flags & V_FFLAGS_NOCACHE) == 0) {
|
||||
uintmax_t pageoffset, pagecount, startoffset;
|
||||
bytestopages(offset, size, &pageoffset, &pagecount, &startoffset);
|
||||
page_t *page = NULL;
|
||||
@@ -637,11 +620,6 @@ int vfs_read_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size,
|
||||
|
||||
*bytesread += readsize;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
// try to turn it into anonymous memory
|
||||
mm_cache_evict(page);
|
||||
}
|
||||
|
||||
pageoffset += 1;
|
||||
pagecount -= 1;
|
||||
|
||||
@@ -664,20 +642,18 @@ int vfs_read_iovec(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size,
|
||||
}
|
||||
|
||||
*bytesread += readsize;
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
// try to turn it into anonymous memory
|
||||
mm_cache_evict(page);
|
||||
}
|
||||
mm_release_page(FROM_HHDM(address));
|
||||
}
|
||||
leave:
|
||||
MUTEX_RELEASE(&node->size_lock);
|
||||
} else {
|
||||
// special file, just read as size doesn't matter
|
||||
// Non-cacheable objects and direct I/O bypass the page cache.
|
||||
VOP_LOCK(node);
|
||||
err = VOP_READ(node, iovec_iterator, size, offset, flags, bytesread, getcred());
|
||||
VOP_UNLOCK(node);
|
||||
}
|
||||
|
||||
leave:
|
||||
if (cacheable)
|
||||
MUTEX_RELEASE(&node->size_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user