From 8bc9542f9dadb9a99f92c20af3291a048e3a75fd Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Wed, 21 Aug 2024 11:58:32 -0400
Subject: kernel: vfs: Add sys_close()

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/include/sys/syscall.h |  1 +
 sys/include/sys/vfs.h     |  1 +
 sys/kern/kern_syscall.c   |  1 +
 sys/kern/vfs_syscalls.c   | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 38 insertions(+)

diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index 9aa96e7..4df3825 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -39,6 +39,7 @@
 #define SYS_exit    1
 #define SYS_open    2
 #define SYS_read    3
+#define SYS_close   4
 
 #if defined(_KERNEL)
 /* Syscall return value and arg type */
diff --git a/sys/include/sys/vfs.h b/sys/include/sys/vfs.h
index 52d35f3..776ee66 100644
--- a/sys/include/sys/vfs.h
+++ b/sys/include/sys/vfs.h
@@ -36,6 +36,7 @@
 #if defined(_KERNEL)
 
 scret_t sys_open(struct syscall_args *scargs);
+scret_t sys_close(struct syscall_args *args);
 scret_t sys_read(struct syscall_args *scargs);
 
 #endif  /* _KERNEL */
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index 416a8ec..b36c6af 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -37,6 +37,7 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
     sys_exit,   /* SYS_exit */
     sys_open,   /* SYS_open */
     sys_read,   /* SYS_read */
+    sys_close,  /* SYS_close */
 };
 
 const size_t MAX_SYSCALLS = NELEM(g_sctab);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 937ae87..77070ab 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -34,6 +34,7 @@
 #include <sys/errno.h>
 #include <sys/sio.h>
 #include <sys/filedesc.h>
+#include <sys/atomic.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/limits.h>
@@ -139,6 +140,40 @@ sys_open(struct syscall_args *scargs)
     return filedes->fdno;
 }
 
+/*
+ * arg0: fd
+ */
+scret_t
+sys_close(struct syscall_args *args)
+{
+    struct filedesc *filedes;
+    struct proc *td;
+    int fd = args->arg0;
+
+    if ((filedes = fd_get(fd)) == NULL) {
+        return -EBADF;
+    }
+
+    /* Return if other threads still hold a ref */
+    if (atomic_dec_int(&filedes->refcnt) > 0) {
+        return 0;
+    }
+
+    td = this_td();
+
+    /*
+     * Each file descriptor structure references a vnode,
+     * we want to reclaim it or at the very least drop
+     * one of its references. After we've cleaned up within
+     * the file descriptor, we can clear it from the fd table
+     * and free up the memory for it.
+     */
+    vfs_release_vnode(filedes->vp);
+    td->fds[fd] = NULL;
+    dynfree(filedes);
+    return 0;
+}
+
 /*
  * arg0: fd
  * arg1: buf
-- 
cgit v1.2.3