mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
syscalls: fsync
This commit is contained in:
@@ -65,6 +65,7 @@ extern syscall_sigreturn
|
||||
extern syscall_uname
|
||||
extern syscall_hostname
|
||||
extern syscall_sync
|
||||
extern syscall_fsync
|
||||
syscalltab:
|
||||
dq syscall_print
|
||||
dq syscall_mmap
|
||||
@@ -132,7 +133,8 @@ dq syscall_sigreturn
|
||||
dq syscall_uname
|
||||
dq syscall_hostname
|
||||
dq syscall_sync
|
||||
syscallcount equ 66
|
||||
dq syscall_fsync
|
||||
syscallcount equ 67
|
||||
section .text
|
||||
global arch_syscall_entry
|
||||
; on entry:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#ifdef SYSCALL_LOGGING
|
||||
|
||||
#define SYSCALL_COUNT 66
|
||||
#define SYSCALL_COUNT 67
|
||||
#define LOGSTR(x) arch_e9_puts(x)
|
||||
|
||||
static char *name[] = {
|
||||
@@ -73,7 +73,8 @@ static char *name[] = {
|
||||
"sigreturn",
|
||||
"uname",
|
||||
"hostname",
|
||||
"sync"
|
||||
"sync",
|
||||
"fsync"
|
||||
};
|
||||
|
||||
static char *args[] = {
|
||||
@@ -142,7 +143,8 @@ static char *args[] = {
|
||||
"N/A", // sigreturn
|
||||
"utsname %p", // uname
|
||||
"new %p newsize %lu old %p oldsize %lu", // hostname
|
||||
"N/A" // sync
|
||||
"N/A", // sync
|
||||
"fd %d" // fsync
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+11
-1
@@ -1654,6 +1654,15 @@ static int ext2_rename(vnode_t *sourcedir, char *oldname, vnode_t *targetdir, ch
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext2_sync(vnode_t *vnode) {
|
||||
int e = vmmcache_sync(vnode);
|
||||
ext2fs_t *fs = (ext2fs_t *)vnode->vfs;
|
||||
// TODO don't sync the entire disk but rather only the inodes and blocks
|
||||
int e2 = vmmcache_sync(fs->backing);
|
||||
// only the first errors are reported
|
||||
return e ? e : e2;
|
||||
}
|
||||
|
||||
static int ext2_inactive(vnode_t *vnode) {
|
||||
ext2node_t *node = (ext2node_t *)vnode;
|
||||
ext2fs_t *fs = (ext2fs_t *)vnode->vfs;
|
||||
@@ -1829,7 +1838,8 @@ static vops_t vnops = {
|
||||
.inactive = ext2_inactive,
|
||||
.rename = ext2_rename,
|
||||
.getpage = ext2_getpage,
|
||||
.putpage = ext2_putpage
|
||||
.putpage = ext2_putpage,
|
||||
.sync = ext2_sync
|
||||
};
|
||||
|
||||
void ext2_init() {
|
||||
|
||||
@@ -260,7 +260,8 @@ static vops_t vnops = {
|
||||
.resize = pipefs_enodev,
|
||||
.rename = pipefs_enodev,
|
||||
.putpage = pipefs_enodev,
|
||||
.getpage = pipefs_enodev
|
||||
.getpage = pipefs_enodev,
|
||||
.sync = pipefs_enodev
|
||||
};
|
||||
|
||||
static void ctor(scache_t *cache, void *obj) {
|
||||
|
||||
@@ -186,7 +186,8 @@ static vops_t vnops = {
|
||||
.rename = sockfs_enodev,
|
||||
.ioctl = sockfs_ioctl,
|
||||
.putpage = sockfs_enodev,
|
||||
.getpage = sockfs_enodev
|
||||
.getpage = sockfs_enodev,
|
||||
.sync = sockfs_enodev
|
||||
};
|
||||
|
||||
static void ctor(scache_t *cache, void *obj) {
|
||||
|
||||
@@ -493,6 +493,11 @@ static int tmpfs_putpage(vnode_t *node, uintmax_t offset, struct page_t *page) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmpfs_sync(vnode_t *node) {
|
||||
// sync is a no-op on tmpfs
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vfsops_t vfsops = {
|
||||
.mount = tmpfs_mount,
|
||||
.root = tmpfs_root
|
||||
@@ -520,7 +525,8 @@ static vops_t vnops = {
|
||||
.resize = tmpfs_resize,
|
||||
.rename = tmpfs_rename,
|
||||
.getpage = tmpfs_getpage,
|
||||
.putpage = tmpfs_putpage
|
||||
.putpage = tmpfs_putpage,
|
||||
.sync = tmpfs_sync
|
||||
};
|
||||
|
||||
static tmpfsnode_t *newnode(vfs_t *vfs, int type) {
|
||||
|
||||
@@ -105,6 +105,7 @@ typedef struct vops_t {
|
||||
int (*rename)(vnode_t *source, char *oldname, vnode_t *target, char *newname, int flags);
|
||||
int (*getpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
||||
int (*putpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
||||
int (*sync)(vnode_t *node);
|
||||
} vops_t;
|
||||
|
||||
#define VFS_INIT(v, o, f) \
|
||||
@@ -156,6 +157,7 @@ typedef struct vops_t {
|
||||
#define VOP_RENAME(s, o, t, n, f) (s)->ops->rename(s, o, t, n, f)
|
||||
#define VOP_GETPAGE(v, o, p) (v)->ops->getpage(v, o, p)
|
||||
#define VOP_PUTPAGE(v, o, p) (v)->ops->putpage(v, o, p)
|
||||
#define VOP_SYNC(v) (v)->ops->sync(v)
|
||||
#define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
|
||||
#define VOP_RELEASE(v) {\
|
||||
if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\
|
||||
|
||||
@@ -9,7 +9,7 @@ int vmmcache_getpage(vnode_t *vnode, uintmax_t offset, page_t **res);
|
||||
int vmmcache_takepage(page_t *page);
|
||||
int vmmcache_makedirty(page_t *page);
|
||||
int vmmcache_truncate(vnode_t *vnode, uintmax_t offset);
|
||||
int vmmcache_syncvnode(vnode_t *vnode);
|
||||
int vmmcache_syncvnode(vnode_t *vnode, uintmax_t startoffset, size_t size);
|
||||
int vmmcache_sync();
|
||||
|
||||
#endif
|
||||
|
||||
+65
-13
@@ -232,12 +232,73 @@ int vmmcache_truncate(vnode_t *vnode, uintmax_t offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vmmcache_syncvnode(vnode_t *vnode) {
|
||||
__assert(!"unimplemented");
|
||||
// called with lock held
|
||||
// returns with lock released
|
||||
static int syncpage(page_t *page) {
|
||||
__assert(page->flags & PAGE_FLAGS_DIRTY);
|
||||
page->flags &= ~PAGE_FLAGS_DIRTY;
|
||||
RELEASE_LOCK();
|
||||
int e = 0;
|
||||
if ((page->flags & PAGE_FLAGS_TRUNCATED) == 0) {
|
||||
e = VOP_PUTPAGE(page->backing, page->offset, (page_t *)page);
|
||||
VOP_RELEASE(page->backing);
|
||||
}
|
||||
|
||||
pmm_release(pmm_getpageaddress((page_t *)page));
|
||||
return e;
|
||||
}
|
||||
|
||||
static page_t *dirtylist;
|
||||
|
||||
int vmmcache_syncvnode(vnode_t *vnode, uintmax_t offset, size_t size) {
|
||||
offset = ROUND_DOWN(offset, PAGE_SIZE);
|
||||
uintmax_t top = offset + size;
|
||||
// overflow check
|
||||
__assert(top > offset);
|
||||
HOLD_LOCK();
|
||||
|
||||
// loop through all vnode pages in memory and check which ones are in the range and are dirty
|
||||
// TODO create a proper vnode dirty list as to not have to loop through the ENTIRE thing in memory
|
||||
page_t *page = vnode->pages;
|
||||
page_t *vnodedirtylist = NULL;
|
||||
for (; page; page = page->vnodenext) {
|
||||
if (page->offset < offset || page->offset >= top)
|
||||
continue;
|
||||
|
||||
// remove from write list and add to an internal list using the write pointers
|
||||
// in a singly linked list way
|
||||
if (page->writenext)
|
||||
page->writenext->writeprev = page->writeprev;
|
||||
|
||||
if (page->writeprev)
|
||||
page->writeprev->writenext = page->writenext;
|
||||
else
|
||||
dirtylist = page->writenext;
|
||||
|
||||
page->writenext = vnodedirtylist;
|
||||
page->writeprev = NULL;
|
||||
vnodedirtylist = page;
|
||||
}
|
||||
|
||||
RELEASE_LOCK();
|
||||
|
||||
int e = 0;
|
||||
while (vnodedirtylist) {
|
||||
// in the case of failure, only the first error to occur will be reported and we will not
|
||||
// retry the write and keep on syncing the pages to disk
|
||||
HOLD_LOCK();
|
||||
page_t *page = vnodedirtylist;
|
||||
vnodedirtylist = vnodedirtylist->writenext;
|
||||
page->writenext = NULL;
|
||||
int error = syncpage(page);
|
||||
if (e == 0)
|
||||
e = error;
|
||||
// syncpage returns with lock released
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
int vmmcache_sync() {
|
||||
polldesc_t polldesc = {0};
|
||||
int e = poll_initdesc(&polldesc, 1);
|
||||
@@ -313,22 +374,13 @@ static void writer() {
|
||||
continue;
|
||||
}
|
||||
|
||||
__assert(page->flags & PAGE_FLAGS_DIRTY);
|
||||
page->flags &= ~PAGE_FLAGS_DIRTY;
|
||||
|
||||
dirtylist = page->writenext;
|
||||
if (dirtylist)
|
||||
dirtylist->writeprev = NULL;
|
||||
|
||||
page->writenext = NULL;
|
||||
|
||||
RELEASE_LOCK();
|
||||
if ((page->flags & PAGE_FLAGS_TRUNCATED) == 0) {
|
||||
VOP_PUTPAGE(page->backing, page->offset, (page_t *)page);
|
||||
VOP_RELEASE(page->backing);
|
||||
}
|
||||
|
||||
pmm_release(pmm_getpageaddress((page_t *)page));
|
||||
// TODO notify error on vmmcache_syncvnode
|
||||
syncpage((page_t *)page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,3 +6,20 @@ syscallret_t syscall_sync(context_t *) {
|
||||
vmmcache_sync();
|
||||
return ret;
|
||||
}
|
||||
|
||||
syscallret_t syscall_fsync(context_t *context, int fd) {
|
||||
syscallret_t ret = {
|
||||
.ret = -1
|
||||
};
|
||||
|
||||
file_t *file = fd_get(fd);
|
||||
if (file == NULL) {
|
||||
ret.errno = EBADF;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret.errno = VOP_SYNC(file->vnode);
|
||||
|
||||
fd_release(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user