mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
vfs: support for uncached read/write
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <logging.h>
|
||||
#include <arch/e9.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <kernel/vmmcache.h>
|
||||
|
||||
#ifdef SYSCALL_LOGGING
|
||||
|
||||
@@ -158,7 +159,7 @@ __attribute__((no_caller_saved_registers)) void arch_syscall_log(int syscall, ui
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread->proc;
|
||||
snprintf(argbuff, 768, syscall < SYSCALL_COUNT ? args[syscall] : "N/A", a1, a2, a3, a4, a5, a6);
|
||||
snprintf(printbuff, 1024, "\e[92msyscall: pid %d tid %d: %s: %s (%lu free pages)\n\e[0m", proc->pid, thread->tid, syscall < SYSCALL_COUNT ? name[syscall] : "invalid syscall", argbuff, freepagecount);
|
||||
snprintf(printbuff, 1024, "\e[92msyscall: pid %d tid %d: %s: %s (%lu cached pages, %lu free pages)\n\e[0m", proc->pid, thread->tid, syscall < SYSCALL_COUNT ? name[syscall] : "invalid syscall", argbuff, vmmcache_cachedpages, freepagecount);
|
||||
|
||||
LOGSTR(printbuff);
|
||||
#endif
|
||||
@@ -171,7 +172,7 @@ __attribute__((no_caller_saved_registers)) void arch_syscall_log_return(uint64_t
|
||||
thread_t *thread = _cpu()->thread;
|
||||
proc_t *proc = thread->proc;
|
||||
|
||||
snprintf(printbuff, 1024, "\e[94msyscall return: pid %d tid %d: %lu %lu (%lu free pages)\n\e[0m", proc->pid, thread->tid, ret, errno, freepagecount);
|
||||
snprintf(printbuff, 1024, "\e[94msyscall return: pid %d tid %d: %lu %lu (%lu cached pages, %lu free pages)\n\e[0m", proc->pid, thread->tid, ret, errno, vmmcache_cachedpages, freepagecount);
|
||||
LOGSTR(printbuff);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/timekeeper.h>
|
||||
#include <kernel/pmm.h>
|
||||
#include <kernel/vmmcache.h>
|
||||
|
||||
static devnode_t *devfsroot;
|
||||
|
||||
@@ -354,6 +355,10 @@ static int devfs_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
return error;
|
||||
}
|
||||
|
||||
static int devfs_sync(vnode_t *vnode) {
|
||||
return vmmcache_sync(vnode);
|
||||
}
|
||||
|
||||
static int devfs_enodev() {
|
||||
return ENODEV;
|
||||
}
|
||||
@@ -388,7 +393,8 @@ static vops_t vnops = {
|
||||
.resize = devfs_enodev,
|
||||
.rename = devfs_enodev,
|
||||
.putpage = devfs_putpage,
|
||||
.getpage = devfs_getpage
|
||||
.getpage = devfs_getpage,
|
||||
.sync = devfs_sync
|
||||
};
|
||||
|
||||
static void ctor(scache_t *cache, void *obj) {
|
||||
|
||||
+24
-24
@@ -211,7 +211,7 @@ static scache_t *nodecache;
|
||||
|
||||
static int syncsuperblock(ext2fs_t *fs) {
|
||||
size_t tmp;
|
||||
return vfs_write(fs->backing, &fs->superblock, sizeof(ext2superblock_t), SUPERBLOCK_OFFSET, &tmp, 0);
|
||||
return vfs_write(fs->backing, &fs->superblock, sizeof(ext2superblock_t), SUPERBLOCK_OFFSET, &tmp, V_FFLAGS_NOCACHE);
|
||||
}
|
||||
|
||||
static int changedircount(ext2fs_t *fs, int bg, int change) {
|
||||
@@ -723,7 +723,7 @@ static int resizeinode(ext2fs_t *fs, ext2node_t *node, size_t newsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rwblocks(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t index, bool write) {
|
||||
static int rwblocks(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t index, bool write, bool cache) {
|
||||
for (uintmax_t i = 0; i < count; ++i) {
|
||||
void *bufferp = (void *)((uintptr_t)buffer + i * fs->blocksize);
|
||||
blockptr_t block;
|
||||
@@ -735,8 +735,8 @@ static int rwblocks(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count,
|
||||
|
||||
size_t donecount;
|
||||
e = write ?
|
||||
vfs_write(fs->backing, bufferp, fs->blocksize, BLOCK_GETDISKOFFSET(fs, block), &donecount, 0) :
|
||||
vfs_read(fs->backing, bufferp, fs->blocksize, BLOCK_GETDISKOFFSET(fs, block), &donecount, 0);
|
||||
vfs_write(fs->backing, bufferp, fs->blocksize, BLOCK_GETDISKOFFSET(fs, block), &donecount, cache ? 0 : V_FFLAGS_NOCACHE) :
|
||||
vfs_read(fs->backing, bufferp, fs->blocksize, BLOCK_GETDISKOFFSET(fs, block), &donecount, cache ? 0 : V_FFLAGS_NOCACHE);
|
||||
|
||||
if (e)
|
||||
return e;
|
||||
@@ -746,7 +746,7 @@ static int rwblocks(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rwblock(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t offset, uintmax_t index, bool write) {
|
||||
static int rwblock(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t offset, uintmax_t index, bool write, bool cache) {
|
||||
__assert(offset + count <= fs->blocksize);
|
||||
blockptr_t block;
|
||||
int e = getinodeblock(fs, node, index, &block);
|
||||
@@ -757,8 +757,8 @@ static int rwblock(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, u
|
||||
|
||||
size_t donecount;
|
||||
e = write ?
|
||||
vfs_write(fs->backing, buffer, count, BLOCK_GETDISKOFFSET(fs, block) + offset, &donecount, 0) :
|
||||
vfs_read(fs->backing, buffer, count, BLOCK_GETDISKOFFSET(fs, block) + offset, &donecount, 0);
|
||||
vfs_write(fs->backing, buffer, count, BLOCK_GETDISKOFFSET(fs, block) + offset, &donecount, cache ? 0 : V_FFLAGS_NOCACHE) :
|
||||
vfs_read(fs->backing, buffer, count, BLOCK_GETDISKOFFSET(fs, block) + offset, &donecount, cache ? 0 : V_FFLAGS_NOCACHE);
|
||||
|
||||
if (e)
|
||||
return e;
|
||||
@@ -767,7 +767,7 @@ static int rwblock(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, u
|
||||
return e;
|
||||
}
|
||||
|
||||
static int rwbytes(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t offset, bool write) {
|
||||
static int rwbytes(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, uintmax_t offset, bool write, bool cache) {
|
||||
uintmax_t index = offset / fs->blocksize;
|
||||
uintmax_t startoffset = offset % fs->blocksize;
|
||||
|
||||
@@ -775,7 +775,7 @@ static int rwbytes(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, u
|
||||
if (startoffset) {
|
||||
size_t blockremaining = fs->blocksize - startoffset;
|
||||
size_t docount = min(blockremaining, count);
|
||||
int e = rwblock(fs, node, buffer, docount, startoffset, index, write);
|
||||
int e = rwblock(fs, node, buffer, docount, startoffset, index, write, cache);
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
@@ -787,7 +787,7 @@ static int rwbytes(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, u
|
||||
// r/w all middle blocks
|
||||
size_t blocks = count / fs->blocksize;
|
||||
if (blocks) {
|
||||
int e = rwblocks(fs, node, buffer, blocks, index, write);
|
||||
int e = rwblocks(fs, node, buffer, blocks, index, write, cache);
|
||||
if (e)
|
||||
return e;
|
||||
|
||||
@@ -797,7 +797,7 @@ static int rwbytes(ext2fs_t *fs, ext2node_t *node, void *buffer, size_t count, u
|
||||
}
|
||||
|
||||
// r/w remaining block if there's any data left and return
|
||||
return count ? rwblock(fs, node, buffer, count, 0, index, write) : 0;
|
||||
return count ? rwblock(fs, node, buffer, count, 0, index, write, cache) : 0;
|
||||
}
|
||||
|
||||
#define BUFFER_MAP_FLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC)
|
||||
@@ -808,7 +808,7 @@ static int findindir(ext2fs_t *fs, ext2node_t *node, char *name, int *inode, ext
|
||||
if (dirbuffer == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
int err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false);
|
||||
int err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false, true);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
@@ -825,7 +825,7 @@ static int findindir(ext2fs_t *fs, ext2node_t *node, char *name, int *inode, ext
|
||||
if (switchnode) {
|
||||
dent->inode = switchnode->id;
|
||||
dent->type = vfstoext2denttypetable[switchnode->vnode.type];
|
||||
err = rwbytes(fs, node, dent, dent->size, offset, true);
|
||||
err = rwbytes(fs, node, dent, dent->size, offset, true, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -865,7 +865,7 @@ static int insertdent(ext2fs_t *fs, ext2node_t *node, char *name, int inode, int
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
err = rwbytes(fs, node, dirbuffer, inodesize, 0, false);
|
||||
err = rwbytes(fs, node, dirbuffer, inodesize, 0, false, true);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
@@ -891,14 +891,14 @@ static int insertdent(ext2fs_t *fs, ext2node_t *node, char *name, int inode, int
|
||||
goto cleanup;
|
||||
|
||||
dentbuffer->size = fs->blocksize;
|
||||
err = rwbytes(fs, node, dentbuffer, entlen, inodesize, true);
|
||||
err = rwbytes(fs, node, dentbuffer, entlen, inodesize, true, true);
|
||||
ASSERT_UNCLEAN(fs, err == 0);
|
||||
} else {
|
||||
size_t writesize = splitdent->size;
|
||||
splitdent->size = truesize;
|
||||
dentbuffer->size = freesize;
|
||||
memcpy((void *)((uintptr_t)splitdent + truesize), dentbuffer, entlen);
|
||||
err = rwbytes(fs, node, splitdent, writesize, offset, true);
|
||||
err = rwbytes(fs, node, splitdent, writesize, offset, true, true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@@ -914,7 +914,7 @@ static int removedent(ext2fs_t *fs, ext2node_t *node, char *name, int *inode) {
|
||||
if (dirbuffer == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
int err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false);
|
||||
int err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false, true);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
@@ -948,11 +948,11 @@ static int removedent(ext2fs_t *fs, ext2node_t *node, char *name, int *inode) {
|
||||
|
||||
if (offset % fs->blocksize) { // can expand last dent size?
|
||||
lastdent->size += dent->size;
|
||||
err = rwbytes(fs, node, lastdent, lastdent->size, offset - lastsize, true);
|
||||
err = rwbytes(fs, node, lastdent, lastdent->size, offset - lastsize, true, true);
|
||||
} else { // nope, set current as unused
|
||||
dent->inode = 0;
|
||||
dent->name[0] = '\0';
|
||||
err = rwbytes(fs, node, dent, dent->size, offset, true);
|
||||
err = rwbytes(fs, node, dent, dent->size, offset, true, true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@@ -1152,7 +1152,7 @@ static int ext2_getdents(vnode_t *vnode, dent_t *buffer, size_t count, uintmax_t
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false);
|
||||
err = rwbytes(fs, node, dirbuffer, INODE_SIZE(&node->inode), 0, false, true);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
@@ -1207,7 +1207,7 @@ static int ext2_readlink(vnode_t *vnode, char **link, cred_t *cred) {
|
||||
// if the length of a symlink is larger than 60 bytes, its stored normally
|
||||
// otherwise, its stored in the inode strucutre itself
|
||||
if (linksize > 60)
|
||||
err = rwbytes(fs, node, buf, linksize, 0, false);
|
||||
err = rwbytes(fs, node, buf, linksize, 0, false, true);
|
||||
else
|
||||
memcpy(buf, node->inode.directpointer, linksize);
|
||||
|
||||
@@ -1248,7 +1248,7 @@ static int ext2_read(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset
|
||||
if (size == 0)
|
||||
goto cleanup;
|
||||
|
||||
err = rwbytes(fs, node, buffer, size, offset, false);
|
||||
err = rwbytes(fs, node, buffer, size, offset, false, false);
|
||||
|
||||
*readc = err ? -1 : size;
|
||||
|
||||
@@ -1278,7 +1278,7 @@ int ext2_write(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset, int
|
||||
size = min(endoffset, inodesize) - offset;
|
||||
}
|
||||
|
||||
err = rwbytes(fs, node, buffer, size, offset, true);
|
||||
err = rwbytes(fs, node, buffer, size, offset, true, false);
|
||||
*writec = err ? -1 : size;
|
||||
if (err)
|
||||
goto cleanup;
|
||||
@@ -1441,7 +1441,7 @@ static int ext2_symlink(vnode_t *vnode, char *name, vattr_t *attr, char *path, c
|
||||
if (err)
|
||||
goto cleanup;
|
||||
|
||||
err = rwbytes(fs, newnode, path, linklen, 0, true);
|
||||
err = rwbytes(fs, newnode, path, linklen, 0, true, true);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
+41
-6
@@ -154,9 +154,24 @@ 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
|
||||
int e;
|
||||
if (node->type == V_TYPE_REGULAR)
|
||||
e = VOP_SYNC(node);
|
||||
else
|
||||
e = vmmcache_syncvnode(node, pageoffset, PAGE_SIZE);
|
||||
|
||||
// try to turn it into anonymous memory
|
||||
vmmcache_evict(page);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t *written, int flags) {
|
||||
int err;
|
||||
// TODO skip caching flag, cred check
|
||||
if (node->type == V_TYPE_REGULAR || node->type == V_TYPE_BLKDEV) {
|
||||
*written = 0;
|
||||
// can't write a size 0 buffer
|
||||
@@ -211,10 +226,16 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
|
||||
void *address = MAKE_HHDM(pmm_getpageaddress(page));
|
||||
memcpy((void *)((uintptr_t)address + startoffset), buffer, writesize);
|
||||
vmmcache_makedirty(page);
|
||||
pmm_release(FROM_HHDM(address));
|
||||
*written += writesize;
|
||||
pageoffset += 1;
|
||||
pagecount -= 1;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
err = writenocache(node, page, pageoffset * PAGE_SIZE);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
pmm_release(FROM_HHDM(address));
|
||||
}
|
||||
|
||||
for (uintmax_t offset = 0; offset < pagecount * PAGE_SIZE; offset += PAGE_SIZE) {
|
||||
@@ -227,8 +248,14 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
|
||||
void *address = MAKE_HHDM(pmm_getpageaddress(page));
|
||||
memcpy(address, (void *)((uintptr_t)buffer + *written), writesize);
|
||||
vmmcache_makedirty(page);
|
||||
pmm_release(FROM_HHDM(address));
|
||||
*written += writesize;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
err = writenocache(node, page, pageoffset * PAGE_SIZE + offset);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
pmm_release(FROM_HHDM(address));
|
||||
}
|
||||
|
||||
leave:
|
||||
@@ -242,7 +269,6 @@ int vfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
|
||||
}
|
||||
|
||||
int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t *bytesread, int flags) {
|
||||
// TODO skip caching flag, cred check
|
||||
int err;
|
||||
if (node->type == V_TYPE_REGULAR || node->type == V_TYPE_BLKDEV) {
|
||||
*bytesread = 0;
|
||||
@@ -294,10 +320,15 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
|
||||
size_t readsize = min(PAGE_SIZE - startoffset, size);
|
||||
void *address = MAKE_HHDM(pmm_getpageaddress(page));
|
||||
memcpy(buffer, (void *)((uintptr_t)address + startoffset), readsize);
|
||||
pmm_release(FROM_HHDM(address));
|
||||
*bytesread += readsize;
|
||||
pageoffset += 1;
|
||||
pagecount -= 1;
|
||||
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
// try to turn it into anonymous memory
|
||||
vmmcache_evict(page);
|
||||
}
|
||||
pmm_release(FROM_HHDM(address));
|
||||
}
|
||||
|
||||
for (uintmax_t offset = 0; offset < pagecount * PAGE_SIZE; offset += PAGE_SIZE) {
|
||||
@@ -309,8 +340,12 @@ int vfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, size_t
|
||||
size_t readsize = min(PAGE_SIZE, size - *bytesread);
|
||||
void *address = MAKE_HHDM(pmm_getpageaddress(page));
|
||||
memcpy((void *)((uintptr_t)buffer + *bytesread), address, readsize);
|
||||
pmm_release(FROM_HHDM(address));
|
||||
*bytesread += readsize;
|
||||
if (flags & V_FFLAGS_NOCACHE) {
|
||||
// try to turn it into anonymous memory
|
||||
vmmcache_evict(page);
|
||||
}
|
||||
pmm_release(FROM_HHDM(address));
|
||||
}
|
||||
|
||||
leave:
|
||||
|
||||
@@ -47,6 +47,7 @@ int fd_clone(proc_t *proc);
|
||||
#define O_NONBLOCK 04000
|
||||
#define O_DSYNC 010000
|
||||
#define O_ASYNC 020000
|
||||
#define O_DIRECT 040000
|
||||
#define O_LARGEFILE 0100000
|
||||
#define O_DIRECTORY 0200000
|
||||
#define O_NOFOLLOW 0400000
|
||||
@@ -66,6 +67,8 @@ static inline int fileflagstovnodeflags(int flags) {
|
||||
vnflags |= V_FFLAGS_NONBLOCKING;
|
||||
if (flags & O_NOCTTY)
|
||||
vnflags |= V_FFLAGS_NOCTTY;
|
||||
if (flags & (O_DIRECT | O_SYNC | O_DSYNC))
|
||||
vnflags |= V_FFLAGS_NOCACHE;
|
||||
|
||||
return vnflags;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ typedef struct vfs_t {
|
||||
#define V_FFLAGS_SHARED 8
|
||||
#define V_FFLAGS_EXEC 16
|
||||
#define V_FFLAGS_NOCTTY 32
|
||||
#define V_FFLAGS_NOCACHE 64
|
||||
|
||||
typedef struct vnode_t {
|
||||
struct vops_t *ops;
|
||||
|
||||
Reference in New Issue
Block a user