aboutsummaryrefslogtreecommitdiff
path: root/kernel/include/fs
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/include/fs
Created student weenix repository
Diffstat (limited to 'kernel/include/fs')
-rw-r--r--kernel/include/fs/dirent.h25
-rw-r--r--kernel/include/fs/fcntl.h18
-rw-r--r--kernel/include/fs/file.h62
-rw-r--r--kernel/include/fs/lseek.h5
-rw-r--r--kernel/include/fs/open.h5
-rw-r--r--kernel/include/fs/pipe.h10
-rw-r--r--kernel/include/fs/ramfs/ramfs.h5
-rw-r--r--kernel/include/fs/s5fs/s5fs.h145
-rw-r--r--kernel/include/fs/s5fs/s5fs_privtest.h6
-rw-r--r--kernel/include/fs/s5fs/s5fs_subr.h53
-rw-r--r--kernel/include/fs/stat.h44
-rw-r--r--kernel/include/fs/vfs.h162
-rw-r--r--kernel/include/fs/vfs_privtest.h3
-rw-r--r--kernel/include/fs/vfs_syscall.h39
-rw-r--r--kernel/include/fs/vnode.h358
-rw-r--r--kernel/include/fs/vnode_specials.h0
16 files changed, 940 insertions, 0 deletions
diff --git a/kernel/include/fs/dirent.h b/kernel/include/fs/dirent.h
new file mode 100644
index 0000000..10fa845
--- /dev/null
+++ b/kernel/include/fs/dirent.h
@@ -0,0 +1,25 @@
+/* dirent.h - filesystem-independent directory entry
+ * mcc, kma, jal
+ */
+#pragma once
+
+/* Kernel and user header (via symlink) */
+
+#ifdef __KERNEL__
+#include "config.h"
+#include "types.h"
+#else
+
+#include "sys/types.h"
+#include "weenix/config.h"
+
+#endif
+
+typedef struct dirent
+{
+ ino_t d_ino; /* entry inode number */
+ off_t d_off; /* seek pointer of next entry */
+ char d_name[NAME_LEN]; /* filename */
+} dirent_t;
+
+#define d_fileno d_ino
diff --git a/kernel/include/fs/fcntl.h b/kernel/include/fs/fcntl.h
new file mode 100644
index 0000000..fd719f2
--- /dev/null
+++ b/kernel/include/fs/fcntl.h
@@ -0,0 +1,18 @@
+/* fcntl.h - File access bits
+ * mcc, jal
+ */
+
+#pragma once
+
+/* Kernel and user header (via symlink) */
+
+/* File access modes for open(). */
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#define O_ACCESSMODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+/* File status flags for open(). */
+#define O_CREAT 0x100 /* Create file if non-existent. */
+#define O_TRUNC 0x200 /* Truncate to zero length. */
+#define O_APPEND 0x400 /* Append to file. */
diff --git a/kernel/include/fs/file.h b/kernel/include/fs/file.h
new file mode 100644
index 0000000..72caee4
--- /dev/null
+++ b/kernel/include/fs/file.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "types.h"
+
+#define FMODE_READ 1
+#define FMODE_WRITE 2
+#define FMODE_APPEND 4
+#define FMODE_MAX_VALUE (FMODE_READ | FMODE_WRITE | FMODE_APPEND)
+
+struct vnode;
+
+typedef struct file
+{
+ /*
+ * The current position in the file. Can be modified by system calls
+ * like lseek(2), read(2), and write(2) (and possibly others) as
+ * described in the man pages of those calls.
+ */
+ size_t f_pos;
+
+ /*
+ * The mode in which this file was opened. This is a mask of the flags
+ * FMODE_READ, FMODE_WRITE, and FMODE_APPEND. It is set when the file
+ * is first opened, and use to restrict the operations that can be
+ * performed on the underlying vnode.
+ */
+ unsigned int f_mode;
+
+ /*
+ * The number of references to this struct.
+ */
+ size_t f_refcount;
+
+ /*
+ * The vnode which corresponds to this file.
+ */
+ struct vnode *f_vnode;
+} file_t;
+
+struct file *fcreate(int fd, struct vnode *vnode, unsigned int mode);
+
+/*
+ * Returns the file_t assiciated with the given file descriptor for the
+ * current process. If there is no associated file_t, returns NULL.
+ */
+struct file *fget(int fd);
+
+/*
+ * fref() increments the reference count on the given file.
+ */
+void fref(file_t *file);
+
+/*
+ * fput() decrements the reference count on the given file.
+ *
+ * If the refcount reaches 0, the storage for the given file_t will be
+ * released (f won't point to a valid memory address anymore), and the
+ * refcount on the associated vnode (if any) will be decremented.
+ *
+ * The vnode release operation will also be called if it exists.
+ */
+void fput(file_t **filep);
diff --git a/kernel/include/fs/lseek.h b/kernel/include/fs/lseek.h
new file mode 100644
index 0000000..3520e77
--- /dev/null
+++ b/kernel/include/fs/lseek.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
diff --git a/kernel/include/fs/open.h b/kernel/include/fs/open.h
new file mode 100644
index 0000000..fd10234
--- /dev/null
+++ b/kernel/include/fs/open.h
@@ -0,0 +1,5 @@
+#pragma once
+
+long do_open(const char *filename, int flags);
+
+long get_empty_fd(int *fd);
diff --git a/kernel/include/fs/pipe.h b/kernel/include/fs/pipe.h
new file mode 100644
index 0000000..61b9cc9
--- /dev/null
+++ b/kernel/include/fs/pipe.h
@@ -0,0 +1,10 @@
+/*
+ * FILE: pipe.h
+ * AUTH: eric
+ * DESC:
+ * DATE: Thu Dec 26 17:07:10 2013
+ */
+
+#pragma once
+
+int do_pipe(int pipefd[2]);
diff --git a/kernel/include/fs/ramfs/ramfs.h b/kernel/include/fs/ramfs/ramfs.h
new file mode 100644
index 0000000..b43f4eb
--- /dev/null
+++ b/kernel/include/fs/ramfs/ramfs.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "fs/vfs.h"
+
+long ramfs_mount(struct fs *fs);
diff --git a/kernel/include/fs/s5fs/s5fs.h b/kernel/include/fs/s5fs/s5fs.h
new file mode 100644
index 0000000..7bde185
--- /dev/null
+++ b/kernel/include/fs/s5fs/s5fs.h
@@ -0,0 +1,145 @@
+/*
+ * FILE: s5fs.h
+ * AUTHOR: kma
+ * DESCR: shared structures for the System V file system...
+ */
+
+#pragma once
+
+#ifdef __FSMAKER__
+#include <stdint.h>
+#else
+
+#include "config.h"
+
+#include "drivers/blockdev.h"
+#include "fs/vfs.h"
+#include "fs/vnode.h"
+#include "mm/page.h"
+#include "proc/kmutex.h"
+
+#endif
+
+#define S5_SUPER_BLOCK 0 /* the blockno of the superblock */
+#define S5_IS_SUPER(blkno) ((blkno) == S5_SUPER_BLOCK)
+
+#define S5_NBLKS_PER_FNODE 30
+
+#define S5_BLOCK_SIZE 4096
+#define S5_NDIRECT_BLOCKS 28
+#define S5_INODES_PER_BLOCK (S5_BLOCK_SIZE / sizeof(s5_inode_t))
+#define S5_DIRENTS_PER_BLOCK (S5_BLOCK_SIZE / sizeof(s5_dirent_t))
+#define S5_MAX_FILE_BLOCKS (S5_NDIRECT_BLOCKS + S5_NIDIRECT_BLOCKS)
+#define S5_MAX_FILE_SIZE (S5_MAX_FILE_BLOCKS * S5_BLOCK_SIZE)
+#define S5_NAME_LEN 28
+
+#define S5_TYPE_FREE 0x0
+#define S5_TYPE_DATA 0x1
+#define S5_TYPE_DIR 0x2
+#define S5_TYPE_CHR 0x4
+#define S5_TYPE_BLK 0x8
+
+#define S5_MAGIC 071177
+#define S5_CURRENT_VERSION 3
+
+/* Number of blocks stored in the indirect block */
+#define S5_NIDIRECT_BLOCKS (S5_BLOCK_SIZE / sizeof(uint32_t))
+
+/* Given a file offset, returns the block number that it is in */
+#define S5_DATA_BLOCK(seekptr) ((seekptr) / S5_BLOCK_SIZE)
+
+/* Given a file offset, returns the offset into the pointer's block */
+#define S5_DATA_OFFSET(seekptr) ((seekptr) % S5_BLOCK_SIZE)
+
+/* Given an inode number, tells the block that inode is stored in. */
+#define S5_INODE_BLOCK(inum) ((inum) / S5_INODES_PER_BLOCK + 1)
+
+/*
+ * Given an inode number, tells the offset (in units of s5_inode_t) of
+ * that inode within the block returned by S5_INODE_BLOCK.
+ */
+#define S5_INODE_OFFSET(inum) ((inum) % S5_INODES_PER_BLOCK)
+
+/* Given an FS struct, get the S5FS (private data) struct. */
+#define FS_TO_S5FS(fs) ((s5fs_t *)(fs)->fs_i)
+
+/* each node of the free block list looks like this: */
+/*
+typedef struct s5_fbl_node {
+ int free_blocks[S5_NBLKS_PER_FNODE-1];
+ int more;
+} s5_fbl_node_t;
+*/
+
+/* Note that all on-disk types need to have hard-coded sizes (to ensure
+ * inter-machine compatibility of s5 disks) */
+
+/* The contents of the superblock, as stored on disk. */
+typedef struct s5_super
+{
+ uint32_t s5s_magic; /* the magic number */
+ uint32_t s5s_free_inode; /* the free inode pointer */
+ uint32_t s5s_nfree; /* number of blocks currently in
+ * s5s_free_blocks */
+ /* First "node" of free block list */
+ uint32_t s5s_free_blocks[S5_NBLKS_PER_FNODE];
+
+ uint32_t s5s_root_inode; /* root inode */
+ uint32_t s5s_num_inodes; /* number of inodes */
+ uint32_t s5s_version; /* version of this disk format */
+} s5_super_t;
+
+/* The contents of an inode, as stored on disk. */
+typedef struct s5_inode
+{
+ union {
+ uint32_t s5_next_free; /* inode free list ptr */
+ uint32_t s5_size; /* file size */
+ } s5_un;
+ uint32_t s5_number; /* this inode's number */
+ uint16_t s5_type; /* one of S5_TYPE_{FREE,DATA,DIR,CHR,BLK} */
+ int16_t s5_linkcount; /* link count of this inode */
+ uint32_t s5_direct_blocks[S5_NDIRECT_BLOCKS];
+ uint32_t s5_indirect_block;
+} s5_inode_t;
+
+typedef struct s5_node
+{
+ vnode_t vnode;
+ s5_inode_t inode;
+ long dirtied_inode;
+} s5_node_t;
+
+#define VNODE_TO_S5NODE(vn) CONTAINER_OF(vn, s5_node_t, vnode)
+
+/* The contents of a directory entry, as stored on disk. */
+typedef struct s5_dirent
+{
+ uint32_t s5d_inode;
+ char s5d_name[S5_NAME_LEN];
+} s5_dirent_t;
+
+#ifndef __FSMAKER__
+/* Our in-memory representation of a s5fs filesytem (fs_i points to this) */
+typedef struct s5fs
+{
+ blockdev_t *s5f_bdev;
+ s5_super_t s5f_super;
+ kmutex_t s5f_mutex;
+ fs_t *s5f_fs;
+#ifndef OLD
+ mobj_t s5f_mobj;
+#endif
+} s5fs_t;
+
+long s5fs_mount(struct fs *fs);
+
+void s5_get_meta_disk_block(s5fs_t *s5fs, uint64_t blocknum, long forwrite,
+ pframe_t **pfp);
+
+//void s5_get_file_disk_block(vnode_t *vnode, blocknum_t blocknum, long forwrite,
+// pframe_t **pfp);
+
+void s5_release_disk_block(pframe_t **pfp);
+
+#endif
diff --git a/kernel/include/fs/s5fs/s5fs_privtest.h b/kernel/include/fs/s5fs/s5fs_privtest.h
new file mode 100644
index 0000000..38278ef
--- /dev/null
+++ b/kernel/include/fs/s5fs/s5fs_privtest.h
@@ -0,0 +1,6 @@
+#ifndef __S5FS_PRIVTEST_H
+#define __S5FS_PRIVTEST_H
+
+int s5fs_start(const char *testroot);
+
+#endif
diff --git a/kernel/include/fs/s5fs/s5fs_subr.h b/kernel/include/fs/s5fs/s5fs_subr.h
new file mode 100644
index 0000000..ff4c570
--- /dev/null
+++ b/kernel/include/fs/s5fs/s5fs_subr.h
@@ -0,0 +1,53 @@
+/*
+ * FILE: s5fs_subr.h
+ * AUTHOR: afenn
+ * DESCR: S5 low-level subroutines
+ */
+
+#pragma once
+
+#include "types.h"
+#include "mm/pframe.h"
+#include "fs/s5fs/s5fs.h"
+
+struct s5fs;
+struct s5_node;
+
+long s5_alloc_inode(struct s5fs *s5fs, uint16_t type, devid_t devid);
+
+void s5_free_inode(struct s5fs *s5fs, ino_t ino);
+
+ssize_t s5_read_file(struct s5_node *sn, size_t pos, char *buf, size_t len);
+
+ssize_t s5_write_file(struct s5_node *sn, size_t pos, const char *buf,
+ size_t len);
+
+long s5_link(struct s5_node *dir, const char *name, size_t namelen,
+ struct s5_node *child);
+
+long s5_find_dirent(struct s5_node *dir, const char *name, size_t namelen,
+ size_t *filepos);
+
+void s5_remove_dirent(struct s5_node *dir, const char *name, size_t namelen,
+ struct s5_node *ent);
+
+void s5_replace_dirent(struct s5_node *sn, const char *name, size_t namelen,
+ struct s5_node *old, struct s5_node *new);
+
+long s5_file_block_to_disk_block(struct s5_node *sn, size_t file_blocknum,
+ int alloc, int *new);
+
+long s5_inode_blocks(struct s5_node *vnode);
+
+void s5_remove_blocks(struct s5_node *vnode);
+
+/* Converts a vnode_t* to the s5fs_t* (s5fs file system) struct */
+#define VNODE_TO_S5FS(vn) ((s5fs_t *)((vn)->vn_fs->fs_i))
+
+#ifdef OLD
+/* Converts an s5fs_t* to its memory object (the memory object of the block device) */
+#define S5FS_TO_VMOBJ(s5fs) (&(s5fs)->s5f_bdev->bd_mobj)
+#endif
+
+
+pframe_t *s5_cache_and_clear_block(mobj_t *mo, long block, long loc);
diff --git a/kernel/include/fs/stat.h b/kernel/include/fs/stat.h
new file mode 100644
index 0000000..08e477d
--- /dev/null
+++ b/kernel/include/fs/stat.h
@@ -0,0 +1,44 @@
+/*
+ * FILE: stat.h
+ * AUTH: mcc
+ * DESC:
+ * DATE: Fri Mar 13 23:10:46 1998
+ */
+
+#pragma once
+
+/* Kernel and user header (via symlink) */
+
+typedef struct stat
+{
+ int st_mode;
+ int st_ino;
+ int st_dev;
+ int st_rdev;
+ int st_nlink;
+ int st_uid;
+ int st_gid;
+ int st_size;
+ int st_atime;
+ int st_mtime;
+ int st_ctime;
+ int st_blksize;
+ int st_blocks;
+} stat_t;
+
+/* vnode vn_mode masks */
+
+#define S_IFCHR 0x0100 /* character special */
+#define S_IFDIR 0x0200 /* directory */
+#define S_IFBLK 0x0400 /* block special */
+#define S_IFREG 0x0800 /* regular */
+#define S_IFLNK 0x1000 /* symlink */
+#define S_IFIFO 0x2000 /* fifo/pipe */
+
+#define _S_TYPE(m) ((m)&0xFF00)
+#define S_ISCHR(m) (_S_TYPE(m) == S_IFCHR)
+#define S_ISDIR(m) (_S_TYPE(m) == S_IFDIR)
+#define S_ISBLK(m) (_S_TYPE(m) == S_IFBLK)
+#define S_ISREG(m) (_S_TYPE(m) == S_IFREG)
+#define S_ISLNK(m) (_S_TYPE(m) == S_IFLNK)
+#define S_ISFIFO(m) (_S_TYPE(m) == S_IFIFO)
diff --git a/kernel/include/fs/vfs.h b/kernel/include/fs/vfs.h
new file mode 100644
index 0000000..23f418a
--- /dev/null
+++ b/kernel/include/fs/vfs.h
@@ -0,0 +1,162 @@
+#pragma once
+
+#include "types.h"
+
+#include "fs/open.h"
+#include "proc/kmutex.h"
+#include "util/list.h"
+
+struct vnode;
+struct file;
+struct vfs;
+struct fs;
+struct slab_allocator;
+
+/* name_match: fname should be null-terminated, name is namelen long */
+#define name_match(fname, name, namelen) \
+ (strlen(fname) == namelen && !strncmp((fname), (name), (namelen)))
+
+typedef struct fs_ops
+{
+ /*
+ * Initialize vn_ops, vn_mode, vn_devid and vn_len.
+ * If the filesystem wishes, it may initialize and use vn_i.
+ */
+ void (*read_vnode)(struct fs *fs, struct vnode *vn);
+
+ /*
+ * Called when the vnode's reference count drops to 0.
+ * Perform any necessary cleanup for the corresponding inode.
+ */
+ void (*delete_vnode)(struct fs *fs, struct vnode *vn);
+
+ /*
+ * Optional. Default behavior is to vput() fs_root.
+ * Unmount the filesystem, performing any desired sanity checks
+ * and/or necessary cleanup.
+ * Return 0 on success; negative number on error.
+ */
+ long (*umount)(struct fs *fs);
+
+ void (*sync)(struct fs *fs);
+} fs_ops_t;
+
+#ifndef STR_MAX
+#define STR_MAX 32
+#endif
+
+/* similar to Linux's super_block. */
+typedef struct fs
+{
+ /*
+ * The string name of the device from which this file system should
+ * be mounted. This may be used by the mount function of some file
+ * systems which need to know which device they are mounting.
+ */
+ char fs_dev[STR_MAX];
+ /*
+ * The type of file system this structure represents (given as a
+ * well-defined string). This is used by the generic VFS mount
+ * function to decide which filesystem-specific mount function to
+ * call. Valid values are hard-coded in vfs.c.
+ */
+ char fs_type[STR_MAX];
+
+#ifdef __MOUNTING__
+ /*
+ * If mounting is implemented then this should point to the vnode
+ * of the file that this file system is mounted on. For the root file
+ * system this will just point to the root of that file system.
+ */
+ struct vnode *fs_mtpt;
+
+ /*
+ * An identifier for the mounted file system. This should be enlisted
+ * by the the kernel to keep track of all mounted file systems.
+ */
+ list_link_t fs_link;
+#endif
+
+ /*
+ * The following members are initialized by the filesystem
+ * implementation's mount routine:
+ */
+
+ /*
+ * The struct of operations that define which filesystem-specific
+ * functions to call to perform filesystem manipulation.
+ */
+ fs_ops_t *fs_ops;
+
+ /*
+ * The root vnode for this filesystem (not to be confused with
+ * either / (the root of VFS) or the vnode where the filesystem is
+ * mounted, which is on a different file system.
+ */
+ struct vnode *fs_root;
+
+ /* Filesystem-specific data. */
+ void *fs_i;
+
+ struct slab_allocator *fs_vnode_allocator;
+ list_t vnode_list;
+ kmutex_t vnode_list_mutex;
+ kmutex_t vnode_rename_mutex;
+
+} fs_t;
+
+/* - this is the vnode on which we will mount the vfsroot fs.
+ */
+extern fs_t vfs_root_fs;
+
+void do_sync();
+
+/* VFS {{{ */
+/*
+ * - called by the init process at system shutdown
+ * - at this point, init process is the only process running
+ * => so, there should be no "live" vnodes
+ *
+ * unmount the root filesystem (and first unmount any filesystems mounted
+ * on the root filesystem in the proper order (bottom up)).
+ *
+ */
+
+/* VFS }}} */
+/* VFS Shutdown: */
+/*
+ * Called by the init process at system shutdown.
+ *
+ * At this point, the init process is the only process running
+ * => so, there should be no "live" vnodes
+ */
+long vfs_shutdown();
+
+/* Pathname resolution: */
+/* (the corresponding definitions live in namev.c) */
+long namev_lookup(struct vnode *dir, const char *name, size_t namelen,
+ struct vnode **out);
+
+long namev_dir(struct vnode *base, const char *path, struct vnode **res_vnode,
+ const char **name, size_t *namelen);
+
+long namev_open(struct vnode *base, const char *path, int oflags, int mode,
+ devid_t devid, struct vnode **res_vnode);
+
+long namev_resolve(struct vnode *base, const char *path,
+ struct vnode **res_vnode);
+
+long namev_get_child(struct vnode *dir, char *name, size_t namelen,
+ struct vnode **out);
+
+long namev_get_parent(struct vnode *dir, struct vnode **out);
+
+long namev_is_descendant(struct vnode *a, struct vnode *b);
+
+#ifdef __GETCWD__
+long lookup_name(struct vnode *dir, struct vnode *entry, char *buf,
+ size_t size);
+long lookup_dirpath(struct vnode *dir, char *buf, size_t size);
+#endif /* __GETCWD__ */
+
+long mountfunc(fs_t *fs);
diff --git a/kernel/include/fs/vfs_privtest.h b/kernel/include/fs/vfs_privtest.h
new file mode 100644
index 0000000..1b5fb0b
--- /dev/null
+++ b/kernel/include/fs/vfs_privtest.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void vfs_privtest(void);
diff --git a/kernel/include/fs/vfs_syscall.h b/kernel/include/fs/vfs_syscall.h
new file mode 100644
index 0000000..c5be65d
--- /dev/null
+++ b/kernel/include/fs/vfs_syscall.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "dirent.h"
+
+#include "types.h"
+
+#include "fs/open.h"
+#include "fs/pipe.h"
+#include "fs/stat.h"
+
+long do_close(int fd);
+
+ssize_t do_read(int fd, void *buf, size_t len);
+
+ssize_t do_write(int fd, const void *buf, size_t len);
+
+long do_dup(int fd);
+
+long do_dup2(int ofd, int nfd);
+
+long do_mknod(const char *path, int mode, devid_t devid);
+
+long do_mkdir(const char *path);
+
+long do_rmdir(const char *path);
+
+long do_unlink(const char *path);
+
+long do_link(const char *oldpath, const char *newpath);
+
+long do_rename(const char *oldpath, const char *newpath);
+
+long do_chdir(const char *path);
+
+ssize_t do_getdent(int fd, struct dirent *dirp);
+
+off_t do_lseek(int fd, off_t offset, int whence);
+
+long do_stat(const char *path, struct stat *uf);
diff --git a/kernel/include/fs/vnode.h b/kernel/include/fs/vnode.h
new file mode 100644
index 0000000..ff4b9be
--- /dev/null
+++ b/kernel/include/fs/vnode.h
@@ -0,0 +1,358 @@
+/*
+ * FILE: vnode.h
+ * AUTH: mcc
+ * DESC:
+ * DATE: Fri Mar 13 18:54:11 1998
+ * $Id: vnode.h,v 1.2.2.2 2006/06/04 01:02:32 afenn Exp $
+ */
+
+#pragma once
+
+#include "drivers/blockdev.h"
+#include "drivers/chardev.h"
+#include "drivers/dev.h"
+#include "mm/mobj.h"
+#include "mm/pframe.h"
+#include "proc/kmutex.h"
+#include "util/list.h"
+
+struct fs;
+struct dirent;
+struct stat;
+struct file;
+struct vnode;
+struct kmutex;
+
+#define VNODE_LOADING 0
+#define VNODE_LOADED 1
+
+typedef struct vnode_ops
+{
+ /* The following functions map directly to their corresponding
+ * system calls. Unless otherwise noted, they return 0 on
+ * success, and -errno on failure.
+ */
+
+ /* Operations that can be performed on non-directory files: */
+ /*
+ * read transfers at most count bytes from file into buf. It
+ * begins reading from the file at pos bytes into the file. On
+ * success, it returns the number of bytes transferred, or 0 if the
+ * end of the file has been reached (pos >= file->vn_len).
+ */
+ ssize_t (*read)(struct vnode *file, size_t pos, void *buf, size_t count);
+
+ /*
+ * write transfers count bytes from buf into file. It begins
+ * writing at pos bytes into the file. If offset+count extends
+ * past the end of the file, the file's length will be increased.
+ * If offset is before the end of the file, the existing data is
+ * overwritten. On success, it returns the number of bytes
+ * transferred.
+ */
+ ssize_t (*write)(struct vnode *file, size_t pos, const void *buf,
+ size_t count);
+
+ /*
+ * Implementations should supply an mobj through the "ret"
+ * argument (not by setting vma->vma_obj). If for any reason
+ * this cannot be done an appropriate error code should be
+ * returned instead.
+ */
+ long (*mmap)(struct vnode *file, struct mobj **ret);
+
+ /* Operations that can be performed on directory files: */
+
+ /*
+ * mknod creates a special specified by name and namelen in the
+ * directory pointed to by dir with the specified mode and devid.
+ *
+ * Upon success, ret must point to the newly created file.
+ */
+ long (*mknod)(struct vnode *dir, const char *name, size_t namelen, int mode,
+ devid_t devid, struct vnode **ret);
+
+ /*
+ * lookup attempts to find the file specified by name and namelen in the
+ * directory pointed to by dir.
+ *
+ * Upon success, ret must point to the child vnode.
+ */
+ long (*lookup)(struct vnode *dir, const char *name, size_t namelen,
+ struct vnode **out);
+
+ /*
+ * Creates a directory entry in dir specified by name and namelen pointing
+ * to the inode of target.
+ */
+ long (*link)(struct vnode *dir, const char *name, size_t namelen,
+ struct vnode *target);
+
+ /*
+ * unlink removes the directory entry in dir corresponding to the file
+ * specified by name and namelen.
+ */
+ long (*unlink)(struct vnode *dir, const char *name, size_t namelen);
+
+ /*
+ * rename
+ */
+ long (*rename)(struct vnode *olddir, const char *oldname, size_t oldnamelen,
+ struct vnode *newdir, const char *newname,
+ size_t newnamelen);
+
+ /*
+ * mkdir creates a directory specified by name and namelen in the
+ * directory pointed to by out.
+ *
+ * Upon success, out must point to the newly created directory.
+ * Upon failure, out must be unchanged.
+ */
+ long (*mkdir)(struct vnode *dir, const char *name, size_t namelen,
+ struct vnode **out);
+
+ /*
+ * rmdir removes the directory specified by name and namelen from dir.
+ * The directory to be removed must be empty: the only directory entries
+ * must be "." and "..".
+ */
+ long (*rmdir)(struct vnode *dir, const char *name, size_t namelen);
+
+ /*
+ * readdir reads one directory entry from the dir into the struct
+ * dirent. On success, it returns the amount that offset should be
+ * increased by to obtain the next directory entry with a
+ * subsequent call to readdir. If the end of the file as been
+ * reached (offset == file->vn_len), no directory entry will be
+ * read and 0 will be returned.
+ */
+ ssize_t (*readdir)(struct vnode *dir, size_t pos, struct dirent *d);
+
+ /* Operations that can be performed on any type of "file" (
+ * includes normal file, directory, block/byte device */
+ /*
+ * stat sets the fields in the given buf, filling it with
+ * information about file.
+ */
+ long (*stat)(struct vnode *vnode, struct stat *buf);
+
+ /*
+ * acquire is called on a vnode when a file takes its first
+ * reference to the vnode. The file is passed in.
+ */
+ long (*acquire)(struct vnode *vnode, struct file *file);
+
+ /*
+ * release is called on a vnode when the refcount of a file
+ * descriptor that has it open comes down to 0. Each call to
+ * acquire has exactly one matching call to release with the
+ * same file that was passed to acquire.
+ */
+ long (*release)(struct vnode *vnode, struct file *file);
+
+ long (*get_pframe)(struct vnode *vnode, size_t pagenum, long forwrite,
+ pframe_t **pfp);
+
+ /*
+ * Read the page of 'vnode' containing 'offset' into the
+ * page-aligned and page-sized buffer pointed to by
+ * 'buf'.
+ */
+ long (*fill_pframe)(struct vnode *vnode, pframe_t *pf);
+
+ /*
+ * Write the contents of the page-aligned and page-sized
+ * buffer pointed to by 'buf' to the page of 'vnode'
+ * containing 'offset'.
+ */
+ long (*flush_pframe)(struct vnode *vnode, pframe_t *pf);
+
+ /*
+ * This will truncate the file to have a length of zero
+ * Should only be used on regular files, not directories.
+ */
+ void (*truncate_file)(struct vnode *vnode);
+} vnode_ops_t;
+
+typedef struct vnode
+{
+ /*
+ * Function pointers to the implementations of file operations (the
+ * functions are provided by the filesystem implementation).
+ */
+ struct vnode_ops *vn_ops;
+
+ /*
+ * The filesystem to which this vnode belongs. This is initialized by
+ * the VFS subsystem when the vnode is first created and should never
+ * change.
+ */
+ struct fs *vn_fs;
+
+#ifdef __MOUNTING__
+ /* This field is used only for implementing mount points (not required) */
+ /* This field points the the root of the file system mounted at
+ * this vnode. If no file system is mounted at this point this is a
+ * self pointer (i.e. vn->vn_mount = vn). See vget for why this is
+ * makes things easier for us. */
+ struct vnode *vn_mount;
+#endif
+
+ /*
+ * The object responsible for managing the memory where pages read
+ * from this file reside. The VFS subsystem may use this field, but it
+ * does not need to create it.
+ */
+ struct mobj vn_mobj;
+
+ /*
+ * A number which uniquely identifies this vnode within its filesystem.
+ * (Similar and usually identical to what you might know as the inode
+ * number of a file).
+ */
+ ino_t vn_vno;
+
+ /*
+ * File type. See stat.h.
+ */
+ int vn_mode;
+
+ /*
+ * Length of file. Initialized at the fs-implementation-level (in the
+ * 'read_vnode' fs_t entry point). Maintained at the filesystem
+ * implementation level (within the implementations of relevant vnode
+ * entry points).
+ */
+ size_t vn_len;
+
+ /*
+ * A generic pointer which the file system can use to store any extra
+ * data it needs.
+ */
+ void *vn_i;
+
+ /*
+ * The device identifier.
+ * Only relevant to vnodes representing device files.
+ */
+ devid_t vn_devid;
+
+ /*
+ * The state of the vnode. Can either be loading or loaded. The vnode
+ * cannot be used until the vnode is in the loaded state. Potential
+ * users should wait on `vn_waitq` if the vnode is being loaded.
+ * This field is protected by the 'vn_state_lock'.
+ */
+ int vn_state;
+
+ /*
+ * Allows vnode users to wait on the vnode, until the vnode is ready.
+ */
+ ktqueue_t vn_waitq;
+
+ union {
+ chardev_t *chardev;
+ blockdev_t *blockdev;
+ } vn_dev;
+
+ /* Used (only) by the v{get,ref,put} facilities (vfs/vnode.c): */
+ list_link_t vn_link; /* link on system vnode list */
+} vnode_t;
+
+void init_special_vnode(vnode_t *vn);
+
+/* Core vnode management routines: */
+/*
+ * Obtain a vnode representing the file that filesystem 'fs' identifies
+ * by inode number 'vnum'; returns the vnode_t corresponding to the
+ * given filesystem and vnode number. If a vnode for the given file
+ * already exists (it already has an entry in the system inode table) then
+ * the reference count of that vnode is incremented and it is returned.
+ * Otherwise a new vnode is created in the system inode table with a
+ * reference count of 1.
+ * This function has no unsuccessful return.
+ *
+ * MAY BLOCK.
+ */
+struct vnode *vget(struct fs *fs, ino_t vnum);
+
+/*
+ * Lock a vnode (locks vn_mobj).
+ */
+void vlock(vnode_t *vn);
+
+/*
+ * Lock two vnodes in order! This prevents the A/B locking problem when locking
+ * two directories or two files.
+ */
+void vlock_in_order(vnode_t *a, vnode_t *b);
+
+/*
+ * Acquires a vnode locked (see vget above)
+ */
+vnode_t *vget_locked(struct fs *fs, ino_t ino);
+
+/**
+ * Unlock and put a vnode (see vput)
+ */
+void vput_locked(struct vnode **vnp);
+
+/**
+ * Unlocks a vnode
+ */
+void vunlock(vnode_t *vn);
+
+/**
+ * Unlocks two vnodes (effectively just 2 unlocks)
+ */
+void vunlock_in_order(vnode_t *a, vnode_t *b);
+
+/*
+ * Increments the reference count of the provided vnode
+ * (i.e. the refcount of vn_mobj).
+ */
+void vref(vnode_t *vn);
+
+/*
+ * This function decrements the reference count on this vnode
+ * (i.e. the refcount of vn_mobj).
+ *
+ * If, as a result of this, refcount reaches zero, the underlying
+ * fs's 'delete_vnode' entry point will be called and the vnode will be
+ * freed.
+ *
+ * If the linkcount of the corresponding on inode on the filesystem is zero,
+ * then the inode will be freed.
+ *
+ */
+void vput(vnode_t **vnp);
+
+/* Auxilliary: */
+
+/* Unmounting (shutting down the VFS) is the primary reason for the
+ * existence of the following three routines (when unmounting an s5 fs,
+ * they are used in the order that they are listed here): */
+/*
+ * Checks to see if there are any actively-referenced vnodes
+ * belonging to the specified filesystem.
+ * Returns -EBUSY if there is at least one such actively-referenced
+ * vnode, and 0 otherwise.
+ *
+ */
+long vfs_is_in_use(struct fs *fs);
+
+/*
+ * Returns the number of vnodes from this filesystem that are in
+ * use.
+ */
+size_t vfs_count_active_vnodes(struct fs *fs);
+
+/* Diagnostic: */
+/*
+ * Prints the vnodes that are in use. Specifying a fs_t will restrict
+ * the vnodes to just that fs. Specifying NULL will print all vnodes
+ * in the entire system.
+ *
+ * Note that this is currently unimplemented.
+ */
+void vnode_print(struct fs *fs);
diff --git a/kernel/include/fs/vnode_specials.h b/kernel/include/fs/vnode_specials.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kernel/include/fs/vnode_specials.h