aboutsummaryrefslogtreecommitdiff
path: root/kernel/fs/vnode_specials.c
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/fs/vnode_specials.c
Created student weenix repository
Diffstat (limited to 'kernel/fs/vnode_specials.c')
-rw-r--r--kernel/fs/vnode_specials.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/kernel/fs/vnode_specials.c b/kernel/fs/vnode_specials.c
new file mode 100644
index 0000000..a6c38a3
--- /dev/null
+++ b/kernel/fs/vnode_specials.c
@@ -0,0 +1,176 @@
+#include <errno.h>
+#include <fs/stat.h>
+#include <fs/vfs.h>
+#include <fs/vnode.h>
+#include <util/debug.h>
+
+static long special_file_stat(vnode_t *file, stat_t *ss);
+
+static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
+ size_t count);
+
+static ssize_t chardev_file_write(vnode_t *file, size_t pos, const void *buf,
+ size_t count);
+
+static long chardev_file_mmap(vnode_t *file, mobj_t **ret);
+
+static long chardev_file_fill_pframe(vnode_t *file, pframe_t *pf);
+
+static long chardev_file_flush_pframe(vnode_t *file, pframe_t *pf);
+
+static vnode_ops_t chardev_spec_vops = {
+ .read = chardev_file_read,
+ .write = chardev_file_write,
+ .mmap = chardev_file_mmap,
+ .mknod = NULL,
+ .lookup = NULL,
+ .link = NULL,
+ .unlink = NULL,
+ .mkdir = NULL,
+ .rmdir = NULL,
+ .readdir = NULL,
+ .stat = special_file_stat,
+ .get_pframe = NULL,
+ .fill_pframe = chardev_file_fill_pframe,
+ .flush_pframe = chardev_file_flush_pframe,
+};
+
+static ssize_t blockdev_file_read(vnode_t *file, size_t pos, void *buf,
+ size_t count);
+
+static ssize_t blockdev_file_write(vnode_t *file, size_t pos, const void *buf,
+ size_t count);
+
+static long blockdev_file_mmap(vnode_t *file, mobj_t **ret);
+
+static long blockdev_file_fill_pframe(vnode_t *file, pframe_t *pf);
+
+static long blockdev_file_flush_pframe(vnode_t *file, pframe_t *pf);
+
+static vnode_ops_t blockdev_spec_vops = {
+ .read = blockdev_file_read,
+ .write = blockdev_file_write,
+ .mmap = blockdev_file_mmap,
+ .mknod = NULL,
+ .lookup = NULL,
+ .link = NULL,
+ .unlink = NULL,
+ .mkdir = NULL,
+ .rmdir = NULL,
+ .readdir = NULL,
+ .stat = special_file_stat,
+ .get_pframe = NULL,
+ .fill_pframe = blockdev_file_fill_pframe,
+ .flush_pframe = blockdev_file_flush_pframe,
+};
+
+void init_special_vnode(vnode_t *vn)
+{
+ if (S_ISCHR(vn->vn_mode))
+ {
+ vn->vn_ops = &chardev_spec_vops;
+ vn->vn_dev.chardev = chardev_lookup(vn->vn_devid);
+ }
+ else
+ {
+ KASSERT(S_ISBLK(vn->vn_mode));
+ vn->vn_ops = &blockdev_spec_vops;
+ vn->vn_dev.blockdev = blockdev_lookup(vn->vn_devid);
+ }
+}
+
+static long special_file_stat(vnode_t *file, stat_t *ss)
+{
+ KASSERT(file->vn_fs->fs_root->vn_ops->stat != NULL);
+ // call the containing file system's stat routine
+ return file->vn_fs->fs_root->vn_ops->stat(file, ss);
+}
+
+/*
+ * Make a read by deferring to the underlying chardev and its read operation.
+ *
+ * Returns what the chardev's read returned.
+ *
+ * Hint: Watch out! chardev_file_read and chardev_file_write are indirectly
+ * called in do_read and do_write, respectively, as the read/write ops for
+ * chardev-type vnodes. This means that the vnode file should be locked
+ * upon entry to this function.
+ *
+ * However, tty_read and tty_write, the read/write ops for the tty chardev,
+ * are potentially blocking. To avoid deadlock, you should unlock the file
+ * before calling the chardev's read, and lock it again after. If you fail
+ * to do this, a shell reading from /dev/tty0 for instance, will block all
+ * access to the /dev/tty0 vnode. This means that if someone runs `ls /dev/`,
+ * while a shell is reading from `/dev/tty0`, the `ls` call will hang.
+ *
+ * Also, if a vnode represents a chardev, you can access the chardev using
+ * vnode->vn_dev.chardev.
+ *
+ */
+static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
+ size_t count)
+{
+ NOT_YET_IMPLEMENTED("VFS: ***none***");
+ return 0;
+}
+
+/*
+ * Make a write by deferring to the underlying chardev and its write operation.
+ *
+ * Return what the chardev's write returned.
+ *
+ * See the comments from chardev_file_read above for hints.
+ *
+ */
+static long chardev_file_write(vnode_t *file, size_t pos, const void *buf,
+ size_t count)
+{
+ NOT_YET_IMPLEMENTED("VFS: ***none***");
+ return 0;
+}
+
+/*
+ * For this and the following chardev functions, simply defer to the underlying
+ * chardev's corresponding operations.
+ */
+static long chardev_file_mmap(vnode_t *file, mobj_t **ret)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}
+
+static long chardev_file_fill_pframe(vnode_t *file, pframe_t *pf)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}
+
+static long chardev_file_flush_pframe(vnode_t *file, pframe_t *pf)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}
+
+static ssize_t blockdev_file_read(vnode_t *file, size_t pos, void *buf,
+ size_t count)
+{
+ return -ENOTSUP;
+}
+
+static long blockdev_file_write(vnode_t *file, size_t pos, const void *buf,
+ size_t count)
+{
+ return -ENOTSUP;
+}
+
+static long blockdev_file_mmap(vnode_t *file, mobj_t **ret) { return -ENOTSUP; }
+
+static long blockdev_file_fill_pframe(vnode_t *file, pframe_t *pf)
+{
+ return -ENOTSUP;
+}
+
+static long blockdev_file_flush_pframe(vnode_t *file, pframe_t *pf)
+{
+ return -ENOTSUP;
+}