diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index b4ef52b0..f1eaa7f2 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -1,6 +1,7 @@ #include #include #include +#include #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 } diff --git a/kernel-src/fs/devfs.c b/kernel-src/fs/devfs.c index 1570c328..b018c82c 100644 --- a/kernel-src/fs/devfs.c +++ b/kernel-src/fs/devfs.c @@ -7,6 +7,7 @@ #include #include #include +#include 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) { diff --git a/kernel-src/fs/ext2.c b/kernel-src/fs/ext2.c index d80d5af9..d9bc177e 100644 --- a/kernel-src/fs/ext2.c +++ b/kernel-src/fs/ext2.c @@ -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; } diff --git a/kernel-src/fs/vfs.c b/kernel-src/fs/vfs.c index 60ba04ad..e468dec6 100644 --- a/kernel-src/fs/vfs.c +++ b/kernel-src/fs/vfs.c @@ -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: diff --git a/kernel-src/include/kernel/file.h b/kernel-src/include/kernel/file.h index 1aba4d21..6da8ebef 100644 --- a/kernel-src/include/kernel/file.h +++ b/kernel-src/include/kernel/file.h @@ -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; } diff --git a/kernel-src/include/kernel/vfs.h b/kernel-src/include/kernel/vfs.h index ff24b09a..a0daa853 100644 --- a/kernel-src/include/kernel/vfs.h +++ b/kernel-src/include/kernel/vfs.h @@ -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;